* [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem
@ 2026-04-21 2:18 Jakub Kicinski
2026-04-21 6:04 ` Greg KH
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Jakub Kicinski @ 2026-04-21 2:18 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, Jakub Kicinski,
corbet, skhan, federico.vaga, carlos.bilbao, avadhut.naik, alexs,
si.yanteng, dzm91, 2023002089, tsbogend, dsahern, jani.nikula,
mchehab+huawei, gregkh, jirislaby, tytso, herbert, ebiggers,
johannes.berg, geert, pablo, tglx, mashiro.chen, mingo, dqfext,
jreuter, sdf, pkshih, enelsonmoore, mkl, toke, kees, crossd,
jlayton, wangliang74, aha310510, takamitz, kuniyu, linux-doc,
linux-mips
Remove the amateur radio (AX.25, NET/ROM, ROSE) protocol implementation
and all associated hamradio device drivers from the kernel tree.
This set of protocols has long been a huge bug/syzbot magnet,
and since nobody stepped up to help us deal with the influx
of the AI-generated bug reports we need to move it out of tree
to protect our sanity.
The code is moved to an out-of-tree repo:
https://github.com/linux-netdev/mod-orphan
if it's cleaned up and reworked there we can accept it back.
Minimal stub headers are kept for include/net/ax25.h (AX25_P_IP,
AX25_ADDR_LEN, ax25_address) and include/net/rose.h (ROSE_ADDR_LEN)
so that the conditional integration code in arp.c and tun.c continues
to compile and work when the out-of-tree modules are loaded.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: corbet@lwn.net
CC: skhan@linuxfoundation.org
CC: federico.vaga@vaga.pv.it
CC: carlos.bilbao@kernel.org
CC: avadhut.naik@amd.com
CC: alexs@kernel.org
CC: si.yanteng@linux.dev
CC: dzm91@hust.edu.cn
CC: 2023002089@link.tyut.edu.cn
CC: tsbogend@alpha.franken.de
CC: dsahern@kernel.org
CC: jani.nikula@intel.com
CC: mchehab+huawei@kernel.org
CC: gregkh@linuxfoundation.org
CC: jirislaby@kernel.org
CC: tytso@mit.edu
CC: herbert@gondor.apana.org.au
CC: ebiggers@kernel.org
CC: johannes.berg@intel.com
CC: geert@linux-m68k.org
CC: pablo@netfilter.org
CC: tglx@kernel.org
CC: mashiro.chen@mailbox.org
CC: mingo@kernel.org
CC: dqfext@gmail.com
CC: jreuter@yaina.de
CC: sdf@fomichev.me
CC: pkshih@realtek.com
CC: enelsonmoore@gmail.com
CC: mkl@pengutronix.de
CC: toke@toke.dk
CC: kees@kernel.org
CC: crossd@gmail.com
CC: jlayton@kernel.org
CC: wangliang74@huawei.com
CC: aha310510@gmail.com
CC: takamitz@amazon.co.jp
CC: kuniyu@google.com
CC: linux-doc@vger.kernel.org
CC: linux-mips@vger.kernel.org
---
MAINTAINERS | 73 -
Documentation/.renames.txt | 2 -
.../admin-guide/kernel-parameters.txt | 18 -
Documentation/networking/6pack.rst | 191 --
Documentation/networking/ax25.rst | 17 -
.../device_drivers/hamradio/baycom.rst | 174 --
.../device_drivers/hamradio/index.rst | 12 -
.../device_drivers/hamradio/z8530drv.rst | 686 ------
.../networking/device_drivers/index.rst | 1 -
Documentation/networking/index.rst | 2 -
Documentation/staging/magic-number.rst | 3 -
.../it_IT/staging/magic-number.rst | 3 -
.../sp_SP/process/magic-number.rst | 3 -
.../zh_CN/process/magic-number.rst | 3 -
.../zh_TW/process/magic-number.rst | 3 -
drivers/net/hamradio/Kconfig | 162 --
net/Kconfig | 1 -
net/ax25/Kconfig | 108 -
drivers/net/Makefile | 1 -
drivers/net/hamradio/Makefile | 22 -
net/Makefile | 3 -
net/ax25/Makefile | 12 -
net/netrom/Makefile | 10 -
net/rose/Makefile | 10 -
drivers/net/hamradio/z8530.h | 246 --
include/linux/hdlcdrv.h | 276 ---
include/linux/netdevice.h | 5 +-
include/linux/scc.h | 86 -
include/linux/yam.h | 67 -
include/net/ax25.h | 476 +---
include/net/netrom.h | 273 ---
include/net/rose.h | 263 +-
include/uapi/linux/baycom.h | 40 -
include/uapi/linux/hdlcdrv.h | 111 -
include/uapi/linux/netrom.h | 37 -
include/uapi/linux/rose.h | 91 -
include/uapi/linux/scc.h | 174 --
drivers/net/hamradio/6pack.c | 912 -------
drivers/net/hamradio/baycom_epp.c | 1316 ----------
drivers/net/hamradio/baycom_par.c | 598 -----
drivers/net/hamradio/baycom_ser_fdx.c | 678 -----
drivers/net/hamradio/baycom_ser_hdx.c | 727 ------
drivers/net/hamradio/bpqether.c | 593 -----
drivers/net/hamradio/hdlcdrv.c | 747 ------
drivers/net/hamradio/mkiss.c | 980 --------
drivers/net/hamradio/scc.c | 2179 -----------------
drivers/net/hamradio/yam.c | 1191 ---------
net/ax25/af_ax25.c | 2089 ----------------
net/ax25/ax25_addr.c | 303 ---
net/ax25/ax25_dev.c | 200 --
net/ax25/ax25_ds_in.c | 298 ---
net/ax25/ax25_ds_subr.c | 204 --
net/ax25/ax25_ds_timer.c | 235 --
net/ax25/ax25_iface.c | 214 --
net/ax25/ax25_in.c | 455 ----
net/ax25/ax25_ip.c | 247 --
net/ax25/ax25_out.c | 398 ---
net/ax25/ax25_route.c | 416 ----
net/ax25/ax25_std_in.c | 443 ----
net/ax25/ax25_std_subr.c | 83 -
net/ax25/ax25_std_timer.c | 175 --
net/ax25/ax25_subr.c | 296 ---
net/ax25/ax25_timer.c | 224 --
net/ax25/ax25_uid.c | 204 --
net/ax25/sysctl_net_ax25.c | 181 --
net/ipv4/arp.c | 1 -
net/netrom/af_netrom.c | 1536 ------------
net/netrom/nr_dev.c | 178 --
net/netrom/nr_in.c | 301 ---
net/netrom/nr_loopback.c | 73 -
net/netrom/nr_out.c | 272 --
net/netrom/nr_route.c | 989 --------
net/netrom/nr_subr.c | 280 ---
net/netrom/nr_timer.c | 249 --
net/netrom/sysctl_net_netrom.c | 156 --
net/rose/af_rose.c | 1687 -------------
net/rose/rose_dev.c | 141 --
net/rose/rose_in.c | 301 ---
net/rose/rose_link.c | 289 ---
net/rose/rose_loopback.c | 133 -
net/rose/rose_out.c | 122 -
net/rose/rose_route.c | 1333 ----------
net/rose/rose_subr.c | 556 -----
net/rose/rose_timer.c | 227 --
net/rose/sysctl_net_rose.c | 125 -
arch/mips/configs/bcm47xx_defconfig | 1 -
arch/mips/configs/bigsur_defconfig | 10 -
arch/mips/configs/gpr_defconfig | 11 -
arch/mips/configs/mtx1_defconfig | 11 -
arch/mips/configs/rb532_defconfig | 1 -
arch/mips/configs/rm200_defconfig | 7 -
arch/mips/configs/rt305x_defconfig | 1 -
arch/mips/configs/xway_defconfig | 1 -
93 files changed, 6 insertions(+), 29237 deletions(-)
delete mode 100644 Documentation/networking/6pack.rst
delete mode 100644 Documentation/networking/ax25.rst
delete mode 100644 Documentation/networking/device_drivers/hamradio/baycom.rst
delete mode 100644 Documentation/networking/device_drivers/hamradio/index.rst
delete mode 100644 Documentation/networking/device_drivers/hamradio/z8530drv.rst
delete mode 100644 drivers/net/hamradio/Kconfig
delete mode 100644 net/ax25/Kconfig
delete mode 100644 drivers/net/hamradio/Makefile
delete mode 100644 net/ax25/Makefile
delete mode 100644 net/netrom/Makefile
delete mode 100644 net/rose/Makefile
delete mode 100644 drivers/net/hamradio/z8530.h
delete mode 100644 include/linux/hdlcdrv.h
delete mode 100644 include/linux/scc.h
delete mode 100644 include/linux/yam.h
delete mode 100644 include/net/netrom.h
delete mode 100644 include/uapi/linux/baycom.h
delete mode 100644 include/uapi/linux/hdlcdrv.h
delete mode 100644 include/uapi/linux/netrom.h
delete mode 100644 include/uapi/linux/rose.h
delete mode 100644 include/uapi/linux/scc.h
delete mode 100644 drivers/net/hamradio/6pack.c
delete mode 100644 drivers/net/hamradio/baycom_epp.c
delete mode 100644 drivers/net/hamradio/baycom_par.c
delete mode 100644 drivers/net/hamradio/baycom_ser_fdx.c
delete mode 100644 drivers/net/hamradio/baycom_ser_hdx.c
delete mode 100644 drivers/net/hamradio/bpqether.c
delete mode 100644 drivers/net/hamradio/hdlcdrv.c
delete mode 100644 drivers/net/hamradio/mkiss.c
delete mode 100644 drivers/net/hamradio/scc.c
delete mode 100644 drivers/net/hamradio/yam.c
delete mode 100644 net/ax25/af_ax25.c
delete mode 100644 net/ax25/ax25_addr.c
delete mode 100644 net/ax25/ax25_dev.c
delete mode 100644 net/ax25/ax25_ds_in.c
delete mode 100644 net/ax25/ax25_ds_subr.c
delete mode 100644 net/ax25/ax25_ds_timer.c
delete mode 100644 net/ax25/ax25_iface.c
delete mode 100644 net/ax25/ax25_in.c
delete mode 100644 net/ax25/ax25_ip.c
delete mode 100644 net/ax25/ax25_out.c
delete mode 100644 net/ax25/ax25_route.c
delete mode 100644 net/ax25/ax25_std_in.c
delete mode 100644 net/ax25/ax25_std_subr.c
delete mode 100644 net/ax25/ax25_std_timer.c
delete mode 100644 net/ax25/ax25_subr.c
delete mode 100644 net/ax25/ax25_timer.c
delete mode 100644 net/ax25/ax25_uid.c
delete mode 100644 net/ax25/sysctl_net_ax25.c
delete mode 100644 net/netrom/af_netrom.c
delete mode 100644 net/netrom/nr_dev.c
delete mode 100644 net/netrom/nr_in.c
delete mode 100644 net/netrom/nr_loopback.c
delete mode 100644 net/netrom/nr_out.c
delete mode 100644 net/netrom/nr_route.c
delete mode 100644 net/netrom/nr_subr.c
delete mode 100644 net/netrom/nr_timer.c
delete mode 100644 net/netrom/sysctl_net_netrom.c
delete mode 100644 net/rose/af_rose.c
delete mode 100644 net/rose/rose_dev.c
delete mode 100644 net/rose/rose_in.c
delete mode 100644 net/rose/rose_link.c
delete mode 100644 net/rose/rose_loopback.c
delete mode 100644 net/rose/rose_out.c
delete mode 100644 net/rose/rose_route.c
delete mode 100644 net/rose/rose_subr.c
delete mode 100644 net/rose/rose_timer.c
delete mode 100644 net/rose/sysctl_net_rose.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 66f29cde4985..cfcf422dd40a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -102,12 +102,6 @@ F: Documentation/networking/6lowpan.rst
F: include/net/6lowpan.h
F: net/6lowpan/
-6PACK NETWORK DRIVER FOR AX.25
-M: Andreas Koensgen <ajk@comnets.uni-bremen.de>
-L: linux-hams@vger.kernel.org
-S: Maintained
-F: drivers/net/hamradio/6pack.c
-
802.11 (including CFG80211/NL80211)
M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org
@@ -4281,14 +4275,6 @@ S: Maintained
F: Documentation/devicetree/bindings/leds/backlight/awinic,aw99706.yaml
F: drivers/video/backlight/aw99706.c
-AX.25 NETWORK LAYER
-L: linux-hams@vger.kernel.org
-S: Orphan
-W: https://linux-ax25.in-berlin.de
-F: include/net/ax25.h
-F: include/uapi/linux/ax25.h
-F: net/ax25/
-
AXENTIA ARM DEVICES
M: Peter Rosin <peda@axentia.se>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -4430,13 +4416,6 @@ F: include/uapi/linux/batadv_packet.h
F: include/uapi/linux/batman_adv.h
F: net/batman-adv/
-BAYCOM/HDLCDRV DRIVERS FOR AX.25
-M: Thomas Sailer <t.sailer@alumni.ethz.ch>
-L: linux-hams@vger.kernel.org
-S: Maintained
-W: http://www.baycom.org/~tom/ham/ham.html
-F: drivers/net/hamradio/baycom*
-
BCACHE (BLOCK LAYER CACHE)
M: Coly Li <colyli@fnnas.com>
M: Kent Overstreet <kent.overstreet@linux.dev>
@@ -7020,20 +6999,6 @@ S: Maintained
F: drivers/rtc/rtc-ds1685.c
F: include/linux/rtc/ds1685.h
-DAMA SLAVE for AX.25
-M: Joerg Reuter <jreuter@yaina.de>
-L: linux-hams@vger.kernel.org
-S: Maintained
-W: http://yaina.de/jreuter/
-W: http://www.qsl.net/dl1bke/
-F: net/ax25/af_ax25.c
-F: net/ax25/ax25_dev.c
-F: net/ax25/ax25_ds_*
-F: net/ax25/ax25_in.c
-F: net/ax25/ax25_out.c
-F: net/ax25/ax25_timer.c
-F: net/ax25/sysctl_net_ax25.c
-
DASHARO ACPI PLATFORM DRIVER
M: Michał Kopeć <michal.kopec@3mdeb.com>
S: Maintained
@@ -11444,11 +11409,6 @@ T: git https://github.com/Rust-for-Linux/linux.git timekeeping-next
F: rust/kernel/time.rs
F: rust/kernel/time/
-HIGH-SPEED SCC DRIVER FOR AX.25
-L: linux-hams@vger.kernel.org
-S: Orphan
-F: drivers/net/hamradio/scc.c
-
HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
M: HighPoint Linux Team <linux@highpoint-tech.com>
S: Supported
@@ -18272,14 +18232,6 @@ F: net/bridge/br_netfilter*.c
F: net/netfilter/
F: tools/testing/selftests/net/netfilter/
-NETROM NETWORK LAYER
-L: linux-hams@vger.kernel.org
-S: Orphan
-W: https://linux-ax25.in-berlin.de
-F: include/net/netrom.h
-F: include/uapi/linux/netrom.h
-F: net/netrom/
-
NETRONIX EMBEDDED CONTROLLER
M: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
S: Maintained
@@ -23072,14 +23024,6 @@ F: include/linux/mfd/rohm-bd96802.h
F: include/linux/mfd/rohm-generic.h
F: include/linux/mfd/rohm-shared.h
-ROSE NETWORK LAYER
-L: linux-hams@vger.kernel.org
-S: Orphan
-W: https://linux-ax25.in-berlin.de
-F: include/net/rose.h
-F: include/uapi/linux/rose.h
-F: net/rose/
-
ROTATION DRIVER FOR ALLWINNER A83T
M: Jernej Skrabec <jernej.skrabec@gmail.com>
L: linux-media@vger.kernel.org
@@ -29105,13 +29049,6 @@ F: lib/decompress_unxz.c
F: lib/xz/
F: scripts/xz_wrap.sh
-YAM DRIVER FOR AX.25
-M: Jean-Paul Roubelat <jpr@f6fbb.org>
-L: linux-hams@vger.kernel.org
-S: Maintained
-F: drivers/net/hamradio/yam*
-F: include/linux/yam.h
-
YAMA SECURITY MODULE
M: Kees Cook <kees@kernel.org>
S: Supported
@@ -29133,16 +29070,6 @@ S: Maintained
F: Documentation/input/devices/yealink.rst
F: drivers/input/misc/yealink.*
-Z8530 DRIVER FOR AX.25
-M: Joerg Reuter <jreuter@yaina.de>
-L: linux-hams@vger.kernel.org
-S: Maintained
-W: http://yaina.de/jreuter/
-W: http://www.qsl.net/dl1bke/
-F: Documentation/networking/device_drivers/hamradio/z8530drv.rst
-F: drivers/net/hamradio/*scc.c
-F: drivers/net/hamradio/z8530.h
-
ZD1211RW WIRELESS DRIVER
L: linux-wireless@vger.kernel.org
S: Orphan
diff --git a/Documentation/.renames.txt b/Documentation/.renames.txt
index c4de5200abdb..df4db1121995 100644
--- a/Documentation/.renames.txt
+++ b/Documentation/.renames.txt
@@ -783,7 +783,6 @@ namespaces/compatibility-list admin-guide/namespaces/compatibility-list
namespaces/index admin-guide/namespaces/index
namespaces/resource-control admin-guide/namespaces/resource-control
networking/altera_tse networking/device_drivers/ethernet/altera/altera_tse
-networking/baycom networking/device_drivers/hamradio/baycom
networking/bpf_flow_dissector bpf/prog_flow_dissector
networking/cxacru networking/device_drivers/atm/cxacru
networking/defza networking/device_drivers/fddi/defza
@@ -846,7 +845,6 @@ networking/ixgbe networking/device_drivers/ethernet/intel/ixgbe
networking/ixgbevf networking/device_drivers/ethernet/intel/ixgbevf
networking/netdev-FAQ process/maintainer-netdev
networking/skfp networking/device_drivers/fddi/skfp
-networking/z8530drv networking/device_drivers/hamradio/z8530drv
nfc/index driver-api/nfc/index
nfc/nfc-hci driver-api/nfc/nfc-hci
nfc/nfc-pn544 driver-api/nfc/nfc-pn544
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index f2ce1f4975c1..09354ff7cff2 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6,7 +6,6 @@
APPARMOR AppArmor support is enabled.
ARM ARM architecture is enabled.
ARM64 ARM64 architecture is enabled.
- AX25 Appropriate AX.25 support is enabled.
CLK Common clock infrastructure is enabled.
CMA Contiguous Memory Area support is enabled.
DRM Direct Rendering Management support is enabled.
@@ -633,23 +632,6 @@ Kernel parameters
1 - Enable the BAU.
unset - Disable the BAU.
- baycom_epp= [HW,AX25]
- Format: <io>,<mode>
-
- baycom_par= [HW,AX25] BayCom Parallel Port AX.25 Modem
- Format: <io>,<mode>
- See header of drivers/net/hamradio/baycom_par.c.
-
- baycom_ser_fdx= [HW,AX25]
- BayCom Serial Port AX.25 Modem (Full Duplex Mode)
- Format: <io>,<irq>,<mode>[,<baud>]
- See header of drivers/net/hamradio/baycom_ser_fdx.c.
-
- baycom_ser_hdx= [HW,AX25]
- BayCom Serial Port AX.25 Modem (Half Duplex Mode)
- Format: <io>,<irq>,<mode>
- See header of drivers/net/hamradio/baycom_ser_hdx.c.
-
bdev_allow_write_mounted=
Format: <bool>
Control the ability to open a mounted block device
diff --git a/Documentation/networking/6pack.rst b/Documentation/networking/6pack.rst
deleted file mode 100644
index 66d5fd4fc821..000000000000
--- a/Documentation/networking/6pack.rst
+++ /dev/null
@@ -1,191 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-==============
-6pack Protocol
-==============
-
-This is the 6pack-mini-HOWTO, written by
-
-Andreas Könsgen DG3KQ
-
-:Internet: ajk@comnets.uni-bremen.de
-:AMPR-net: dg3kq@db0pra.ampr.org
-:AX.25: dg3kq@db0ach.#nrw.deu.eu
-
-Last update: April 7, 1998
-
-1. What is 6pack, and what are the advantages to KISS?
-======================================================
-
-6pack is a transmission protocol for data exchange between the PC and
-the TNC over a serial line. It can be used as an alternative to KISS.
-
-6pack has two major advantages:
-
-- The PC is given full control over the radio
- channel. Special control data is exchanged between the PC and the TNC so
- that the PC knows at any time if the TNC is receiving data, if a TNC
- buffer underrun or overrun has occurred, if the PTT is
- set and so on. This control data is processed at a higher priority than
- normal data, so a data stream can be interrupted at any time to issue an
- important event. This helps to improve the channel access and timing
- algorithms as everything is computed in the PC. It would even be possible
- to experiment with something completely different from the known CSMA and
- DAMA channel access methods.
- This kind of real-time control is especially important to supply several
- TNCs that are connected between each other and the PC by a daisy chain
- (however, this feature is not supported yet by the Linux 6pack driver).
-
-- Each packet transferred over the serial line is supplied with a checksum,
- so it is easy to detect errors due to problems on the serial line.
- Received packets that are corrupt are not passed on to the AX.25 layer.
- Damaged packets that the TNC has received from the PC are not transmitted.
-
-More details about 6pack are described in the file 6pack.ps that is located
-in the doc directory of the AX.25 utilities package.
-
-2. Who has developed the 6pack protocol?
-========================================
-
-The 6pack protocol has been developed by Ekki Plicht DF4OR, Henning Rech
-DF9IC and Gunter Jost DK7WJ. A driver for 6pack, written by Gunter Jost and
-Matthias Welwarsky DG2FEF, comes along with the PC version of FlexNet.
-They have also written a firmware for TNCs to perform the 6pack
-protocol (see section 4 below).
-
-3. Where can I get the latest version of 6pack for LinuX?
-=========================================================
-
-At the moment, the 6pack stuff can obtained via anonymous ftp from
-db0bm.automation.fh-aachen.de. In the directory /incoming/dg3kq,
-there is a file named 6pack.tgz.
-
-4. Preparing the TNC for 6pack operation
-========================================
-
-To be able to use 6pack, a special firmware for the TNC is needed. The EPROM
-of a newly bought TNC does not contain 6pack, so you will have to
-program an EPROM yourself. The image file for 6pack EPROMs should be
-available on any packet radio box where PC/FlexNet can be found. The name of
-the file is 6pack.bin. This file is copyrighted and maintained by the FlexNet
-team. It can be used under the terms of the license that comes along
-with PC/FlexNet. Please do not ask me about the internals of this file as I
-don't know anything about it. I used a textual description of the 6pack
-protocol to program the Linux driver.
-
-TNCs contain a 64kByte EPROM, the lower half of which is used for
-the firmware/KISS. The upper half is either empty or is sometimes
-programmed with software called TAPR. In the latter case, the TNC
-is supplied with a DIP switch so you can easily change between the
-two systems. When programming a new EPROM, one of the systems is replaced
-by 6pack. It is useful to replace TAPR, as this software is rarely used
-nowadays. If your TNC is not equipped with the switch mentioned above, you
-can build in one yourself that switches over the highest address pin
-of the EPROM between HIGH and LOW level. After having inserted the new EPROM
-and switched to 6pack, apply power to the TNC for a first test. The connect
-and the status LED are lit for about a second if the firmware initialises
-the TNC correctly.
-
-5. Building and installing the 6pack driver
-===========================================
-
-The driver has been tested with kernel version 2.1.90. Use with older
-kernels may lead to a compilation error because the interface to a kernel
-function has been changed in the 2.1.8x kernels.
-
-How to turn on 6pack support:
------------------------------
-
-- In the linux kernel configuration program, select the code maturity level
- options menu and turn on the prompting for development drivers.
-
-- Select the amateur radio support menu and turn on the serial port 6pack
- driver.
-
-- Compile and install the kernel and the modules.
-
-To use the driver, the kissattach program delivered with the AX.25 utilities
-has to be modified.
-
-- Do a cd to the directory that holds the kissattach sources. Edit the
- kissattach.c file. At the top, insert the following lines::
-
- #ifndef N_6PACK
- #define N_6PACK (N_AX25+1)
- #endif
-
- Then find the line:
-
- int disc = N_AX25;
-
- and replace N_AX25 by N_6PACK.
-
-- Recompile kissattach. Rename it to spattach to avoid confusions.
-
-Installing the driver:
-----------------------
-
-- Do an insmod 6pack. Look at your /var/log/messages file to check if the
- module has printed its initialization message.
-
-- Do a spattach as you would launch kissattach when starting a KISS port.
- Check if the kernel prints the message '6pack: TNC found'.
-
-- From here, everything should work as if you were setting up a KISS port.
- The only difference is that the network device that represents
- the 6pack port is called sp instead of sl or ax. So, sp0 would be the
- first 6pack port.
-
-Although the driver has been tested on various platforms, I still declare it
-ALPHA. BE CAREFUL! Sync your disks before insmoding the 6pack module
-and spattaching. Watch out if your computer behaves strangely. Read section
-6 of this file about known problems.
-
-Note that the connect and status LEDs of the TNC are controlled in a
-different way than they are when the TNC is used with PC/FlexNet. When using
-FlexNet, the connect LED is on if there is a connection; the status LED is
-on if there is data in the buffer of the PC's AX.25 engine that has to be
-transmitted. Under Linux, the 6pack layer is beyond the AX.25 layer,
-so the 6pack driver doesn't know anything about connects or data that
-has not yet been transmitted. Therefore the LEDs are controlled
-as they are in KISS mode: The connect LED is turned on if data is transferred
-from the PC to the TNC over the serial line, the status LED if data is
-sent to the PC.
-
-6. Known problems
-=================
-
-When testing the driver with 2.0.3x kernels and
-operating with data rates on the radio channel of 9600 Baud or higher,
-the driver may, on certain systems, sometimes print the message '6pack:
-bad checksum', which is due to data loss if the other station sends two
-or more subsequent packets. I have been told that this is due to a problem
-with the serial driver of 2.0.3x kernels. I don't know yet if the problem
-still exists with 2.1.x kernels, as I have heard that the serial driver
-code has been changed with 2.1.x.
-
-When shutting down the sp interface with ifconfig, the kernel crashes if
-there is still an AX.25 connection left over which an IP connection was
-running, even if that IP connection is already closed. The problem does not
-occur when there is a bare AX.25 connection still running. I don't know if
-this is a problem of the 6pack driver or something else in the kernel.
-
-The driver has been tested as a module, not yet as a kernel-builtin driver.
-
-The 6pack protocol supports daisy-chaining of TNCs in a token ring, which is
-connected to one serial port of the PC. This feature is not implemented
-and at least at the moment I won't be able to do it because I do not have
-the opportunity to build a TNC daisy-chain and test it.
-
-Some of the comments in the source code are inaccurate. They are left from
-the SLIP/KISS driver, from which the 6pack driver has been derived.
-I haven't modified or removed them yet -- sorry! The code itself needs
-some cleaning and optimizing. This will be done in a later release.
-
-If you encounter a bug or if you have a question or suggestion concerning the
-driver, feel free to mail me, using the addresses given at the beginning of
-this file.
-
-Have fun!
-
-Andreas
diff --git a/Documentation/networking/ax25.rst b/Documentation/networking/ax25.rst
deleted file mode 100644
index 89c79dd6c6f9..000000000000
--- a/Documentation/networking/ax25.rst
+++ /dev/null
@@ -1,17 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-=====
-AX.25
-=====
-
-To use the amateur radio protocols within Linux you will need to get a
-suitable copy of the AX.25 Utilities. More detailed information about
-AX.25, NET/ROM and ROSE, associated programs and utilities can be
-found on https://linux-ax25.in-berlin.de.
-
-There is a mailing list for discussing Linux amateur radio matters
-called linux-hams@vger.kernel.org. To subscribe to it, send a message to
-linux-hams+subscribe@vger.kernel.org or use the web interface at
-https://vger.kernel.org. The subject and body of the message are
-ignored. You don't need to be subscribed to post but of course that
-means you might miss an answer.
diff --git a/Documentation/networking/device_drivers/hamradio/baycom.rst b/Documentation/networking/device_drivers/hamradio/baycom.rst
deleted file mode 100644
index fe2d010f0e86..000000000000
--- a/Documentation/networking/device_drivers/hamradio/baycom.rst
+++ /dev/null
@@ -1,174 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-===============================
-Linux Drivers for Baycom Modems
-===============================
-
-Thomas M. Sailer, HB9JNX/AE4WA, <sailer@ife.ee.ethz.ch>
-
-The drivers for the baycom modems have been split into
-separate drivers as they did not share any code, and the driver
-and device names have changed.
-
-This document describes the Linux Kernel Drivers for simple Baycom style
-amateur radio modems.
-
-The following drivers are available:
-====================================
-
-baycom_ser_fdx:
- This driver supports the SER12 modems either full or half duplex.
- Its baud rate may be changed via the ``baud`` module parameter,
- therefore it supports just about every bit bang modem on a
- serial port. Its devices are called bcsf0 through bcsf3.
- This is the recommended driver for SER12 type modems,
- however if you have a broken UART clone that does not have working
- delta status bits, you may try baycom_ser_hdx.
-
-baycom_ser_hdx:
- This is an alternative driver for SER12 type modems.
- It only supports half duplex, and only 1200 baud. Its devices
- are called bcsh0 through bcsh3. Use this driver only if baycom_ser_fdx
- does not work with your UART.
-
-baycom_par:
- This driver supports the par96 and picpar modems.
- Its devices are called bcp0 through bcp3.
-
-baycom_epp:
- This driver supports the EPP modem.
- Its devices are called bce0 through bce3.
- This driver is work-in-progress.
-
-The following modems are supported:
-
-======= ========================================================================
-ser12 This is a very simple 1200 baud AFSK modem. The modem consists only
- of a modulator/demodulator chip, usually a TI TCM3105. The computer
- is responsible for regenerating the receiver bit clock, as well as
- for handling the HDLC protocol. The modem connects to a serial port,
- hence the name. Since the serial port is not used as an async serial
- port, the kernel driver for serial ports cannot be used, and this
- driver only supports standard serial hardware (8250, 16450, 16550)
-
-par96 This is a modem for 9600 baud FSK compatible to the G3RUH standard.
- The modem does all the filtering and regenerates the receiver clock.
- Data is transferred from and to the PC via a shift register.
- The shift register is filled with 16 bits and an interrupt is signalled.
- The PC then empties the shift register in a burst. This modem connects
- to the parallel port, hence the name. The modem leaves the
- implementation of the HDLC protocol and the scrambler polynomial to
- the PC.
-
-picpar This is a redesign of the par96 modem by Henning Rech, DF9IC. The modem
- is protocol compatible to par96, but uses only three low power ICs
- and can therefore be fed from the parallel port and does not require
- an additional power supply. Furthermore, it incorporates a carrier
- detect circuitry.
-
-EPP This is a high-speed modem adaptor that connects to an enhanced parallel
- port.
-
- Its target audience is users working over a high speed hub (76.8kbit/s).
-
-eppfpga This is a redesign of the EPP adaptor.
-======= ========================================================================
-
-All of the above modems only support half duplex communications. However,
-the driver supports the KISS (see below) fullduplex command. It then simply
-starts to send as soon as there's a packet to transmit and does not care
-about DCD, i.e. it starts to send even if there's someone else on the channel.
-This command is required by some implementations of the DAMA channel
-access protocol.
-
-
-The Interface of the drivers
-============================
-
-Unlike previous drivers, these drivers are no longer character devices,
-but they are now true kernel network interfaces. Installation is therefore
-simple. Once installed, four interfaces named bc{sf,sh,p,e}[0-3] are available.
-sethdlc from the ax25 utilities may be used to set driver states etc.
-Users of userland AX.25 stacks may use the net2kiss utility (also available
-in the ax25 utilities package) to convert packets of a network interface
-to a KISS stream on a pseudo tty. There's also a patch available from
-me for WAMPES which allows attaching a kernel network interface directly.
-
-
-Configuring the driver
-======================
-
-Every time a driver is inserted into the kernel, it has to know which
-modems it should access at which ports. This can be done with the setbaycom
-utility. If you are only using one modem, you can also configure the
-driver from the insmod command line (or by means of an option line in
-``/etc/modprobe.d/*.conf``).
-
-Examples::
-
- modprobe baycom_ser_fdx mode="ser12*" iobase=0x3f8 irq=4
- sethdlc -i bcsf0 -p mode "ser12*" io 0x3f8 irq 4
-
-Both lines configure the first port to drive a ser12 modem at the first
-serial port (COM1 under DOS). The * in the mode parameter instructs the driver
-to use the software DCD algorithm (see below)::
-
- insmod baycom_par mode="picpar" iobase=0x378
- sethdlc -i bcp0 -p mode "picpar" io 0x378
-
-Both lines configure the first port to drive a picpar modem at the
-first parallel port (LPT1 under DOS). (Note: picpar implies
-hardware DCD, par96 implies software DCD).
-
-The channel access parameters can be set with sethdlc -a or kissparms.
-Note that both utilities interpret the values slightly differently.
-
-
-Hardware DCD versus Software DCD
-================================
-
-To avoid collisions on the air, the driver must know when the channel is
-busy. This is the task of the DCD circuitry/software. The driver may either
-utilise a software DCD algorithm (options=1) or use a DCD signal from
-the hardware (options=0).
-
-======= =================================================================
-ser12 if software DCD is utilised, the radio's squelch should always be
- open. It is highly recommended to use the software DCD algorithm,
- as it is much faster than most hardware squelch circuitry. The
- disadvantage is a slightly higher load on the system.
-
-par96 the software DCD algorithm for this type of modem is rather poor.
- The modem simply does not provide enough information to implement
- a reasonable DCD algorithm in software. Therefore, if your radio
- feeds the DCD input of the PAR96 modem, the use of the hardware
- DCD circuitry is recommended.
-
-picpar the picpar modem features a builtin DCD hardware, which is highly
- recommended.
-======= =================================================================
-
-
-
-Compatibility with the rest of the Linux kernel
-===============================================
-
-The serial driver and the baycom serial drivers compete
-for the same hardware resources. Of course only one driver can access a given
-interface at a time. The serial driver grabs all interfaces it can find at
-startup time. Therefore the baycom drivers subsequently won't be able to
-access a serial port. You might therefore find it necessary to release
-a port owned by the serial driver with 'setserial /dev/ttyS# uart none', where
-# is the number of the interface. The baycom drivers do not reserve any
-ports at startup, unless one is specified on the 'insmod' command line. Another
-method to solve the problem is to compile all drivers as modules and
-leave it to kmod to load the correct driver depending on the application.
-
-The parallel port drivers (baycom_par, baycom_epp) now use the parport subsystem
-to arbitrate the ports between different client drivers.
-
-vy 73s de
-
-Tom Sailer, sailer@ife.ee.ethz.ch
-
-hb9jnx @ hb9w.ampr.org
diff --git a/Documentation/networking/device_drivers/hamradio/index.rst b/Documentation/networking/device_drivers/hamradio/index.rst
deleted file mode 100644
index 6af481c5b020..000000000000
--- a/Documentation/networking/device_drivers/hamradio/index.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-
-Amateur Radio Device Drivers
-============================
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
- baycom
- z8530drv
diff --git a/Documentation/networking/device_drivers/hamradio/z8530drv.rst b/Documentation/networking/device_drivers/hamradio/z8530drv.rst
deleted file mode 100644
index d2942760f167..000000000000
--- a/Documentation/networking/device_drivers/hamradio/z8530drv.rst
+++ /dev/null
@@ -1,686 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-=========================================================
-SCC.C - Linux driver for Z8530 based HDLC cards for AX.25
-=========================================================
-
-
-This is a subset of the documentation. To use this driver you MUST have the
-full package from:
-
-Internet:
-
- 1. ftp://ftp.ccac.rwth-aachen.de/pub/jr/z8530drv-utils_3.0-3.tar.gz
-
- 2. ftp://ftp.pspt.fi/pub/ham/linux/ax25/z8530drv-utils_3.0-3.tar.gz
-
-Please note that the information in this document may be hopelessly outdated.
-A new version of the documentation, along with links to other important
-Linux Kernel AX.25 documentation and programs, is available on
-http://yaina.de/jreuter
-
-Copyright |copy| 1993,2000 by Joerg Reuter DL1BKE <jreuter@yaina.de>
-
-portions Copyright |copy| 1993 Guido ten Dolle PE1NNZ
-
-for the complete copyright notice see >> Copying.Z8530DRV <<
-
-1. Initialization of the driver
-===============================
-
-To use the driver, 3 steps must be performed:
-
- 1. if compiled as module: loading the module
- 2. Setup of hardware, MODEM and KISS parameters with sccinit
- 3. Attach each channel to the Linux kernel AX.25 with "ifconfig"
-
-Unlike the versions below 2.4 this driver is a real network device
-driver. If you want to run xNOS instead of our fine kernel AX.25
-use a 2.x version (available from above sites) or read the
-AX.25-HOWTO on how to emulate a KISS TNC on network device drivers.
-
-
-1.1 Loading the module
-======================
-
-(If you're going to compile the driver as a part of the kernel image,
- skip this chapter and continue with 1.2)
-
-Before you can use a module, you'll have to load it with::
-
- insmod scc.o
-
-please read 'man insmod' that comes with module-init-tools.
-
-You should include the insmod in one of the /etc/rc.d/rc.* files,
-and don't forget to insert a call of sccinit after that. It
-will read your /etc/z8530drv.conf.
-
-1.2. /etc/z8530drv.conf
-=======================
-
-To setup all parameters you must run /sbin/sccinit from one
-of your rc.*-files. This has to be done BEFORE you can
-"ifconfig" an interface. Sccinit reads the file /etc/z8530drv.conf
-and sets the hardware, MODEM and KISS parameters. A sample file is
-delivered with this package. Change it to your needs.
-
-The file itself consists of two main sections.
-
-1.2.1 configuration of hardware parameters
-==========================================
-
-The hardware setup section defines the following parameters for each
-Z8530::
-
- chip 1
- data_a 0x300 # data port A
- ctrl_a 0x304 # control port A
- data_b 0x301 # data port B
- ctrl_b 0x305 # control port B
- irq 5 # IRQ No. 5
- pclock 4915200 # clock
- board BAYCOM # hardware type
- escc no # enhanced SCC chip? (8580/85180/85280)
- vector 0 # latch for interrupt vector
- special no # address of special function register
- option 0 # option to set via sfr
-
-
-chip
- - this is just a delimiter to make sccinit a bit simpler to
- program. A parameter has no effect.
-
-data_a
- - the address of the data port A of this Z8530 (needed)
-ctrl_a
- - the address of the control port A (needed)
-data_b
- - the address of the data port B (needed)
-ctrl_b
- - the address of the control port B (needed)
-
-irq
- - the used IRQ for this chip. Different chips can use different
- IRQs or the same. If they share an interrupt, it needs to be
- specified within one chip-definition only.
-
-pclock - the clock at the PCLK pin of the Z8530 (option, 4915200 is
- default), measured in Hertz
-
-board
- - the "type" of the board:
-
- ======================= ========
- SCC type value
- ======================= ========
- PA0HZP SCC card PA0HZP
- EAGLE card EAGLE
- PC100 card PC100
- PRIMUS-PC (DG9BL) card PRIMUS
- BayCom (U)SCC card BAYCOM
- ======================= ========
-
-escc
- - if you want support for ESCC chips (8580, 85180, 85280), set
- this to "yes" (option, defaults to "no")
-
-vector
- - address of the vector latch (aka "intack port") for PA0HZP
- cards. There can be only one vector latch for all chips!
- (option, defaults to 0)
-
-special
- - address of the special function register on several cards.
- (option, defaults to 0)
-
-option - The value you write into that register (option, default is 0)
-
-You can specify up to four chips (8 channels). If this is not enough,
-just change::
-
- #define MAXSCC 4
-
-to a higher value.
-
-Example for the BAYCOM USCC:
-----------------------------
-
-::
-
- chip 1
- data_a 0x300 # data port A
- ctrl_a 0x304 # control port A
- data_b 0x301 # data port B
- ctrl_b 0x305 # control port B
- irq 5 # IRQ No. 5 (#)
- board BAYCOM # hardware type (*)
- #
- # SCC chip 2
- #
- chip 2
- data_a 0x302
- ctrl_a 0x306
- data_b 0x303
- ctrl_b 0x307
- board BAYCOM
-
-An example for a PA0HZP card:
------------------------------
-
-::
-
- chip 1
- data_a 0x153
- data_b 0x151
- ctrl_a 0x152
- ctrl_b 0x150
- irq 9
- pclock 4915200
- board PA0HZP
- vector 0x168
- escc no
- #
- #
- #
- chip 2
- data_a 0x157
- data_b 0x155
- ctrl_a 0x156
- ctrl_b 0x154
- irq 9
- pclock 4915200
- board PA0HZP
- vector 0x168
- escc no
-
-A DRSI would should probably work with this:
---------------------------------------------
-(actually: two DRSI cards...)
-
-::
-
- chip 1
- data_a 0x303
- data_b 0x301
- ctrl_a 0x302
- ctrl_b 0x300
- irq 7
- pclock 4915200
- board DRSI
- escc no
- #
- #
- #
- chip 2
- data_a 0x313
- data_b 0x311
- ctrl_a 0x312
- ctrl_b 0x310
- irq 7
- pclock 4915200
- board DRSI
- escc no
-
-Note that you cannot use the on-board baudrate generator off DRSI
-cards. Use "mode dpll" for clock source (see below).
-
-This is based on information provided by Mike Bilow (and verified
-by Paul Helay)
-
-The utility "gencfg"
---------------------
-
-If you only know the parameters for the PE1CHL driver for DOS,
-run gencfg. It will generate the correct port addresses (I hope).
-Its parameters are exactly the same as the ones you use with
-the "attach scc" command in net, except that the string "init" must
-not appear. Example::
-
- gencfg 2 0x150 4 2 0 1 0x168 9 4915200
-
-will print a skeleton z8530drv.conf for the OptoSCC to stdout.
-
-::
-
- gencfg 2 0x300 2 4 5 -4 0 7 4915200 0x10
-
-does the same for the BAYCOM USCC card. In my opinion it is much easier
-to edit scc_config.h...
-
-
-1.2.2 channel configuration
-===========================
-
-The channel definition is divided into three sub sections for each
-channel:
-
-An example for scc0::
-
- # DEVICE
-
- device scc0 # the device for the following params
-
- # MODEM / BUFFERS
-
- speed 1200 # the default baudrate
- clock dpll # clock source:
- # dpll = normal half duplex operation
- # external = MODEM provides own Rx/Tx clock
- # divider = use full duplex divider if
- # installed (1)
- mode nrzi # HDLC encoding mode
- # nrzi = 1k2 MODEM, G3RUH 9k6 MODEM
- # nrz = DF9IC 9k6 MODEM
- #
- bufsize 384 # size of buffers. Note that this must include
- # the AX.25 header, not only the data field!
- # (optional, defaults to 384)
-
- # KISS (Layer 1)
-
- txdelay 36 # (see chapter 1.4)
- persist 64
- slot 8
- tail 8
- fulldup 0
- wait 12
- min 3
- maxkey 7
- idle 3
- maxdef 120
- group 0
- txoff off
- softdcd on
- slip off
-
-The order WITHIN these sections is unimportant. The order OF these
-sections IS important. The MODEM parameters are set with the first
-recognized KISS parameter...
-
-Please note that you can initialize the board only once after boot
-(or insmod). You can change all parameters but "mode" and "clock"
-later with the Sccparam program or through KISS. Just to avoid
-security holes...
-
-(1) this divider is usually mounted on the SCC-PBC (PA0HZP) or not
- present at all (BayCom). It feeds back the output of the DPLL
- (digital pll) as transmit clock. Using this mode without a divider
- installed will normally result in keying the transceiver until
- maxkey expires --- of course without sending anything (useful).
-
-2. Attachment of a channel by your AX.25 software
-=================================================
-
-2.1 Kernel AX.25
-================
-
-To set up an AX.25 device you can simply type::
-
- ifconfig scc0 44.128.1.1 hw ax25 dl0tha-7
-
-This will create a network interface with the IP number 44.128.20.107
-and the callsign "dl0tha". If you do not have any IP number (yet) you
-can use any of the 44.128.0.0 network. Note that you do not need
-axattach. The purpose of axattach (like slattach) is to create a KISS
-network device linked to a TTY. Please read the documentation of the
-ax25-utils and the AX.25-HOWTO to learn how to set the parameters of
-the kernel AX.25.
-
-2.2 NOS, NET and TFKISS
-=======================
-
-Since the TTY driver (aka KISS TNC emulation) is gone you need
-to emulate the old behaviour. The cost of using these programs is
-that you probably need to compile the kernel AX.25, regardless of whether
-you actually use it or not. First setup your /etc/ax25/axports,
-for example::
-
- 9k6 dl0tha-9 9600 255 4 9600 baud port (scc3)
- axlink dl0tha-15 38400 255 4 Link to NOS
-
-Now "ifconfig" the scc device::
-
- ifconfig scc3 44.128.1.1 hw ax25 dl0tha-9
-
-You can now axattach a pseudo-TTY::
-
- axattach /dev/ptys0 axlink
-
-and start your NOS and attach /dev/ptys0 there. The problem is that
-NOS is reachable only via digipeating through the kernel AX.25
-(disastrous on a DAMA controlled channel). To solve this problem,
-configure "rxecho" to echo the incoming frames from "9k6" to "axlink"
-and outgoing frames from "axlink" to "9k6" and start::
-
- rxecho
-
-Or simply use "kissbridge" coming with z8530drv-utils::
-
- ifconfig scc3 hw ax25 dl0tha-9
- kissbridge scc3 /dev/ptys0
-
-
-3. Adjustment and Display of parameters
-=======================================
-
-3.1 Displaying SCC Parameters:
-==============================
-
-Once a SCC channel has been attached, the parameter settings and
-some statistic information can be shown using the param program::
-
- dl1bke-u:~$ sccstat scc0
-
- Parameters:
-
- speed : 1200 baud
- txdelay : 36
- persist : 255
- slottime : 0
- txtail : 8
- fulldup : 1
- waittime : 12
- mintime : 3 sec
- maxkeyup : 7 sec
- idletime : 3 sec
- maxdefer : 120 sec
- group : 0x00
- txoff : off
- softdcd : on
- SLIP : off
-
- Status:
-
- HDLC Z8530 Interrupts Buffers
- -----------------------------------------------------------------------
- Sent : 273 RxOver : 0 RxInts : 125074 Size : 384
- Received : 1095 TxUnder: 0 TxInts : 4684 NoSpace : 0
- RxErrors : 1591 ExInts : 11776
- TxErrors : 0 SpInts : 1503
- Tx State : idle
-
-
-The status info shown is:
-
-============== ==============================================================
-Sent number of frames transmitted
-Received number of frames received
-RxErrors number of receive errors (CRC, ABORT)
-TxErrors number of discarded Tx frames (due to various reasons)
-Tx State status of the Tx interrupt handler: idle/busy/active/tail (2)
-RxOver number of receiver overruns
-TxUnder number of transmitter underruns
-RxInts number of receiver interrupts
-TxInts number of transmitter interrupts
-EpInts number of receiver special condition interrupts
-SpInts number of external/status interrupts
-Size maximum size of an AX.25 frame (*with* AX.25 headers!)
-NoSpace number of times a buffer could not get allocated
-============== ==============================================================
-
-An overrun is abnormal. If lots of these occur, the product of
-baudrate and number of interfaces is too high for the processing
-power of your computer. NoSpace errors are unlikely to be caused by the
-driver or the kernel AX.25.
-
-
-3.2 Setting Parameters
-======================
-
-
-The setting of parameters of the emulated KISS TNC is done in the
-same way in the SCC driver. You can change parameters by using
-the kissparms program from the ax25-utils package or use the program
-"sccparam"::
-
- sccparam <device> <paramname> <decimal-|hexadecimal value>
-
-You can change the following parameters:
-
-=========== =====
-param value
-=========== =====
-speed 1200
-txdelay 36
-persist 255
-slottime 0
-txtail 8
-fulldup 1
-waittime 12
-mintime 3
-maxkeyup 7
-idletime 3
-maxdefer 120
-group 0x00
-txoff off
-softdcd on
-SLIP off
-=========== =====
-
-
-The parameters have the following meaning:
-
-speed:
- The baudrate on this channel in bits/sec
-
- Example: sccparam /dev/scc3 speed 9600
-
-txdelay:
- The delay (in units of 10 ms) after keying of the
- transmitter, until the first byte is sent. This is usually
- called "TXDELAY" in a TNC. When 0 is specified, the driver
- will just wait until the CTS signal is asserted. This
- assumes the presence of a timer or other circuitry in the
- MODEM and/or transmitter, that asserts CTS when the
- transmitter is ready for data.
- A normal value of this parameter is 30-36.
-
- Example: sccparam /dev/scc0 txd 20
-
-persist:
- This is the probability that the transmitter will be keyed
- when the channel is found to be free. It is a value from 0
- to 255, and the probability is (value+1)/256. The value
- should be somewhere near 50-60, and should be lowered when
- the channel is used more heavily.
-
- Example: sccparam /dev/scc2 persist 20
-
-slottime:
- This is the time between samples of the channel. It is
- expressed in units of 10 ms. About 200-300 ms (value 20-30)
- seems to be a good value.
-
- Example: sccparam /dev/scc0 slot 20
-
-tail:
- The time the transmitter will remain keyed after the last
- byte of a packet has been transferred to the SCC. This is
- necessary because the CRC and a flag still have to leave the
- SCC before the transmitter is keyed down. The value depends
- on the baudrate selected. A few character times should be
- sufficient, e.g. 40ms at 1200 baud. (value 4)
- The value of this parameter is in 10 ms units.
-
- Example: sccparam /dev/scc2 4
-
-full:
- The full-duplex mode switch. This can be one of the following
- values:
-
- 0: The interface will operate in CSMA mode (the normal
- half-duplex packet radio operation)
- 1: Fullduplex mode, i.e. the transmitter will be keyed at
- any time, without checking the received carrier. It
- will be unkeyed when there are no packets to be sent.
- 2: Like 1, but the transmitter will remain keyed, also
- when there are no packets to be sent. Flags will be
- sent in that case, until a timeout (parameter 10)
- occurs.
-
- Example: sccparam /dev/scc0 fulldup off
-
-wait:
- The initial waittime before any transmit attempt, after the
- frame has been queue for transmit. This is the length of
- the first slot in CSMA mode. In full duplex modes it is
- set to 0 for maximum performance.
- The value of this parameter is in 10 ms units.
-
- Example: sccparam /dev/scc1 wait 4
-
-maxkey:
- The maximal time the transmitter will be keyed to send
- packets, in seconds. This can be useful on busy CSMA
- channels, to avoid "getting a bad reputation" when you are
- generating a lot of traffic. After the specified time has
- elapsed, no new frame will be started. Instead, the trans-
- mitter will be switched off for a specified time (parameter
- min), and then the selected algorithm for keyup will be
- started again.
- The value 0 as well as "off" will disable this feature,
- and allow infinite transmission time.
-
- Example: sccparam /dev/scc0 maxk 20
-
-min:
- This is the time the transmitter will be switched off when
- the maximum transmission time is exceeded.
-
- Example: sccparam /dev/scc3 min 10
-
-idle:
- This parameter specifies the maximum idle time in full duplex
- 2 mode, in seconds. When no frames have been sent for this
- time, the transmitter will be keyed down. A value of 0 is
- has same result as the fullduplex mode 1. This parameter
- can be disabled.
-
- Example: sccparam /dev/scc2 idle off # transmit forever
-
-maxdefer
- This is the maximum time (in seconds) to wait for a free channel
- to send. When this timer expires the transmitter will be keyed
- IMMEDIATELY. If you love to get trouble with other users you
- should set this to a very low value ;-)
-
- Example: sccparam /dev/scc0 maxdefer 240 # 2 minutes
-
-
-txoff:
- When this parameter has the value 0, the transmission of packets
- is enable. Otherwise it is disabled.
-
- Example: sccparam /dev/scc2 txoff on
-
-group:
- It is possible to build special radio equipment to use more than
- one frequency on the same band, e.g. using several receivers and
- only one transmitter that can be switched between frequencies.
- Also, you can connect several radios that are active on the same
- band. In these cases, it is not possible, or not a good idea, to
- transmit on more than one frequency. The SCC driver provides a
- method to lock transmitters on different interfaces, using the
- "param <interface> group <x>" command. This will only work when
- you are using CSMA mode (parameter full = 0).
-
- The number <x> must be 0 if you want no group restrictions, and
- can be computed as follows to create restricted groups:
- <x> is the sum of some OCTAL numbers:
-
-
- === =======================================================
- 200 This transmitter will only be keyed when all other
- transmitters in the group are off.
- 100 This transmitter will only be keyed when the carrier
- detect of all other interfaces in the group is off.
- 0xx A byte that can be used to define different groups.
- Interfaces are in the same group, when the logical AND
- between their xx values is nonzero.
- === =======================================================
-
- Examples:
-
- When 2 interfaces use group 201, their transmitters will never be
- keyed at the same time.
-
- When 2 interfaces use group 101, the transmitters will only key
- when both channels are clear at the same time. When group 301,
- the transmitters will not be keyed at the same time.
-
- Don't forget to convert the octal numbers into decimal before
- you set the parameter.
-
- Example: (to be written)
-
-softdcd:
- use a software dcd instead of the real one... Useful for a very
- slow squelch.
-
- Example: sccparam /dev/scc0 soft on
-
-
-4. Problems
-===========
-
-If you have tx-problems with your BayCom USCC card please check
-the manufacturer of the 8530. SGS chips have a slightly
-different timing. Try Zilog... A solution is to write to register 8
-instead to the data port, but this won't work with the ESCC chips.
-*SIGH!*
-
-A very common problem is that the PTT locks until the maxkeyup timer
-expires, although interrupts and clock source are correct. In most
-cases compiling the driver with CONFIG_SCC_DELAY (set with
-make config) solves the problems. For more hints read the (pseudo) FAQ
-and the documentation coming with z8530drv-utils.
-
-I got reports that the driver has problems on some 386-based systems.
-(i.e. Amstrad) Those systems have a bogus AT bus timing which will
-lead to delayed answers on interrupts. You can recognize these
-problems by looking at the output of Sccstat for the suspected
-port. If it shows under- and overruns you own such a system.
-
-Delayed processing of received data: This depends on
-
-- the kernel version
-
-- kernel profiling compiled or not
-
-- a high interrupt load
-
-- a high load of the machine --- running X, Xmorph, XV and Povray,
- while compiling the kernel... hmm ... even with 32 MB RAM ... ;-)
- Or running a named for the whole .ampr.org domain on an 8 MB
- box...
-
-- using information from rxecho or kissbridge.
-
-Kernel panics: please read /linux/README and find out if it
-really occurred within the scc driver.
-
-If you cannot solve a problem, send me
-
-- a description of the problem,
-- information on your hardware (computer system, scc board, modem)
-- your kernel version
-- the output of cat /proc/net/z8530
-
-4. Thor RLC100
-==============
-
-Mysteriously this board seems not to work with the driver. Anyone
-got it up-and-running?
-
-
-Many thanks to Linus Torvalds and Alan Cox for including the driver
-in the Linux standard distribution and their support.
-
-::
-
- Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org
- AX-25 : DL1BKE @ DB0ABH.#BAY.DEU.EU
- Internet: jreuter@yaina.de
- WWW : http://yaina.de/jreuter
diff --git a/Documentation/networking/device_drivers/index.rst b/Documentation/networking/device_drivers/index.rst
index 1df51c9f7827..1f54f01d24be 100644
--- a/Documentation/networking/device_drivers/index.rst
+++ b/Documentation/networking/device_drivers/index.rst
@@ -13,6 +13,5 @@ Hardware Device Drivers
cellular/index
ethernet/index
fddi/index
- hamradio/index
wifi/index
wwan/index
diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst
index 2e946924ad3f..44a422ad3b05 100644
--- a/Documentation/networking/index.rst
+++ b/Documentation/networking/index.rst
@@ -40,11 +40,9 @@ Refer to :ref:`netdev-FAQ` for a guide on netdev development process specifics.
tls-handshake
nfc
6lowpan
- 6pack
arcnet-hardware
arcnet
atm
- ax25
bonding
cdc_mbim
dctcp
diff --git a/Documentation/staging/magic-number.rst b/Documentation/staging/magic-number.rst
index 79afddf0e692..670d3189a976 100644
--- a/Documentation/staging/magic-number.rst
+++ b/Documentation/staging/magic-number.rst
@@ -72,11 +72,8 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/uapi/l
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip/slip.h``
-BAYCOM_MAGIC 19730510 baycom_state ``drivers/net/hamradio/baycom_epp.c``
-HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
-YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
diff --git a/Documentation/translations/it_IT/staging/magic-number.rst b/Documentation/translations/it_IT/staging/magic-number.rst
index cd8f23571835..43dd6398300b 100644
--- a/Documentation/translations/it_IT/staging/magic-number.rst
+++ b/Documentation/translations/it_IT/staging/magic-number.rst
@@ -78,11 +78,8 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
-BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
-HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
-YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
diff --git a/Documentation/translations/sp_SP/process/magic-number.rst b/Documentation/translations/sp_SP/process/magic-number.rst
index beb4b4c1de11..f5b4c3f2849f 100644
--- a/Documentation/translations/sp_SP/process/magic-number.rst
+++ b/Documentation/translations/sp_SP/process/magic-number.rst
@@ -77,11 +77,8 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
-BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
-HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
-YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst
index 4ebc84cc0c54..05ee75cf4346 100644
--- a/Documentation/translations/zh_CN/process/magic-number.rst
+++ b/Documentation/translations/zh_CN/process/magic-number.rst
@@ -70,11 +70,8 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
-BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
-HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
-YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
diff --git a/Documentation/translations/zh_TW/process/magic-number.rst b/Documentation/translations/zh_TW/process/magic-number.rst
index 5582df6d7ca7..bc7eb025dd1e 100644
--- a/Documentation/translations/zh_TW/process/magic-number.rst
+++ b/Documentation/translations/zh_TW/process/magic-number.rst
@@ -64,11 +64,8 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
-BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
-HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
-YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
deleted file mode 100644
index 36a9aade9f33..000000000000
--- a/drivers/net/hamradio/Kconfig
+++ /dev/null
@@ -1,162 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config MKISS
- tristate "Serial port KISS driver"
- depends on AX25 && TTY
- select CRC16
- help
- KISS is a protocol used for the exchange of data between a computer
- and a Terminal Node Controller (a small embedded system commonly
- used for networking over AX.25 amateur radio connections; it
- connects the computer's serial port with the radio's microphone
- input and speaker output).
-
- Although KISS is less advanced than the 6pack protocol, it has
- the advantage that it is already supported by most modern TNCs
- without the need for a firmware upgrade.
-
- To compile this driver as a module, choose M here: the module
- will be called mkiss.
-
-config 6PACK
- tristate "Serial port 6PACK driver"
- depends on AX25 && TTY
- help
- 6pack is a transmission protocol for the data exchange between your
- PC and your TNC (the Terminal Node Controller acts as a kind of
- modem connecting your computer's serial port to your radio's
- microphone input and speaker output). This protocol can be used as
- an alternative to KISS for networking over AX.25 amateur radio
- connections, but it has some extended functionality.
-
- Note that this driver is still experimental and might cause
- problems. For details about the features and the usage of the
- driver, read <file:Documentation/networking/6pack.rst>.
-
- To compile this driver as a module, choose M here: the module
- will be called 6pack.
-
-config BPQETHER
- tristate "BPQ Ethernet driver"
- depends on AX25
- help
- AX.25 is the protocol used for computer communication over amateur
- radio. If you say Y here, you will be able to send and receive AX.25
- traffic over Ethernet (also called "BPQ AX.25"), which could be
- useful if some other computer on your local network has a direct
- amateur radio connection.
-
-config SCC
- tristate "Z8530 SCC driver"
- depends on ISA && AX25
- help
- These cards are used to connect your Linux box to an amateur radio
- in order to communicate with other computers. If you want to use
- this, read
- <file:Documentation/networking/device_drivers/hamradio/z8530drv.rst>
- and the AX25-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Also make sure to say Y
- to "Amateur Radio AX.25 Level 2" support.
-
- To compile this driver as a module, choose M here: the module
- will be called scc.
-
-config SCC_DELAY
- bool "additional delay for PA0HZP OptoSCC compatible boards"
- depends on SCC
- help
- Say Y here if you experience problems with the SCC driver not
- working properly; please read
- <file:Documentation/networking/device_drivers/hamradio/z8530drv.rst>
- for details.
-
- If unsure, say N.
-
-config SCC_TRXECHO
- bool "support for TRX that feedback the tx signal to rx"
- depends on SCC
- help
- Some transmitters feed the transmitted signal back to the receive
- line. Say Y here to foil this by explicitly disabling the receiver
- during data transmission.
-
- If in doubt, say Y.
-
-config BAYCOM_SER_FDX
- tristate "BAYCOM ser12 fullduplex driver for AX.25"
- depends on AX25 && HAS_IOPORT
- select CRC_CCITT
- help
- This is one of two drivers for Baycom style simple amateur radio
- modems that connect to a serial interface. The driver supports the
- ser12 design in full-duplex mode. In addition, it allows the
- baudrate to be set between 300 and 4800 baud (however not all modems
- support all baudrates). This is the preferred driver. The next
- driver, "BAYCOM ser12 half-duplex driver for AX.25" is the old
- driver and still provided in case this driver does not work with
- your serial interface chip. To configure the driver, use the sethdlc
- utility available in the standard ax25 utilities package.
- For more information on the modems, see
- <file:Documentation/networking/device_drivers/hamradio/baycom.rst>.
-
- To compile this driver as a module, choose M here: the module
- will be called baycom_ser_fdx. This is recommended.
-
-config BAYCOM_SER_HDX
- tristate "BAYCOM ser12 halfduplex driver for AX.25"
- depends on AX25 && HAS_IOPORT
- select CRC_CCITT
- help
- This is one of two drivers for Baycom style simple amateur radio
- modems that connect to a serial interface. The driver supports the
- ser12 design in half-duplex mode. This is the old driver. It is
- still provided in case your serial interface chip does not work with
- the full-duplex driver. This driver is deprecated. To configure
- the driver, use the sethdlc utility available in the standard ax25
- utilities package. For more information on the modems, see
- <file:Documentation/networking/device_drivers/hamradio/baycom.rst>.
-
- To compile this driver as a module, choose M here: the module
- will be called baycom_ser_hdx. This is recommended.
-
-config BAYCOM_PAR
- tristate "BAYCOM picpar and par96 driver for AX.25"
- depends on PARPORT && AX25
- select CRC_CCITT
- help
- This is a driver for Baycom style simple amateur radio modems that
- connect to a parallel interface. The driver supports the picpar and
- par96 designs. To configure the driver, use the sethdlc utility
- available in the standard ax25 utilities package.
- For more information on the modems, see
- <file:Documentation/networking/device_drivers/hamradio/baycom.rst>.
-
- To compile this driver as a module, choose M here: the module
- will be called baycom_par. This is recommended.
-
-config BAYCOM_EPP
- tristate "BAYCOM epp driver for AX.25"
- depends on PARPORT && AX25 && !64BIT
- select CRC_CCITT
- help
- This is a driver for Baycom style simple amateur radio modems that
- connect to a parallel interface. The driver supports the EPP
- designs. To configure the driver, use the sethdlc utility available
- in the standard ax25 utilities package.
- For more information on the modems, see
- <file:Documentation/networking/device_drivers/hamradio/baycom.rst>.
-
- To compile this driver as a module, choose M here: the module
- will be called baycom_epp. This is recommended.
-
-config YAM
- tristate "YAM driver for AX.25"
- depends on AX25 && HAS_IOPORT
- help
- The YAM is a modem for packet radio which connects to the serial
- port and includes some of the functions of a Terminal Node
- Controller. If you have one of those, say Y here.
-
- To compile this driver as a module, choose M here: the module
- will be called yam.
-
-
diff --git a/net/Kconfig b/net/Kconfig
index 5c588dbcbdbd..bdea8aef7983 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -414,7 +414,6 @@ endmenu # Network testing
endmenu # Networking options
-source "net/ax25/Kconfig"
source "net/can/Kconfig"
source "net/bluetooth/Kconfig"
source "net/rxrpc/Kconfig"
diff --git a/net/ax25/Kconfig b/net/ax25/Kconfig
deleted file mode 100644
index 310169ce1488..000000000000
--- a/net/ax25/Kconfig
+++ /dev/null
@@ -1,108 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Amateur Radio protocols and AX.25 device configuration
-#
-
-menuconfig HAMRADIO
- depends on NET
- bool "Amateur Radio support"
- help
- If you want to connect your Linux box to an amateur radio, answer Y
- here. You want to read <https://www.tapr.org/>
- and more specifically about AX.25 on Linux
- <https://linux-ax25.in-berlin.de>.
-
- Note that the answer to this question won't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about amateur radio.
-
-comment "Packet Radio protocols"
- depends on HAMRADIO
-
-config AX25
- tristate "Amateur Radio AX.25 Level 2 protocol"
- depends on HAMRADIO
- help
- This is the protocol used for computer communication over amateur
- radio. It is either used by itself for point-to-point links, or to
- carry other protocols such as tcp/ip. To use it, you need a device
- that connects your Linux box to your amateur radio. You can either
- use a low speed TNC (a Terminal Node Controller acts as a kind of
- modem connecting your computer's serial port to your radio's
- microphone input and speaker output) supporting the KISS protocol or
- one of the various SCC cards that are supported by the generic Z8530
- or the DMA SCC driver. Another option are the Baycom modem serial
- and parallel port hacks or the sound card modem (supported by their
- own drivers). If you say Y here, you also have to say Y to one of
- those drivers.
-
- Information about where to get supporting software for Linux amateur
- radio as well as information about how to configure an AX.25 port is
- contained in the AX25-HOWTO, available from
- <https://www.tldp.org/docs.html#howto>. You might also want to
- check out the file <file:Documentation/networking/ax25.rst> in the
- kernel source. More information about digital amateur radio in
- general is on the WWW at
- <https://www.tapr.org/>.
-
- To compile this driver as a module, choose M here: the
- module will be called ax25.
-
-config AX25_DAMA_SLAVE
- bool "AX.25 DAMA Slave support"
- default y
- depends on AX25
- help
- DAMA is a mechanism to prevent collisions when doing AX.25
- networking. A DAMA server (called "master") accepts incoming traffic
- from clients (called "slaves") and redistributes it to other slaves.
- If you say Y here, your Linux box will act as a DAMA slave; this is
- transparent in that you don't have to do any special DAMA
- configuration. Linux cannot yet act as a DAMA server. This option
- only compiles DAMA slave support into the kernel. It still needs to
- be enabled at runtime. For more about DAMA see
- <https://linux-ax25.in-berlin.de>. If unsure, say Y.
-
-config NETROM
- tristate "Amateur Radio NET/ROM protocol"
- depends on AX25
- help
- NET/ROM is a network layer protocol on top of AX.25 useful for
- routing.
-
- A comprehensive listing of all the software for Linux amateur radio
- users as well as information about how to configure an AX.25 port is
- contained in the Linux Ham Wiki, available from
- <https://linux-ax25.in-berlin.de>. You also might want to check out
- the file <file:Documentation/networking/ax25.rst>. More information
- about digital amateur radio in general is on the WWW at
- <https://www.tapr.org/>.
-
- To compile this driver as a module, choose M here: the
- module will be called netrom.
-
-config ROSE
- tristate "Amateur Radio X.25 PLP (Rose)"
- depends on AX25
- help
- The Packet Layer Protocol (PLP) is a way to route packets over X.25
- connections in general and amateur radio AX.25 connections in
- particular, essentially an alternative to NET/ROM.
-
- A comprehensive listing of all the software for Linux amateur radio
- users as well as information about how to configure an AX.25 port is
- contained in the Linux Ham Wiki, available from
- <https://linux-ax25.in-berlin.de>. You also might want to check out
- the file <file:Documentation/networking/ax25.rst>. More information
- about digital amateur radio in general is on the WWW at
- <https://www.tapr.org/>.
-
- To compile this driver as a module, choose M here: the
- module will be called rose.
-
-menu "AX.25 network device drivers"
- depends on HAMRADIO && AX25
-
-source "drivers/net/hamradio/Kconfig"
-
-endmenu
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 3b2d28127634..b87a741fc952 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -54,7 +54,6 @@ obj-y += dsa/
endif
obj-$(CONFIG_ETHERNET) += ethernet/
obj-$(CONFIG_FDDI) += fddi/
-obj-$(CONFIG_HAMRADIO) += hamradio/
obj-$(CONFIG_QCOM_IPA) += ipa/
obj-$(CONFIG_PLIP) += plip/
obj-$(CONFIG_PPP) += ppp/
diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile
deleted file mode 100644
index 25fc400369ba..000000000000
--- a/drivers/net/hamradio/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for the Linux AX.25 and HFMODEM device drivers.
-#
-#
-# 19971130 Moved the amateur radio related network drivers from
-# drivers/net/ to drivers/hamradio for easier maintenance.
-# Joerg Reuter DL1BKE <jreuter@yaina.de>
-#
-# 20000806 Rewritten to use lists instead of if-statements.
-# Christoph Hellwig <hch@infradead.org>
-#
-
-obj-$(CONFIG_SCC) += scc.o
-obj-$(CONFIG_MKISS) += mkiss.o
-obj-$(CONFIG_6PACK) += 6pack.o
-obj-$(CONFIG_YAM) += yam.o
-obj-$(CONFIG_BPQETHER) += bpqether.o
-obj-$(CONFIG_BAYCOM_SER_FDX) += baycom_ser_fdx.o hdlcdrv.o
-obj-$(CONFIG_BAYCOM_SER_HDX) += baycom_ser_hdx.o hdlcdrv.o
-obj-$(CONFIG_BAYCOM_PAR) += baycom_par.o hdlcdrv.o
-obj-$(CONFIG_BAYCOM_EPP) += baycom_epp.o hdlcdrv.o
diff --git a/net/Makefile b/net/Makefile
index 98e182829eff..d2175fce0406 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -28,9 +28,6 @@ obj-y += dsa/
obj-$(CONFIG_ATALK) += appletalk/
obj-$(CONFIG_X25) += x25/
obj-$(CONFIG_LAPB) += lapb/
-obj-$(CONFIG_NETROM) += netrom/
-obj-$(CONFIG_ROSE) += rose/
-obj-$(CONFIG_AX25) += ax25/
obj-$(CONFIG_CAN) += can/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_SUNRPC) += sunrpc/
diff --git a/net/ax25/Makefile b/net/ax25/Makefile
deleted file mode 100644
index 2e53affc8568..000000000000
--- a/net/ax25/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for the Linux AX.25 layer.
-#
-
-obj-$(CONFIG_AX25) += ax25.o
-
-ax25-y := ax25_addr.o ax25_dev.o ax25_iface.o ax25_in.o ax25_ip.o ax25_out.o \
- ax25_route.o ax25_std_in.o ax25_std_subr.o ax25_std_timer.o \
- ax25_subr.o ax25_timer.o ax25_uid.o af_ax25.o
-ax25-$(CONFIG_AX25_DAMA_SLAVE) += ax25_ds_in.o ax25_ds_subr.o ax25_ds_timer.o
-ax25-$(CONFIG_SYSCTL) += sysctl_net_ax25.o
diff --git a/net/netrom/Makefile b/net/netrom/Makefile
deleted file mode 100644
index 603e36c9af2e..000000000000
--- a/net/netrom/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Linux NET/ROM layer.
-#
-
-obj-$(CONFIG_NETROM) += netrom.o
-
-netrom-y := af_netrom.o nr_dev.o nr_in.o nr_loopback.o \
- nr_out.o nr_route.o nr_subr.o nr_timer.o
-netrom-$(CONFIG_SYSCTL) += sysctl_net_netrom.o
diff --git a/net/rose/Makefile b/net/rose/Makefile
deleted file mode 100644
index 3e6638f5ba57..000000000000
--- a/net/rose/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Linux Rose (X.25 PLP) layer.
-#
-
-obj-$(CONFIG_ROSE) += rose.o
-
-rose-y := af_rose.o rose_dev.o rose_in.o rose_link.o rose_loopback.o \
- rose_out.o rose_route.o rose_subr.o rose_timer.o
-rose-$(CONFIG_SYSCTL) += sysctl_net_rose.o
diff --git a/drivers/net/hamradio/z8530.h b/drivers/net/hamradio/z8530.h
deleted file mode 100644
index 1655901d713b..000000000000
--- a/drivers/net/hamradio/z8530.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-/* 8530 Serial Communications Controller Register definitions */
-#define FLAG 0x7e
-
-/* Write Register 0 */
-#define R0 0 /* Register selects */
-#define R1 1
-#define R2 2
-#define R3 3
-#define R4 4
-#define R5 5
-#define R6 6
-#define R7 7
-#define R8 8
-#define R9 9
-#define R10 10
-#define R11 11
-#define R12 12
-#define R13 13
-#define R14 14
-#define R15 15
-
-#define NULLCODE 0 /* Null Code */
-#define POINT_HIGH 0x8 /* Select upper half of registers */
-#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
-#define SEND_ABORT 0x18 /* HDLC Abort */
-#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
-#define RES_Tx_P 0x28 /* Reset TxINT Pending */
-#define ERR_RES 0x30 /* Error Reset */
-#define RES_H_IUS 0x38 /* Reset highest IUS */
-
-#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
-#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
-#define RES_EOM_L 0xC0 /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
-#define TxINT_ENAB 0x2 /* Tx Int Enable */
-#define PAR_SPEC 0x4 /* Parity is special condition */
-
-#define RxINT_DISAB 0 /* Rx Int Disable */
-#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
-#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
-#define INT_ERR_Rx 0x18 /* Int on error only */
-
-#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
-#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
-#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define RxENABLE 0x1 /* Rx Enable */
-#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
-#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
-#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
-#define ENT_HM 0x10 /* Enter Hunt Mode */
-#define AUTO_ENAB 0x20 /* Auto Enables */
-#define Rx5 0x0 /* Rx 5 Bits/Character */
-#define Rx7 0x40 /* Rx 7 Bits/Character */
-#define Rx6 0x80 /* Rx 6 Bits/Character */
-#define Rx8 0xc0 /* Rx 8 Bits/Character */
-
-/* Write Register 4 */
-
-#define PAR_ENA 0x1 /* Parity Enable */
-#define PAR_EVEN 0x2 /* Parity Even/Odd* */
-
-#define SYNC_ENAB 0 /* Sync Modes Enable */
-#define SB1 0x4 /* 1 stop bit/char */
-#define SB15 0x8 /* 1.5 stop bits/char */
-#define SB2 0xc /* 2 stop bits/char */
-
-#define MONSYNC 0 /* 8 Bit Sync character */
-#define BISYNC 0x10 /* 16 bit sync character */
-#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
-#define EXTSYNC 0x30 /* External Sync Mode */
-
-#define X1CLK 0x0 /* x1 clock mode */
-#define X16CLK 0x40 /* x16 clock mode */
-#define X32CLK 0x80 /* x32 clock mode */
-#define X64CLK 0xC0 /* x64 clock mode */
-
-/* Write Register 5 */
-
-#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
-#define RTS 0x2 /* RTS */
-#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
-#define TxENAB 0x8 /* Tx Enable */
-#define SND_BRK 0x10 /* Send Break */
-#define Tx5 0x0 /* Tx 5 bits (or less)/character */
-#define Tx7 0x20 /* Tx 7 bits/character */
-#define Tx6 0x40 /* Tx 6 bits/character */
-#define Tx8 0x60 /* Tx 8 bits/character */
-#define DTR 0x80 /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define VIS 1 /* Vector Includes Status */
-#define NV 2 /* No Vector */
-#define DLC 4 /* Disable Lower Chain */
-#define MIE 8 /* Master Interrupt Enable */
-#define STATHI 0x10 /* Status high */
-#define NORESET 0 /* No reset on write to R9 */
-#define CHRB 0x40 /* Reset channel B */
-#define CHRA 0x80 /* Reset channel A */
-#define FHWRES 0xc0 /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define BIT6 1 /* 6 bit/8bit sync */
-#define LOOPMODE 2 /* SDLC Loop mode */
-#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
-#define MARKIDLE 8 /* Mark/flag on idle */
-#define GAOP 0x10 /* Go active on poll */
-#define NRZ 0 /* NRZ mode */
-#define NRZI 0x20 /* NRZI mode */
-#define FM1 0x40 /* FM1 (transition = 1) */
-#define FM0 0x60 /* FM0 (transition = 0) */
-#define CRCPS 0x80 /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define TRxCXT 0 /* TRxC = Xtal output */
-#define TRxCTC 1 /* TRxC = Transmit clock */
-#define TRxCBR 2 /* TRxC = BR Generator Output */
-#define TRxCDP 3 /* TRxC = DPLL output */
-#define TRxCOI 4 /* TRxC O/I */
-#define TCRTxCP 0 /* Transmit clock = RTxC pin */
-#define TCTRxCP 8 /* Transmit clock = TRxC pin */
-#define TCBR 0x10 /* Transmit clock = BR Generator output */
-#define TCDPLL 0x18 /* Transmit clock = DPLL output */
-#define RCRTxCP 0 /* Receive clock = RTxC pin */
-#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
-#define RCBR 0x40 /* Receive clock = BR Generator output */
-#define RCDPLL 0x60 /* Receive clock = DPLL output */
-#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define BRENABL 1 /* Baud rate generator enable */
-#define BRSRC 2 /* Baud rate generator source */
-#define DTRREQ 4 /* DTR/Request function */
-#define AUTOECHO 8 /* Auto Echo */
-#define LOOPBAK 0x10 /* Local loopback */
-#define SEARCH 0x20 /* Enter search mode */
-#define RMC 0x40 /* Reset missing clock */
-#define DISDPLL 0x60 /* Disable DPLL */
-#define SSBR 0x80 /* Set DPLL source = BR generator */
-#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
-#define SFMM 0xc0 /* Set FM mode */
-#define SNRZI 0xe0 /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define ZCIE 2 /* Zero count IE */
-#define DCDIE 8 /* DCD IE */
-#define SYNCIE 0x10 /* Sync/hunt IE */
-#define CTSIE 0x20 /* CTS IE */
-#define TxUIE 0x40 /* Tx Underrun/EOM IE */
-#define BRKIE 0x80 /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define Rx_CH_AV 0x1 /* Rx Character Available */
-#define ZCOUNT 0x2 /* Zero count */
-#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
-#define DCD 0x8 /* DCD */
-#define SYNC_HUNT 0x10 /* Sync/hunt */
-#define CTS 0x20 /* CTS */
-#define TxEOM 0x40 /* Tx underrun */
-#define BRK_ABRT 0x80 /* Break/Abort */
-
-/* Read Register 1 */
-#define ALL_SNT 0x1 /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define RES3 0x8 /* 0/3 */
-#define RES4 0x4 /* 0/4 */
-#define RES5 0xc /* 0/5 */
-#define RES6 0x2 /* 0/6 */
-#define RES7 0xa /* 0/7 */
-#define RES8 0x6 /* 0/8 */
-#define RES18 0xe /* 1/8 */
-#define RES28 0x0 /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define PAR_ERR 0x10 /* Parity error */
-#define Rx_OVR 0x20 /* Rx Overrun Error */
-#define CRC_ERR 0x40 /* CRC/Framing Error */
-#define END_FR 0x80 /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
-#define CHBTxIP 0x2 /* Channel B Tx IP */
-#define CHBRxIP 0x4 /* Channel B Rx IP */
-#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
-#define CHATxIP 0x10 /* Channel A Tx IP */
-#define CHARxIP 0x20 /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10 (misc status bits) */
-#define ONLOOP 2 /* On loop */
-#define LOOPSEND 0x10 /* Loop sending */
-#define CLK2MIS 0x40 /* Two clocks missing */
-#define CLK1MIS 0x80 /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Z85C30/Z85230 Enhanced SCC register definitions */
-
-/* Write Register 7' (SDLC/HDLC Programmable Enhancements) */
-#define AUTOTXF 0x01 /* Auto Tx Flag */
-#define AUTOEOM 0x02 /* Auto EOM Latch Reset */
-#define AUTORTS 0x04 /* Auto RTS */
-#define TXDNRZI 0x08 /* TxD Pulled High in SDLC NRZI mode */
-#define RXFIFOH 0x08 /* Z85230: Int on RX FIFO half full */
-#define FASTDTR 0x10 /* Fast DTR/REQ Mode */
-#define CRCCBCR 0x20 /* CRC Check Bytes Completely Received */
-#define TXFIFOE 0x20 /* Z85230: Int on TX FIFO completely empty */
-#define EXTRDEN 0x40 /* Extended Read Enabled */
-
-/* Write Register 15 (external/status interrupt control) */
-#define SHDLCE 1 /* SDLC/HDLC Enhancements Enable */
-#define FIFOE 4 /* FIFO Enable */
-
-/* Read Register 6 (frame status FIFO) */
-#define BCLSB 0xff /* LSB of 14 bits count */
-
-/* Read Register 7 (frame status FIFO) */
-#define BCMSB 0x3f /* MSB of 14 bits count */
-#define FDA 0x40 /* FIFO Data Available Status */
-#define FOS 0x80 /* FIFO Overflow Status */
diff --git a/include/linux/hdlcdrv.h b/include/linux/hdlcdrv.h
deleted file mode 100644
index 5d70c3f98f5b..000000000000
--- a/include/linux/hdlcdrv.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * hdlcdrv.h -- HDLC packet radio network driver.
- * The Linux soundcard driver for 1200 baud and 9600 baud packet radio
- * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA
- */
-#ifndef _HDLCDRV_H
-#define _HDLCDRV_H
-
-
-#include <linux/netdevice.h>
-#include <linux/if.h>
-#include <linux/spinlock.h>
-#include <uapi/linux/hdlcdrv.h>
-
-#define HDLCDRV_MAGIC 0x5ac6e778
-#define HDLCDRV_HDLCBUFFER 32 /* should be a power of 2 for speed reasons */
-#define HDLCDRV_BITBUFFER 256 /* should be a power of 2 for speed reasons */
-#undef HDLCDRV_LOOPBACK /* define for HDLC debugging purposes */
-#define HDLCDRV_DEBUG
-
-/* maximum packet length, excluding CRC */
-#define HDLCDRV_MAXFLEN 400
-
-
-struct hdlcdrv_hdlcbuffer {
- spinlock_t lock;
- unsigned rd, wr;
- unsigned short buf[HDLCDRV_HDLCBUFFER];
-};
-
-#ifdef HDLCDRV_DEBUG
-struct hdlcdrv_bitbuffer {
- unsigned int rd;
- unsigned int wr;
- unsigned int shreg;
- unsigned char buffer[HDLCDRV_BITBUFFER];
-};
-
-static inline void hdlcdrv_add_bitbuffer(struct hdlcdrv_bitbuffer *buf,
- unsigned int bit)
-{
- unsigned char new;
-
- new = buf->shreg & 1;
- buf->shreg >>= 1;
- buf->shreg |= (!!bit) << 7;
- if (new) {
- buf->buffer[buf->wr] = buf->shreg;
- buf->wr = (buf->wr+1) % sizeof(buf->buffer);
- buf->shreg = 0x80;
- }
-}
-
-static inline void hdlcdrv_add_bitbuffer_word(struct hdlcdrv_bitbuffer *buf,
- unsigned int bits)
-{
- buf->buffer[buf->wr] = bits & 0xff;
- buf->wr = (buf->wr+1) % sizeof(buf->buffer);
- buf->buffer[buf->wr] = (bits >> 8) & 0xff;
- buf->wr = (buf->wr+1) % sizeof(buf->buffer);
-
-}
-#endif /* HDLCDRV_DEBUG */
-
-/* -------------------------------------------------------------------- */
-/*
- * Information that need to be kept for each driver.
- */
-
-struct hdlcdrv_ops {
- /*
- * first some informations needed by the hdlcdrv routines
- */
- const char *drvname;
- const char *drvinfo;
- /*
- * the routines called by the hdlcdrv routines
- */
- int (*open)(struct net_device *);
- int (*close)(struct net_device *);
- int (*ioctl)(struct net_device *, void __user *,
- struct hdlcdrv_ioctl *, int);
-};
-
-struct hdlcdrv_state {
- int magic;
- int opened;
-
- const struct hdlcdrv_ops *ops;
-
- struct {
- int bitrate;
- } par;
-
- struct hdlcdrv_pttoutput {
- int dma2;
- int seriobase;
- int pariobase;
- int midiiobase;
- unsigned int flags;
- } ptt_out;
-
- struct hdlcdrv_channel_params ch_params;
-
- struct hdlcdrv_hdlcrx {
- struct hdlcdrv_hdlcbuffer hbuf;
- unsigned long in_hdlc_rx;
- /* 0 = sync hunt, != 0 receiving */
- int rx_state;
- unsigned int bitstream;
- unsigned int bitbuf;
- int numbits;
- unsigned char dcd;
-
- int len;
- unsigned char *bp;
- unsigned char buffer[HDLCDRV_MAXFLEN+2];
- } hdlcrx;
-
- struct hdlcdrv_hdlctx {
- struct hdlcdrv_hdlcbuffer hbuf;
- unsigned long in_hdlc_tx;
- /*
- * 0 = send flags
- * 1 = send txtail (flags)
- * 2 = send packet
- */
- int tx_state;
- int numflags;
- unsigned int bitstream;
- unsigned char ptt;
- int calibrate;
- int slotcnt;
-
- unsigned int bitbuf;
- int numbits;
-
- int len;
- unsigned char *bp;
- unsigned char buffer[HDLCDRV_MAXFLEN+2];
- } hdlctx;
-
-#ifdef HDLCDRV_DEBUG
- struct hdlcdrv_bitbuffer bitbuf_channel;
- struct hdlcdrv_bitbuffer bitbuf_hdlc;
-#endif /* HDLCDRV_DEBUG */
-
- int ptt_keyed;
-
- /* queued skb for transmission */
- struct sk_buff *skb;
-};
-
-
-/* -------------------------------------------------------------------- */
-
-static inline int hdlcdrv_hbuf_full(struct hdlcdrv_hdlcbuffer *hb)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&hb->lock, flags);
- ret = !((HDLCDRV_HDLCBUFFER - 1 + hb->rd - hb->wr) % HDLCDRV_HDLCBUFFER);
- spin_unlock_irqrestore(&hb->lock, flags);
- return ret;
-}
-
-/* -------------------------------------------------------------------- */
-
-static inline int hdlcdrv_hbuf_empty(struct hdlcdrv_hdlcbuffer *hb)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&hb->lock, flags);
- ret = (hb->rd == hb->wr);
- spin_unlock_irqrestore(&hb->lock, flags);
- return ret;
-}
-
-/* -------------------------------------------------------------------- */
-
-static inline unsigned short hdlcdrv_hbuf_get(struct hdlcdrv_hdlcbuffer *hb)
-{
- unsigned long flags;
- unsigned short val;
- unsigned newr;
-
- spin_lock_irqsave(&hb->lock, flags);
- if (hb->rd == hb->wr)
- val = 0;
- else {
- newr = (hb->rd+1) % HDLCDRV_HDLCBUFFER;
- val = hb->buf[hb->rd];
- hb->rd = newr;
- }
- spin_unlock_irqrestore(&hb->lock, flags);
- return val;
-}
-
-/* -------------------------------------------------------------------- */
-
-static inline void hdlcdrv_hbuf_put(struct hdlcdrv_hdlcbuffer *hb,
- unsigned short val)
-{
- unsigned newp;
- unsigned long flags;
-
- spin_lock_irqsave(&hb->lock, flags);
- newp = (hb->wr+1) % HDLCDRV_HDLCBUFFER;
- if (newp != hb->rd) {
- hb->buf[hb->wr] = val & 0xffff;
- hb->wr = newp;
- }
- spin_unlock_irqrestore(&hb->lock, flags);
-}
-
-/* -------------------------------------------------------------------- */
-
-static inline void hdlcdrv_putbits(struct hdlcdrv_state *s, unsigned int bits)
-{
- hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, bits);
-}
-
-static inline unsigned int hdlcdrv_getbits(struct hdlcdrv_state *s)
-{
- unsigned int ret;
-
- if (hdlcdrv_hbuf_empty(&s->hdlctx.hbuf)) {
- if (s->hdlctx.calibrate > 0)
- s->hdlctx.calibrate--;
- else
- s->hdlctx.ptt = 0;
- ret = 0;
- } else
- ret = hdlcdrv_hbuf_get(&s->hdlctx.hbuf);
-#ifdef HDLCDRV_LOOPBACK
- hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, ret);
-#endif /* HDLCDRV_LOOPBACK */
- return ret;
-}
-
-static inline void hdlcdrv_channelbit(struct hdlcdrv_state *s, unsigned int bit)
-{
-#ifdef HDLCDRV_DEBUG
- hdlcdrv_add_bitbuffer(&s->bitbuf_channel, bit);
-#endif /* HDLCDRV_DEBUG */
-}
-
-static inline void hdlcdrv_setdcd(struct hdlcdrv_state *s, int dcd)
-{
- s->hdlcrx.dcd = !!dcd;
-}
-
-static inline int hdlcdrv_ptt(struct hdlcdrv_state *s)
-{
- return s->hdlctx.ptt || (s->hdlctx.calibrate > 0);
-}
-
-/* -------------------------------------------------------------------- */
-
-void hdlcdrv_receiver(struct net_device *, struct hdlcdrv_state *);
-void hdlcdrv_transmitter(struct net_device *, struct hdlcdrv_state *);
-void hdlcdrv_arbitrate(struct net_device *, struct hdlcdrv_state *);
-struct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops,
- unsigned int privsize, const char *ifname,
- unsigned int baseaddr, unsigned int irq,
- unsigned int dma);
-void hdlcdrv_unregister(struct net_device *dev);
-
-/* -------------------------------------------------------------------- */
-
-
-
-#endif /* _HDLCDRV_H */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 7969fcdd5ac4..e9e2ec8d4c19 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -162,7 +162,7 @@ static inline bool dev_xmit_complete(int rc)
#if defined(CONFIG_HYPERV_NET)
# define LL_MAX_HEADER 128
-#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
+#elif defined(CONFIG_WLAN)
# if defined(CONFIG_MAC80211_MESH)
# define LL_MAX_HEADER 128
# else
@@ -2316,9 +2316,6 @@ struct net_device {
#if IS_ENABLED(CONFIG_ATALK)
void *atalk_ptr;
#endif
-#if IS_ENABLED(CONFIG_AX25)
- struct ax25_dev __rcu *ax25_ptr;
-#endif
#if IS_ENABLED(CONFIG_CFG80211)
struct wireless_dev *ieee80211_ptr;
#endif
diff --git a/include/linux/scc.h b/include/linux/scc.h
deleted file mode 100644
index 745eabd17c10..000000000000
--- a/include/linux/scc.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* $Id: scc.h,v 1.29 1997/04/02 14:56:45 jreuter Exp jreuter $ */
-#ifndef _SCC_H
-#define _SCC_H
-
-#include <uapi/linux/scc.h>
-
-
-enum {TX_OFF, TX_ON}; /* command for scc_key_trx() */
-
-/* Vector masks in RR2B */
-
-#define VECTOR_MASK 0x06
-#define TXINT 0x00
-#define EXINT 0x02
-#define RXINT 0x04
-#define SPINT 0x06
-
-#ifdef CONFIG_SCC_DELAY
-#define Inb(port) inb_p(port)
-#define Outb(port, val) outb_p(val, port)
-#else
-#define Inb(port) inb(port)
-#define Outb(port, val) outb(val, port)
-#endif
-
-/* SCC channel control structure for KISS */
-
-struct scc_kiss {
- unsigned char txdelay; /* Transmit Delay 10 ms/cnt */
- unsigned char persist; /* Persistence (0-255) as a % */
- unsigned char slottime; /* Delay to wait on persistence hit */
- unsigned char tailtime; /* Delay after last byte written */
- unsigned char fulldup; /* Full Duplex mode 0=CSMA 1=DUP 2=ALWAYS KEYED */
- unsigned char waittime; /* Waittime before any transmit attempt */
- unsigned int maxkeyup; /* Maximum time to transmit (seconds) */
- unsigned int mintime; /* Minimal offtime after MAXKEYUP timeout (seconds) */
- unsigned int idletime; /* Maximum idle time in ALWAYS KEYED mode (seconds) */
- unsigned int maxdefer; /* Timer for CSMA channel busy limit */
- unsigned char tx_inhibit; /* Transmit is not allowed when set */
- unsigned char group; /* Group ID for AX.25 TX interlocking */
- unsigned char mode; /* 'normal' or 'hwctrl' mode (unused) */
- unsigned char softdcd; /* Use DPLL instead of DCD pin for carrier detect */
-};
-
-
-/* SCC channel structure */
-
-struct scc_channel {
- int init; /* channel exists? */
-
- struct net_device *dev; /* link to device control structure */
- struct net_device_stats dev_stat;/* device statistics */
-
- char brand; /* manufacturer of the board */
- long clock; /* used clock */
-
- io_port ctrl; /* I/O address of CONTROL register */
- io_port data; /* I/O address of DATA register */
- io_port special; /* I/O address of special function port */
- int irq; /* Number of Interrupt */
-
- char option;
- char enhanced; /* Enhanced SCC support */
-
- unsigned char wreg[16]; /* Copy of last written value in WRx */
- unsigned char status; /* Copy of R0 at last external interrupt */
- unsigned char dcd; /* DCD status */
-
- struct scc_kiss kiss; /* control structure for KISS params */
- struct scc_stat stat; /* statistical information */
- struct scc_modem modem; /* modem information */
-
- struct sk_buff_head tx_queue; /* next tx buffer */
- struct sk_buff *rx_buff; /* pointer to frame currently received */
- struct sk_buff *tx_buff; /* pointer to frame currently transmitted */
-
- /* Timer */
- struct timer_list tx_t; /* tx timer for this channel */
- struct timer_list tx_wdog; /* tx watchdogs */
-
- /* Channel lock */
- spinlock_t lock; /* Channel guard lock */
-};
-
-#endif /* defined(_SCC_H) */
diff --git a/include/linux/yam.h b/include/linux/yam.h
deleted file mode 100644
index a29b04fa1e66..000000000000
--- a/include/linux/yam.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*****************************************************************************/
-
-/*
- * yam.h -- YAM radio modem driver.
- *
- * Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr)
- * Adapted from baycom.c driver written by Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * Please note that the GPL allows you to use the driver, NOT the radio.
- * In order to use the radio, you need a license from the communications
- * authority of your country.
- */
-
-/*****************************************************************************/
-
-#define SIOCYAMRESERVED (0)
-#define SIOCYAMSCFG (1) /* Set configuration */
-#define SIOCYAMGCFG (2) /* Get configuration */
-#define SIOCYAMSMCS (3) /* Set mcs data */
-
-#define YAM_IOBASE (1 << 0)
-#define YAM_IRQ (1 << 1)
-#define YAM_BITRATE (1 << 2) /* Bit rate of radio port ->57600 */
-#define YAM_MODE (1 << 3) /* 0=simplex 1=duplex 2=duplex+tempo */
-#define YAM_HOLDDLY (1 << 4) /* duplex tempo (sec) */
-#define YAM_TXDELAY (1 << 5) /* Tx Delay (ms) */
-#define YAM_TXTAIL (1 << 6) /* Tx Tail (ms) */
-#define YAM_PERSIST (1 << 7) /* Persist (ms) */
-#define YAM_SLOTTIME (1 << 8) /* Slottime (ms) */
-#define YAM_BAUDRATE (1 << 9) /* Baud rate of rs232 port ->115200 */
-
-#define YAM_MAXBITRATE 57600
-#define YAM_MAXBAUDRATE 115200
-#define YAM_MAXMODE 2
-#define YAM_MAXHOLDDLY 99
-#define YAM_MAXTXDELAY 999
-#define YAM_MAXTXTAIL 999
-#define YAM_MAXPERSIST 255
-#define YAM_MAXSLOTTIME 999
-
-#define YAM_FPGA_SIZE 5302
-
-struct yamcfg {
- unsigned int mask; /* Mask of commands */
- unsigned int iobase; /* IO Base of COM port */
- unsigned int irq; /* IRQ of COM port */
- unsigned int bitrate; /* Bit rate of radio port */
- unsigned int baudrate; /* Baud rate of the RS232 port */
- unsigned int txdelay; /* TxDelay */
- unsigned int txtail; /* TxTail */
- unsigned int persist; /* Persistence */
- unsigned int slottime; /* Slottime */
- unsigned int mode; /* mode 0 (simp), 1(Dupl), 2(Dupl+delay) */
- unsigned int holddly; /* PTT delay in FullDuplex 2 mode */
-};
-
-struct yamdrv_ioctl_cfg {
- int cmd;
- struct yamcfg cfg;
-};
-
-struct yamdrv_ioctl_mcs {
- int cmd;
- unsigned int bitrate;
- unsigned char bits[YAM_FPGA_SIZE];
-};
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 9fc6a6657266..6b2f518facdb 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -1,480 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Declarations of AX.25 type objects.
- *
- * Alan Cox (GW4PTS) 10/11/93
- */
#ifndef _AX25_H
-#define _AX25_H
+#define _AX25_H
#include <linux/ax25.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/refcount.h>
-#include <net/neighbour.h>
-#include <net/sock.h>
-#include <linux/seq_file.h>
-#define AX25_T1CLAMPLO 1
-#define AX25_T1CLAMPHI (30 * HZ)
-
-#define AX25_BPQ_HEADER_LEN 16
-#define AX25_KISS_HEADER_LEN 1
-
-#define AX25_HEADER_LEN 17
-#define AX25_ADDR_LEN 7
-#define AX25_DIGI_HEADER_LEN (AX25_MAX_DIGIS * AX25_ADDR_LEN)
-#define AX25_MAX_HEADER_LEN (AX25_HEADER_LEN + AX25_DIGI_HEADER_LEN)
-
-/* AX.25 Protocol IDs */
-#define AX25_P_ROSE 0x01
-#define AX25_P_VJCOMP 0x06 /* Compressed TCP/IP packet */
- /* Van Jacobsen (RFC 1144) */
-#define AX25_P_VJUNCOMP 0x07 /* Uncompressed TCP/IP packet */
- /* Van Jacobsen (RFC 1144) */
-#define AX25_P_SEGMENT 0x08 /* Segmentation fragment */
-#define AX25_P_TEXNET 0xc3 /* TEXTNET datagram protocol */
-#define AX25_P_LQ 0xc4 /* Link Quality Protocol */
-#define AX25_P_ATALK 0xca /* Appletalk */
-#define AX25_P_ATALK_ARP 0xcb /* Appletalk ARP */
-#define AX25_P_IP 0xcc /* ARPA Internet Protocol */
-#define AX25_P_ARP 0xcd /* ARPA Address Resolution */
-#define AX25_P_FLEXNET 0xce /* FlexNet */
-#define AX25_P_NETROM 0xcf /* NET/ROM */
-#define AX25_P_TEXT 0xF0 /* No layer 3 protocol impl. */
-
-/* AX.25 Segment control values */
-#define AX25_SEG_REM 0x7F
-#define AX25_SEG_FIRST 0x80
-
-#define AX25_CBIT 0x80 /* Command/Response bit */
-#define AX25_EBIT 0x01 /* HDLC Address Extension bit */
-#define AX25_HBIT 0x80 /* Has been repeated bit */
-
-#define AX25_SSSID_SPARE 0x60 /* Unused bits in SSID for standard AX.25 */
-#define AX25_ESSID_SPARE 0x20 /* Unused bits in SSID for extended AX.25 */
-#define AX25_DAMA_FLAG 0x20 /* Well, it is *NOT* unused! (dl1bke 951121 */
-
-#define AX25_COND_ACK_PENDING 0x01
-#define AX25_COND_REJECT 0x02
-#define AX25_COND_PEER_RX_BUSY 0x04
-#define AX25_COND_OWN_RX_BUSY 0x08
-#define AX25_COND_DAMA_MODE 0x10
-
-#ifndef _LINUX_NETDEVICE_H
-#include <linux/netdevice.h>
-#endif
-
-/* Upper sub-layer (LAPB) definitions */
-
-/* Control field templates */
-#define AX25_I 0x00 /* Information frames */
-#define AX25_S 0x01 /* Supervisory frames */
-#define AX25_RR 0x01 /* Receiver ready */
-#define AX25_RNR 0x05 /* Receiver not ready */
-#define AX25_REJ 0x09 /* Reject */
-#define AX25_U 0x03 /* Unnumbered frames */
-#define AX25_SABM 0x2f /* Set Asynchronous Balanced Mode */
-#define AX25_SABME 0x6f /* Set Asynchronous Balanced Mode Extended */
-#define AX25_DISC 0x43 /* Disconnect */
-#define AX25_DM 0x0f /* Disconnected mode */
-#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 */
-
-#define AX25_ILLEGAL 0x100 /* Impossible to be a real frame type */
-
-#define AX25_POLLOFF 0
-#define AX25_POLLON 1
-
-/* AX25 L2 C-bit */
-#define AX25_COMMAND 1
-#define AX25_RESPONSE 2
-
-/* Define Link State constants. */
-
-enum {
- AX25_STATE_0, /* Listening */
- AX25_STATE_1, /* SABM sent */
- AX25_STATE_2, /* DISC sent */
- AX25_STATE_3, /* Established */
- AX25_STATE_4 /* Recovery */
-};
-
-#define AX25_MODULUS 8 /* Standard AX.25 modulus */
-#define AX25_EMODULUS 128 /* Extended AX.25 modulus */
-
-enum {
- AX25_PROTO_STD_SIMPLEX,
- AX25_PROTO_STD_DUPLEX,
-#ifdef CONFIG_AX25_DAMA_SLAVE
- AX25_PROTO_DAMA_SLAVE,
-#endif
- __AX25_PROTO_MAX,
- AX25_PROTO_MAX = __AX25_PROTO_MAX -1
-};
-
-enum {
- AX25_VALUES_IPDEFMODE, /* 0=DG 1=VC */
- AX25_VALUES_AXDEFMODE, /* 0=Normal 1=Extended Seq Nos */
- AX25_VALUES_BACKOFF, /* 0=None 1=Linear 2=Exponential */
- AX25_VALUES_CONMODE, /* Allow connected modes - 0=No 1=no "PID text" 2=all PIDs */
- AX25_VALUES_WINDOW, /* Default window size for standard AX.25 */
- AX25_VALUES_EWINDOW, /* Default window size for extended AX.25 */
- AX25_VALUES_T1, /* Default T1 timeout value */
- AX25_VALUES_T2, /* Default T2 timeout value */
- AX25_VALUES_T3, /* Default T3 timeout value */
- AX25_VALUES_IDLE, /* Connected mode idle timer */
- AX25_VALUES_N2, /* Default N2 value */
- AX25_VALUES_PACLEN, /* AX.25 MTU */
- AX25_VALUES_PROTOCOL, /* Std AX.25, DAMA Slave */
-#ifdef CONFIG_AX25_DAMA_SLAVE
- AX25_VALUES_DS_TIMEOUT, /* DAMA Slave timeout */
-#endif
- AX25_MAX_VALUES /* THIS MUST REMAIN THE LAST ENTRY OF THIS LIST */
-};
-
-#define AX25_DEF_IPDEFMODE 0 /* Datagram */
-#define AX25_DEF_AXDEFMODE 0 /* Normal */
-#define AX25_DEF_BACKOFF 1 /* Linear backoff */
-#define AX25_DEF_CONMODE 2 /* Connected mode allowed */
-#define AX25_DEF_WINDOW 2 /* Window=2 */
-#define AX25_DEF_EWINDOW 32 /* Module-128 Window=32 */
-#define AX25_DEF_T1 10000 /* T1=10s */
-#define AX25_DEF_T2 3000 /* T2=3s */
-#define AX25_DEF_T3 300000 /* T3=300s */
-#define AX25_DEF_N2 10 /* N2=10 */
-#define AX25_DEF_IDLE 0 /* Idle=None */
-#define AX25_DEF_PACLEN 256 /* Paclen=256 */
-#define AX25_DEF_PROTOCOL AX25_PROTO_STD_SIMPLEX /* Standard AX.25 */
-#define AX25_DEF_DS_TIMEOUT 180000 /* DAMA timeout 3 minutes */
-
-typedef struct ax25_uid_assoc {
- struct hlist_node uid_node;
- refcount_t refcount;
- kuid_t uid;
- ax25_address call;
-} ax25_uid_assoc;
-
-#define ax25_uid_for_each(__ax25, list) \
- hlist_for_each_entry(__ax25, list, uid_node)
-
-#define ax25_uid_hold(ax25) \
- refcount_inc(&((ax25)->refcount))
-
-static inline void ax25_uid_put(ax25_uid_assoc *assoc)
-{
- if (refcount_dec_and_test(&assoc->refcount)) {
- kfree(assoc);
- }
-}
-
-typedef struct {
- ax25_address calls[AX25_MAX_DIGIS];
- unsigned char repeated[AX25_MAX_DIGIS];
- unsigned char ndigi;
- signed char lastrepeat;
-} ax25_digi;
-
-typedef struct ax25_route {
- struct ax25_route *next;
- ax25_address callsign;
- struct net_device *dev;
- ax25_digi *digipeat;
- char ip_mode;
-} ax25_route;
-
-void __ax25_put_route(ax25_route *ax25_rt);
-
-extern rwlock_t ax25_route_lock;
-
-static inline void ax25_route_lock_use(void)
-{
- read_lock(&ax25_route_lock);
-}
-
-static inline void ax25_route_lock_unuse(void)
-{
- read_unlock(&ax25_route_lock);
-}
-
-typedef struct {
- char slave; /* slave_mode? */
- struct timer_list slave_timer; /* timeout timer */
- unsigned short slave_timeout; /* when? */
-} ax25_dama_info;
-
-typedef struct ax25_dev {
- struct list_head list;
-
- struct net_device *dev;
- netdevice_tracker dev_tracker;
-
- struct net_device *forward;
- struct ctl_table_header *sysheader;
- int values[AX25_MAX_VALUES];
-#ifdef CONFIG_AX25_DAMA_SLAVE
- ax25_dama_info dama;
-#endif
- refcount_t refcount;
- bool device_up;
- struct rcu_head rcu;
-} ax25_dev;
-
-typedef struct ax25_cb {
- struct hlist_node ax25_node;
- ax25_address source_addr, dest_addr;
- ax25_digi *digipeat;
- ax25_dev *ax25_dev;
- netdevice_tracker dev_tracker;
- unsigned char iamdigi;
- unsigned char state, modulus, pidincl;
- unsigned short vs, vr, va;
- unsigned char condition, backoff;
- unsigned char n2, n2count;
- struct timer_list t1timer, t2timer, t3timer, idletimer;
- unsigned long t1, t2, t3, idle, rtt;
- unsigned short paclen, fragno, fraglen;
- struct sk_buff_head write_queue;
- struct sk_buff_head reseq_queue;
- struct sk_buff_head ack_queue;
- struct sk_buff_head frag_queue;
- unsigned char window;
- struct timer_list timer, dtimer;
- struct sock *sk; /* Backlink to socket */
- refcount_t refcount;
-} ax25_cb;
-
-struct ax25_sock {
- struct sock sk;
- struct ax25_cb *cb;
-};
-
-#define ax25_sk(ptr) container_of_const(ptr, struct ax25_sock, sk)
-
-static inline struct ax25_cb *sk_to_ax25(const struct sock *sk)
-{
- return ax25_sk(sk)->cb;
-}
-
-#define ax25_for_each(__ax25, list) \
- hlist_for_each_entry(__ax25, list, ax25_node)
-
-#define ax25_cb_hold(__ax25) \
- refcount_inc(&((__ax25)->refcount))
-
-static __inline__ void ax25_cb_put(ax25_cb *ax25)
-{
- if (refcount_dec_and_test(&ax25->refcount)) {
- kfree(ax25->digipeat);
- kfree(ax25);
- }
-}
-
-static inline void ax25_dev_hold(ax25_dev *ax25_dev)
-{
- refcount_inc(&ax25_dev->refcount);
-}
-
-static inline void ax25_dev_put(ax25_dev *ax25_dev)
-{
- if (refcount_dec_and_test(&ax25_dev->refcount))
- kfree_rcu(ax25_dev, rcu);
-}
-static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
- skb->dev = dev;
- skb_reset_mac_header(skb);
- skb->pkt_type = PACKET_HOST;
- return htons(ETH_P_AX25);
-}
-
-/* af_ax25.c */
-extern struct hlist_head ax25_list;
-extern spinlock_t ax25_list_lock;
-void ax25_cb_add(ax25_cb *);
-struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int);
-struct sock *ax25_get_socket(ax25_address *, ax25_address *, int);
-ax25_cb *ax25_find_cb(const ax25_address *, ax25_address *, ax25_digi *,
- struct net_device *);
-void ax25_send_to_raw(ax25_address *, struct sk_buff *, int);
-void ax25_destroy_socket(ax25_cb *);
-ax25_cb * __must_check ax25_create_cb(void);
-void ax25_fillin_cb(ax25_cb *, ax25_dev *);
-struct sock *ax25_make_new(struct sock *, struct ax25_dev *);
-
-/* ax25_addr.c */
-extern const ax25_address ax25_bcast;
-extern const ax25_address ax25_defaddr;
-extern const ax25_address null_ax25_address;
-char *ax2asc(char *buf, const ax25_address *);
-void asc2ax(ax25_address *addr, const char *callsign);
-int ax25cmp(const ax25_address *, const ax25_address *);
-int ax25digicmp(const ax25_digi *, const ax25_digi *);
-const unsigned char *ax25_addr_parse(const unsigned char *, int,
- ax25_address *, ax25_address *, ax25_digi *, int *, int *);
-int ax25_addr_build(unsigned char *, const ax25_address *,
- const ax25_address *, const ax25_digi *, int, int);
-int ax25_addr_size(const ax25_digi *);
-void ax25_digi_invert(const ax25_digi *, ax25_digi *);
-
-/* ax25_dev.c */
-extern spinlock_t ax25_dev_lock;
-
-#if IS_ENABLED(CONFIG_AX25)
-static inline ax25_dev *ax25_dev_ax25dev(const struct net_device *dev)
-{
- return rcu_dereference_rtnl(dev->ax25_ptr);
-}
-#endif
-
-ax25_dev *ax25_addr_ax25dev(ax25_address *);
-void ax25_dev_device_up(struct net_device *);
-void ax25_dev_device_down(struct net_device *);
-int ax25_fwd_ioctl(unsigned int, struct ax25_fwd_struct *);
-struct net_device *ax25_fwd_dev(struct net_device *);
-void ax25_dev_free(void);
-
-/* ax25_ds_in.c */
-int ax25_ds_frame_in(ax25_cb *, struct sk_buff *, int);
-
-/* ax25_ds_subr.c */
-void ax25_ds_nr_error_recovery(ax25_cb *);
-void ax25_ds_enquiry_response(ax25_cb *);
-void ax25_ds_establish_data_link(ax25_cb *);
-void ax25_dev_dama_off(ax25_dev *);
-void ax25_dama_on(ax25_cb *);
-void ax25_dama_off(ax25_cb *);
-
-/* ax25_ds_timer.c */
-void ax25_ds_setup_timer(ax25_dev *);
-void ax25_ds_set_timer(ax25_dev *);
-void ax25_ds_del_timer(ax25_dev *);
-void ax25_ds_timer(ax25_cb *);
-void ax25_ds_t1_timeout(ax25_cb *);
-void ax25_ds_heartbeat_expiry(ax25_cb *);
-void ax25_ds_t3timer_expiry(ax25_cb *);
-void ax25_ds_idletimer_expiry(ax25_cb *);
-
-/* ax25_iface.c */
-
-struct ax25_protocol {
- struct ax25_protocol *next;
- unsigned int pid;
- int (*func)(struct sk_buff *, ax25_cb *);
-};
-
-void ax25_register_pid(struct ax25_protocol *ap);
-void ax25_protocol_release(unsigned int);
-
-struct ax25_linkfail {
- struct hlist_node lf_node;
- void (*func)(ax25_cb *, int);
-};
-
-void ax25_linkfail_register(struct ax25_linkfail *lf);
-void ax25_linkfail_release(struct ax25_linkfail *lf);
-int __must_check ax25_listen_register(const ax25_address *,
- struct net_device *);
-void ax25_listen_release(const ax25_address *, struct net_device *);
-int(*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *);
-int ax25_listen_mine(const ax25_address *, struct net_device *);
-void ax25_link_failed(ax25_cb *, int);
-int ax25_protocol_is_registered(unsigned int);
-
-/* ax25_in.c */
-int ax25_rx_iframe(ax25_cb *, struct sk_buff *);
-int ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *,
- struct net_device *);
-
-/* ax25_ip.c */
-netdev_tx_t ax25_ip_xmit(struct sk_buff *skb);
-extern const struct header_ops ax25_header_ops;
-
-/* ax25_out.c */
-ax25_cb *ax25_send_frame(struct sk_buff *, int, const ax25_address *,
- ax25_address *, ax25_digi *, struct net_device *);
-void ax25_output(ax25_cb *, int, struct sk_buff *);
-void ax25_kick(ax25_cb *);
-void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int);
-void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev);
-int ax25_check_iframes_acked(ax25_cb *, unsigned short);
-
-/* ax25_route.c */
-void ax25_rt_device_down(struct net_device *);
-int ax25_rt_ioctl(unsigned int, void __user *);
-extern const struct seq_operations ax25_rt_seqops;
-ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev);
-struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *,
- ax25_address *, ax25_digi *);
-void ax25_rt_free(void);
-
-/* ax25_std_in.c */
-int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int);
-
-/* ax25_std_subr.c */
-void ax25_std_nr_error_recovery(ax25_cb *);
-void ax25_std_establish_data_link(ax25_cb *);
-void ax25_std_transmit_enquiry(ax25_cb *);
-void ax25_std_enquiry_response(ax25_cb *);
-void ax25_std_timeout_response(ax25_cb *);
-
-/* ax25_std_timer.c */
-void ax25_std_heartbeat_expiry(ax25_cb *);
-void ax25_std_t1timer_expiry(ax25_cb *);
-void ax25_std_t2timer_expiry(ax25_cb *);
-void ax25_std_t3timer_expiry(ax25_cb *);
-void ax25_std_idletimer_expiry(ax25_cb *);
-
-/* ax25_subr.c */
-void ax25_clear_queues(ax25_cb *);
-void ax25_frames_acked(ax25_cb *, unsigned short);
-void ax25_requeue_frames(ax25_cb *);
-int ax25_validate_nr(ax25_cb *, unsigned short);
-int ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *);
-void ax25_send_control(ax25_cb *, int, int, int);
-void ax25_return_dm(struct net_device *, ax25_address *, ax25_address *,
- ax25_digi *);
-void ax25_calculate_t1(ax25_cb *);
-void ax25_calculate_rtt(ax25_cb *);
-void ax25_disconnect(ax25_cb *, int);
-
-/* ax25_timer.c */
-void ax25_setup_timers(ax25_cb *);
-void ax25_start_heartbeat(ax25_cb *);
-void ax25_start_t1timer(ax25_cb *);
-void ax25_start_t2timer(ax25_cb *);
-void ax25_start_t3timer(ax25_cb *);
-void ax25_start_idletimer(ax25_cb *);
-void ax25_stop_heartbeat(ax25_cb *);
-void ax25_stop_t1timer(ax25_cb *);
-void ax25_stop_t2timer(ax25_cb *);
-void ax25_stop_t3timer(ax25_cb *);
-void ax25_stop_idletimer(ax25_cb *);
-int ax25_t1timer_running(ax25_cb *);
-unsigned long ax25_display_timer(struct timer_list *);
-
-/* ax25_uid.c */
-extern int ax25_uid_policy;
-ax25_uid_assoc *ax25_findbyuid(kuid_t);
-int __must_check ax25_uid_ioctl(int, struct sockaddr_ax25 *);
-extern const struct seq_operations ax25_uid_seqops;
-void ax25_uid_free(void);
-
-/* sysctl_net_ax25.c */
-#ifdef CONFIG_SYSCTL
-int ax25_register_dev_sysctl(ax25_dev *ax25_dev);
-void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev);
-#else
-static inline int ax25_register_dev_sysctl(ax25_dev *ax25_dev) { return 0; }
-static inline void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev) {}
-#endif /* CONFIG_SYSCTL */
+#define AX25_ADDR_LEN 7
+#define AX25_P_IP 0xCC
#endif
diff --git a/include/net/netrom.h b/include/net/netrom.h
deleted file mode 100644
index f0565a5987d1..000000000000
--- a/include/net/netrom.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Declarations of NET/ROM type objects.
- *
- * Jonathan Naylor G4KLX 9/4/95
- */
-
-#ifndef _NETROM_H
-#define _NETROM_H
-
-#include <linux/netrom.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <net/sock.h>
-#include <linux/refcount.h>
-#include <linux/seq_file.h>
-#include <net/ax25.h>
-
-#define NR_NETWORK_LEN 15
-#define NR_TRANSPORT_LEN 5
-
-#define NR_PROTO_IP 0x0C
-
-#define NR_PROTOEXT 0x00
-#define NR_CONNREQ 0x01
-#define NR_CONNACK 0x02
-#define NR_DISCREQ 0x03
-#define NR_DISCACK 0x04
-#define NR_INFO 0x05
-#define NR_INFOACK 0x06
-#define NR_RESET 0x07
-
-#define NR_CHOKE_FLAG 0x80
-#define NR_NAK_FLAG 0x40
-#define NR_MORE_FLAG 0x20
-
-/* Define Link State constants. */
-enum {
- NR_STATE_0,
- NR_STATE_1,
- NR_STATE_2,
- NR_STATE_3
-};
-
-#define NR_COND_ACK_PENDING 0x01
-#define NR_COND_REJECT 0x02
-#define NR_COND_PEER_RX_BUSY 0x04
-#define NR_COND_OWN_RX_BUSY 0x08
-
-#define NR_DEFAULT_T1 120000 /* Outstanding frames - 120 seconds */
-#define NR_DEFAULT_T2 5000 /* Response delay - 5 seconds */
-#define NR_DEFAULT_N2 3 /* Number of Retries - 3 */
-#define NR_DEFAULT_T4 180000 /* Busy Delay - 180 seconds */
-#define NR_DEFAULT_IDLE 0 /* No Activity Timeout - none */
-#define NR_DEFAULT_WINDOW 4 /* Default Window Size - 4 */
-#define NR_DEFAULT_OBS 6 /* Default Obsolescence Count - 6 */
-#define NR_DEFAULT_QUAL 10 /* Default Neighbour Quality - 10 */
-#define NR_DEFAULT_TTL 16 /* Default Time To Live - 16 */
-#define NR_DEFAULT_ROUTING 1 /* Is routing enabled ? */
-#define NR_DEFAULT_FAILS 2 /* Link fails until route fails */
-#define NR_DEFAULT_RESET 0 /* Sent / accept reset cmds? */
-
-#define NR_MODULUS 256
-#define NR_MAX_WINDOW_SIZE 127 /* Maximum Window Allowable - 127 */
-#define NR_MAX_PACKET_SIZE 236 /* Maximum Packet Length - 236 */
-
-struct nr_sock {
- struct sock sock;
- ax25_address user_addr, source_addr, dest_addr;
- struct net_device *device;
- unsigned char my_index, my_id;
- unsigned char your_index, your_id;
- unsigned char state, condition, bpqext, window;
- unsigned short vs, vr, va, vl;
- unsigned char n2, n2count;
- unsigned long t1, t2, t4, idle;
- unsigned short fraglen;
- struct timer_list t1timer;
- struct timer_list t2timer;
- struct timer_list t4timer;
- struct timer_list idletimer;
- struct sk_buff_head ack_queue;
- struct sk_buff_head reseq_queue;
- struct sk_buff_head frag_queue;
-};
-
-#define nr_sk(sk) ((struct nr_sock *)(sk))
-
-struct nr_neigh {
- struct hlist_node neigh_node;
- ax25_address callsign;
- ax25_digi *digipeat;
- ax25_cb *ax25;
- struct net_device *dev;
- unsigned char quality;
- unsigned char locked;
- unsigned short count;
- unsigned int number;
- unsigned char failed;
- refcount_t refcount;
-};
-
-struct nr_route {
- unsigned char quality;
- unsigned char obs_count;
- struct nr_neigh *neighbour;
-};
-
-struct nr_node {
- struct hlist_node node_node;
- ax25_address callsign;
- char mnemonic[7];
- unsigned char which;
- unsigned char count;
- struct nr_route routes[3];
- refcount_t refcount;
- spinlock_t node_lock;
-};
-
-/*********************************************************************
- * nr_node & nr_neigh lists, refcounting and locking
- *********************************************************************/
-
-#define nr_node_hold(__nr_node) \
- refcount_inc(&((__nr_node)->refcount))
-
-static __inline__ void nr_node_put(struct nr_node *nr_node)
-{
- if (refcount_dec_and_test(&nr_node->refcount)) {
- kfree(nr_node);
- }
-}
-
-#define nr_neigh_hold(__nr_neigh) \
- refcount_inc(&((__nr_neigh)->refcount))
-
-static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh)
-{
- if (refcount_dec_and_test(&nr_neigh->refcount)) {
- if (nr_neigh->ax25)
- ax25_cb_put(nr_neigh->ax25);
- kfree(nr_neigh->digipeat);
- kfree(nr_neigh);
- }
-}
-
-/* nr_node_lock and nr_node_unlock also hold/put the node's refcounter.
- */
-static __inline__ void nr_node_lock(struct nr_node *nr_node)
-{
- nr_node_hold(nr_node);
- spin_lock_bh(&nr_node->node_lock);
-}
-
-static __inline__ void nr_node_unlock(struct nr_node *nr_node)
-{
- spin_unlock_bh(&nr_node->node_lock);
- nr_node_put(nr_node);
-}
-
-#define nr_neigh_for_each(__nr_neigh, list) \
- hlist_for_each_entry(__nr_neigh, list, neigh_node)
-
-#define nr_neigh_for_each_safe(__nr_neigh, node2, list) \
- hlist_for_each_entry_safe(__nr_neigh, node2, list, neigh_node)
-
-#define nr_node_for_each(__nr_node, list) \
- hlist_for_each_entry(__nr_node, list, node_node)
-
-#define nr_node_for_each_safe(__nr_node, node2, list) \
- hlist_for_each_entry_safe(__nr_node, node2, list, node_node)
-
-
-/*********************************************************************/
-
-/* af_netrom.c */
-extern int sysctl_netrom_default_path_quality;
-extern int sysctl_netrom_obsolescence_count_initialiser;
-extern int sysctl_netrom_network_ttl_initialiser;
-extern int sysctl_netrom_transport_timeout;
-extern int sysctl_netrom_transport_maximum_tries;
-extern int sysctl_netrom_transport_acknowledge_delay;
-extern int sysctl_netrom_transport_busy_delay;
-extern int sysctl_netrom_transport_requested_window_size;
-extern int sysctl_netrom_transport_no_activity_timeout;
-extern int sysctl_netrom_routing_control;
-extern int sysctl_netrom_link_fails_count;
-extern int sysctl_netrom_reset_circuit;
-
-int nr_rx_frame(struct sk_buff *, struct net_device *);
-void nr_destroy_socket(struct sock *);
-
-/* nr_dev.c */
-int nr_rx_ip(struct sk_buff *, struct net_device *);
-void nr_setup(struct net_device *);
-
-/* nr_in.c */
-int nr_process_rx_frame(struct sock *, struct sk_buff *);
-
-/* nr_loopback.c */
-void nr_loopback_init(void);
-void nr_loopback_clear(void);
-int nr_loopback_queue(struct sk_buff *);
-
-/* nr_out.c */
-void nr_output(struct sock *, struct sk_buff *);
-void nr_send_nak_frame(struct sock *);
-void nr_kick(struct sock *);
-void nr_transmit_buffer(struct sock *, struct sk_buff *);
-void nr_establish_data_link(struct sock *);
-void nr_enquiry_response(struct sock *);
-void nr_check_iframes_acked(struct sock *, unsigned short);
-
-/* nr_route.c */
-void nr_rt_device_down(struct net_device *);
-struct net_device *nr_dev_first(void);
-struct net_device *nr_dev_get(ax25_address *);
-int nr_rt_ioctl(unsigned int, void __user *);
-void nr_link_failed(ax25_cb *, int);
-int nr_route_frame(struct sk_buff *, ax25_cb *);
-extern const struct seq_operations nr_node_seqops;
-extern const struct seq_operations nr_neigh_seqops;
-void nr_rt_free(void);
-
-/* nr_subr.c */
-void nr_clear_queues(struct sock *);
-void nr_frames_acked(struct sock *, unsigned short);
-void nr_requeue_frames(struct sock *);
-int nr_validate_nr(struct sock *, unsigned short);
-int nr_in_rx_window(struct sock *, unsigned short);
-void nr_write_internal(struct sock *, int);
-
-void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags);
-
-/*
- * This routine is called when a Connect Acknowledge with the Choke Flag
- * set is needed to refuse a connection.
- */
-#define nr_transmit_refusal(skb, mine) \
-do { \
- __nr_transmit_reply((skb), (mine), NR_CONNACK | NR_CHOKE_FLAG); \
-} while (0)
-
-/*
- * This routine is called when we don't have a circuit matching an incoming
- * NET/ROM packet. This is an G8PZT Xrouter extension.
- */
-#define nr_transmit_reset(skb, mine) \
-do { \
- __nr_transmit_reply((skb), (mine), NR_RESET); \
-} while (0)
-
-void nr_disconnect(struct sock *, int);
-
-/* nr_timer.c */
-void nr_init_timers(struct sock *sk);
-void nr_start_heartbeat(struct sock *);
-void nr_start_t1timer(struct sock *);
-void nr_start_t2timer(struct sock *);
-void nr_start_t4timer(struct sock *);
-void nr_start_idletimer(struct sock *);
-void nr_stop_heartbeat(struct sock *);
-void nr_stop_t1timer(struct sock *);
-void nr_stop_t2timer(struct sock *);
-void nr_stop_t4timer(struct sock *);
-void nr_stop_idletimer(struct sock *);
-int nr_t1timer_running(struct sock *);
-
-/* sysctl_net_netrom.c */
-int nr_register_sysctl(void);
-void nr_unregister_sysctl(void);
-
-#endif
diff --git a/include/net/rose.h b/include/net/rose.h
index 2b5491bbf39a..41bfcb224f0b 100644
--- a/include/net/rose.h
+++ b/include/net/rose.h
@@ -1,266 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Declarations of Rose type objects.
- *
- * Jonathan Naylor G4KLX 25/8/96
- */
-
#ifndef _ROSE_H
-#define _ROSE_H
+#define _ROSE_H
-#include <linux/refcount.h>
-#include <linux/rose.h>
-#include <net/ax25.h>
-#include <net/sock.h>
-
-#define ROSE_ADDR_LEN 5
-
-#define ROSE_MIN_LEN 3
-
-#define ROSE_CALL_REQ_ADDR_LEN_OFF 3
-#define ROSE_CALL_REQ_ADDR_LEN_VAL 0xAA /* each address is 10 digits */
-#define ROSE_CALL_REQ_DEST_ADDR_OFF 4
-#define ROSE_CALL_REQ_SRC_ADDR_OFF 9
-#define ROSE_CALL_REQ_FACILITIES_OFF 14
-
-#define ROSE_GFI 0x10
-#define ROSE_Q_BIT 0x80
-#define ROSE_D_BIT 0x40
-#define ROSE_M_BIT 0x10
-
-#define ROSE_CALL_REQUEST 0x0B
-#define ROSE_CALL_ACCEPTED 0x0F
-#define ROSE_CLEAR_REQUEST 0x13
-#define ROSE_CLEAR_CONFIRMATION 0x17
-#define ROSE_DATA 0x00
-#define ROSE_INTERRUPT 0x23
-#define ROSE_INTERRUPT_CONFIRMATION 0x27
-#define ROSE_RR 0x01
-#define ROSE_RNR 0x05
-#define ROSE_REJ 0x09
-#define ROSE_RESET_REQUEST 0x1B
-#define ROSE_RESET_CONFIRMATION 0x1F
-#define ROSE_REGISTRATION_REQUEST 0xF3
-#define ROSE_REGISTRATION_CONFIRMATION 0xF7
-#define ROSE_RESTART_REQUEST 0xFB
-#define ROSE_RESTART_CONFIRMATION 0xFF
-#define ROSE_DIAGNOSTIC 0xF1
-#define ROSE_ILLEGAL 0xFD
-
-/* Define Link State constants. */
-
-enum {
- ROSE_STATE_0, /* Ready */
- ROSE_STATE_1, /* Awaiting Call Accepted */
- ROSE_STATE_2, /* Awaiting Clear Confirmation */
- ROSE_STATE_3, /* Data Transfer */
- ROSE_STATE_4, /* Awaiting Reset Confirmation */
- ROSE_STATE_5 /* Deferred Call Acceptance */
-};
-
-#define ROSE_DEFAULT_T0 180000 /* Default T10 T20 value */
-#define ROSE_DEFAULT_T1 200000 /* Default T11 T21 value */
-#define ROSE_DEFAULT_T2 180000 /* Default T12 T22 value */
-#define ROSE_DEFAULT_T3 180000 /* Default T13 T23 value */
-#define ROSE_DEFAULT_HB 5000 /* Default Holdback value */
-#define ROSE_DEFAULT_IDLE 0 /* No Activity Timeout - none */
-#define ROSE_DEFAULT_ROUTING 1 /* Default routing flag */
-#define ROSE_DEFAULT_FAIL_TIMEOUT 120000 /* Time until link considered usable */
-#define ROSE_DEFAULT_MAXVC 50 /* Maximum number of VCs per neighbour */
-#define ROSE_DEFAULT_WINDOW_SIZE 7 /* Default window size */
-
-#define ROSE_MODULUS 8
-#define ROSE_MAX_PACKET_SIZE 251 /* Maximum packet size */
-
-#define ROSE_COND_ACK_PENDING 0x01
-#define ROSE_COND_PEER_RX_BUSY 0x02
-#define ROSE_COND_OWN_RX_BUSY 0x04
-
-#define FAC_NATIONAL 0x00
-#define FAC_CCITT 0x0F
-
-#define FAC_NATIONAL_RAND 0x7F
-#define FAC_NATIONAL_FLAGS 0x3F
-#define FAC_NATIONAL_DEST_DIGI 0xE9
-#define FAC_NATIONAL_SRC_DIGI 0xEB
-#define FAC_NATIONAL_FAIL_CALL 0xED
-#define FAC_NATIONAL_FAIL_ADD 0xEE
-#define FAC_NATIONAL_DIGIS 0xEF
-
-#define FAC_CCITT_DEST_NSAP 0xC9
-#define FAC_CCITT_SRC_NSAP 0xCB
-
-struct rose_neigh {
- struct rose_neigh *next;
- ax25_address callsign;
- ax25_digi *digipeat;
- ax25_cb *ax25;
- struct net_device *dev;
- unsigned short count;
- refcount_t use;
- unsigned int number;
- char restarted;
- char dce_mode;
- char loopback;
- struct sk_buff_head queue;
- struct timer_list t0timer;
- struct timer_list ftimer;
-};
-
-struct rose_node {
- struct rose_node *next;
- rose_address address;
- unsigned short mask;
- unsigned char count;
- char loopback;
- struct rose_neigh *neighbour[3];
-};
-
-struct rose_route {
- struct rose_route *next;
- unsigned int lci1, lci2;
- rose_address src_addr, dest_addr;
- ax25_address src_call, dest_call;
- struct rose_neigh *neigh1, *neigh2;
- unsigned int rand;
-};
-
-struct rose_sock {
- struct sock sock;
- rose_address source_addr, dest_addr;
- ax25_address source_call, dest_call;
- unsigned char source_ndigis, dest_ndigis;
- ax25_address source_digis[ROSE_MAX_DIGIS];
- ax25_address dest_digis[ROSE_MAX_DIGIS];
- struct rose_neigh *neighbour;
- struct net_device *device;
- netdevice_tracker dev_tracker;
- unsigned int lci, rand;
- unsigned char state, condition, qbitincl, defer;
- unsigned char cause, diagnostic;
- unsigned short vs, vr, va, vl;
- unsigned long t1, t2, t3, hb, idle;
-#ifdef M_BIT
- unsigned short fraglen;
- struct sk_buff_head frag_queue;
-#endif
- struct sk_buff_head ack_queue;
- struct rose_facilities_struct facilities;
- struct timer_list timer;
- struct timer_list idletimer;
-};
-
-#define rose_sk(sk) ((struct rose_sock *)(sk))
-
-static inline void rose_neigh_hold(struct rose_neigh *rose_neigh)
-{
- refcount_inc(&rose_neigh->use);
-}
-
-static inline void rose_neigh_put(struct rose_neigh *rose_neigh)
-{
- if (refcount_dec_and_test(&rose_neigh->use)) {
- if (rose_neigh->ax25)
- ax25_cb_put(rose_neigh->ax25);
- kfree(rose_neigh->digipeat);
- kfree(rose_neigh);
- }
-}
-
-/* af_rose.c */
-extern ax25_address rose_callsign;
-extern int sysctl_rose_restart_request_timeout;
-extern int sysctl_rose_call_request_timeout;
-extern int sysctl_rose_reset_request_timeout;
-extern int sysctl_rose_clear_request_timeout;
-extern int sysctl_rose_no_activity_timeout;
-extern int sysctl_rose_ack_hold_back_timeout;
-extern int sysctl_rose_routing_control;
-extern int sysctl_rose_link_fail_timeout;
-extern int sysctl_rose_maximum_vcs;
-extern int sysctl_rose_window_size;
-
-int rosecmp(const rose_address *, const rose_address *);
-int rosecmpm(const rose_address *, const rose_address *, unsigned short);
-char *rose2asc(char *buf, const rose_address *);
-struct sock *rose_find_socket(unsigned int, struct rose_neigh *);
-void rose_kill_by_neigh(struct rose_neigh *);
-unsigned int rose_new_lci(struct rose_neigh *);
-int rose_rx_call_request(struct sk_buff *, struct net_device *,
- struct rose_neigh *, unsigned int);
-void rose_destroy_socket(struct sock *);
-
-/* rose_dev.c */
-void rose_setup(struct net_device *);
-
-/* rose_in.c */
-int rose_process_rx_frame(struct sock *, struct sk_buff *);
-
-/* rose_link.c */
-void rose_start_ftimer(struct rose_neigh *);
-void rose_stop_ftimer(struct rose_neigh *);
-void rose_stop_t0timer(struct rose_neigh *);
-int rose_ftimer_running(struct rose_neigh *);
-void rose_link_rx_restart(struct sk_buff *, struct rose_neigh *,
- unsigned short);
-void rose_transmit_clear_request(struct rose_neigh *, unsigned int,
- unsigned char, unsigned char);
-void rose_transmit_link(struct sk_buff *, struct rose_neigh *);
-
-/* rose_loopback.c */
-void rose_loopback_init(void);
-void rose_loopback_clear(void);
-int rose_loopback_queue(struct sk_buff *, struct rose_neigh *);
-
-/* rose_out.c */
-void rose_kick(struct sock *);
-void rose_enquiry_response(struct sock *);
-
-/* rose_route.c */
-extern struct rose_neigh *rose_loopback_neigh;
-extern const struct seq_operations rose_neigh_seqops;
-extern const struct seq_operations rose_node_seqops;
-extern struct seq_operations rose_route_seqops;
-
-void rose_add_loopback_neigh(void);
-int __must_check rose_add_loopback_node(const rose_address *);
-void rose_del_loopback_node(const rose_address *);
-void rose_rt_device_down(struct net_device *);
-void rose_link_device_down(struct net_device *);
-struct net_device *rose_dev_first(void);
-struct net_device *rose_dev_get(rose_address *);
-struct rose_route *rose_route_free_lci(unsigned int, struct rose_neigh *);
-struct rose_neigh *rose_get_neigh(rose_address *, unsigned char *,
- unsigned char *, int);
-int rose_rt_ioctl(unsigned int, void __user *);
-void rose_link_failed(ax25_cb *, int);
-int rose_route_frame(struct sk_buff *, ax25_cb *);
-void rose_rt_free(void);
-
-/* rose_subr.c */
-void rose_clear_queues(struct sock *);
-void rose_frames_acked(struct sock *, unsigned short);
-void rose_requeue_frames(struct sock *);
-int rose_validate_nr(struct sock *, unsigned short);
-void rose_write_internal(struct sock *, int);
-int rose_decode(struct sk_buff *, int *, int *, int *, int *, int *);
-int rose_parse_facilities(unsigned char *, unsigned int,
- struct rose_facilities_struct *);
-void rose_disconnect(struct sock *, int, int, int);
-
-/* rose_timer.c */
-void rose_start_heartbeat(struct sock *);
-void rose_start_t1timer(struct sock *);
-void rose_start_t2timer(struct sock *);
-void rose_start_t3timer(struct sock *);
-void rose_start_hbtimer(struct sock *);
-void rose_start_idletimer(struct sock *);
-void rose_stop_heartbeat(struct sock *);
-void rose_stop_timer(struct sock *);
-void rose_stop_idletimer(struct sock *);
-
-/* sysctl_net_rose.c */
-void rose_register_sysctl(void);
-void rose_unregister_sysctl(void);
+#define ROSE_ADDR_LEN 5
#endif
diff --git a/include/uapi/linux/baycom.h b/include/uapi/linux/baycom.h
deleted file mode 100644
index 478cb565ae52..000000000000
--- a/include/uapi/linux/baycom.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * The Linux BAYCOM driver for the Baycom serial 1200 baud modem
- * and the parallel 9600 baud modem
- * (C) 1997-1998 by Thomas Sailer, HB9JNX/AE4WA
- */
-
-#ifndef _BAYCOM_H
-#define _BAYCOM_H
-
-/* -------------------------------------------------------------------- */
-/*
- * structs for the IOCTL commands
- */
-
-struct baycom_debug_data {
- unsigned long debug1;
- unsigned long debug2;
- long debug3;
-};
-
-struct baycom_ioctl {
- int cmd;
- union {
- struct baycom_debug_data dbg;
- } data;
-};
-
-/* -------------------------------------------------------------------- */
-
-/*
- * ioctl values change for baycom
- */
-#define BAYCOMCTL_GETDEBUG 0x92
-
-/* -------------------------------------------------------------------- */
-
-#endif /* _BAYCOM_H */
-
-/* --------------------------------------------------------------------- */
diff --git a/include/uapi/linux/hdlcdrv.h b/include/uapi/linux/hdlcdrv.h
deleted file mode 100644
index 9fe9499403a6..000000000000
--- a/include/uapi/linux/hdlcdrv.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * hdlcdrv.h -- HDLC packet radio network driver.
- * The Linux soundcard driver for 1200 baud and 9600 baud packet radio
- * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA
- */
-
-#ifndef _UAPI_HDLCDRV_H
-#define _UAPI_HDLCDRV_H
-
-/* -------------------------------------------------------------------- */
-/*
- * structs for the IOCTL commands
- */
-
-struct hdlcdrv_params {
- int iobase;
- int irq;
- int dma;
- int dma2;
- int seriobase;
- int pariobase;
- int midiiobase;
-};
-
-struct hdlcdrv_channel_params {
- int tx_delay; /* the transmitter keyup delay in 10ms units */
- int tx_tail; /* the transmitter keyoff delay in 10ms units */
- int slottime; /* the slottime in 10ms; usually 10 = 100ms */
- int ppersist; /* the p-persistence 0..255 */
- int fulldup; /* some driver do not support full duplex, setting */
- /* this just makes them send even if DCD is on */
-};
-
-struct hdlcdrv_old_channel_state {
- int ptt;
- int dcd;
- int ptt_keyed;
-};
-
-struct hdlcdrv_channel_state {
- int ptt;
- int dcd;
- int ptt_keyed;
- unsigned long tx_packets;
- unsigned long tx_errors;
- unsigned long rx_packets;
- unsigned long rx_errors;
-};
-
-struct hdlcdrv_ioctl {
- int cmd;
- union {
- struct hdlcdrv_params mp;
- struct hdlcdrv_channel_params cp;
- struct hdlcdrv_channel_state cs;
- struct hdlcdrv_old_channel_state ocs;
- unsigned int calibrate;
- unsigned char bits;
- char modename[128];
- char drivername[32];
- } data;
-};
-
-/* -------------------------------------------------------------------- */
-
-/*
- * ioctl values
- */
-#define HDLCDRVCTL_GETMODEMPAR 0
-#define HDLCDRVCTL_SETMODEMPAR 1
-#define HDLCDRVCTL_MODEMPARMASK 2 /* not handled by hdlcdrv */
-#define HDLCDRVCTL_GETCHANNELPAR 10
-#define HDLCDRVCTL_SETCHANNELPAR 11
-#define HDLCDRVCTL_OLDGETSTAT 20
-#define HDLCDRVCTL_CALIBRATE 21
-#define HDLCDRVCTL_GETSTAT 22
-
-/*
- * these are mainly for debugging purposes
- */
-#define HDLCDRVCTL_GETSAMPLES 30
-#define HDLCDRVCTL_GETBITS 31
-
-/*
- * not handled by hdlcdrv, but by its depending drivers
- */
-#define HDLCDRVCTL_GETMODE 40
-#define HDLCDRVCTL_SETMODE 41
-#define HDLCDRVCTL_MODELIST 42
-#define HDLCDRVCTL_DRIVERNAME 43
-
-/*
- * mask of needed modem parameters, returned by HDLCDRVCTL_MODEMPARMASK
- */
-#define HDLCDRV_PARMASK_IOBASE (1<<0)
-#define HDLCDRV_PARMASK_IRQ (1<<1)
-#define HDLCDRV_PARMASK_DMA (1<<2)
-#define HDLCDRV_PARMASK_DMA2 (1<<3)
-#define HDLCDRV_PARMASK_SERIOBASE (1<<4)
-#define HDLCDRV_PARMASK_PARIOBASE (1<<5)
-#define HDLCDRV_PARMASK_MIDIIOBASE (1<<6)
-
-/* -------------------------------------------------------------------- */
-
-
-/* -------------------------------------------------------------------- */
-
-#endif /* _UAPI_HDLCDRV_H */
-
-/* -------------------------------------------------------------------- */
diff --git a/include/uapi/linux/netrom.h b/include/uapi/linux/netrom.h
deleted file mode 100644
index 7498ea3c3940..000000000000
--- a/include/uapi/linux/netrom.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * These are the public elements of the Linux kernel NET/ROM implementation.
- * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the
- * definition of the ax25_address structure.
- */
-
-#ifndef NETROM_KERNEL_H
-#define NETROM_KERNEL_H
-
-#include <linux/ax25.h>
-
-#define NETROM_MTU 236
-
-#define NETROM_T1 1
-#define NETROM_T2 2
-#define NETROM_N2 3
-#define NETROM_T4 6
-#define NETROM_IDLE 7
-
-#define SIOCNRDECOBS (SIOCPROTOPRIVATE+2)
-
-struct nr_route_struct {
-#define NETROM_NEIGH 0
-#define NETROM_NODE 1
- int type;
- ax25_address callsign;
- char device[16];
- unsigned int quality;
- char mnemonic[7];
- ax25_address neighbour;
- unsigned int obs_count;
- unsigned int ndigis;
- ax25_address digipeaters[AX25_MAX_DIGIS];
-};
-
-#endif
diff --git a/include/uapi/linux/rose.h b/include/uapi/linux/rose.h
deleted file mode 100644
index 19aa4693c8fc..000000000000
--- a/include/uapi/linux/rose.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * These are the public elements of the Linux kernel Rose implementation.
- * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the
- * definition of the ax25_address structure.
- */
-
-#ifndef ROSE_KERNEL_H
-#define ROSE_KERNEL_H
-
-#include <linux/socket.h>
-#include <linux/ax25.h>
-
-#define ROSE_MTU 251
-
-#define ROSE_MAX_DIGIS 6
-
-#define ROSE_DEFER 1
-#define ROSE_T1 2
-#define ROSE_T2 3
-#define ROSE_T3 4
-#define ROSE_IDLE 5
-#define ROSE_QBITINCL 6
-#define ROSE_HOLDBACK 7
-
-#define SIOCRSGCAUSE (SIOCPROTOPRIVATE+0)
-#define SIOCRSSCAUSE (SIOCPROTOPRIVATE+1)
-#define SIOCRSL2CALL (SIOCPROTOPRIVATE+2)
-#define SIOCRSSL2CALL (SIOCPROTOPRIVATE+2)
-#define SIOCRSACCEPT (SIOCPROTOPRIVATE+3)
-#define SIOCRSCLRRT (SIOCPROTOPRIVATE+4)
-#define SIOCRSGL2CALL (SIOCPROTOPRIVATE+5)
-#define SIOCRSGFACILITIES (SIOCPROTOPRIVATE+6)
-
-#define ROSE_DTE_ORIGINATED 0x00
-#define ROSE_NUMBER_BUSY 0x01
-#define ROSE_INVALID_FACILITY 0x03
-#define ROSE_NETWORK_CONGESTION 0x05
-#define ROSE_OUT_OF_ORDER 0x09
-#define ROSE_ACCESS_BARRED 0x0B
-#define ROSE_NOT_OBTAINABLE 0x0D
-#define ROSE_REMOTE_PROCEDURE 0x11
-#define ROSE_LOCAL_PROCEDURE 0x13
-#define ROSE_SHIP_ABSENT 0x39
-
-typedef struct {
- char rose_addr[5];
-} rose_address;
-
-struct sockaddr_rose {
- __kernel_sa_family_t srose_family;
- rose_address srose_addr;
- ax25_address srose_call;
- int srose_ndigis;
- ax25_address srose_digi;
-};
-
-struct full_sockaddr_rose {
- __kernel_sa_family_t srose_family;
- rose_address srose_addr;
- ax25_address srose_call;
- unsigned int srose_ndigis;
- ax25_address srose_digis[ROSE_MAX_DIGIS];
-};
-
-struct rose_route_struct {
- rose_address address;
- unsigned short mask;
- ax25_address neighbour;
- char device[16];
- unsigned char ndigis;
- ax25_address digipeaters[AX25_MAX_DIGIS];
-};
-
-struct rose_cause_struct {
- unsigned char cause;
- unsigned char diagnostic;
-};
-
-struct rose_facilities_struct {
- rose_address source_addr, dest_addr;
- ax25_address source_call, dest_call;
- unsigned char source_ndigis, dest_ndigis;
- ax25_address source_digis[ROSE_MAX_DIGIS];
- ax25_address dest_digis[ROSE_MAX_DIGIS];
- unsigned int rand;
- rose_address fail_addr;
- ax25_address fail_call;
-};
-
-#endif
diff --git a/include/uapi/linux/scc.h b/include/uapi/linux/scc.h
deleted file mode 100644
index 947edb17ce9d..000000000000
--- a/include/uapi/linux/scc.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/* $Id: scc.h,v 1.29 1997/04/02 14:56:45 jreuter Exp jreuter $ */
-
-#ifndef _UAPI_SCC_H
-#define _UAPI_SCC_H
-
-#include <linux/sockios.h>
-
-/* selection of hardware types */
-
-#define PA0HZP 0x00 /* hardware type for PA0HZP SCC card and compatible */
-#define EAGLE 0x01 /* hardware type for EAGLE card */
-#define PC100 0x02 /* hardware type for PC100 card */
-#define PRIMUS 0x04 /* hardware type for PRIMUS-PC (DG9BL) card */
-#define DRSI 0x08 /* hardware type for DRSI PC*Packet card */
-#define BAYCOM 0x10 /* hardware type for BayCom (U)SCC */
-
-/* DEV ioctl() commands */
-
-enum SCC_ioctl_cmds {
- SIOCSCCRESERVED = SIOCDEVPRIVATE,
- SIOCSCCCFG,
- SIOCSCCINI,
- SIOCSCCCHANINI,
- SIOCSCCSMEM,
- SIOCSCCGKISS,
- SIOCSCCSKISS,
- SIOCSCCGSTAT,
- SIOCSCCCAL
-};
-
-/* Device parameter control (from WAMPES) */
-
-enum L1_params {
- PARAM_DATA,
- PARAM_TXDELAY,
- PARAM_PERSIST,
- PARAM_SLOTTIME,
- PARAM_TXTAIL,
- PARAM_FULLDUP,
- PARAM_SOFTDCD, /* was: PARAM_HW */
- PARAM_MUTE, /* ??? */
- PARAM_DTR,
- PARAM_RTS,
- PARAM_SPEED,
- PARAM_ENDDELAY, /* ??? */
- PARAM_GROUP,
- PARAM_IDLE,
- PARAM_MIN,
- PARAM_MAXKEY,
- PARAM_WAIT,
- PARAM_MAXDEFER,
- PARAM_TX,
- PARAM_HWEVENT = 31,
- PARAM_RETURN = 255 /* reset kiss mode */
-};
-
-/* fulldup parameter */
-
-enum FULLDUP_modes {
- KISS_DUPLEX_HALF, /* normal CSMA operation */
- KISS_DUPLEX_FULL, /* fullduplex, key down trx after transmission */
- KISS_DUPLEX_LINK, /* fullduplex, key down trx after 'idletime' sec */
- KISS_DUPLEX_OPTIMA /* fullduplex, let the protocol layer control the hw */
-};
-
-/* misc. parameters */
-
-#define TIMER_OFF 65535U /* to switch off timers */
-#define NO_SUCH_PARAM 65534U /* param not implemented */
-
-/* HWEVENT parameter */
-
-enum HWEVENT_opts {
- HWEV_DCD_ON,
- HWEV_DCD_OFF,
- HWEV_ALL_SENT
-};
-
-/* channel grouping */
-
-#define RXGROUP 0100 /* if set, only tx when all channels clear */
-#define TXGROUP 0200 /* if set, don't transmit simultaneously */
-
-/* Tx/Rx clock sources */
-
-enum CLOCK_sources {
- CLK_DPLL, /* normal halfduplex operation */
- CLK_EXTERNAL, /* external clocking (G3RUH/DF9IC modems) */
- CLK_DIVIDER, /* Rx = DPLL, Tx = divider (fullduplex with */
- /* modems without clock regeneration */
- CLK_BRG /* experimental fullduplex mode with DPLL/BRG for */
- /* MODEMs without clock recovery */
-};
-
-/* Tx state */
-
-enum TX_state {
- TXS_IDLE, /* Transmitter off, no data pending */
- TXS_BUSY, /* waiting for permission to send / tailtime */
- TXS_ACTIVE, /* Transmitter on, sending data */
- TXS_NEWFRAME, /* reset CRC and send (next) frame */
- TXS_IDLE2, /* Transmitter on, no data pending */
- TXS_WAIT, /* Waiting for Mintime to expire */
- TXS_TIMEOUT /* We had a transmission timeout */
-};
-
-typedef unsigned long io_port; /* type definition for an 'io port address' */
-
-/* SCC statistical information */
-
-struct scc_stat {
- long rxints; /* Receiver interrupts */
- long txints; /* Transmitter interrupts */
- long exints; /* External/status interrupts */
- long spints; /* Special receiver interrupts */
-
- long txframes; /* Packets sent */
- long rxframes; /* Number of Frames Actually Received */
- long rxerrs; /* CRC Errors */
- long txerrs; /* KISS errors */
-
- unsigned int nospace; /* "Out of buffers" */
- unsigned int rx_over; /* Receiver Overruns */
- unsigned int tx_under; /* Transmitter Underruns */
-
- unsigned int tx_state; /* Transmitter state */
- int tx_queued; /* tx frames enqueued */
-
- unsigned int maxqueue; /* allocated tx_buffers */
- unsigned int bufsize; /* used buffersize */
-};
-
-struct scc_modem {
- long speed; /* Line speed, bps */
- char clocksrc; /* 0 = DPLL, 1 = external, 2 = divider */
- char nrz; /* NRZ instead of NRZI */
-};
-
-struct scc_kiss_cmd {
- int command; /* one of the KISS-Commands defined above */
- unsigned param; /* KISS-Param */
-};
-
-struct scc_hw_config {
- io_port data_a; /* data port channel A */
- io_port ctrl_a; /* control port channel A */
- io_port data_b; /* data port channel B */
- io_port ctrl_b; /* control port channel B */
- io_port vector_latch; /* INTACK-Latch (#) */
- io_port special; /* special function port */
-
- int irq; /* irq */
- long clock; /* clock */
- char option; /* command for function port */
-
- char brand; /* hardware type */
- char escc; /* use ext. features of a 8580/85180/85280 */
-};
-
-/* (#) only one INTACK latch allowed. */
-
-
-struct scc_mem_config {
- unsigned int dummy;
- unsigned int bufsize;
-};
-
-struct scc_calibrate {
- unsigned int time;
- unsigned char pattern;
-};
-
-#endif /* _UAPI_SCC_H */
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
deleted file mode 100644
index c8b2dc5c1bec..000000000000
--- a/drivers/net/hamradio/6pack.c
+++ /dev/null
@@ -1,912 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * 6pack.c This module implements the 6pack protocol for kernel-based
- * devices like TTY. It interfaces between a raw TTY and the
- * kernel's AX.25 protocol layers.
- *
- * Authors: Andreas Könsgen <ajk@comnets.uni-bremen.de>
- * Ralf Baechle DL5RB <ralf@linux-mips.org>
- *
- * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by
- *
- * Laurence Culhane, <loz@holmes.demon.co.uk>
- * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- */
-
-#include <linux/module.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/rtnetlink.h>
-#include <linux/spinlock.h>
-#include <linux/if_arp.h>
-#include <linux/init.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/semaphore.h>
-#include <linux/refcount.h>
-
-/* sixpack priority commands */
-#define SIXP_SEOF 0x40 /* start and end of a 6pack frame */
-#define SIXP_TX_URUN 0x48 /* transmit overrun */
-#define SIXP_RX_ORUN 0x50 /* receive overrun */
-#define SIXP_RX_BUF_OVL 0x58 /* receive buffer overflow */
-
-#define SIXP_CHKSUM 0xFF /* valid checksum of a 6pack frame */
-
-/* masks to get certain bits out of the status bytes sent by the TNC */
-
-#define SIXP_CMD_MASK 0xC0
-#define SIXP_CHN_MASK 0x07
-#define SIXP_PRIO_CMD_MASK 0x80
-#define SIXP_STD_CMD_MASK 0x40
-#define SIXP_PRIO_DATA_MASK 0x38
-#define SIXP_TX_MASK 0x20
-#define SIXP_RX_MASK 0x10
-#define SIXP_RX_DCD_MASK 0x18
-#define SIXP_LEDS_ON 0x78
-#define SIXP_LEDS_OFF 0x60
-#define SIXP_CON 0x08
-#define SIXP_STA 0x10
-
-#define SIXP_FOUND_TNC 0xe9
-#define SIXP_CON_ON 0x68
-#define SIXP_DCD_MASK 0x08
-#define SIXP_DAMA_OFF 0
-
-/* default level 2 parameters */
-#define SIXP_TXDELAY 25 /* 250 ms */
-#define SIXP_PERSIST 50 /* in 256ths */
-#define SIXP_SLOTTIME 10 /* 100 ms */
-#define SIXP_INIT_RESYNC_TIMEOUT (3*HZ/2) /* in 1 s */
-#define SIXP_RESYNC_TIMEOUT 5*HZ /* in 1 s */
-
-/* 6pack configuration. */
-#define SIXP_NRUNIT 31 /* MAX number of 6pack channels */
-#define SIXP_MTU 256 /* Default MTU */
-
-enum sixpack_flags {
- SIXPF_ERROR, /* Parity, etc. error */
-};
-
-struct sixpack {
- /* Various fields. */
- struct tty_struct *tty; /* ptr to TTY structure */
- struct net_device *dev; /* easy for intr handling */
-
- /* These are pointers to the malloc()ed frame buffers. */
- int rcount; /* received chars counter */
- unsigned char *xbuff; /* transmitter buffer */
- unsigned char *xhead; /* next byte to XMIT */
- int xleft; /* bytes left in XMIT queue */
-
- u8 raw_buf[4];
- u8 cooked_buf[400];
-
- unsigned int rx_count;
- unsigned int rx_count_cooked;
- spinlock_t rxlock;
-
- unsigned long flags; /* Flag values/ mode etc */
- unsigned char mode; /* 6pack mode */
-
- /* 6pack stuff */
- unsigned char tx_delay;
- unsigned char persistence;
- unsigned char slottime;
- unsigned char duplex;
- unsigned char led_state;
- u8 status;
- u8 status1;
- unsigned char status2;
- unsigned char tx_enable;
- unsigned char tnc_state;
-
- struct timer_list tx_t;
- struct timer_list resync_t;
- spinlock_t lock;
-};
-
-#define AX25_6PACK_HEADER_LEN 0
-
-static void sixpack_decode(struct sixpack *, const u8 *, size_t);
-static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char);
-
-/*
- * Perform the persistence/slottime algorithm for CSMA access. If the
- * persistence check was successful, write the data to the serial driver.
- * Note that in case of DAMA operation, the data is not sent here.
- */
-
-static void sp_xmit_on_air(struct timer_list *t)
-{
- struct sixpack *sp = timer_container_of(sp, t, tx_t);
- int actual, when = sp->slottime;
- static unsigned char random;
-
- random = random * 17 + 41;
-
- if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
- sp->led_state = 0x70;
- sp->tty->ops->write(sp->tty, &sp->led_state, 1);
- sp->tx_enable = 1;
- actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
- sp->xleft -= actual;
- sp->xhead += actual;
- sp->led_state = 0x60;
- sp->tty->ops->write(sp->tty, &sp->led_state, 1);
- sp->status2 = 0;
- } else
- mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100);
-}
-
-/* ----> 6pack timer interrupt handler and friends. <---- */
-
-/* Encapsulate one AX.25 frame and stuff into a TTY queue. */
-static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
-{
- unsigned char *msg, *p = icp;
- int actual, count;
-
- if (len > AX25_MTU + 73) {
- msg = "oversized transmit packet!";
- goto out_drop;
- }
-
- if (p[0] > 5) {
- msg = "invalid KISS command";
- goto out_drop;
- }
-
- if ((p[0] != 0) && (len > 2)) {
- msg = "KISS control packet too long";
- goto out_drop;
- }
-
- if ((p[0] == 0) && (len < 15)) {
- msg = "bad AX.25 packet to transmit";
- goto out_drop;
- }
-
- count = encode_sixpack(p, sp->xbuff, len, sp->tx_delay);
- set_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
-
- switch (p[0]) {
- case 1: sp->tx_delay = p[1];
- return;
- case 2: sp->persistence = p[1];
- return;
- case 3: sp->slottime = p[1];
- return;
- case 4: /* ignored */
- return;
- case 5: sp->duplex = p[1];
- return;
- }
-
- if (p[0] != 0)
- return;
-
- /*
- * In case of fullduplex or DAMA operation, we don't take care about the
- * state of the DCD or of any timers, as the determination of the
- * correct time to send is the job of the AX.25 layer. We send
- * immediately after data has arrived.
- */
- if (sp->duplex == 1) {
- sp->led_state = 0x70;
- sp->tty->ops->write(sp->tty, &sp->led_state, 1);
- sp->tx_enable = 1;
- actual = sp->tty->ops->write(sp->tty, sp->xbuff, count);
- sp->xleft = count - actual;
- sp->xhead = sp->xbuff + actual;
- sp->led_state = 0x60;
- sp->tty->ops->write(sp->tty, &sp->led_state, 1);
- } else {
- sp->xleft = count;
- sp->xhead = sp->xbuff;
- sp->status2 = count;
- sp_xmit_on_air(&sp->tx_t);
- }
-
- return;
-
-out_drop:
- sp->dev->stats.tx_dropped++;
- netif_start_queue(sp->dev);
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);
-}
-
-/* Encapsulate an IP datagram and kick it into a TTY queue. */
-
-static netdev_tx_t sp_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct sixpack *sp = netdev_priv(dev);
-
- if (skb->protocol == htons(ETH_P_IP))
- return ax25_ip_xmit(skb);
-
- spin_lock_bh(&sp->lock);
- /* We were not busy, so we are now... :-) */
- netif_stop_queue(dev);
- dev->stats.tx_bytes += skb->len;
- sp_encaps(sp, skb->data, skb->len);
- spin_unlock_bh(&sp->lock);
-
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-static int sp_open_dev(struct net_device *dev)
-{
- struct sixpack *sp = netdev_priv(dev);
-
- if (sp->tty == NULL)
- return -ENODEV;
- return 0;
-}
-
-/* Close the low-level part of the 6pack channel. */
-static int sp_close(struct net_device *dev)
-{
- struct sixpack *sp = netdev_priv(dev);
-
- spin_lock_bh(&sp->lock);
- if (sp->tty) {
- /* TTY discipline is running. */
- clear_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
- }
- netif_stop_queue(dev);
- spin_unlock_bh(&sp->lock);
-
- return 0;
-}
-
-static int sp_set_mac_address(struct net_device *dev, void *addr)
-{
- struct sockaddr_ax25 *sa = addr;
-
- netif_tx_lock_bh(dev);
- netif_addr_lock(dev);
- __dev_addr_set(dev, &sa->sax25_call, AX25_ADDR_LEN);
- netif_addr_unlock(dev);
- netif_tx_unlock_bh(dev);
-
- return 0;
-}
-
-static const struct net_device_ops sp_netdev_ops = {
- .ndo_open = sp_open_dev,
- .ndo_stop = sp_close,
- .ndo_start_xmit = sp_xmit,
- .ndo_set_mac_address = sp_set_mac_address,
-};
-
-static void sp_setup(struct net_device *dev)
-{
- /* Finish setting up the DEVICE info. */
- dev->netdev_ops = &sp_netdev_ops;
- dev->mtu = SIXP_MTU;
- dev->hard_header_len = AX25_MAX_HEADER_LEN;
- dev->header_ops = &ax25_header_ops;
-
- dev->addr_len = AX25_ADDR_LEN;
- dev->type = ARPHRD_AX25;
- dev->tx_queue_len = 10;
-
- /* Only activated in AX.25 mode */
- memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
- dev_addr_set(dev, (u8 *)&ax25_defaddr);
-
- dev->flags = 0;
-}
-
-/* Send one completely decapsulated IP datagram to the IP layer. */
-
-/*
- * This is the routine that sends the received data to the kernel AX.25.
- * 'cmd' is the KISS command. For AX.25 data, it is zero.
- */
-
-static void sp_bump(struct sixpack *sp, char cmd)
-{
- struct sk_buff *skb;
- int count;
- u8 *ptr;
-
- count = sp->rcount + 1;
-
- sp->dev->stats.rx_bytes += count;
-
- if ((skb = dev_alloc_skb(count + 1)) == NULL)
- goto out_mem;
-
- ptr = skb_put(skb, count + 1);
- *ptr++ = cmd; /* KISS command */
-
- memcpy(ptr, sp->cooked_buf + 1, count);
- skb->protocol = ax25_type_trans(skb, sp->dev);
- netif_rx(skb);
- sp->dev->stats.rx_packets++;
-
- return;
-
-out_mem:
- sp->dev->stats.rx_dropped++;
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * Called by the TTY driver when there's room for more data. If we have
- * more packets to send, we send them here.
- */
-static void sixpack_write_wakeup(struct tty_struct *tty)
-{
- struct sixpack *sp = tty->disc_data;
- int actual;
-
- if (!sp)
- return;
- if (sp->xleft <= 0) {
- /* Now serial buffer is almost free & we can start
- * transmission of another packet */
- sp->dev->stats.tx_packets++;
- clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sp->tx_enable = 0;
- netif_wake_queue(sp->dev);
- return;
- }
-
- if (sp->tx_enable) {
- actual = tty->ops->write(tty, sp->xhead, sp->xleft);
- sp->xleft -= actual;
- sp->xhead += actual;
- }
-}
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * Handle the 'receiver data ready' interrupt.
- * This function is called by the tty module in the kernel when
- * a block of 6pack data has been received, which can now be decapsulated
- * and sent on to some IP layer for further processing.
- */
-static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp,
- const u8 *fp, size_t count)
-{
- struct sixpack *sp;
-
- if (!count)
- return;
-
- sp = tty->disc_data;
- if (!sp)
- return;
-
- /* Read the characters out of the buffer */
- while (count--) {
- if (fp && *fp++) {
- if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))
- sp->dev->stats.rx_errors++;
- cp++;
- continue;
- }
- sixpack_decode(sp, cp, 1);
- cp++;
- }
-
- tty_unthrottle(tty);
-}
-
-/*
- * Try to resync the TNC. Called by the resync timer defined in
- * decode_prio_command
- */
-
-#define TNC_UNINITIALIZED 0
-#define TNC_UNSYNC_STARTUP 1
-#define TNC_UNSYNCED 2
-#define TNC_IN_SYNC 3
-
-static void __tnc_set_sync_state(struct sixpack *sp, int new_tnc_state)
-{
- char *msg;
-
- switch (new_tnc_state) {
- default: /* gcc oh piece-o-crap ... */
- case TNC_UNSYNC_STARTUP:
- msg = "Synchronizing with TNC";
- break;
- case TNC_UNSYNCED:
- msg = "Lost synchronization with TNC\n";
- break;
- case TNC_IN_SYNC:
- msg = "Found TNC";
- break;
- }
-
- sp->tnc_state = new_tnc_state;
- printk(KERN_INFO "%s: %s\n", sp->dev->name, msg);
-}
-
-static inline void tnc_set_sync_state(struct sixpack *sp, int new_tnc_state)
-{
- int old_tnc_state = sp->tnc_state;
-
- if (old_tnc_state != new_tnc_state)
- __tnc_set_sync_state(sp, new_tnc_state);
-}
-
-static void resync_tnc(struct timer_list *t)
-{
- struct sixpack *sp = timer_container_of(sp, t, resync_t);
- static char resync_cmd = 0xe8;
-
- /* clear any data that might have been received */
-
- sp->rx_count = 0;
- sp->rx_count_cooked = 0;
-
- /* reset state machine */
-
- sp->status = 1;
- sp->status1 = 1;
- sp->status2 = 0;
-
- /* resync the TNC */
-
- sp->led_state = 0x60;
- sp->tty->ops->write(sp->tty, &sp->led_state, 1);
- sp->tty->ops->write(sp->tty, &resync_cmd, 1);
-
-
- /* Start resync timer again -- the TNC might be still absent */
- mod_timer(&sp->resync_t, jiffies + SIXP_RESYNC_TIMEOUT);
-}
-
-static inline int tnc_init(struct sixpack *sp)
-{
- unsigned char inbyte = 0xe8;
-
- tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP);
-
- sp->tty->ops->write(sp->tty, &inbyte, 1);
-
- mod_timer(&sp->resync_t, jiffies + SIXP_RESYNC_TIMEOUT);
-
- return 0;
-}
-
-/*
- * Open the high-level part of the 6pack channel.
- * This function is called by the TTY module when the
- * 6pack line discipline is called for. Because we are
- * sure the tty line exists, we only have to link it to
- * a free 6pcack channel...
- */
-static int sixpack_open(struct tty_struct *tty)
-{
- char *xbuff = NULL;
- struct net_device *dev;
- struct sixpack *sp;
- unsigned long len;
- int err = 0;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (tty->ops->write == NULL)
- return -EOPNOTSUPP;
-
- dev = alloc_netdev(sizeof(struct sixpack), "sp%d", NET_NAME_UNKNOWN,
- sp_setup);
- if (!dev) {
- err = -ENOMEM;
- goto out;
- }
-
- sp = netdev_priv(dev);
- sp->dev = dev;
-
- spin_lock_init(&sp->lock);
- spin_lock_init(&sp->rxlock);
-
- /* !!! length of the buffers. MTU is IP MTU, not PACLEN! */
-
- len = dev->mtu * 2;
-
- xbuff = kmalloc(len + 4, GFP_KERNEL);
- if (xbuff == NULL) {
- err = -ENOBUFS;
- goto out_free;
- }
-
- spin_lock_bh(&sp->lock);
-
- sp->tty = tty;
-
- sp->xbuff = xbuff;
-
- sp->rcount = 0;
- sp->rx_count = 0;
- sp->rx_count_cooked = 0;
- sp->xleft = 0;
-
- sp->flags = 0; /* Clear ESCAPE & ERROR flags */
-
- sp->duplex = 0;
- sp->tx_delay = SIXP_TXDELAY;
- sp->persistence = SIXP_PERSIST;
- sp->slottime = SIXP_SLOTTIME;
- sp->led_state = 0x60;
- sp->status = 1;
- sp->status1 = 1;
- sp->status2 = 0;
- sp->tx_enable = 0;
-
- netif_start_queue(dev);
-
- timer_setup(&sp->tx_t, sp_xmit_on_air, 0);
-
- timer_setup(&sp->resync_t, resync_tnc, 0);
-
- spin_unlock_bh(&sp->lock);
-
- /* Done. We have linked the TTY line to a channel. */
- tty->disc_data = sp;
- tty->receive_room = 65536;
-
- /* Now we're ready to register. */
- err = register_netdev(dev);
- if (err)
- goto out_free;
-
- tnc_init(sp);
-
- return 0;
-
-out_free:
- kfree(xbuff);
-
- free_netdev(dev);
-
-out:
- return err;
-}
-
-
-/*
- * Close down a 6pack channel.
- * This means flushing out any pending queues, and then restoring the
- * TTY line discipline to what it was before it got hooked to 6pack
- * (which usually is TTY again).
- */
-static void sixpack_close(struct tty_struct *tty)
-{
- struct sixpack *sp;
-
- sp = tty->disc_data;
- if (!sp)
- return;
-
- tty->disc_data = NULL;
-
- /* We must stop the queue to avoid potentially scribbling
- * on the free buffers. The sp->dead completion is not sufficient
- * to protect us from sp->xbuff access.
- */
- netif_stop_queue(sp->dev);
-
- unregister_netdev(sp->dev);
-
- timer_delete_sync(&sp->tx_t);
- timer_delete_sync(&sp->resync_t);
-
- /* Free all 6pack frame buffers after unreg. */
- kfree(sp->xbuff);
-
- free_netdev(sp->dev);
-}
-
-/* Perform I/O control on an active 6pack channel. */
-static int sixpack_ioctl(struct tty_struct *tty, unsigned int cmd,
- unsigned long arg)
-{
- struct sixpack *sp = tty->disc_data;
- struct net_device *dev;
- unsigned int tmp, err;
-
- if (!sp)
- return -ENXIO;
- dev = sp->dev;
-
- switch(cmd) {
- case SIOCGIFNAME:
- err = copy_to_user((void __user *) arg, dev->name,
- strlen(dev->name) + 1) ? -EFAULT : 0;
- break;
-
- case SIOCGIFENCAP:
- err = put_user(0, (int __user *) arg);
- break;
-
- case SIOCSIFENCAP:
- if (get_user(tmp, (int __user *) arg)) {
- err = -EFAULT;
- break;
- }
-
- sp->mode = tmp;
- dev->addr_len = AX25_ADDR_LEN;
- dev->hard_header_len = AX25_KISS_HEADER_LEN +
- AX25_MAX_HEADER_LEN + 3;
- dev->type = ARPHRD_AX25;
-
- err = 0;
- break;
-
- case SIOCSIFHWADDR: {
- char addr[AX25_ADDR_LEN];
-
- if (copy_from_user(&addr,
- (void __user *)arg, AX25_ADDR_LEN)) {
- err = -EFAULT;
- break;
- }
-
- netif_tx_lock_bh(dev);
- __dev_addr_set(dev, &addr, AX25_ADDR_LEN);
- netif_tx_unlock_bh(dev);
- err = 0;
- break;
- }
- default:
- err = tty_mode_ioctl(tty, cmd, arg);
- }
-
- return err;
-}
-
-static struct tty_ldisc_ops sp_ldisc = {
- .owner = THIS_MODULE,
- .num = N_6PACK,
- .name = "6pack",
- .open = sixpack_open,
- .close = sixpack_close,
- .ioctl = sixpack_ioctl,
- .receive_buf = sixpack_receive_buf,
- .write_wakeup = sixpack_write_wakeup,
-};
-
-/* Initialize 6pack control device -- register 6pack line discipline */
-
-static int __init sixpack_init_driver(void)
-{
- int status;
-
- /* Register the provided line protocol discipline */
- status = tty_register_ldisc(&sp_ldisc);
- if (status)
- pr_err("6pack: can't register line discipline (err = %d)\n", status);
-
- return status;
-}
-
-static void __exit sixpack_exit_driver(void)
-{
- tty_unregister_ldisc(&sp_ldisc);
-}
-
-/* encode an AX.25 packet into 6pack */
-
-static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw,
- int length, unsigned char tx_delay)
-{
- int count = 0;
- unsigned char checksum = 0, buf[400];
- int raw_count = 0;
-
- tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK;
- tx_buf_raw[raw_count++] = SIXP_SEOF;
-
- buf[0] = tx_delay;
- for (count = 1; count < length; count++)
- buf[count] = tx_buf[count];
-
- for (count = 0; count < length; count++)
- checksum += buf[count];
- buf[length] = (unsigned char) 0xff - checksum;
-
- for (count = 0; count <= length; count++) {
- if ((count % 3) == 0) {
- tx_buf_raw[raw_count++] = (buf[count] & 0x3f);
- tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30);
- } else if ((count % 3) == 1) {
- tx_buf_raw[raw_count++] |= (buf[count] & 0x0f);
- tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x3c);
- } else {
- tx_buf_raw[raw_count++] |= (buf[count] & 0x03);
- tx_buf_raw[raw_count++] = (buf[count] >> 2);
- }
- }
- if ((length % 3) != 2)
- raw_count++;
- tx_buf_raw[raw_count++] = SIXP_SEOF;
- return raw_count;
-}
-
-/* decode 4 sixpack-encoded bytes into 3 data bytes */
-
-static void decode_data(struct sixpack *sp, u8 inbyte)
-{
- u8 *buf;
-
- if (sp->rx_count != 3) {
- sp->raw_buf[sp->rx_count++] = inbyte;
-
- return;
- }
-
- if (sp->rx_count_cooked + 2 >= sizeof(sp->cooked_buf)) {
- pr_err("6pack: cooked buffer overrun, data loss\n");
- sp->rx_count = 0;
- return;
- }
-
- buf = sp->raw_buf;
- sp->cooked_buf[sp->rx_count_cooked++] =
- buf[0] | ((buf[1] << 2) & 0xc0);
- sp->cooked_buf[sp->rx_count_cooked++] =
- (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0);
- sp->cooked_buf[sp->rx_count_cooked++] =
- (buf[2] & 0x03) | (inbyte << 2);
- sp->rx_count = 0;
-}
-
-/* identify and execute a 6pack priority command byte */
-
-static void decode_prio_command(struct sixpack *sp, u8 cmd)
-{
- ssize_t actual;
-
- if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */
-
- /* RX and DCD flags can only be set in the same prio command,
- if the DCD flag has been set without the RX flag in the previous
- prio command. If DCD has not been set before, something in the
- transmission has gone wrong. In this case, RX and DCD are
- cleared in order to prevent the decode_data routine from
- reading further data that might be corrupt. */
-
- if (((sp->status & SIXP_DCD_MASK) == 0) &&
- ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) {
- if (sp->status != 1)
- printk(KERN_DEBUG "6pack: protocol violation\n");
- else
- sp->status = 0;
- cmd &= ~SIXP_RX_DCD_MASK;
- }
- sp->status = cmd & SIXP_PRIO_DATA_MASK;
- } else { /* output watchdog char if idle */
- if ((sp->status2 != 0) && (sp->duplex == 1)) {
- sp->led_state = 0x70;
- sp->tty->ops->write(sp->tty, &sp->led_state, 1);
- sp->tx_enable = 1;
- actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
- sp->xleft -= actual;
- sp->xhead += actual;
- sp->led_state = 0x60;
- sp->status2 = 0;
-
- }
- }
-
- /* needed to trigger the TNC watchdog */
- sp->tty->ops->write(sp->tty, &sp->led_state, 1);
-
- /* if the state byte has been received, the TNC is present,
- so the resync timer can be reset. */
-
- if (sp->tnc_state == TNC_IN_SYNC)
- mod_timer(&sp->resync_t, jiffies + SIXP_INIT_RESYNC_TIMEOUT);
-
- sp->status1 = cmd & SIXP_PRIO_DATA_MASK;
-}
-
-/* identify and execute a standard 6pack command byte */
-
-static void decode_std_command(struct sixpack *sp, u8 cmd)
-{
- u8 checksum = 0, rest = 0;
- short i;
-
- switch (cmd & SIXP_CMD_MASK) { /* normal command */
- case SIXP_SEOF:
- if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) {
- if ((sp->status & SIXP_RX_DCD_MASK) ==
- SIXP_RX_DCD_MASK) {
- sp->led_state = 0x68;
- sp->tty->ops->write(sp->tty, &sp->led_state, 1);
- }
- } else {
- sp->led_state = 0x60;
- /* fill trailing bytes with zeroes */
- sp->tty->ops->write(sp->tty, &sp->led_state, 1);
- spin_lock_bh(&sp->rxlock);
- rest = sp->rx_count;
- if (rest != 0)
- for (i = rest; i <= 3; i++)
- decode_data(sp, 0);
- if (rest == 2)
- sp->rx_count_cooked -= 2;
- else if (rest == 3)
- sp->rx_count_cooked -= 1;
- for (i = 0; i < sp->rx_count_cooked; i++)
- checksum += sp->cooked_buf[i];
- if (checksum != SIXP_CHKSUM) {
- printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum);
- } else {
- sp->rcount = sp->rx_count_cooked-2;
- sp_bump(sp, 0);
- }
- sp->rx_count_cooked = 0;
- spin_unlock_bh(&sp->rxlock);
- }
- break;
- case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n");
- break;
- case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n");
- break;
- case SIXP_RX_BUF_OVL:
- printk(KERN_DEBUG "6pack: RX buffer overflow\n");
- }
-}
-
-/* decode a 6pack packet */
-
-static void
-sixpack_decode(struct sixpack *sp, const u8 *pre_rbuff, size_t count)
-{
- size_t count1;
- u8 inbyte;
-
- for (count1 = 0; count1 < count; count1++) {
- inbyte = pre_rbuff[count1];
- if (inbyte == SIXP_FOUND_TNC) {
- tnc_set_sync_state(sp, TNC_IN_SYNC);
- timer_delete(&sp->resync_t);
- }
- if ((inbyte & SIXP_PRIO_CMD_MASK) != 0)
- decode_prio_command(sp, inbyte);
- else if ((inbyte & SIXP_STD_CMD_MASK) != 0)
- decode_std_command(sp, inbyte);
- else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) {
- spin_lock_bh(&sp->rxlock);
- decode_data(sp, inbyte);
- spin_unlock_bh(&sp->rxlock);
- }
- }
-}
-
-MODULE_AUTHOR("Ralf Baechle DO1GRB <ralf@linux-mips.org>");
-MODULE_DESCRIPTION("6pack driver for AX.25");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_6PACK);
-
-module_init(sixpack_init_driver);
-module_exit(sixpack_exit_driver);
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
deleted file mode 100644
index 5fda7a0fcce0..000000000000
--- a/drivers/net/hamradio/baycom_epp.c
+++ /dev/null
@@ -1,1316 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*****************************************************************************/
-
-/*
- * baycom_epp.c -- baycom epp radio modem driver.
- *
- * Copyright (C) 1998-2000
- * Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * Please note that the GPL allows you to use the driver, NOT the radio.
- * In order to use the radio, you need a license from the communications
- * authority of your country.
- *
- * History:
- * 0.1 xx.xx.1998 Initial version by Matthias Welwarsky (dg2fef)
- * 0.2 21.04.1998 Massive rework by Thomas Sailer
- * Integrated FPGA EPP modem configuration routines
- * 0.3 11.05.1998 Took FPGA config out and moved it into a separate program
- * 0.4 26.07.1999 Adapted to new lowlevel parport driver interface
- * 0.5 03.08.1999 adapt to Linus' new __setup/__initcall
- * removed some pre-2.2 kernel compatibility cruft
- * 0.6 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts
- * 0.7 12.02.2000 adapted to softnet driver interface
- */
-
-/*****************************************************************************/
-
-#include <linux/crc-ccitt.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/workqueue.h>
-#include <linux/fs.h>
-#include <linux/parport.h>
-#include <linux/if_arp.h>
-#include <linux/hdlcdrv.h>
-#include <linux/baycom.h>
-#include <linux/jiffies.h>
-#include <linux/random.h>
-#include <net/ax25.h>
-#include <linux/uaccess.h>
-
-/* --------------------------------------------------------------------- */
-
-#define BAYCOM_DEBUG
-#define BAYCOM_MAGIC 19730510
-
-/* --------------------------------------------------------------------- */
-
-static const char paranoia_str[] = KERN_ERR
- "baycom_epp: bad magic number for hdlcdrv_state struct in routine %s\n";
-
-static const char bc_drvname[] = "baycom_epp";
-static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_epp: version 0.7\n";
-
-/* --------------------------------------------------------------------- */
-
-#define NR_PORTS 4
-
-static struct net_device *baycom_device[NR_PORTS];
-
-/* --------------------------------------------------------------------- */
-
-/* EPP status register */
-#define EPP_DCDBIT 0x80
-#define EPP_PTTBIT 0x08
-#define EPP_NREF 0x01
-#define EPP_NRAEF 0x02
-#define EPP_NRHF 0x04
-#define EPP_NTHF 0x20
-#define EPP_NTAEF 0x10
-#define EPP_NTEF EPP_PTTBIT
-
-/* EPP control register */
-#define EPP_TX_FIFO_ENABLE 0x10
-#define EPP_RX_FIFO_ENABLE 0x08
-#define EPP_MODEM_ENABLE 0x20
-#define EPP_LEDS 0xC0
-#define EPP_IRQ_ENABLE 0x10
-
-/* LPT registers */
-#define LPTREG_ECONTROL 0x402
-#define LPTREG_CONFIGB 0x401
-#define LPTREG_CONFIGA 0x400
-#define LPTREG_EPPDATA 0x004
-#define LPTREG_EPPADDR 0x003
-#define LPTREG_CONTROL 0x002
-#define LPTREG_STATUS 0x001
-#define LPTREG_DATA 0x000
-
-/* LPT control register */
-#define LPTCTRL_PROGRAM 0x04 /* 0 to reprogram */
-#define LPTCTRL_WRITE 0x01
-#define LPTCTRL_ADDRSTB 0x08
-#define LPTCTRL_DATASTB 0x02
-#define LPTCTRL_INTEN 0x10
-
-/* LPT status register */
-#define LPTSTAT_SHIFT_NINTR 6
-#define LPTSTAT_WAIT 0x80
-#define LPTSTAT_NINTR (1<<LPTSTAT_SHIFT_NINTR)
-#define LPTSTAT_PE 0x20
-#define LPTSTAT_DONE 0x10
-#define LPTSTAT_NERROR 0x08
-#define LPTSTAT_EPPTIMEOUT 0x01
-
-/* LPT data register */
-#define LPTDATA_SHIFT_TDI 0
-#define LPTDATA_SHIFT_TMS 2
-#define LPTDATA_TDI (1<<LPTDATA_SHIFT_TDI)
-#define LPTDATA_TCK 0x02
-#define LPTDATA_TMS (1<<LPTDATA_SHIFT_TMS)
-#define LPTDATA_INITBIAS 0x80
-
-
-/* EPP modem config/status bits */
-#define EPP_DCDBIT 0x80
-#define EPP_PTTBIT 0x08
-#define EPP_RXEBIT 0x01
-#define EPP_RXAEBIT 0x02
-#define EPP_RXHFULL 0x04
-
-#define EPP_NTHF 0x20
-#define EPP_NTAEF 0x10
-#define EPP_NTEF EPP_PTTBIT
-
-#define EPP_TX_FIFO_ENABLE 0x10
-#define EPP_RX_FIFO_ENABLE 0x08
-#define EPP_MODEM_ENABLE 0x20
-#define EPP_LEDS 0xC0
-#define EPP_IRQ_ENABLE 0x10
-
-/* Xilinx 4k JTAG instructions */
-#define XC4K_IRLENGTH 3
-#define XC4K_EXTEST 0
-#define XC4K_PRELOAD 1
-#define XC4K_CONFIGURE 5
-#define XC4K_BYPASS 7
-
-#define EPP_CONVENTIONAL 0
-#define EPP_FPGA 1
-#define EPP_FPGAEXTSTATUS 2
-
-#define TXBUFFER_SIZE ((HDLCDRV_MAXFLEN*6/5)+8)
-
-/* ---------------------------------------------------------------------- */
-/*
- * Information that need to be kept for each board.
- */
-
-struct baycom_state {
- int magic;
-
- struct pardevice *pdev;
- struct net_device *dev;
- unsigned int work_running;
- struct delayed_work run_work;
- unsigned int modem;
- unsigned int bitrate;
- unsigned char stat;
-
- struct {
- unsigned int intclk;
- unsigned int fclk;
- unsigned int bps;
- unsigned int extmodem;
- unsigned int loopback;
- } cfg;
-
- struct hdlcdrv_channel_params ch_params;
-
- struct {
- unsigned int bitbuf, bitstream, numbits, state;
- unsigned char *bufptr;
- int bufcnt;
- unsigned char buf[TXBUFFER_SIZE];
- } hdlcrx;
-
- struct {
- int calibrate;
- int slotcnt;
- int flags;
- enum { tx_idle = 0, tx_keyup, tx_data, tx_tail } state;
- unsigned char *bufptr;
- int bufcnt;
- unsigned char buf[TXBUFFER_SIZE];
- } hdlctx;
-
- unsigned int ptt_keyed;
- struct sk_buff *skb; /* next transmit packet */
-
-#ifdef BAYCOM_DEBUG
- struct debug_vals {
- unsigned long last_jiffies;
- unsigned cur_intcnt;
- unsigned last_intcnt;
- int cur_pllcorr;
- int last_pllcorr;
- unsigned int mod_cycles;
- unsigned int demod_cycles;
- } debug_vals;
-#endif /* BAYCOM_DEBUG */
-};
-
-/* --------------------------------------------------------------------- */
-
-#define KISS_VERBOSE
-
-/* --------------------------------------------------------------------- */
-
-#define PARAM_TXDELAY 1
-#define PARAM_PERSIST 2
-#define PARAM_SLOTTIME 3
-#define PARAM_TXTAIL 4
-#define PARAM_FULLDUP 5
-#define PARAM_HARDWARE 6
-#define PARAM_RETURN 255
-
-/* --------------------------------------------------------------------- */
-/*
- * the CRC routines are stolen from WAMPES
- * by Dieter Deyke
- */
-
-
-/*---------------------------------------------------------------------------*/
-
-#if 0
-static inline void append_crc_ccitt(unsigned char *buffer, int len)
-{
- unsigned int crc = 0xffff;
-
- for (;len>0;len--)
- crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff];
- crc ^= 0xffff;
- *buffer++ = crc;
- *buffer++ = crc >> 8;
-}
-#endif
-
-/*---------------------------------------------------------------------------*/
-
-static inline int check_crc_ccitt(const unsigned char *buf, int cnt)
-{
- return (crc_ccitt(0xffff, buf, cnt) & 0xffff) == 0xf0b8;
-}
-
-/*---------------------------------------------------------------------------*/
-
-static inline int calc_crc_ccitt(const unsigned char *buf, int cnt)
-{
- return (crc_ccitt(0xffff, buf, cnt) ^ 0xffff) & 0xffff;
-}
-
-/* ---------------------------------------------------------------------- */
-
-#define tenms_to_flags(bc,tenms) ((tenms * bc->bitrate) / 800)
-
-/* --------------------------------------------------------------------- */
-
-static inline void baycom_int_freq(struct baycom_state *bc)
-{
-#ifdef BAYCOM_DEBUG
- unsigned long cur_jiffies = jiffies;
- /*
- * measure the interrupt frequency
- */
- bc->debug_vals.cur_intcnt++;
- if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
- bc->debug_vals.last_jiffies = cur_jiffies;
- bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
- bc->debug_vals.cur_intcnt = 0;
- bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
- bc->debug_vals.cur_pllcorr = 0;
- }
-#endif /* BAYCOM_DEBUG */
-}
-
-/* ---------------------------------------------------------------------- */
-/*
- * eppconfig_path should be setable via /proc/sys.
- */
-
-static char const eppconfig_path[] = "/usr/sbin/eppfpga";
-
-static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };
-
-/* eppconfig: called during ifconfig up to configure the modem */
-static int eppconfig(struct baycom_state *bc)
-{
- char modearg[256];
- char portarg[16];
- char *argv[] = {
- (char *)eppconfig_path,
- "-s",
- "-p", portarg,
- "-m", modearg,
- NULL };
-
- /* set up arguments */
- sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat",
- bc->cfg.intclk ? "int" : "ext",
- bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps,
- (bc->cfg.fclk + 8 * bc->cfg.bps) / (16 * bc->cfg.bps),
- bc->cfg.loopback ? ",loopback" : "");
- sprintf(portarg, "%ld", bc->pdev->port->base);
- printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
-
- return call_usermodehelper(eppconfig_path, argv, envp, UMH_WAIT_PROC);
-}
-
-/* ---------------------------------------------------------------------- */
-
-static inline void do_kiss_params(struct baycom_state *bc,
- unsigned char *data, unsigned long len)
-{
-
-#ifdef KISS_VERBOSE
-#define PKP(a,b) printk(KERN_INFO "baycomm_epp: channel params: " a "\n", b)
-#else /* KISS_VERBOSE */
-#define PKP(a,b)
-#endif /* KISS_VERBOSE */
-
- if (len < 2)
- return;
- switch(data[0]) {
- case PARAM_TXDELAY:
- bc->ch_params.tx_delay = data[1];
- PKP("TX delay = %ums", 10 * bc->ch_params.tx_delay);
- break;
- case PARAM_PERSIST:
- bc->ch_params.ppersist = data[1];
- PKP("p persistence = %u", bc->ch_params.ppersist);
- break;
- case PARAM_SLOTTIME:
- bc->ch_params.slottime = data[1];
- PKP("slot time = %ums", bc->ch_params.slottime);
- break;
- case PARAM_TXTAIL:
- bc->ch_params.tx_tail = data[1];
- PKP("TX tail = %ums", bc->ch_params.tx_tail);
- break;
- case PARAM_FULLDUP:
- bc->ch_params.fulldup = !!data[1];
- PKP("%s duplex", bc->ch_params.fulldup ? "full" : "half");
- break;
- default:
- break;
- }
-#undef PKP
-}
-
-/* --------------------------------------------------------------------- */
-
-static void encode_hdlc(struct baycom_state *bc)
-{
- struct sk_buff *skb;
- unsigned char *wp, *bp;
- int pkt_len;
- unsigned bitstream, notbitstream, bitbuf, numbit, crc;
- unsigned char crcarr[2];
- int j;
-
- if (bc->hdlctx.bufcnt > 0)
- return;
- skb = bc->skb;
- if (!skb)
- return;
- bc->skb = NULL;
- pkt_len = skb->len-1; /* strip KISS byte */
- wp = bc->hdlctx.buf;
- bp = skb->data+1;
- crc = calc_crc_ccitt(bp, pkt_len);
- crcarr[0] = crc;
- crcarr[1] = crc >> 8;
- *wp++ = 0x7e;
- bitstream = bitbuf = numbit = 0;
- while (pkt_len > -2) {
- bitstream >>= 8;
- bitstream |= ((unsigned int)*bp) << 8;
- bitbuf |= ((unsigned int)*bp) << numbit;
- notbitstream = ~bitstream;
- bp++;
- pkt_len--;
- if (!pkt_len)
- bp = crcarr;
- for (j = 0; j < 8; j++)
- if (unlikely(!(notbitstream & (0x1f0 << j)))) {
- bitstream &= ~(0x100 << j);
- bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) |
- ((bitbuf & ~(((2 << j) << numbit) - 1)) << 1);
- numbit++;
- notbitstream = ~bitstream;
- }
- numbit += 8;
- while (numbit >= 8) {
- *wp++ = bitbuf;
- bitbuf >>= 8;
- numbit -= 8;
- }
- }
- bitbuf |= 0x7e7e << numbit;
- numbit += 16;
- while (numbit >= 8) {
- *wp++ = bitbuf;
- bitbuf >>= 8;
- numbit -= 8;
- }
- bc->hdlctx.bufptr = bc->hdlctx.buf;
- bc->hdlctx.bufcnt = wp - bc->hdlctx.buf;
- dev_kfree_skb(skb);
- bc->dev->stats.tx_packets++;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int transmit(struct baycom_state *bc, int cnt, unsigned char stat)
-{
- struct parport *pp = bc->pdev->port;
- unsigned char tmp[128];
- int i, j;
-
- if (bc->hdlctx.state == tx_tail && !(stat & EPP_PTTBIT))
- bc->hdlctx.state = tx_idle;
- if (bc->hdlctx.state == tx_idle && bc->hdlctx.calibrate <= 0) {
- if (bc->hdlctx.bufcnt <= 0)
- encode_hdlc(bc);
- if (bc->hdlctx.bufcnt <= 0)
- return 0;
- if (!bc->ch_params.fulldup) {
- if (!(stat & EPP_DCDBIT)) {
- bc->hdlctx.slotcnt = bc->ch_params.slottime;
- return 0;
- }
- if ((--bc->hdlctx.slotcnt) > 0)
- return 0;
- bc->hdlctx.slotcnt = bc->ch_params.slottime;
- if (get_random_u8() > bc->ch_params.ppersist)
- return 0;
- }
- }
- if (bc->hdlctx.state == tx_idle && bc->hdlctx.bufcnt > 0) {
- bc->hdlctx.state = tx_keyup;
- bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_delay);
- bc->ptt_keyed++;
- }
- while (cnt > 0) {
- switch (bc->hdlctx.state) {
- case tx_keyup:
- i = min_t(int, cnt, bc->hdlctx.flags);
- cnt -= i;
- bc->hdlctx.flags -= i;
- if (bc->hdlctx.flags <= 0)
- bc->hdlctx.state = tx_data;
- memset(tmp, 0x7e, sizeof(tmp));
- while (i > 0) {
- j = (i > sizeof(tmp)) ? sizeof(tmp) : i;
- if (j != pp->ops->epp_write_data(pp, tmp, j, 0))
- return -1;
- i -= j;
- }
- break;
-
- case tx_data:
- if (bc->hdlctx.bufcnt <= 0) {
- encode_hdlc(bc);
- if (bc->hdlctx.bufcnt <= 0) {
- bc->hdlctx.state = tx_tail;
- bc->hdlctx.flags = tenms_to_flags(bc, bc->ch_params.tx_tail);
- break;
- }
- }
- i = min_t(int, cnt, bc->hdlctx.bufcnt);
- bc->hdlctx.bufcnt -= i;
- cnt -= i;
- if (i != pp->ops->epp_write_data(pp, bc->hdlctx.bufptr, i, 0))
- return -1;
- bc->hdlctx.bufptr += i;
- break;
-
- case tx_tail:
- encode_hdlc(bc);
- if (bc->hdlctx.bufcnt > 0) {
- bc->hdlctx.state = tx_data;
- break;
- }
- i = min_t(int, cnt, bc->hdlctx.flags);
- if (i) {
- cnt -= i;
- bc->hdlctx.flags -= i;
- memset(tmp, 0x7e, sizeof(tmp));
- while (i > 0) {
- j = (i > sizeof(tmp)) ? sizeof(tmp) : i;
- if (j != pp->ops->epp_write_data(pp, tmp, j, 0))
- return -1;
- i -= j;
- }
- break;
- }
- fallthrough;
-
- default:
- if (bc->hdlctx.calibrate <= 0)
- return 0;
- i = min_t(int, cnt, bc->hdlctx.calibrate);
- cnt -= i;
- bc->hdlctx.calibrate -= i;
- memset(tmp, 0, sizeof(tmp));
- while (i > 0) {
- j = (i > sizeof(tmp)) ? sizeof(tmp) : i;
- if (j != pp->ops->epp_write_data(pp, tmp, j, 0))
- return -1;
- i -= j;
- }
- break;
- }
- }
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void do_rxpacket(struct net_device *dev)
-{
- struct baycom_state *bc = netdev_priv(dev);
- struct sk_buff *skb;
- unsigned char *cp;
- unsigned pktlen;
-
- if (bc->hdlcrx.bufcnt < 4)
- return;
- if (!check_crc_ccitt(bc->hdlcrx.buf, bc->hdlcrx.bufcnt))
- return;
- pktlen = bc->hdlcrx.bufcnt-2+1; /* KISS kludge */
- if (!(skb = dev_alloc_skb(pktlen))) {
- printk("%s: memory squeeze, dropping packet\n", dev->name);
- dev->stats.rx_dropped++;
- return;
- }
- cp = skb_put(skb, pktlen);
- *cp++ = 0; /* KISS kludge */
- memcpy(cp, bc->hdlcrx.buf, pktlen - 1);
- skb->protocol = ax25_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
-}
-
-static int receive(struct net_device *dev, int cnt)
-{
- struct baycom_state *bc = netdev_priv(dev);
- struct parport *pp = bc->pdev->port;
- unsigned int bitbuf, notbitstream, bitstream, numbits, state;
- unsigned char tmp[128];
- unsigned char *cp;
- int cnt2, ret = 0;
- int j;
-
- numbits = bc->hdlcrx.numbits;
- state = bc->hdlcrx.state;
- bitstream = bc->hdlcrx.bitstream;
- bitbuf = bc->hdlcrx.bitbuf;
- while (cnt > 0) {
- cnt2 = (cnt > sizeof(tmp)) ? sizeof(tmp) : cnt;
- cnt -= cnt2;
- if (cnt2 != pp->ops->epp_read_data(pp, tmp, cnt2, 0)) {
- ret = -1;
- break;
- }
- cp = tmp;
- for (; cnt2 > 0; cnt2--, cp++) {
- bitstream >>= 8;
- bitstream |= (*cp) << 8;
- bitbuf >>= 8;
- bitbuf |= (*cp) << 8;
- numbits += 8;
- notbitstream = ~bitstream;
- for (j = 0; j < 8; j++) {
-
- /* flag or abort */
- if (unlikely(!(notbitstream & (0x0fc << j)))) {
-
- /* abort received */
- if (!(notbitstream & (0x1fc << j)))
- state = 0;
-
- /* flag received */
- else if ((bitstream & (0x1fe << j)) == (0x0fc << j)) {
- if (state)
- do_rxpacket(dev);
- bc->hdlcrx.bufcnt = 0;
- bc->hdlcrx.bufptr = bc->hdlcrx.buf;
- state = 1;
- numbits = 7-j;
- }
- }
-
- /* stuffed bit */
- else if (unlikely((bitstream & (0x1f8 << j)) == (0xf8 << j))) {
- numbits--;
- bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1);
- }
- }
- while (state && numbits >= 8) {
- if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) {
- state = 0;
- } else {
- *(bc->hdlcrx.bufptr)++ = bitbuf >> (16-numbits);
- bc->hdlcrx.bufcnt++;
- numbits -= 8;
- }
- }
- }
- }
- bc->hdlcrx.numbits = numbits;
- bc->hdlcrx.state = state;
- bc->hdlcrx.bitstream = bitstream;
- bc->hdlcrx.bitbuf = bitbuf;
- return ret;
-}
-
-/* --------------------------------------------------------------------- */
-
-#define GETTICK(x) \
-({ \
- x = (unsigned int)get_cycles(); \
-})
-
-static void epp_bh(struct work_struct *work)
-{
- struct net_device *dev;
- struct baycom_state *bc;
- struct parport *pp;
- unsigned char stat;
- unsigned char tmp[2];
- unsigned int time1 = 0, time2 = 0, time3 = 0;
- int cnt, cnt2;
-
- bc = container_of(work, struct baycom_state, run_work.work);
- dev = bc->dev;
- if (!bc->work_running)
- return;
- baycom_int_freq(bc);
- pp = bc->pdev->port;
- /* update status */
- if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
- goto epptimeout;
- bc->stat = stat;
- bc->debug_vals.last_pllcorr = stat;
- GETTICK(time1);
- if (bc->modem == EPP_FPGAEXTSTATUS) {
- /* get input count */
- tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1;
- if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1)
- goto epptimeout;
- if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2)
- goto epptimeout;
- cnt = tmp[0] | (tmp[1] << 8);
- cnt &= 0x7fff;
- /* get output count */
- tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2;
- if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1)
- goto epptimeout;
- if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2)
- goto epptimeout;
- cnt2 = tmp[0] | (tmp[1] << 8);
- cnt2 = 16384 - (cnt2 & 0x7fff);
- /* return to normal */
- tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
- if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1)
- goto epptimeout;
- if (transmit(bc, cnt2, stat))
- goto epptimeout;
- GETTICK(time2);
- if (receive(dev, cnt))
- goto epptimeout;
- if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
- goto epptimeout;
- bc->stat = stat;
- } else {
- /* try to tx */
- switch (stat & (EPP_NTAEF|EPP_NTHF)) {
- case EPP_NTHF:
- cnt = 2048 - 256;
- break;
-
- case EPP_NTAEF:
- cnt = 2048 - 1793;
- break;
-
- case 0:
- cnt = 0;
- break;
-
- default:
- cnt = 2048 - 1025;
- break;
- }
- if (transmit(bc, cnt, stat))
- goto epptimeout;
- GETTICK(time2);
- /* do receiver */
- while ((stat & (EPP_NRAEF|EPP_NRHF)) != EPP_NRHF) {
- switch (stat & (EPP_NRAEF|EPP_NRHF)) {
- case EPP_NRAEF:
- cnt = 1025;
- break;
-
- case 0:
- cnt = 1793;
- break;
-
- default:
- cnt = 256;
- break;
- }
- if (receive(dev, cnt))
- goto epptimeout;
- if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
- goto epptimeout;
- }
- cnt = 0;
- if (bc->bitrate < 50000)
- cnt = 256;
- else if (bc->bitrate < 100000)
- cnt = 128;
- while (cnt > 0 && stat & EPP_NREF) {
- if (receive(dev, 1))
- goto epptimeout;
- cnt--;
- if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
- goto epptimeout;
- }
- }
- GETTICK(time3);
-#ifdef BAYCOM_DEBUG
- bc->debug_vals.mod_cycles = time2 - time1;
- bc->debug_vals.demod_cycles = time3 - time2;
-#endif /* BAYCOM_DEBUG */
- schedule_delayed_work(&bc->run_work, 1);
- if (!bc->skb)
- netif_wake_queue(dev);
- return;
- epptimeout:
- printk(KERN_ERR "%s: EPP timeout!\n", bc_drvname);
-}
-
-/* ---------------------------------------------------------------------- */
-/*
- * ===================== network driver interface =========================
- */
-
-static netdev_tx_t baycom_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
- struct baycom_state *bc = netdev_priv(dev);
-
- if (skb->protocol == htons(ETH_P_IP))
- return ax25_ip_xmit(skb);
-
- if (skb->data[0] != 0) {
- do_kiss_params(bc, skb->data, skb->len);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- if (bc->skb) {
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- /* strip KISS byte */
- if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) {
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- netif_stop_queue(dev);
- bc->skb = skb;
- return NETDEV_TX_OK;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_set_mac_address(struct net_device *dev, void *addr)
-{
- struct sockaddr *sa = (struct sockaddr *)addr;
-
- /* addr is an AX.25 shifted ASCII mac address */
- dev_addr_set(dev, sa->sa_data);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void epp_wakeup(void *handle)
-{
- struct net_device *dev = (struct net_device *)handle;
- struct baycom_state *bc = netdev_priv(dev);
-
- printk(KERN_DEBUG "baycom_epp: %s: why am I being woken up?\n", dev->name);
- if (!parport_claim(bc->pdev))
- printk(KERN_DEBUG "baycom_epp: %s: I'm broken.\n", dev->name);
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
- */
-
-static int epp_open(struct net_device *dev)
-{
- struct baycom_state *bc = netdev_priv(dev);
- struct parport *pp = parport_find_base(dev->base_addr);
- unsigned int i, j;
- unsigned char tmp[128];
- unsigned char stat;
- unsigned long tstart;
- struct pardev_cb par_cb;
-
- if (!pp) {
- printk(KERN_ERR "%s: parport at 0x%lx unknown\n", bc_drvname, dev->base_addr);
- return -ENXIO;
- }
-#if 0
- if (pp->irq < 0) {
- printk(KERN_ERR "%s: parport at 0x%lx has no irq\n", bc_drvname, pp->base);
- parport_put_port(pp);
- return -ENXIO;
- }
-#endif
- if ((~pp->modes) & (PARPORT_MODE_TRISTATE | PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) {
- printk(KERN_ERR "%s: parport at 0x%lx cannot be used\n",
- bc_drvname, pp->base);
- parport_put_port(pp);
- return -EIO;
- }
- memset(&bc->modem, 0, sizeof(bc->modem));
- memset(&par_cb, 0, sizeof(par_cb));
- par_cb.wakeup = epp_wakeup;
- par_cb.private = (void *)dev;
- par_cb.flags = PARPORT_DEV_EXCL;
- for (i = 0; i < NR_PORTS; i++)
- if (baycom_device[i] == dev)
- break;
-
- if (i == NR_PORTS) {
- pr_err("%s: no device found\n", bc_drvname);
- parport_put_port(pp);
- return -ENODEV;
- }
-
- bc->pdev = parport_register_dev_model(pp, dev->name, &par_cb, i);
- parport_put_port(pp);
- if (!bc->pdev) {
- printk(KERN_ERR "%s: cannot register parport at 0x%lx\n", bc_drvname, pp->base);
- return -ENXIO;
- }
- if (parport_claim(bc->pdev)) {
- printk(KERN_ERR "%s: parport at 0x%lx busy\n", bc_drvname, pp->base);
- parport_unregister_device(bc->pdev);
- return -EBUSY;
- }
- dev->irq = /*pp->irq*/ 0;
- INIT_DELAYED_WORK(&bc->run_work, epp_bh);
- bc->work_running = 1;
- bc->modem = EPP_CONVENTIONAL;
- if (eppconfig(bc))
- printk(KERN_INFO "%s: no FPGA detected, assuming conventional EPP modem\n", bc_drvname);
- else
- bc->modem = /*EPP_FPGA*/ EPP_FPGAEXTSTATUS;
- parport_write_control(pp, LPTCTRL_PROGRAM); /* prepare EPP mode; we aren't using interrupts */
- /* reset the modem */
- tmp[0] = 0;
- tmp[1] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
- if (pp->ops->epp_write_addr(pp, tmp, 2, 0) != 2)
- goto epptimeout;
- /* autoprobe baud rate */
- tstart = jiffies;
- i = 0;
- while (time_before(jiffies, tstart + HZ/3)) {
- if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
- goto epptimeout;
- if ((stat & (EPP_NRAEF|EPP_NRHF)) == EPP_NRHF) {
- schedule();
- continue;
- }
- if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128)
- goto epptimeout;
- if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128)
- goto epptimeout;
- i += 256;
- }
- for (j = 0; j < 256; j++) {
- if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
- goto epptimeout;
- if (!(stat & EPP_NREF))
- break;
- if (pp->ops->epp_read_data(pp, tmp, 1, 0) != 1)
- goto epptimeout;
- i++;
- }
- tstart = jiffies - tstart;
- bc->bitrate = i * (8 * HZ) / tstart;
- j = 1;
- i = bc->bitrate >> 3;
- while (j < 7 && i > 150) {
- j++;
- i >>= 1;
- }
- printk(KERN_INFO "%s: autoprobed bitrate: %d int divider: %d int rate: %d\n",
- bc_drvname, bc->bitrate, j, bc->bitrate >> (j+2));
- tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE/*|j*/;
- if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1)
- goto epptimeout;
- /*
- * initialise hdlc variables
- */
- bc->hdlcrx.state = 0;
- bc->hdlcrx.numbits = 0;
- bc->hdlctx.state = tx_idle;
- bc->hdlctx.bufcnt = 0;
- bc->hdlctx.slotcnt = bc->ch_params.slottime;
- bc->hdlctx.calibrate = 0;
- /* start the bottom half stuff */
- schedule_delayed_work(&bc->run_work, 1);
- netif_start_queue(dev);
- return 0;
-
- epptimeout:
- printk(KERN_ERR "%s: epp timeout during bitrate probe\n", bc_drvname);
- parport_write_control(pp, 0); /* reset the adapter */
- parport_release(bc->pdev);
- parport_unregister_device(bc->pdev);
- return -EIO;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int epp_close(struct net_device *dev)
-{
- struct baycom_state *bc = netdev_priv(dev);
- struct parport *pp = bc->pdev->port;
- unsigned char tmp[1];
-
- bc->work_running = 0;
- cancel_delayed_work_sync(&bc->run_work);
- bc->stat = EPP_DCDBIT;
- tmp[0] = 0;
- pp->ops->epp_write_addr(pp, tmp, 1, 0);
- parport_write_control(pp, 0); /* reset the adapter */
- parport_release(bc->pdev);
- parport_unregister_device(bc->pdev);
- dev_kfree_skb(bc->skb);
- bc->skb = NULL;
- printk(KERN_INFO "%s: close epp at iobase 0x%lx irq %u\n",
- bc_drvname, dev->base_addr, dev->irq);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_setmode(struct baycom_state *bc, const char *modestr)
-{
- const char *cp;
-
- if (strstr(modestr,"intclk"))
- bc->cfg.intclk = 1;
- if (strstr(modestr,"extclk"))
- bc->cfg.intclk = 0;
- if (strstr(modestr,"intmodem"))
- bc->cfg.extmodem = 0;
- if (strstr(modestr,"extmodem"))
- bc->cfg.extmodem = 1;
- if (strstr(modestr,"loopback"))
- bc->cfg.loopback = 1;
- if (strstr(modestr, "noloopback"))
- bc->cfg.loopback = 0;
- if ((cp = strstr(modestr,"fclk="))) {
- bc->cfg.fclk = simple_strtoul(cp+5, NULL, 0);
- if (bc->cfg.fclk < 1000000)
- bc->cfg.fclk = 1000000;
- if (bc->cfg.fclk > 25000000)
- bc->cfg.fclk = 25000000;
- }
- if ((cp = strstr(modestr,"bps="))) {
- bc->cfg.bps = simple_strtoul(cp+4, NULL, 0);
- if (bc->cfg.bps < 1000)
- bc->cfg.bps = 1000;
- if (bc->cfg.bps > 1500000)
- bc->cfg.bps = 1500000;
- }
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
- void __user *data, int cmd)
-{
- struct baycom_state *bc = netdev_priv(dev);
- struct hdlcdrv_ioctl hi;
-
- if (cmd != SIOCDEVPRIVATE)
- return -ENOIOCTLCMD;
-
- if (copy_from_user(&hi, data, sizeof(hi)))
- return -EFAULT;
- switch (hi.cmd) {
- default:
- return -ENOIOCTLCMD;
-
- case HDLCDRVCTL_GETCHANNELPAR:
- hi.data.cp.tx_delay = bc->ch_params.tx_delay;
- hi.data.cp.tx_tail = bc->ch_params.tx_tail;
- hi.data.cp.slottime = bc->ch_params.slottime;
- hi.data.cp.ppersist = bc->ch_params.ppersist;
- hi.data.cp.fulldup = bc->ch_params.fulldup;
- break;
-
- case HDLCDRVCTL_SETCHANNELPAR:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- bc->ch_params.tx_delay = hi.data.cp.tx_delay;
- bc->ch_params.tx_tail = hi.data.cp.tx_tail;
- bc->ch_params.slottime = hi.data.cp.slottime;
- bc->ch_params.ppersist = hi.data.cp.ppersist;
- bc->ch_params.fulldup = hi.data.cp.fulldup;
- bc->hdlctx.slotcnt = 1;
- return 0;
-
- case HDLCDRVCTL_GETMODEMPAR:
- hi.data.mp.iobase = dev->base_addr;
- hi.data.mp.irq = dev->irq;
- hi.data.mp.dma = dev->dma;
- hi.data.mp.dma2 = 0;
- hi.data.mp.seriobase = 0;
- hi.data.mp.pariobase = 0;
- hi.data.mp.midiiobase = 0;
- break;
-
- case HDLCDRVCTL_SETMODEMPAR:
- if ((!capable(CAP_SYS_RAWIO)) || netif_running(dev))
- return -EACCES;
- dev->base_addr = hi.data.mp.iobase;
- dev->irq = /*hi.data.mp.irq*/0;
- dev->dma = /*hi.data.mp.dma*/0;
- return 0;
-
- case HDLCDRVCTL_GETSTAT:
- hi.data.cs.ptt = !!(bc->stat & EPP_PTTBIT);
- hi.data.cs.dcd = !(bc->stat & EPP_DCDBIT);
- hi.data.cs.ptt_keyed = bc->ptt_keyed;
- hi.data.cs.tx_packets = dev->stats.tx_packets;
- hi.data.cs.tx_errors = dev->stats.tx_errors;
- hi.data.cs.rx_packets = dev->stats.rx_packets;
- hi.data.cs.rx_errors = dev->stats.rx_errors;
- break;
-
- case HDLCDRVCTL_OLDGETSTAT:
- hi.data.ocs.ptt = !!(bc->stat & EPP_PTTBIT);
- hi.data.ocs.dcd = !(bc->stat & EPP_DCDBIT);
- hi.data.ocs.ptt_keyed = bc->ptt_keyed;
- break;
-
- case HDLCDRVCTL_CALIBRATE:
- if (!capable(CAP_SYS_RAWIO))
- return -EACCES;
- bc->hdlctx.calibrate = hi.data.calibrate * bc->bitrate / 8;
- return 0;
-
- case HDLCDRVCTL_DRIVERNAME:
- strscpy_pad(hi.data.drivername, "baycom_epp");
- break;
-
- case HDLCDRVCTL_GETMODE:
- sprintf(hi.data.modename, "%sclk,%smodem,fclk=%d,bps=%d%s",
- bc->cfg.intclk ? "int" : "ext",
- bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps,
- bc->cfg.loopback ? ",loopback" : "");
- break;
-
- case HDLCDRVCTL_SETMODE:
- if (!capable(CAP_NET_ADMIN) || netif_running(dev))
- return -EACCES;
- hi.data.modename[sizeof(hi.data.modename)-1] = '\0';
- return baycom_setmode(bc, hi.data.modename);
-
- case HDLCDRVCTL_MODELIST:
- strscpy_pad(hi.data.modename, "intclk,extclk,intmodem,extmodem,divider=x");
- break;
-
- case HDLCDRVCTL_MODEMPARMASK:
- return HDLCDRV_PARMASK_IOBASE;
-
- }
- if (copy_to_user(data, &hi, sizeof(hi)))
- return -EFAULT;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static const struct net_device_ops baycom_netdev_ops = {
- .ndo_open = epp_open,
- .ndo_stop = epp_close,
- .ndo_siocdevprivate = baycom_siocdevprivate,
- .ndo_start_xmit = baycom_send_packet,
- .ndo_set_mac_address = baycom_set_mac_address,
-};
-
-/*
- * Check for a network adaptor of this type, and return '0' if one exists.
- * If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- * If dev->base_addr == 2, allocate space for the device and return success
- * (detachable devices only).
- */
-static void baycom_probe(struct net_device *dev)
-{
- const struct hdlcdrv_channel_params dflt_ch_params = {
- 20, 2, 10, 40, 0
- };
- struct baycom_state *bc;
-
- /*
- * not a real probe! only initialize data structures
- */
- bc = netdev_priv(dev);
- /*
- * initialize the baycom_state struct
- */
- bc->ch_params = dflt_ch_params;
- bc->ptt_keyed = 0;
-
- /*
- * initialize the device struct
- */
-
- /* Fill in the fields of the device structure */
- bc->skb = NULL;
-
- dev->netdev_ops = &baycom_netdev_ops;
- dev->header_ops = &ax25_header_ops;
-
- dev->type = ARPHRD_AX25; /* AF_AX25 device */
- dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
- dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */
- dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
- memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
- dev_addr_set(dev, (u8 *)&null_ax25_address);
- dev->tx_queue_len = 16;
-
- /* New style flags */
- dev->flags = 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * command line settable parameters
- */
-static char *mode[NR_PORTS] = { "", };
-static int iobase[NR_PORTS] = { 0x378, };
-
-module_param_array(mode, charp, NULL, 0);
-MODULE_PARM_DESC(mode, "baycom operating mode");
-module_param_hw_array(iobase, int, ioport, NULL, 0);
-MODULE_PARM_DESC(iobase, "baycom io base address");
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("Baycom epp amateur radio modem driver");
-MODULE_LICENSE("GPL");
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_epp_par_probe(struct pardevice *par_dev)
-{
- struct device_driver *drv = par_dev->dev.driver;
- int len = strlen(drv->name);
-
- if (strncmp(par_dev->name, drv->name, len))
- return -ENODEV;
-
- return 0;
-}
-
-static struct parport_driver baycom_epp_par_driver = {
- .name = "bce",
- .probe = baycom_epp_par_probe,
-};
-
-static void __init baycom_epp_dev_setup(struct net_device *dev)
-{
- struct baycom_state *bc = netdev_priv(dev);
-
- /*
- * initialize part of the baycom_state struct
- */
- bc->dev = dev;
- bc->magic = BAYCOM_MAGIC;
- bc->cfg.fclk = 19666600;
- bc->cfg.bps = 9600;
- /*
- * initialize part of the device struct
- */
- baycom_probe(dev);
-}
-
-static int __init init_baycomepp(void)
-{
- int i, found = 0, ret;
- char set_hw = 1;
-
- printk(bc_drvinfo);
-
- ret = parport_register_driver(&baycom_epp_par_driver);
- if (ret)
- return ret;
-
- /*
- * register net devices
- */
- for (i = 0; i < NR_PORTS; i++) {
- struct net_device *dev;
-
- dev = alloc_netdev(sizeof(struct baycom_state), "bce%d",
- NET_NAME_UNKNOWN, baycom_epp_dev_setup);
-
- if (!dev) {
- printk(KERN_WARNING "bce%d : out of memory\n", i);
- return found ? 0 : -ENOMEM;
- }
-
- sprintf(dev->name, "bce%d", i);
- dev->base_addr = iobase[i];
-
- if (!mode[i])
- set_hw = 0;
- if (!set_hw)
- iobase[i] = 0;
-
- if (register_netdev(dev)) {
- printk(KERN_WARNING "%s: cannot register net device %s\n", bc_drvname, dev->name);
- free_netdev(dev);
- break;
- }
- if (set_hw && baycom_setmode(netdev_priv(dev), mode[i]))
- set_hw = 0;
- baycom_device[i] = dev;
- found++;
- }
-
- if (found == 0) {
- parport_unregister_driver(&baycom_epp_par_driver);
- return -ENXIO;
- }
-
- return 0;
-}
-
-static void __exit cleanup_baycomepp(void)
-{
- int i;
-
- for(i = 0; i < NR_PORTS; i++) {
- struct net_device *dev = baycom_device[i];
-
- if (dev) {
- struct baycom_state *bc = netdev_priv(dev);
- if (bc->magic == BAYCOM_MAGIC) {
- unregister_netdev(dev);
- free_netdev(dev);
- } else
- printk(paranoia_str, "cleanup_module");
- }
- }
- parport_unregister_driver(&baycom_epp_par_driver);
-}
-
-module_init(init_baycomepp);
-module_exit(cleanup_baycomepp);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/*
- * format: baycom_epp=io,mode
- * mode: fpga config options
- */
-
-static int __init baycom_epp_setup(char *str)
-{
- static unsigned __initdata nr_dev = 0;
- int ints[2];
-
- if (nr_dev >= NR_PORTS)
- return 0;
- str = get_options(str, 2, ints);
- if (ints[0] < 1)
- return 0;
- mode[nr_dev] = str;
- iobase[nr_dev] = ints[1];
- nr_dev++;
- return 1;
-}
-
-__setup("baycom_epp=", baycom_epp_setup);
-
-#endif /* MODULE */
-/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
deleted file mode 100644
index f03797103c6a..000000000000
--- a/drivers/net/hamradio/baycom_par.c
+++ /dev/null
@@ -1,598 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*****************************************************************************/
-
-/*
- * baycom_par.c -- baycom par96 and picpar radio modem driver.
- *
- * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * Please note that the GPL allows you to use the driver, NOT the radio.
- * In order to use the radio, you need a license from the communications
- * authority of your country.
- *
- * Supported modems
- *
- * par96: This is a modem for 9600 baud FSK compatible to the G3RUH standard.
- * The modem does all the filtering and regenerates the receiver clock.
- * Data is transferred from and to the PC via a shift register.
- * The shift register is filled with 16 bits and an interrupt is
- * signalled. The PC then empties the shift register in a burst. This
- * modem connects to the parallel port, hence the name. The modem
- * leaves the implementation of the HDLC protocol and the scrambler
- * polynomial to the PC. This modem is no longer available (at least
- * from Baycom) and has been replaced by the PICPAR modem (see below).
- * You may however still build one from the schematics published in
- * cq-DL :-).
- *
- * picpar: This is a redesign of the par96 modem by Henning Rech, DF9IC. The
- * modem is protocol compatible to par96, but uses only three low
- * power ICs and can therefore be fed from the parallel port and
- * does not require an additional power supply. It features
- * built in DCD circuitry. The driver should therefore be configured
- * for hardware DCD.
- *
- * Command line options (insmod command line)
- *
- * mode driver mode string. Valid choices are par96 and picpar.
- * iobase base address of the port; common values are 0x378, 0x278, 0x3bc
- *
- * History:
- * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface
- * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user)
- * 0.3 26.04.1997 init code/data tagged
- * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints)
- * 0.5 11.11.1997 split into separate files for ser12/par96
- * 0.6 03.08.1999 adapt to Linus' new __setup/__initcall
- * removed some pre-2.2 kernel compatibility cruft
- * 0.7 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts
- * 0.8 12.02.2000 adapted to softnet driver interface
- * removed direct parport access, uses parport driver methods
- * 0.9 03.07.2000 fix interface name handling
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/hdlcdrv.h>
-#include <linux/baycom.h>
-#include <linux/parport.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <linux/uaccess.h>
-
-/* --------------------------------------------------------------------- */
-
-#define BAYCOM_DEBUG
-
-/*
- * modem options; bit mask
- */
-#define BAYCOM_OPTIONS_SOFTDCD 1
-
-/* --------------------------------------------------------------------- */
-
-static const char bc_drvname[] = "baycom_par";
-static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_par: version 0.9\n";
-
-/* --------------------------------------------------------------------- */
-
-#define NR_PORTS 4
-
-static struct net_device *baycom_device[NR_PORTS];
-
-/* --------------------------------------------------------------------- */
-
-#define PAR96_BURSTBITS 16
-#define PAR96_BURST 4
-#define PAR96_PTT 2
-#define PAR96_TXBIT 1
-#define PAR96_ACK 0x40
-#define PAR96_RXBIT 0x20
-#define PAR96_DCD 0x10
-#define PAR97_POWER 0xf8
-
-/* ---------------------------------------------------------------------- */
-/*
- * Information that need to be kept for each board.
- */
-
-struct baycom_state {
- struct hdlcdrv_state hdrv;
-
- struct pardevice *pdev;
- unsigned int options;
-
- struct modem_state {
- short arb_divider;
- unsigned char flags;
- unsigned int shreg;
- struct modem_state_par96 {
- int dcd_count;
- unsigned int dcd_shreg;
- unsigned long descram;
- unsigned long scram;
- } par96;
- } modem;
-
-#ifdef BAYCOM_DEBUG
- struct debug_vals {
- unsigned long last_jiffies;
- unsigned cur_intcnt;
- unsigned last_intcnt;
- int cur_pllcorr;
- int last_pllcorr;
- } debug_vals;
-#endif /* BAYCOM_DEBUG */
-};
-
-/* --------------------------------------------------------------------- */
-
-static inline void baycom_int_freq(struct baycom_state *bc)
-{
-#ifdef BAYCOM_DEBUG
- unsigned long cur_jiffies = jiffies;
- /*
- * measure the interrupt frequency
- */
- bc->debug_vals.cur_intcnt++;
- if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
- bc->debug_vals.last_jiffies = cur_jiffies;
- bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
- bc->debug_vals.cur_intcnt = 0;
- bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
- bc->debug_vals.cur_pllcorr = 0;
- }
-#endif /* BAYCOM_DEBUG */
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * ===================== PAR96 specific routines =========================
- */
-
-#define PAR96_DESCRAM_TAP1 0x20000
-#define PAR96_DESCRAM_TAP2 0x01000
-#define PAR96_DESCRAM_TAP3 0x00001
-
-#define PAR96_DESCRAM_TAPSH1 17
-#define PAR96_DESCRAM_TAPSH2 12
-#define PAR96_DESCRAM_TAPSH3 0
-
-#define PAR96_SCRAM_TAP1 0x20000 /* X^17 */
-#define PAR96_SCRAM_TAPN 0x00021 /* X^0+X^5 */
-
-/* --------------------------------------------------------------------- */
-
-static inline void par96_tx(struct net_device *dev, struct baycom_state *bc)
-{
- int i;
- unsigned int data = hdlcdrv_getbits(&bc->hdrv);
- struct parport *pp = bc->pdev->port;
-
- for(i = 0; i < PAR96_BURSTBITS; i++, data >>= 1) {
- unsigned char val = PAR97_POWER;
- bc->modem.par96.scram = ((bc->modem.par96.scram << 1) |
- (bc->modem.par96.scram & 1));
- if (!(data & 1))
- bc->modem.par96.scram ^= 1;
- if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 1))
- bc->modem.par96.scram ^=
- (PAR96_SCRAM_TAPN << 1);
- if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 2))
- val |= PAR96_TXBIT;
- pp->ops->write_data(pp, val);
- pp->ops->write_data(pp, val | PAR96_BURST);
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void par96_rx(struct net_device *dev, struct baycom_state *bc)
-{
- int i;
- unsigned int data, mask, mask2, descx;
- struct parport *pp = bc->pdev->port;
-
- /*
- * do receiver; differential decode and descramble on the fly
- */
- for(data = i = 0; i < PAR96_BURSTBITS; i++) {
- bc->modem.par96.descram = (bc->modem.par96.descram << 1);
- if (pp->ops->read_status(pp) & PAR96_RXBIT)
- bc->modem.par96.descram |= 1;
- descx = bc->modem.par96.descram ^
- (bc->modem.par96.descram >> 1);
- /* now the diff decoded data is inverted in descram */
- pp->ops->write_data(pp, PAR97_POWER | PAR96_PTT);
- descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^
- (descx >> PAR96_DESCRAM_TAPSH2));
- data >>= 1;
- if (!(descx & 1))
- data |= 0x8000;
- pp->ops->write_data(pp, PAR97_POWER | PAR96_PTT | PAR96_BURST);
- }
- hdlcdrv_putbits(&bc->hdrv, data);
- /*
- * do DCD algorithm
- */
- if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
- bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg >> 16)
- | (data << 16);
- /* search for flags and set the dcd counter appropriately */
- for(mask = 0x1fe00, mask2 = 0xfc00, i = 0;
- i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1)
- if ((bc->modem.par96.dcd_shreg & mask) == mask2)
- bc->modem.par96.dcd_count = HDLCDRV_MAXFLEN+4;
- /* check for abort/noise sequences */
- for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0;
- i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1)
- if (((bc->modem.par96.dcd_shreg & mask) == mask2) &&
- (bc->modem.par96.dcd_count >= 0))
- bc->modem.par96.dcd_count -= HDLCDRV_MAXFLEN-10;
- /* decrement and set the dcd variable */
- if (bc->modem.par96.dcd_count >= 0)
- bc->modem.par96.dcd_count -= 2;
- hdlcdrv_setdcd(&bc->hdrv, bc->modem.par96.dcd_count > 0);
- } else {
- hdlcdrv_setdcd(&bc->hdrv, !!(pp->ops->read_status(pp) & PAR96_DCD));
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static void par96_interrupt(void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct baycom_state *bc = netdev_priv(dev);
-
- baycom_int_freq(bc);
- /*
- * check if transmitter active
- */
- if (hdlcdrv_ptt(&bc->hdrv))
- par96_tx(dev, bc);
- else {
- par96_rx(dev, bc);
- if (--bc->modem.arb_divider <= 0) {
- bc->modem.arb_divider = 6;
- local_irq_enable();
- hdlcdrv_arbitrate(dev, &bc->hdrv);
- }
- }
- local_irq_enable();
- hdlcdrv_transmitter(dev, &bc->hdrv);
- hdlcdrv_receiver(dev, &bc->hdrv);
- local_irq_disable();
-}
-
-/* --------------------------------------------------------------------- */
-
-static void par96_wakeup(void *handle)
-{
- struct net_device *dev = (struct net_device *)handle;
- struct baycom_state *bc = netdev_priv(dev);
-
- printk(KERN_DEBUG "baycom_par: %s: why am I being woken up?\n", dev->name);
- if (!parport_claim(bc->pdev))
- printk(KERN_DEBUG "baycom_par: %s: I'm broken.\n", dev->name);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int par96_open(struct net_device *dev)
-{
- struct baycom_state *bc = netdev_priv(dev);
- struct pardev_cb par_cb;
- struct parport *pp;
- int i;
-
- if (!dev || !bc)
- return -ENXIO;
- pp = parport_find_base(dev->base_addr);
- if (!pp) {
- printk(KERN_ERR "baycom_par: parport at 0x%lx unknown\n", dev->base_addr);
- return -ENXIO;
- }
- if (pp->irq < 0) {
- printk(KERN_ERR "baycom_par: parport at 0x%lx has no irq\n", pp->base);
- parport_put_port(pp);
- return -ENXIO;
- }
- if ((~pp->modes) & (PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) {
- printk(KERN_ERR "baycom_par: parport at 0x%lx cannot be used\n", pp->base);
- parport_put_port(pp);
- return -ENXIO;
- }
- memset(&bc->modem, 0, sizeof(bc->modem));
- bc->hdrv.par.bitrate = 9600;
- memset(&par_cb, 0, sizeof(par_cb));
- par_cb.wakeup = par96_wakeup;
- par_cb.irq_func = par96_interrupt;
- par_cb.private = (void *)dev;
- par_cb.flags = PARPORT_DEV_EXCL;
- for (i = 0; i < NR_PORTS; i++)
- if (baycom_device[i] == dev)
- break;
-
- if (i == NR_PORTS) {
- pr_err("%s: no device found\n", bc_drvname);
- parport_put_port(pp);
- return -ENODEV;
- }
- bc->pdev = parport_register_dev_model(pp, dev->name, &par_cb, i);
- parport_put_port(pp);
- if (!bc->pdev) {
- printk(KERN_ERR "baycom_par: cannot register parport at 0x%lx\n", dev->base_addr);
- return -ENXIO;
- }
- if (parport_claim(bc->pdev)) {
- printk(KERN_ERR "baycom_par: parport at 0x%lx busy\n", pp->base);
- parport_unregister_device(bc->pdev);
- return -EBUSY;
- }
- pp = bc->pdev->port;
- dev->irq = pp->irq;
- pp->ops->data_forward(pp);
- bc->hdrv.par.bitrate = 9600;
- pp->ops->write_data(pp, PAR96_PTT | PAR97_POWER); /* switch off PTT */
- pp->ops->enable_irq(pp);
- printk(KERN_INFO "%s: par96 at iobase 0x%lx irq %u options 0x%x\n",
- bc_drvname, dev->base_addr, dev->irq, bc->options);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int par96_close(struct net_device *dev)
-{
- struct baycom_state *bc = netdev_priv(dev);
- struct parport *pp;
-
- if (!dev || !bc)
- return -EINVAL;
- pp = bc->pdev->port;
- /* disable interrupt */
- pp->ops->disable_irq(pp);
- /* switch off PTT */
- pp->ops->write_data(pp, PAR96_PTT | PAR97_POWER);
- parport_release(bc->pdev);
- parport_unregister_device(bc->pdev);
- printk(KERN_INFO "%s: close par96 at iobase 0x%lx irq %u\n",
- bc_drvname, dev->base_addr, dev->irq);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * ===================== hdlcdrv driver interface =========================
- */
-
-static int baycom_ioctl(struct net_device *dev, void __user *data,
- struct hdlcdrv_ioctl *hi, int cmd);
-
-/* --------------------------------------------------------------------- */
-
-static const struct hdlcdrv_ops par96_ops = {
- .drvname = bc_drvname,
- .drvinfo = bc_drvinfo,
- .open = par96_open,
- .close = par96_close,
- .ioctl = baycom_ioctl
-};
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_setmode(struct baycom_state *bc, const char *modestr)
-{
- if (!strncmp(modestr, "picpar", 6))
- bc->options = 0;
- else if (!strncmp(modestr, "par96", 5))
- bc->options = BAYCOM_OPTIONS_SOFTDCD;
- else
- bc->options = !!strchr(modestr, '*');
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_ioctl(struct net_device *dev, void __user *data,
- struct hdlcdrv_ioctl *hi, int cmd)
-{
- struct baycom_state *bc;
- struct baycom_ioctl bi;
-
- if (!dev)
- return -EINVAL;
-
- bc = netdev_priv(dev);
- BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC);
-
- if (cmd != SIOCDEVPRIVATE)
- return -ENOIOCTLCMD;
- switch (hi->cmd) {
- default:
- break;
-
- case HDLCDRVCTL_GETMODE:
- strscpy(hi->data.modename, bc->options ? "par96" : "picpar");
- if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl)))
- return -EFAULT;
- return 0;
-
- case HDLCDRVCTL_SETMODE:
- if (netif_running(dev) || !capable(CAP_NET_ADMIN))
- return -EACCES;
- hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
- return baycom_setmode(bc, hi->data.modename);
-
- case HDLCDRVCTL_MODELIST:
- strscpy(hi->data.modename, "par96,picpar");
- if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl)))
- return -EFAULT;
- return 0;
-
- case HDLCDRVCTL_MODEMPARMASK:
- return HDLCDRV_PARMASK_IOBASE;
-
- }
-
- if (copy_from_user(&bi, data, sizeof(bi)))
- return -EFAULT;
- switch (bi.cmd) {
- default:
- return -ENOIOCTLCMD;
-
-#ifdef BAYCOM_DEBUG
- case BAYCOMCTL_GETDEBUG:
- bi.data.dbg.debug1 = bc->hdrv.ptt_keyed;
- bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;
- bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;
- break;
-#endif /* BAYCOM_DEBUG */
-
- }
- if (copy_to_user(data, &bi, sizeof(bi)))
- return -EFAULT;
- return 0;
-
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * command line settable parameters
- */
-static char *mode[NR_PORTS] = { "picpar", };
-static int iobase[NR_PORTS] = { 0x378, };
-
-module_param_array(mode, charp, NULL, 0);
-MODULE_PARM_DESC(mode, "baycom operating mode; eg. par96 or picpar");
-module_param_hw_array(iobase, int, ioport, NULL, 0);
-MODULE_PARM_DESC(iobase, "baycom io base address");
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("Baycom par96 and picpar amateur radio modem driver");
-MODULE_LICENSE("GPL");
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_par_probe(struct pardevice *par_dev)
-{
- struct device_driver *drv = par_dev->dev.driver;
- int len = strlen(drv->name);
-
- if (strncmp(par_dev->name, drv->name, len))
- return -ENODEV;
-
- return 0;
-}
-
-static struct parport_driver baycom_par_driver = {
- .name = "bcp",
- .probe = baycom_par_probe,
-};
-
-static int __init init_baycompar(void)
-{
- int i, found = 0, ret;
- char set_hw = 1;
-
- printk(bc_drvinfo);
-
- ret = parport_register_driver(&baycom_par_driver);
- if (ret)
- return ret;
-
- /*
- * register net devices
- */
- for (i = 0; i < NR_PORTS; i++) {
- struct net_device *dev;
- struct baycom_state *bc;
- char ifname[IFNAMSIZ];
-
- sprintf(ifname, "bcp%d", i);
-
- if (!mode[i])
- set_hw = 0;
- if (!set_hw)
- iobase[i] = 0;
-
- dev = hdlcdrv_register(&par96_ops,
- sizeof(struct baycom_state),
- ifname, iobase[i], 0, 0);
- if (IS_ERR(dev))
- break;
-
- bc = netdev_priv(dev);
- if (set_hw && baycom_setmode(bc, mode[i]))
- set_hw = 0;
- found++;
- baycom_device[i] = dev;
- }
-
- if (!found) {
- parport_unregister_driver(&baycom_par_driver);
- return -ENXIO;
- }
- return 0;
-}
-
-static void __exit cleanup_baycompar(void)
-{
- int i;
-
- for(i = 0; i < NR_PORTS; i++) {
- struct net_device *dev = baycom_device[i];
-
- if (dev)
- hdlcdrv_unregister(dev);
- }
- parport_unregister_driver(&baycom_par_driver);
-}
-
-module_init(init_baycompar);
-module_exit(cleanup_baycompar);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/*
- * format: baycom_par=io,mode
- * mode: par96,picpar
- */
-
-static int __init baycom_par_setup(char *str)
-{
- static unsigned nr_dev;
- int ints[2];
-
- if (nr_dev >= NR_PORTS)
- return 0;
- str = get_options(str, 2, ints);
- if (ints[0] < 1)
- return 0;
- mode[nr_dev] = str;
- iobase[nr_dev] = ints[1];
- nr_dev++;
- return 1;
-}
-
-__setup("baycom_par=", baycom_par_setup);
-
-#endif /* MODULE */
-/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
deleted file mode 100644
index ee5bd3c12040..000000000000
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ /dev/null
@@ -1,678 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*****************************************************************************/
-
-/*
- * baycom_ser_fdx.c -- baycom ser12 fullduplex radio modem driver.
- *
- * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * Please note that the GPL allows you to use the driver, NOT the radio.
- * In order to use the radio, you need a license from the communications
- * authority of your country.
- *
- * Supported modems
- *
- * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only
- * of a modulator/demodulator chip, usually a TI TCM3105. The computer
- * is responsible for regenerating the receiver bit clock, as well as
- * for handling the HDLC protocol. The modem connects to a serial port,
- * hence the name. Since the serial port is not used as an async serial
- * port, the kernel driver for serial ports cannot be used, and this
- * driver only supports standard serial hardware (8250, 16450, 16550A)
- *
- * This modem usually draws its supply current out of the otherwise unused
- * TXD pin of the serial port. Thus a contiguous stream of 0x00-bytes
- * is transmitted to achieve a positive supply voltage.
- *
- * hsk: This is a 4800 baud FSK modem, designed for TNC use. It works fine
- * in 'baycom-mode' :-) In contrast to the TCM3105 modem, power is
- * externally supplied. So there's no need to provide the 0x00-byte-stream
- * when receiving or idle, which drastically reduces interrupt load.
- *
- * Command line options (insmod command line)
- *
- * mode ser# hardware DCD
- * ser#* software DCD
- * ser#+ hardware DCD, inverted signal at DCD pin
- * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD'
- * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8
- * baud baud rate (between 300 and 4800)
- * irq interrupt line of the port; common values are 4,3
- *
- * History:
- * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface
- * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user)
- * 0.3 26.04.1997 init code/data tagged
- * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints)
- * 0.5 11.11.1997 ser12/par96 split into separate files
- * 0.6 24.01.1998 Thorsten Kranzkowski, dl8bcu and Thomas Sailer:
- * reduced interrupt load in transmit case
- * reworked receiver
- * 0.7 03.08.1999 adapt to Linus' new __setup/__initcall
- * 0.8 10.08.1999 use module_init/module_exit
- * 0.9 12.02.2000 adapted to softnet driver interface
- * 0.10 03.07.2000 fix interface name handling
- */
-
-/*****************************************************************************/
-
-#include <linux/capability.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/hdlcdrv.h>
-#include <linux/baycom.h>
-#include <linux/jiffies.h>
-#include <linux/time64.h>
-
-#include <linux/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-/* --------------------------------------------------------------------- */
-
-#define BAYCOM_DEBUG
-
-/* --------------------------------------------------------------------- */
-
-static const char bc_drvname[] = "baycom_ser_fdx";
-static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_ser_fdx: version 0.10\n";
-
-/* --------------------------------------------------------------------- */
-
-#define NR_PORTS 4
-
-static struct net_device *baycom_device[NR_PORTS];
-
-/* --------------------------------------------------------------------- */
-
-#define RBR(iobase) (iobase+0)
-#define THR(iobase) (iobase+0)
-#define IER(iobase) (iobase+1)
-#define IIR(iobase) (iobase+2)
-#define FCR(iobase) (iobase+2)
-#define LCR(iobase) (iobase+3)
-#define MCR(iobase) (iobase+4)
-#define LSR(iobase) (iobase+5)
-#define MSR(iobase) (iobase+6)
-#define SCR(iobase) (iobase+7)
-#define DLL(iobase) (iobase+0)
-#define DLM(iobase) (iobase+1)
-
-#define SER12_EXTENT 8
-
-/* ---------------------------------------------------------------------- */
-/*
- * Information that need to be kept for each board.
- */
-
-struct baycom_state {
- struct hdlcdrv_state hdrv;
-
- unsigned int baud, baud_us, baud_arbdiv, baud_uartdiv, baud_dcdtimeout;
- int opt_dcd;
-
- struct modem_state {
- unsigned char flags;
- unsigned char ptt;
- unsigned int shreg;
- struct modem_state_ser12 {
- unsigned char tx_bit;
- unsigned char last_rxbit;
- int dcd_sum0, dcd_sum1, dcd_sum2;
- int dcd_time;
- unsigned int pll_time;
- unsigned int txshreg;
- } ser12;
- } modem;
-
-#ifdef BAYCOM_DEBUG
- struct debug_vals {
- unsigned long last_jiffies;
- unsigned cur_intcnt;
- unsigned last_intcnt;
- int cur_pllcorr;
- int last_pllcorr;
- } debug_vals;
-#endif /* BAYCOM_DEBUG */
-};
-
-/* --------------------------------------------------------------------- */
-
-static inline void baycom_int_freq(struct baycom_state *bc)
-{
-#ifdef BAYCOM_DEBUG
- unsigned long cur_jiffies = jiffies;
- /*
- * measure the interrupt frequency
- */
- bc->debug_vals.cur_intcnt++;
- if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
- bc->debug_vals.last_jiffies = cur_jiffies;
- bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
- bc->debug_vals.cur_intcnt = 0;
- bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
- bc->debug_vals.cur_pllcorr = 0;
- }
-#endif /* BAYCOM_DEBUG */
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * ===================== SER12 specific routines =========================
- */
-
-/* --------------------------------------------------------------------- */
-
-static inline void ser12_set_divisor(struct net_device *dev,
- unsigned int divisor)
-{
- outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */
- outb(divisor, DLL(dev->base_addr));
- outb(divisor >> 8, DLM(dev->base_addr));
- outb(0x01, LCR(dev->base_addr)); /* word length = 6 */
- /*
- * make sure the next interrupt is generated;
- * 0 must be used to power the modem; the modem draws its
- * power from the TxD line
- */
- outb(0x00, THR(dev->base_addr));
- /*
- * it is important not to set the divider while transmitting;
- * this reportedly makes some UARTs generating interrupts
- * in the hundredthousands per second region
- * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno)
- */
-}
-
-static __inline__ void ser12_rx(struct net_device *dev, struct baycom_state *bc, struct timespec64 *ts, unsigned char curs)
-{
- int timediff;
- int bdus8 = bc->baud_us >> 3;
- int bdus4 = bc->baud_us >> 2;
- int bdus2 = bc->baud_us >> 1;
-
- timediff = 1000000 + ts->tv_nsec / NSEC_PER_USEC -
- bc->modem.ser12.pll_time;
- while (timediff >= 500000)
- timediff -= 1000000;
- while (timediff >= bdus2) {
- timediff -= bc->baud_us;
- bc->modem.ser12.pll_time += bc->baud_us;
- bc->modem.ser12.dcd_time--;
- /* first check if there is room to add a bit */
- if (bc->modem.shreg & 1) {
- hdlcdrv_putbits(&bc->hdrv, (bc->modem.shreg >> 1) ^ 0xffff);
- bc->modem.shreg = 0x10000;
- }
- /* add a one bit */
- bc->modem.shreg >>= 1;
- }
- if (bc->modem.ser12.dcd_time <= 0) {
- if (!bc->opt_dcd)
- hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
- bc->modem.ser12.dcd_sum1 +
- bc->modem.ser12.dcd_sum2) < 0);
- bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
- bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
- bc->modem.ser12.dcd_sum0 = 2; /* slight bias */
- bc->modem.ser12.dcd_time += 120;
- }
- if (bc->modem.ser12.last_rxbit != curs) {
- bc->modem.ser12.last_rxbit = curs;
- bc->modem.shreg |= 0x10000;
- /* adjust the PLL */
- if (timediff > 0)
- bc->modem.ser12.pll_time += bdus8;
- else
- bc->modem.ser12.pll_time += 1000000 - bdus8;
- /* update DCD */
- if (abs(timediff) > bdus4)
- bc->modem.ser12.dcd_sum0 += 4;
- else
- bc->modem.ser12.dcd_sum0--;
-#ifdef BAYCOM_DEBUG
- bc->debug_vals.cur_pllcorr = timediff;
-#endif /* BAYCOM_DEBUG */
- }
- while (bc->modem.ser12.pll_time >= 1000000)
- bc->modem.ser12.pll_time -= 1000000;
-}
-
-/* --------------------------------------------------------------------- */
-
-static irqreturn_t ser12_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct baycom_state *bc = netdev_priv(dev);
- struct timespec64 ts;
- unsigned char iir, msr;
- unsigned int txcount = 0;
-
- if (!bc || bc->hdrv.magic != HDLCDRV_MAGIC)
- return IRQ_NONE;
- /* fast way out for shared irq */
- if ((iir = inb(IIR(dev->base_addr))) & 1)
- return IRQ_NONE;
- /* get current time */
- ktime_get_ts64(&ts);
- msr = inb(MSR(dev->base_addr));
- /* delta DCD */
- if ((msr & 8) && bc->opt_dcd)
- hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80));
- do {
- switch (iir & 6) {
- case 6:
- inb(LSR(dev->base_addr));
- break;
-
- case 4:
- inb(RBR(dev->base_addr));
- break;
-
- case 2:
- /*
- * make sure the next interrupt is generated;
- * 0 must be used to power the modem; the modem draws its
- * power from the TxD line
- */
- outb(0x00, THR(dev->base_addr));
- baycom_int_freq(bc);
- txcount++;
- /*
- * first output the last bit (!) then call HDLC transmitter,
- * since this may take quite long
- */
- if (bc->modem.ptt)
- outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr));
- else
- outb(0x0d, MCR(dev->base_addr)); /* transmitter off */
- break;
-
- default:
- msr = inb(MSR(dev->base_addr));
- /* delta DCD */
- if ((msr & 8) && bc->opt_dcd)
- hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80));
- break;
- }
- iir = inb(IIR(dev->base_addr));
- } while (!(iir & 1));
- ser12_rx(dev, bc, &ts, msr & 0x10); /* CTS */
- if (bc->modem.ptt && txcount) {
- if (bc->modem.ser12.txshreg <= 1) {
- bc->modem.ser12.txshreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv);
- if (!hdlcdrv_ptt(&bc->hdrv)) {
- ser12_set_divisor(dev, 115200/100/8);
- bc->modem.ptt = 0;
- goto end_transmit;
- }
- }
- bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ (bc->modem.ser12.txshreg & 1));
- bc->modem.ser12.txshreg >>= 1;
- }
- end_transmit:
- local_irq_enable();
- if (!bc->modem.ptt && txcount) {
- hdlcdrv_arbitrate(dev, &bc->hdrv);
- if (hdlcdrv_ptt(&bc->hdrv)) {
- ser12_set_divisor(dev, bc->baud_uartdiv);
- bc->modem.ser12.txshreg = 1;
- bc->modem.ptt = 1;
- }
- }
- hdlcdrv_transmitter(dev, &bc->hdrv);
- hdlcdrv_receiver(dev, &bc->hdrv);
- local_irq_disable();
- return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-enum uart { c_uart_unknown, c_uart_8250,
- c_uart_16450, c_uart_16550, c_uart_16550A};
-static const char *uart_str[] = {
- "unknown", "8250", "16450", "16550", "16550A"
-};
-
-static enum uart ser12_check_uart(unsigned int iobase)
-{
- unsigned char b1,b2,b3;
- enum uart u;
- enum uart uart_tab[] =
- { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
-
- b1 = inb(MCR(iobase));
- outb(b1 | 0x10, MCR(iobase)); /* loopback mode */
- b2 = inb(MSR(iobase));
- outb(0x1a, MCR(iobase));
- b3 = inb(MSR(iobase)) & 0xf0;
- outb(b1, MCR(iobase)); /* restore old values */
- outb(b2, MSR(iobase));
- if (b3 != 0x90)
- return c_uart_unknown;
- inb(RBR(iobase));
- inb(RBR(iobase));
- outb(0x01, FCR(iobase)); /* enable FIFOs */
- u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
- if (u == c_uart_16450) {
- outb(0x5a, SCR(iobase));
- b1 = inb(SCR(iobase));
- outb(0xa5, SCR(iobase));
- b2 = inb(SCR(iobase));
- if ((b1 != 0x5a) || (b2 != 0xa5))
- u = c_uart_8250;
- }
- return u;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int ser12_open(struct net_device *dev)
-{
- const unsigned int nr_irqs = irq_get_nr_irqs();
- struct baycom_state *bc = netdev_priv(dev);
- enum uart u;
-
- if (!dev || !bc)
- return -ENXIO;
- if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT ||
- dev->irq < 2 || dev->irq > nr_irqs) {
- printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) "
- "or irq (2 <= irq <= %d)\n",
- 0xffff-SER12_EXTENT, nr_irqs);
- return -ENXIO;
- }
- if (bc->baud < 300 || bc->baud > 4800) {
- printk(KERN_INFO "baycom_ser_fdx: invalid baudrate "
- "(300...4800)\n");
- return -EINVAL;
- }
- if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) {
- printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy\n",
- dev->base_addr);
- return -EACCES;
- }
- memset(&bc->modem, 0, sizeof(bc->modem));
- bc->hdrv.par.bitrate = bc->baud;
- bc->baud_us = 1000000/bc->baud;
- bc->baud_uartdiv = (115200/8)/bc->baud;
- if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown){
- release_region(dev->base_addr, SER12_EXTENT);
- return -EIO;
- }
- outb(0, FCR(dev->base_addr)); /* disable FIFOs */
- outb(0x0d, MCR(dev->base_addr));
- outb(0, IER(dev->base_addr));
- if (request_irq(dev->irq, ser12_interrupt, IRQF_SHARED,
- "baycom_ser_fdx", dev)) {
- release_region(dev->base_addr, SER12_EXTENT);
- return -EBUSY;
- }
- /*
- * set the SIO to 6 Bits/character; during receive,
- * the baud rate is set to produce 100 ints/sec
- * to feed the channel arbitration process,
- * during transmit to baud ints/sec to run
- * the transmitter
- */
- ser12_set_divisor(dev, 115200/100/8);
- /*
- * enable transmitter empty interrupt and modem status interrupt
- */
- outb(0x0a, IER(dev->base_addr));
- /*
- * make sure the next interrupt is generated;
- * 0 must be used to power the modem; the modem draws its
- * power from the TxD line
- */
- outb(0x00, THR(dev->base_addr));
- hdlcdrv_setdcd(&bc->hdrv, 0);
- printk(KERN_INFO "%s: ser_fdx at iobase 0x%lx irq %u baud %u uart %s\n",
- bc_drvname, dev->base_addr, dev->irq, bc->baud, uart_str[u]);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int ser12_close(struct net_device *dev)
-{
- struct baycom_state *bc = netdev_priv(dev);
-
- if (!dev || !bc)
- return -EINVAL;
- /*
- * disable interrupts
- */
- outb(0, IER(dev->base_addr));
- outb(1, MCR(dev->base_addr));
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, SER12_EXTENT);
- printk(KERN_INFO "%s: close ser_fdx at iobase 0x%lx irq %u\n",
- bc_drvname, dev->base_addr, dev->irq);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * ===================== hdlcdrv driver interface =========================
- */
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_ioctl(struct net_device *dev, void __user *data,
- struct hdlcdrv_ioctl *hi, int cmd);
-
-/* --------------------------------------------------------------------- */
-
-static const struct hdlcdrv_ops ser12_ops = {
- .drvname = bc_drvname,
- .drvinfo = bc_drvinfo,
- .open = ser12_open,
- .close = ser12_close,
- .ioctl = baycom_ioctl,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_setmode(struct baycom_state *bc, const char *modestr)
-{
- unsigned int baud;
-
- if (!strncmp(modestr, "ser", 3)) {
- baud = simple_strtoul(modestr+3, NULL, 10);
- if (baud >= 3 && baud <= 48)
- bc->baud = baud*100;
- }
- if (strchr(modestr, '*'))
- bc->opt_dcd = 0;
- else if (strchr(modestr, '+'))
- bc->opt_dcd = -1;
- else
- bc->opt_dcd = 1;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_ioctl(struct net_device *dev, void __user *data,
- struct hdlcdrv_ioctl *hi, int cmd)
-{
- struct baycom_state *bc;
- struct baycom_ioctl bi;
-
- if (!dev)
- return -EINVAL;
-
- bc = netdev_priv(dev);
- BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC);
-
- if (cmd != SIOCDEVPRIVATE)
- return -ENOIOCTLCMD;
- switch (hi->cmd) {
- default:
- break;
-
- case HDLCDRVCTL_GETMODE:
- sprintf(hi->data.modename, "ser%u", bc->baud / 100);
- if (bc->opt_dcd <= 0)
- strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : "+");
- if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl)))
- return -EFAULT;
- return 0;
-
- case HDLCDRVCTL_SETMODE:
- if (netif_running(dev) || !capable(CAP_NET_ADMIN))
- return -EACCES;
- hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
- return baycom_setmode(bc, hi->data.modename);
-
- case HDLCDRVCTL_MODELIST:
- strscpy(hi->data.modename, "ser12,ser3,ser24");
- if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl)))
- return -EFAULT;
- return 0;
-
- case HDLCDRVCTL_MODEMPARMASK:
- return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ;
-
- }
-
- if (copy_from_user(&bi, data, sizeof(bi)))
- return -EFAULT;
- switch (bi.cmd) {
- default:
- return -ENOIOCTLCMD;
-
-#ifdef BAYCOM_DEBUG
- case BAYCOMCTL_GETDEBUG:
- bi.data.dbg.debug1 = bc->hdrv.ptt_keyed;
- bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;
- bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;
- break;
-#endif /* BAYCOM_DEBUG */
-
- }
- if (copy_to_user(data, &bi, sizeof(bi)))
- return -EFAULT;
- return 0;
-
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * command line settable parameters
- */
-static char *mode[NR_PORTS] = { "ser12*", };
-static int iobase[NR_PORTS] = { 0x3f8, };
-static int irq[NR_PORTS] = { 4, };
-static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 };
-
-module_param_array(mode, charp, NULL, 0);
-MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
-module_param_hw_array(iobase, int, ioport, NULL, 0);
-MODULE_PARM_DESC(iobase, "baycom io base address");
-module_param_hw_array(irq, int, irq, NULL, 0);
-MODULE_PARM_DESC(irq, "baycom irq number");
-module_param_array(baud, int, NULL, 0);
-MODULE_PARM_DESC(baud, "baycom baud rate (300 to 4800)");
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver");
-MODULE_LICENSE("GPL");
-
-/* --------------------------------------------------------------------- */
-
-static int __init init_baycomserfdx(void)
-{
- int i, found = 0;
- char set_hw = 1;
-
- printk(bc_drvinfo);
- /*
- * register net devices
- */
- for (i = 0; i < NR_PORTS; i++) {
- struct net_device *dev;
- struct baycom_state *bc;
- char ifname[IFNAMSIZ];
-
- sprintf(ifname, "bcsf%d", i);
-
- if (!mode[i])
- set_hw = 0;
- if (!set_hw)
- iobase[i] = irq[i] = 0;
-
- dev = hdlcdrv_register(&ser12_ops,
- sizeof(struct baycom_state),
- ifname, iobase[i], irq[i], 0);
- if (IS_ERR(dev))
- break;
-
- bc = netdev_priv(dev);
- if (set_hw && baycom_setmode(bc, mode[i]))
- set_hw = 0;
- bc->baud = baud[i];
- found++;
- baycom_device[i] = dev;
- }
-
- if (!found)
- return -ENXIO;
- return 0;
-}
-
-static void __exit cleanup_baycomserfdx(void)
-{
- int i;
-
- for(i = 0; i < NR_PORTS; i++) {
- struct net_device *dev = baycom_device[i];
- if (dev)
- hdlcdrv_unregister(dev);
- }
-}
-
-module_init(init_baycomserfdx);
-module_exit(cleanup_baycomserfdx);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/*
- * format: baycom_ser_fdx=io,irq,mode
- * mode: ser# hardware DCD
- * ser#* software DCD
- * ser#+ hardware DCD, inverted signal at DCD pin
- * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD'
- */
-
-static int __init baycom_ser_fdx_setup(char *str)
-{
- static unsigned nr_dev;
- int ints[4];
-
- if (nr_dev >= NR_PORTS)
- return 0;
- str = get_options(str, 4, ints);
- if (ints[0] < 2)
- return 0;
- mode[nr_dev] = str;
- iobase[nr_dev] = ints[1];
- irq[nr_dev] = ints[2];
- if (ints[0] >= 3)
- baud[nr_dev] = ints[3];
- nr_dev++;
- return 1;
-}
-
-__setup("baycom_ser_fdx=", baycom_ser_fdx_setup);
-
-#endif /* MODULE */
-/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
deleted file mode 100644
index 05bdad214799..000000000000
--- a/drivers/net/hamradio/baycom_ser_hdx.c
+++ /dev/null
@@ -1,727 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*****************************************************************************/
-
-/*
- * baycom_ser_hdx.c -- baycom ser12 halfduplex radio modem driver.
- *
- * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * Please note that the GPL allows you to use the driver, NOT the radio.
- * In order to use the radio, you need a license from the communications
- * authority of your country.
- *
- * Supported modems
- *
- * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only
- * of a modulator/demodulator chip, usually a TI TCM3105. The computer
- * is responsible for regenerating the receiver bit clock, as well as
- * for handling the HDLC protocol. The modem connects to a serial port,
- * hence the name. Since the serial port is not used as an async serial
- * port, the kernel driver for serial ports cannot be used, and this
- * driver only supports standard serial hardware (8250, 16450, 16550A)
- *
- * Command line options (insmod command line)
- *
- * mode ser12 hardware DCD
- * ser12* software DCD
- * ser12@ hardware/software DCD, i.e. no explicit DCD signal but hardware
- * mutes audio input to the modem
- * ser12+ hardware DCD, inverted signal at DCD pin
- * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8
- * irq interrupt line of the port; common values are 4,3
- *
- * History:
- * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface
- * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user)
- * 0.3 26.04.1997 init code/data tagged
- * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints)
- * 0.5 11.11.1997 ser12/par96 split into separate files
- * 0.6 14.04.1998 cleanups
- * 0.7 03.08.1999 adapt to Linus' new __setup/__initcall
- * 0.8 10.08.1999 use module_init/module_exit
- * 0.9 12.02.2000 adapted to softnet driver interface
- * 0.10 03.07.2000 fix interface name handling
- */
-
-/*****************************************************************************/
-
-#include <linux/capability.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-#include <linux/hdlcdrv.h>
-#include <linux/baycom.h>
-#include <linux/jiffies.h>
-
-/* --------------------------------------------------------------------- */
-
-#define BAYCOM_DEBUG
-
-/* --------------------------------------------------------------------- */
-
-static const char bc_drvname[] = "baycom_ser_hdx";
-static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_ser_hdx: version 0.10\n";
-
-/* --------------------------------------------------------------------- */
-
-#define NR_PORTS 4
-
-static struct net_device *baycom_device[NR_PORTS];
-
-/* --------------------------------------------------------------------- */
-
-#define RBR(iobase) (iobase+0)
-#define THR(iobase) (iobase+0)
-#define IER(iobase) (iobase+1)
-#define IIR(iobase) (iobase+2)
-#define FCR(iobase) (iobase+2)
-#define LCR(iobase) (iobase+3)
-#define MCR(iobase) (iobase+4)
-#define LSR(iobase) (iobase+5)
-#define MSR(iobase) (iobase+6)
-#define SCR(iobase) (iobase+7)
-#define DLL(iobase) (iobase+0)
-#define DLM(iobase) (iobase+1)
-
-#define SER12_EXTENT 8
-
-/* ---------------------------------------------------------------------- */
-/*
- * Information that need to be kept for each board.
- */
-
-struct baycom_state {
- struct hdlcdrv_state hdrv;
-
- int opt_dcd;
-
- struct modem_state {
- short arb_divider;
- unsigned char flags;
- unsigned int shreg;
- struct modem_state_ser12 {
- unsigned char tx_bit;
- int dcd_sum0, dcd_sum1, dcd_sum2;
- unsigned char last_sample;
- unsigned char last_rxbit;
- unsigned int dcd_shreg;
- unsigned int dcd_time;
- unsigned int bit_pll;
- unsigned char interm_sample;
- } ser12;
- } modem;
-
-#ifdef BAYCOM_DEBUG
- struct debug_vals {
- unsigned long last_jiffies;
- unsigned cur_intcnt;
- unsigned last_intcnt;
- int cur_pllcorr;
- int last_pllcorr;
- } debug_vals;
-#endif /* BAYCOM_DEBUG */
-};
-
-/* --------------------------------------------------------------------- */
-
-static inline void baycom_int_freq(struct baycom_state *bc)
-{
-#ifdef BAYCOM_DEBUG
- unsigned long cur_jiffies = jiffies;
- /*
- * measure the interrupt frequency
- */
- bc->debug_vals.cur_intcnt++;
- if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
- bc->debug_vals.last_jiffies = cur_jiffies;
- bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
- bc->debug_vals.cur_intcnt = 0;
- bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
- bc->debug_vals.cur_pllcorr = 0;
- }
-#endif /* BAYCOM_DEBUG */
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * ===================== SER12 specific routines =========================
- */
-
-static inline void ser12_set_divisor(struct net_device *dev,
- unsigned char divisor)
-{
- outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */
- outb(divisor, DLL(dev->base_addr));
- outb(0, DLM(dev->base_addr));
- outb(0x01, LCR(dev->base_addr)); /* word length = 6 */
- /*
- * make sure the next interrupt is generated;
- * 0 must be used to power the modem; the modem draws its
- * power from the TxD line
- */
- outb(0x00, THR(dev->base_addr));
- /*
- * it is important not to set the divider while transmitting;
- * this reportedly makes some UARTs generating interrupts
- * in the hundredthousands per second region
- * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno)
- */
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * must call the TX arbitrator every 10ms
- */
-#define SER12_ARB_DIVIDER(bc) (bc->opt_dcd ? 24 : 36)
-
-#define SER12_DCD_INTERVAL(bc) (bc->opt_dcd ? 12 : 240)
-
-static inline void ser12_tx(struct net_device *dev, struct baycom_state *bc)
-{
- /* one interrupt per channel bit */
- ser12_set_divisor(dev, 12);
- /*
- * first output the last bit (!) then call HDLC transmitter,
- * since this may take quite long
- */
- outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr));
- if (bc->modem.shreg <= 1)
- bc->modem.shreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv);
- bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^
- (bc->modem.shreg & 1));
- bc->modem.shreg >>= 1;
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void ser12_rx(struct net_device *dev, struct baycom_state *bc)
-{
- unsigned char cur_s;
- /*
- * do demodulator
- */
- cur_s = inb(MSR(dev->base_addr)) & 0x10; /* the CTS line */
- hdlcdrv_channelbit(&bc->hdrv, cur_s);
- bc->modem.ser12.dcd_shreg = (bc->modem.ser12.dcd_shreg << 1) |
- (cur_s != bc->modem.ser12.last_sample);
- bc->modem.ser12.last_sample = cur_s;
- if(bc->modem.ser12.dcd_shreg & 1) {
- if (!bc->opt_dcd) {
- unsigned int dcdspos, dcdsneg;
-
- dcdspos = dcdsneg = 0;
- dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
- if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
- dcdspos += 2;
- dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
- dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
- dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
-
- bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
- } else
- bc->modem.ser12.dcd_sum0--;
- }
- if(!bc->modem.ser12.dcd_time) {
- hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
- bc->modem.ser12.dcd_sum1 +
- bc->modem.ser12.dcd_sum2) < 0);
- bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
- bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
- /* offset to ensure DCD off on silent input */
- bc->modem.ser12.dcd_sum0 = 2;
- bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
- }
- bc->modem.ser12.dcd_time--;
- if (!bc->opt_dcd) {
- /*
- * PLL code for the improved software DCD algorithm
- */
- if (bc->modem.ser12.interm_sample) {
- /*
- * intermediate sample; set timing correction to normal
- */
- ser12_set_divisor(dev, 4);
- } else {
- /*
- * do PLL correction and call HDLC receiver
- */
- switch (bc->modem.ser12.dcd_shreg & 7) {
- case 1: /* transition too late */
- ser12_set_divisor(dev, 5);
-#ifdef BAYCOM_DEBUG
- bc->debug_vals.cur_pllcorr++;
-#endif /* BAYCOM_DEBUG */
- break;
- case 4: /* transition too early */
- ser12_set_divisor(dev, 3);
-#ifdef BAYCOM_DEBUG
- bc->debug_vals.cur_pllcorr--;
-#endif /* BAYCOM_DEBUG */
- break;
- default:
- ser12_set_divisor(dev, 4);
- break;
- }
- bc->modem.shreg >>= 1;
- if (bc->modem.ser12.last_sample ==
- bc->modem.ser12.last_rxbit)
- bc->modem.shreg |= 0x10000;
- bc->modem.ser12.last_rxbit =
- bc->modem.ser12.last_sample;
- }
- if (++bc->modem.ser12.interm_sample >= 3)
- bc->modem.ser12.interm_sample = 0;
- /*
- * DCD stuff
- */
- if (bc->modem.ser12.dcd_shreg & 1) {
- unsigned int dcdspos, dcdsneg;
-
- dcdspos = dcdsneg = 0;
- dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
- dcdspos += (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
- << 1;
- dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
- dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
- dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
-
- bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
- }
- } else {
- /*
- * PLL algorithm for the hardware squelch DCD algorithm
- */
- if (bc->modem.ser12.interm_sample) {
- /*
- * intermediate sample; set timing correction to normal
- */
- ser12_set_divisor(dev, 6);
- } else {
- /*
- * do PLL correction and call HDLC receiver
- */
- switch (bc->modem.ser12.dcd_shreg & 3) {
- case 1: /* transition too late */
- ser12_set_divisor(dev, 7);
-#ifdef BAYCOM_DEBUG
- bc->debug_vals.cur_pllcorr++;
-#endif /* BAYCOM_DEBUG */
- break;
- case 2: /* transition too early */
- ser12_set_divisor(dev, 5);
-#ifdef BAYCOM_DEBUG
- bc->debug_vals.cur_pllcorr--;
-#endif /* BAYCOM_DEBUG */
- break;
- default:
- ser12_set_divisor(dev, 6);
- break;
- }
- bc->modem.shreg >>= 1;
- if (bc->modem.ser12.last_sample ==
- bc->modem.ser12.last_rxbit)
- bc->modem.shreg |= 0x10000;
- bc->modem.ser12.last_rxbit =
- bc->modem.ser12.last_sample;
- }
- bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample;
- /*
- * DCD stuff
- */
- bc->modem.ser12.dcd_sum0 -= (bc->modem.ser12.dcd_shreg & 1);
- }
- outb(0x0d, MCR(dev->base_addr)); /* transmitter off */
- if (bc->modem.shreg & 1) {
- hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1);
- bc->modem.shreg = 0x10000;
- }
- if(!bc->modem.ser12.dcd_time) {
- if (bc->opt_dcd & 1)
- hdlcdrv_setdcd(&bc->hdrv, !((inb(MSR(dev->base_addr)) ^ bc->opt_dcd) & 0x80));
- else
- hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
- bc->modem.ser12.dcd_sum1 +
- bc->modem.ser12.dcd_sum2) < 0);
- bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
- bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
- /* offset to ensure DCD off on silent input */
- bc->modem.ser12.dcd_sum0 = 2;
- bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
- }
- bc->modem.ser12.dcd_time--;
-}
-
-/* --------------------------------------------------------------------- */
-
-static irqreturn_t ser12_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct baycom_state *bc = netdev_priv(dev);
- unsigned char iir;
-
- if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
- return IRQ_NONE;
- /* fast way out */
- if ((iir = inb(IIR(dev->base_addr))) & 1)
- return IRQ_NONE;
- baycom_int_freq(bc);
- do {
- switch (iir & 6) {
- case 6:
- inb(LSR(dev->base_addr));
- break;
-
- case 4:
- inb(RBR(dev->base_addr));
- break;
-
- case 2:
- /*
- * check if transmitter active
- */
- if (hdlcdrv_ptt(&bc->hdrv))
- ser12_tx(dev, bc);
- else {
- ser12_rx(dev, bc);
- bc->modem.arb_divider--;
- }
- outb(0x00, THR(dev->base_addr));
- break;
-
- default:
- inb(MSR(dev->base_addr));
- break;
- }
- iir = inb(IIR(dev->base_addr));
- } while (!(iir & 1));
- if (bc->modem.arb_divider <= 0) {
- bc->modem.arb_divider = SER12_ARB_DIVIDER(bc);
- local_irq_enable();
- hdlcdrv_arbitrate(dev, &bc->hdrv);
- }
- local_irq_enable();
- hdlcdrv_transmitter(dev, &bc->hdrv);
- hdlcdrv_receiver(dev, &bc->hdrv);
- local_irq_disable();
- return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-enum uart { c_uart_unknown, c_uart_8250,
- c_uart_16450, c_uart_16550, c_uart_16550A};
-static const char *uart_str[] = {
- "unknown", "8250", "16450", "16550", "16550A"
-};
-
-static enum uart ser12_check_uart(unsigned int iobase)
-{
- unsigned char b1,b2,b3;
- enum uart u;
- enum uart uart_tab[] =
- { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
-
- b1 = inb(MCR(iobase));
- outb(b1 | 0x10, MCR(iobase)); /* loopback mode */
- b2 = inb(MSR(iobase));
- outb(0x1a, MCR(iobase));
- b3 = inb(MSR(iobase)) & 0xf0;
- outb(b1, MCR(iobase)); /* restore old values */
- outb(b2, MSR(iobase));
- if (b3 != 0x90)
- return c_uart_unknown;
- inb(RBR(iobase));
- inb(RBR(iobase));
- outb(0x01, FCR(iobase)); /* enable FIFOs */
- u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
- if (u == c_uart_16450) {
- outb(0x5a, SCR(iobase));
- b1 = inb(SCR(iobase));
- outb(0xa5, SCR(iobase));
- b2 = inb(SCR(iobase));
- if ((b1 != 0x5a) || (b2 != 0xa5))
- u = c_uart_8250;
- }
- return u;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int ser12_open(struct net_device *dev)
-{
- struct baycom_state *bc = netdev_priv(dev);
- enum uart u;
-
- if (!dev || !bc)
- return -ENXIO;
- if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT ||
- dev->irq < 2 || dev->irq > 15)
- return -ENXIO;
- if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12"))
- return -EACCES;
- memset(&bc->modem, 0, sizeof(bc->modem));
- bc->hdrv.par.bitrate = 1200;
- if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown) {
- release_region(dev->base_addr, SER12_EXTENT);
- return -EIO;
- }
- outb(0, FCR(dev->base_addr)); /* disable FIFOs */
- outb(0x0d, MCR(dev->base_addr));
- outb(0, IER(dev->base_addr));
- if (request_irq(dev->irq, ser12_interrupt, IRQF_SHARED,
- "baycom_ser12", dev)) {
- release_region(dev->base_addr, SER12_EXTENT);
- return -EBUSY;
- }
- /*
- * enable transmitter empty interrupt
- */
- outb(2, IER(dev->base_addr));
- /*
- * set the SIO to 6 Bits/character and 19200 or 28800 baud, so that
- * we get exactly (hopefully) 2 or 3 interrupts per radio symbol,
- * depending on the usage of the software DCD routine
- */
- ser12_set_divisor(dev, bc->opt_dcd ? 6 : 4);
- printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u uart %s\n",
- bc_drvname, dev->base_addr, dev->irq, uart_str[u]);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int ser12_close(struct net_device *dev)
-{
- struct baycom_state *bc = netdev_priv(dev);
-
- if (!dev || !bc)
- return -EINVAL;
- /*
- * disable interrupts
- */
- outb(0, IER(dev->base_addr));
- outb(1, MCR(dev->base_addr));
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, SER12_EXTENT);
- printk(KERN_INFO "%s: close ser12 at iobase 0x%lx irq %u\n",
- bc_drvname, dev->base_addr, dev->irq);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * ===================== hdlcdrv driver interface =========================
- */
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_ioctl(struct net_device *dev, void __user *data,
- struct hdlcdrv_ioctl *hi, int cmd);
-
-/* --------------------------------------------------------------------- */
-
-static const struct hdlcdrv_ops ser12_ops = {
- .drvname = bc_drvname,
- .drvinfo = bc_drvinfo,
- .open = ser12_open,
- .close = ser12_close,
- .ioctl = baycom_ioctl,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_setmode(struct baycom_state *bc, const char *modestr)
-{
- if (strchr(modestr, '*'))
- bc->opt_dcd = 0;
- else if (strchr(modestr, '+'))
- bc->opt_dcd = -1;
- else if (strchr(modestr, '@'))
- bc->opt_dcd = -2;
- else
- bc->opt_dcd = 1;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int baycom_ioctl(struct net_device *dev, void __user *data,
- struct hdlcdrv_ioctl *hi, int cmd)
-{
- struct baycom_state *bc;
- struct baycom_ioctl bi;
-
- if (!dev)
- return -EINVAL;
-
- bc = netdev_priv(dev);
- BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC);
-
- if (cmd != SIOCDEVPRIVATE)
- return -ENOIOCTLCMD;
- switch (hi->cmd) {
- default:
- break;
-
- case HDLCDRVCTL_GETMODE:
- strscpy(hi->data.modename, "ser12");
- if (bc->opt_dcd <= 0)
- strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : (bc->opt_dcd == -2) ? "@" : "+");
- if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl)))
- return -EFAULT;
- return 0;
-
- case HDLCDRVCTL_SETMODE:
- if (netif_running(dev) || !capable(CAP_NET_ADMIN))
- return -EACCES;
- hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
- return baycom_setmode(bc, hi->data.modename);
-
- case HDLCDRVCTL_MODELIST:
- strscpy(hi->data.modename, "ser12");
- if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl)))
- return -EFAULT;
- return 0;
-
- case HDLCDRVCTL_MODEMPARMASK:
- return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ;
-
- }
-
- if (copy_from_user(&bi, data, sizeof(bi)))
- return -EFAULT;
- switch (bi.cmd) {
- default:
- return -ENOIOCTLCMD;
-
-#ifdef BAYCOM_DEBUG
- case BAYCOMCTL_GETDEBUG:
- bi.data.dbg.debug1 = bc->hdrv.ptt_keyed;
- bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;
- bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;
- break;
-#endif /* BAYCOM_DEBUG */
-
- }
- if (copy_to_user(data, &bi, sizeof(bi)))
- return -EFAULT;
- return 0;
-
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * command line settable parameters
- */
-static char *mode[NR_PORTS] = { "ser12*", };
-static int iobase[NR_PORTS] = { 0x3f8, };
-static int irq[NR_PORTS] = { 4, };
-
-module_param_array(mode, charp, NULL, 0);
-MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
-module_param_hw_array(iobase, int, ioport, NULL, 0);
-MODULE_PARM_DESC(iobase, "baycom io base address");
-module_param_hw_array(irq, int, irq, NULL, 0);
-MODULE_PARM_DESC(irq, "baycom irq number");
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver");
-MODULE_LICENSE("GPL");
-
-/* --------------------------------------------------------------------- */
-
-static int __init init_baycomserhdx(void)
-{
- int i, found = 0;
- char set_hw = 1;
-
- printk(bc_drvinfo);
- /*
- * register net devices
- */
- for (i = 0; i < NR_PORTS; i++) {
- struct net_device *dev;
- struct baycom_state *bc;
- char ifname[IFNAMSIZ];
-
- sprintf(ifname, "bcsh%d", i);
-
- if (!mode[i])
- set_hw = 0;
- if (!set_hw)
- iobase[i] = irq[i] = 0;
-
- dev = hdlcdrv_register(&ser12_ops,
- sizeof(struct baycom_state),
- ifname, iobase[i], irq[i], 0);
- if (IS_ERR(dev))
- break;
-
- bc = netdev_priv(dev);
- if (set_hw && baycom_setmode(bc, mode[i]))
- set_hw = 0;
- found++;
- baycom_device[i] = dev;
- }
-
- if (!found)
- return -ENXIO;
- return 0;
-}
-
-static void __exit cleanup_baycomserhdx(void)
-{
- int i;
-
- for(i = 0; i < NR_PORTS; i++) {
- struct net_device *dev = baycom_device[i];
-
- if (dev)
- hdlcdrv_unregister(dev);
- }
-}
-
-module_init(init_baycomserhdx);
-module_exit(cleanup_baycomserhdx);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/*
- * format: baycom_ser_hdx=io,irq,mode
- * mode: ser12 hardware DCD
- * ser12* software DCD
- * ser12@ hardware/software DCD, i.e. no explicit DCD signal but hardware
- * mutes audio input to the modem
- * ser12+ hardware DCD, inverted signal at DCD pin
- */
-
-static int __init baycom_ser_hdx_setup(char *str)
-{
- static unsigned nr_dev;
- int ints[3];
-
- if (nr_dev >= NR_PORTS)
- return 0;
- str = get_options(str, 3, ints);
- if (ints[0] < 2)
- return 0;
- mode[nr_dev] = str;
- iobase[nr_dev] = ints[1];
- irq[nr_dev] = ints[2];
- nr_dev++;
- return 1;
-}
-
-__setup("baycom_ser_hdx=", baycom_ser_hdx_setup);
-
-#endif /* MODULE */
-/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
deleted file mode 100644
index 214fd1f819a1..000000000000
--- a/drivers/net/hamradio/bpqether.c
+++ /dev/null
@@ -1,593 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * G8BPQ compatible "AX.25 via ethernet" driver release 004
- *
- * This code REQUIRES 2.0.0 or higher/ NET3.029
- *
- * This is a "pseudo" network driver to allow AX.25 over Ethernet
- * using G8BPQ encapsulation. It has been extracted from the protocol
- * implementation because
- *
- * - things got unreadable within the protocol stack
- * - to cure the protocol stack from "feature-ism"
- * - a protocol implementation shouldn't need to know on
- * which hardware it is running
- * - user-level programs like the AX.25 utilities shouldn't
- * need to know about the hardware.
- * - IP over ethernet encapsulated AX.25 was impossible
- * - rxecho.c did not work
- * - to have room for extensions
- * - it just deserves to "live" as an own driver
- *
- * This driver can use any ethernet destination address, and can be
- * limited to accept frames from one dedicated ethernet card only.
- *
- * Note that the driver sets up the BPQ devices automagically on
- * startup or (if started before the "insmod" of an ethernet device)
- * on "ifconfig up". It hopefully will remove the BPQ on "rmmod"ing
- * the ethernet device (in fact: as soon as another ethernet or bpq
- * device gets "ifconfig"ured).
- *
- * I have heard that several people are thinking of experiments
- * with highspeed packet radio using existing ethernet cards.
- * Well, this driver is prepared for this purpose, just add
- * your tx key control and a txdelay / tailtime algorithm,
- * probably some buffering, and /voila/...
- *
- * History
- * BPQ 001 Joerg(DL1BKE) Extracted BPQ code from AX.25
- * protocol stack and added my own
- * yet existing patches
- * BPQ 002 Joerg(DL1BKE) Scan network device list on
- * startup.
- * BPQ 003 Joerg(DL1BKE) Ethernet destination address
- * and accepted source address
- * can be configured by an ioctl()
- * call.
- * Fixed to match Linux networking
- * changes - 2.1.15.
- * BPQ 004 Joerg(DL1BKE) Fixed to not lock up on ifconfig.
- */
-
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/stat.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/rtnetlink.h>
-
-#include <net/ip.h>
-#include <net/arp.h>
-#include <net/netdev_lock.h>
-#include <net/net_namespace.h>
-
-#include <linux/bpqether.h>
-
-static const char banner[] __initconst = KERN_INFO \
- "AX.25: bpqether driver version 004\n";
-
-static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
-static int bpq_device_event(struct notifier_block *, unsigned long, void *);
-
-static struct packet_type bpq_packet_type __read_mostly = {
- .type = cpu_to_be16(ETH_P_BPQ),
- .func = bpq_rcv,
-};
-
-static struct notifier_block bpq_dev_notifier = {
- .notifier_call = bpq_device_event,
-};
-
-
-struct bpqdev {
- struct list_head bpq_list; /* list of bpq devices chain */
- struct net_device *ethdev; /* link to ethernet device */
- struct net_device *axdev; /* bpq device (bpq#) */
- char dest_addr[6]; /* ether destination address */
- char acpt_addr[6]; /* accept ether frames from this address only */
-};
-
-static LIST_HEAD(bpq_devices);
-
-/* ------------------------------------------------------------------------ */
-
-
-/*
- * Get the ethernet device for a BPQ device
- */
-static inline struct net_device *bpq_get_ether_dev(struct net_device *dev)
-{
- struct bpqdev *bpq = netdev_priv(dev);
-
- return bpq ? bpq->ethdev : NULL;
-}
-
-/*
- * Get the BPQ device for the ethernet device
- */
-static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev)
-{
- struct bpqdev *bpq;
-
- list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list,
- lockdep_rtnl_is_held()) {
- if (bpq->ethdev == dev)
- return bpq->axdev;
- }
- return NULL;
-}
-
-static inline int dev_is_ethdev(struct net_device *dev)
-{
- return dev->type == ARPHRD_ETHER && !netdev_need_ops_lock(dev);
-}
-
-/* ------------------------------------------------------------------------ */
-
-
-/*
- * Receive an AX.25 frame via an ethernet interface.
- */
-static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
-{
- int len;
- char * ptr;
- struct ethhdr *eth;
- struct bpqdev *bpq;
-
- if (!net_eq(dev_net(dev), &init_net))
- goto drop;
-
- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
- return NET_RX_DROP;
-
- if (!pskb_may_pull(skb, sizeof(struct ethhdr)))
- goto drop;
-
- rcu_read_lock();
- dev = bpq_get_ax25_dev(dev);
-
- if (dev == NULL || !netif_running(dev))
- goto drop_unlock;
-
- /*
- * if we want to accept frames from just one ethernet device
- * we check the source address of the sender.
- */
-
- bpq = netdev_priv(dev);
-
- eth = eth_hdr(skb);
-
- if (!(bpq->acpt_addr[0] & 0x01) &&
- !ether_addr_equal(eth->h_source, bpq->acpt_addr))
- goto drop_unlock;
-
- if (skb_cow(skb, sizeof(struct ethhdr)))
- goto drop_unlock;
-
- len = skb->data[0] + skb->data[1] * 256 - 5;
-
- if (len < 0 || len > skb->len - 2)
- goto drop_unlock;
-
- skb_pull(skb, 2); /* Remove the length bytes */
- skb_trim(skb, len); /* Set the length of the data */
-
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += len;
-
- ptr = skb_push(skb, 1);
- *ptr = 0;
-
- skb->protocol = ax25_type_trans(skb, dev);
- netif_rx(skb);
-unlock:
-
- rcu_read_unlock();
-
- return 0;
-drop_unlock:
- kfree_skb(skb);
- goto unlock;
-
-drop:
- kfree_skb(skb);
- return 0;
-}
-
-/*
- * Send an AX.25 frame via an ethernet interface
- */
-static netdev_tx_t bpq_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- unsigned char *ptr;
- struct bpqdev *bpq;
- struct net_device *orig_dev;
- int size;
-
- if (skb->protocol == htons(ETH_P_IP))
- return ax25_ip_xmit(skb);
-
- /*
- * Just to be *really* sure not to send anything if the interface
- * is down, the ethernet device may have gone.
- */
- if (!netif_running(dev)) {
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- skb_pull(skb, 1); /* Drop KISS byte */
- size = skb->len;
-
- /*
- * We're about to mess with the skb which may still shared with the
- * generic networking code so unshare and ensure it's got enough
- * space for the BPQ headers.
- */
- if (skb_cow(skb, AX25_BPQ_HEADER_LEN)) {
- if (net_ratelimit())
- pr_err("bpqether: out of memory\n");
- kfree_skb(skb);
-
- return NETDEV_TX_OK;
- }
-
- ptr = skb_push(skb, 2); /* Make space for length */
-
- *ptr++ = (size + 5) % 256;
- *ptr++ = (size + 5) / 256;
-
- bpq = netdev_priv(dev);
-
- orig_dev = dev;
- if ((dev = bpq_get_ether_dev(dev)) == NULL) {
- orig_dev->stats.tx_dropped++;
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- skb->protocol = ax25_type_trans(skb, dev);
- skb_reset_network_header(skb);
- dev_hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
- dev->stats.tx_packets++;
- dev->stats.tx_bytes+=skb->len;
-
- dev_queue_xmit(skb);
- netif_wake_queue(dev);
- return NETDEV_TX_OK;
-}
-
-/*
- * Set AX.25 callsign
- */
-static int bpq_set_mac_address(struct net_device *dev, void *addr)
-{
- struct sockaddr *sa = (struct sockaddr *)addr;
-
- dev_addr_set(dev, sa->sa_data);
-
- return 0;
-}
-
-/* Ioctl commands
- *
- * SIOCSBPQETHOPT reserved for enhancements
- * SIOCSBPQETHADDR set the destination and accepted
- * source ethernet address (broadcast
- * or multicast: accept all)
- */
-static int bpq_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
- void __user *data, int cmd)
-{
- struct bpq_ethaddr __user *ethaddr = data;
- struct bpqdev *bpq = netdev_priv(dev);
- struct bpq_req req;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- switch (cmd) {
- case SIOCSBPQETHOPT:
- if (copy_from_user(&req, data, sizeof(struct bpq_req)))
- return -EFAULT;
- switch (req.cmd) {
- case SIOCGBPQETHPARAM:
- case SIOCSBPQETHPARAM:
- default:
- return -EINVAL;
- }
-
- break;
-
- case SIOCSBPQETHADDR:
- if (copy_from_user(bpq->dest_addr, ethaddr->destination, ETH_ALEN))
- return -EFAULT;
- if (copy_from_user(bpq->acpt_addr, ethaddr->accept, ETH_ALEN))
- return -EFAULT;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * open/close a device
- */
-static int bpq_open(struct net_device *dev)
-{
- netif_start_queue(dev);
- return 0;
-}
-
-static int bpq_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
- return 0;
-}
-
-
-/* ------------------------------------------------------------------------ */
-
-#ifdef CONFIG_PROC_FS
-/*
- * Proc filesystem
- */
-static void *bpq_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(RCU)
-{
- int i = 1;
- struct bpqdev *bpqdev;
-
- rcu_read_lock();
-
- if (*pos == 0)
- return SEQ_START_TOKEN;
-
- list_for_each_entry_rcu(bpqdev, &bpq_devices, bpq_list) {
- if (i == *pos)
- return bpqdev;
- }
- return NULL;
-}
-
-static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- struct list_head *p;
- struct bpqdev *bpqdev = v;
-
- ++*pos;
-
- if (v == SEQ_START_TOKEN)
- p = rcu_dereference(list_next_rcu(&bpq_devices));
- else
- p = rcu_dereference(list_next_rcu(&bpqdev->bpq_list));
-
- return (p == &bpq_devices) ? NULL
- : list_entry(p, struct bpqdev, bpq_list);
-}
-
-static void bpq_seq_stop(struct seq_file *seq, void *v)
- __releases(RCU)
-{
- rcu_read_unlock();
-}
-
-
-static int bpq_seq_show(struct seq_file *seq, void *v)
-{
- if (v == SEQ_START_TOKEN)
- seq_puts(seq,
- "dev ether destination accept from\n");
- else {
- const struct bpqdev *bpqdev = v;
-
- seq_printf(seq, "%-5s %-10s %pM ",
- bpqdev->axdev->name, bpqdev->ethdev->name,
- bpqdev->dest_addr);
-
- if (is_multicast_ether_addr(bpqdev->acpt_addr))
- seq_printf(seq, "*\n");
- else
- seq_printf(seq, "%pM\n", bpqdev->acpt_addr);
-
- }
- return 0;
-}
-
-static const struct seq_operations bpq_seqops = {
- .start = bpq_seq_start,
- .next = bpq_seq_next,
- .stop = bpq_seq_stop,
- .show = bpq_seq_show,
-};
-#endif
-/* ------------------------------------------------------------------------ */
-
-static const struct net_device_ops bpq_netdev_ops = {
- .ndo_open = bpq_open,
- .ndo_stop = bpq_close,
- .ndo_start_xmit = bpq_xmit,
- .ndo_set_mac_address = bpq_set_mac_address,
- .ndo_siocdevprivate = bpq_siocdevprivate,
-};
-
-static void bpq_setup(struct net_device *dev)
-{
- netdev_lockdep_set_classes(dev);
-
- dev->netdev_ops = &bpq_netdev_ops;
- dev->needs_free_netdev = true;
-
- dev->flags = 0;
- dev->lltx = true; /* Allow recursion */
-
-#if IS_ENABLED(CONFIG_AX25)
- dev->header_ops = &ax25_header_ops;
-#endif
-
- dev->type = ARPHRD_AX25;
- dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
- dev->mtu = AX25_DEF_PACLEN;
- dev->addr_len = AX25_ADDR_LEN;
-
- memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
- dev_addr_set(dev, (u8 *)&ax25_defaddr);
-}
-
-/*
- * Setup a new device.
- */
-static int bpq_new_device(struct net_device *edev)
-{
- int err;
- struct net_device *ndev;
- struct bpqdev *bpq;
-
- ndev = alloc_netdev(sizeof(struct bpqdev), "bpq%d", NET_NAME_UNKNOWN,
- bpq_setup);
- if (!ndev)
- return -ENOMEM;
-
-
- bpq = netdev_priv(ndev);
- dev_hold(edev);
- bpq->ethdev = edev;
- bpq->axdev = ndev;
-
- eth_broadcast_addr(bpq->dest_addr);
- eth_broadcast_addr(bpq->acpt_addr);
-
- err = register_netdevice(ndev);
- if (err)
- goto error;
-
- /* List protected by RTNL */
- list_add_rcu(&bpq->bpq_list, &bpq_devices);
- return 0;
-
- error:
- dev_put(edev);
- free_netdev(ndev);
- return err;
-
-}
-
-static void bpq_free_device(struct net_device *ndev)
-{
- struct bpqdev *bpq = netdev_priv(ndev);
-
- dev_put(bpq->ethdev);
- list_del_rcu(&bpq->bpq_list);
-
- unregister_netdevice(ndev);
-}
-
-/*
- * Handle device status changes.
- */
-static int bpq_device_event(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
- if (!dev_is_ethdev(dev) && !bpq_get_ax25_dev(dev))
- return NOTIFY_DONE;
-
- switch (event) {
- case NETDEV_UP: /* new ethernet device -> new BPQ interface */
- if (bpq_get_ax25_dev(dev) == NULL)
- bpq_new_device(dev);
- break;
-
- case NETDEV_DOWN: /* ethernet device closed -> close BPQ interface */
- if ((dev = bpq_get_ax25_dev(dev)) != NULL)
- dev_close(dev);
- break;
-
- case NETDEV_UNREGISTER: /* ethernet device removed -> free BPQ interface */
- if ((dev = bpq_get_ax25_dev(dev)) != NULL)
- bpq_free_device(dev);
- break;
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-
-/* ------------------------------------------------------------------------ */
-
-/*
- * Initialize driver. To be called from af_ax25 if not compiled as a
- * module
- */
-static int __init bpq_init_driver(void)
-{
-#ifdef CONFIG_PROC_FS
- if (!proc_create_seq("bpqether", 0444, init_net.proc_net, &bpq_seqops)) {
- printk(KERN_ERR
- "bpq: cannot create /proc/net/bpqether entry.\n");
- return -ENOENT;
- }
-#endif /* CONFIG_PROC_FS */
-
- dev_add_pack(&bpq_packet_type);
-
- register_netdevice_notifier(&bpq_dev_notifier);
-
- printk(banner);
-
- return 0;
-}
-
-static void __exit bpq_cleanup_driver(void)
-{
- struct bpqdev *bpq;
-
- dev_remove_pack(&bpq_packet_type);
-
- unregister_netdevice_notifier(&bpq_dev_notifier);
-
- remove_proc_entry("bpqether", init_net.proc_net);
-
- rtnl_lock();
- while (!list_empty(&bpq_devices)) {
- bpq = list_entry(bpq_devices.next, struct bpqdev, bpq_list);
- bpq_free_device(bpq->axdev);
- }
- rtnl_unlock();
-}
-
-MODULE_AUTHOR("Joerg Reuter DL1BKE <jreuter@yaina.de>");
-MODULE_DESCRIPTION("Transmit and receive AX.25 packets over Ethernet");
-MODULE_LICENSE("GPL");
-module_init(bpq_init_driver);
-module_exit(bpq_cleanup_driver);
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
deleted file mode 100644
index 3b88e465d08f..000000000000
--- a/drivers/net/hamradio/hdlcdrv.c
+++ /dev/null
@@ -1,747 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*****************************************************************************/
-
-/*
- * hdlcdrv.c -- HDLC packet radio network driver.
- *
- * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * Please note that the GPL allows you to use the driver, NOT the radio.
- * In order to use the radio, you need a license from the communications
- * authority of your country.
- *
- * The driver was derived from Donald Beckers skeleton.c
- * Written 1993-94 by Donald Becker.
- *
- * History:
- * 0.1 21.09.1996 Started
- * 18.10.1996 Changed to new user space access routines
- * (copy_{to,from}_user)
- * 0.2 21.11.1996 various small changes
- * 0.3 03.03.1997 fixed (hopefully) IP not working with ax.25 as a module
- * 0.4 16.04.1997 init code/data tagged
- * 0.5 30.07.1997 made HDLC buffers bigger (solves a problem with the
- * soundmodem driver)
- * 0.6 05.04.1998 add spinlocks
- * 0.7 03.08.1999 removed some old compatibility cruft
- * 0.8 12.02.2000 adapted to softnet driver interface
- */
-
-/*****************************************************************************/
-
-#include <linux/capability.h>
-#include <linux/compat.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/net.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <linux/hdlcdrv.h>
-#include <linux/random.h>
-#include <net/ax25.h>
-#include <linux/uaccess.h>
-
-#include <linux/crc-ccitt.h>
-
-/* --------------------------------------------------------------------- */
-
-#define KISS_VERBOSE
-
-/* --------------------------------------------------------------------- */
-
-#define PARAM_TXDELAY 1
-#define PARAM_PERSIST 2
-#define PARAM_SLOTTIME 3
-#define PARAM_TXTAIL 4
-#define PARAM_FULLDUP 5
-#define PARAM_HARDWARE 6
-#define PARAM_RETURN 255
-
-/* --------------------------------------------------------------------- */
-/*
- * the CRC routines are stolen from WAMPES
- * by Dieter Deyke
- */
-
-
-/*---------------------------------------------------------------------------*/
-
-static inline void append_crc_ccitt(unsigned char *buffer, int len)
-{
- unsigned int crc = crc_ccitt(0xffff, buffer, len) ^ 0xffff;
- buffer += len;
- *buffer++ = crc;
- *buffer++ = crc >> 8;
-}
-
-/*---------------------------------------------------------------------------*/
-
-static inline int check_crc_ccitt(const unsigned char *buf, int cnt)
-{
- return (crc_ccitt(0xffff, buf, cnt) & 0xffff) == 0xf0b8;
-}
-
-/*---------------------------------------------------------------------------*/
-
-#if 0
-static int calc_crc_ccitt(const unsigned char *buf, int cnt)
-{
- unsigned int crc = 0xffff;
-
- for (; cnt > 0; cnt--)
- crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff];
- crc ^= 0xffff;
- return crc & 0xffff;
-}
-#endif
-
-/* ---------------------------------------------------------------------- */
-
-#define tenms_to_2flags(s,tenms) ((tenms * s->par.bitrate) / 100 / 16)
-
-/* ---------------------------------------------------------------------- */
-/*
- * The HDLC routines
- */
-
-static int hdlc_rx_add_bytes(struct hdlcdrv_state *s, unsigned int bits,
- int num)
-{
- int added = 0;
-
- while (s->hdlcrx.rx_state && num >= 8) {
- if (s->hdlcrx.len >= sizeof(s->hdlcrx.buffer)) {
- s->hdlcrx.rx_state = 0;
- return 0;
- }
- *s->hdlcrx.bp++ = bits >> (32-num);
- s->hdlcrx.len++;
- num -= 8;
- added += 8;
- }
- return added;
-}
-
-static void hdlc_rx_flag(struct net_device *dev, struct hdlcdrv_state *s)
-{
- struct sk_buff *skb;
- int pkt_len;
- unsigned char *cp;
-
- if (s->hdlcrx.len < 4)
- return;
- if (!check_crc_ccitt(s->hdlcrx.buffer, s->hdlcrx.len))
- return;
- pkt_len = s->hdlcrx.len - 2 + 1; /* KISS kludge */
- if (!(skb = dev_alloc_skb(pkt_len))) {
- printk("%s: memory squeeze, dropping packet\n", dev->name);
- dev->stats.rx_dropped++;
- return;
- }
- cp = skb_put(skb, pkt_len);
- *cp++ = 0; /* KISS kludge */
- memcpy(cp, s->hdlcrx.buffer, pkt_len - 1);
- skb->protocol = ax25_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
-}
-
-void hdlcdrv_receiver(struct net_device *dev, struct hdlcdrv_state *s)
-{
- int i;
- unsigned int mask1, mask2, mask3, mask4, mask5, mask6, word;
-
- if (!s || s->magic != HDLCDRV_MAGIC)
- return;
- if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx))
- return;
-
- while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) {
- word = hdlcdrv_hbuf_get(&s->hdlcrx.hbuf);
-
-#ifdef HDLCDRV_DEBUG
- hdlcdrv_add_bitbuffer_word(&s->bitbuf_hdlc, word);
-#endif /* HDLCDRV_DEBUG */
- s->hdlcrx.bitstream >>= 16;
- s->hdlcrx.bitstream |= word << 16;
- s->hdlcrx.bitbuf >>= 16;
- s->hdlcrx.bitbuf |= word << 16;
- s->hdlcrx.numbits += 16;
- for(i = 15, mask1 = 0x1fc00, mask2 = 0x1fe00, mask3 = 0x0fc00,
- mask4 = 0x1f800, mask5 = 0xf800, mask6 = 0xffff;
- i >= 0;
- i--, mask1 <<= 1, mask2 <<= 1, mask3 <<= 1, mask4 <<= 1,
- mask5 <<= 1, mask6 = (mask6 << 1) | 1) {
- if ((s->hdlcrx.bitstream & mask1) == mask1)
- s->hdlcrx.rx_state = 0; /* abort received */
- else if ((s->hdlcrx.bitstream & mask2) == mask3) {
- /* flag received */
- if (s->hdlcrx.rx_state) {
- hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf
- << (8+i),
- s->hdlcrx.numbits
- -8-i);
- hdlc_rx_flag(dev, s);
- }
- s->hdlcrx.len = 0;
- s->hdlcrx.bp = s->hdlcrx.buffer;
- s->hdlcrx.rx_state = 1;
- s->hdlcrx.numbits = i;
- } else if ((s->hdlcrx.bitstream & mask4) == mask5) {
- /* stuffed bit */
- s->hdlcrx.numbits--;
- s->hdlcrx.bitbuf = (s->hdlcrx.bitbuf & (~mask6)) |
- ((s->hdlcrx.bitbuf & mask6) << 1);
- }
- }
- s->hdlcrx.numbits -= hdlc_rx_add_bytes(s, s->hdlcrx.bitbuf,
- s->hdlcrx.numbits);
- }
- clear_bit(0, &s->hdlcrx.in_hdlc_rx);
-}
-
-/* ---------------------------------------------------------------------- */
-
-static inline void do_kiss_params(struct hdlcdrv_state *s,
- unsigned char *data, unsigned long len)
-{
-
-#ifdef KISS_VERBOSE
-#define PKP(a,b) printk(KERN_INFO "hdlcdrv.c: channel params: " a "\n", b)
-#else /* KISS_VERBOSE */
-#define PKP(a,b)
-#endif /* KISS_VERBOSE */
-
- if (len < 2)
- return;
- switch(data[0]) {
- case PARAM_TXDELAY:
- s->ch_params.tx_delay = data[1];
- PKP("TX delay = %ums", 10 * s->ch_params.tx_delay);
- break;
- case PARAM_PERSIST:
- s->ch_params.ppersist = data[1];
- PKP("p persistence = %u", s->ch_params.ppersist);
- break;
- case PARAM_SLOTTIME:
- s->ch_params.slottime = data[1];
- PKP("slot time = %ums", s->ch_params.slottime);
- break;
- case PARAM_TXTAIL:
- s->ch_params.tx_tail = data[1];
- PKP("TX tail = %ums", s->ch_params.tx_tail);
- break;
- case PARAM_FULLDUP:
- s->ch_params.fulldup = !!data[1];
- PKP("%s duplex", s->ch_params.fulldup ? "full" : "half");
- break;
- default:
- break;
- }
-#undef PKP
-}
-
-/* ---------------------------------------------------------------------- */
-
-void hdlcdrv_transmitter(struct net_device *dev, struct hdlcdrv_state *s)
-{
- unsigned int mask1, mask2, mask3;
- int i;
- struct sk_buff *skb;
- int pkt_len;
-
- if (!s || s->magic != HDLCDRV_MAGIC)
- return;
- if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx))
- return;
- for (;;) {
- if (s->hdlctx.numbits >= 16) {
- if (hdlcdrv_hbuf_full(&s->hdlctx.hbuf)) {
- clear_bit(0, &s->hdlctx.in_hdlc_tx);
- return;
- }
- hdlcdrv_hbuf_put(&s->hdlctx.hbuf, s->hdlctx.bitbuf);
- s->hdlctx.bitbuf >>= 16;
- s->hdlctx.numbits -= 16;
- }
- switch (s->hdlctx.tx_state) {
- default:
- clear_bit(0, &s->hdlctx.in_hdlc_tx);
- return;
- case 0:
- case 1:
- if (s->hdlctx.numflags) {
- s->hdlctx.numflags--;
- s->hdlctx.bitbuf |=
- 0x7e7e << s->hdlctx.numbits;
- s->hdlctx.numbits += 16;
- break;
- }
- if (s->hdlctx.tx_state == 1) {
- clear_bit(0, &s->hdlctx.in_hdlc_tx);
- return;
- }
- if (!(skb = s->skb)) {
- int flgs = tenms_to_2flags(s, s->ch_params.tx_tail);
- if (flgs < 2)
- flgs = 2;
- s->hdlctx.tx_state = 1;
- s->hdlctx.numflags = flgs;
- break;
- }
- s->skb = NULL;
- netif_wake_queue(dev);
- pkt_len = skb->len-1; /* strip KISS byte */
- if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) {
- s->hdlctx.tx_state = 0;
- s->hdlctx.numflags = 1;
- dev_kfree_skb_irq(skb);
- break;
- }
- skb_copy_from_linear_data_offset(skb, 1,
- s->hdlctx.buffer,
- pkt_len);
- dev_kfree_skb_irq(skb);
- s->hdlctx.bp = s->hdlctx.buffer;
- append_crc_ccitt(s->hdlctx.buffer, pkt_len);
- s->hdlctx.len = pkt_len+2; /* the appended CRC */
- s->hdlctx.tx_state = 2;
- s->hdlctx.bitstream = 0;
- dev->stats.tx_packets++;
- break;
- case 2:
- if (!s->hdlctx.len) {
- s->hdlctx.tx_state = 0;
- s->hdlctx.numflags = 1;
- break;
- }
- s->hdlctx.len--;
- s->hdlctx.bitbuf |= *s->hdlctx.bp <<
- s->hdlctx.numbits;
- s->hdlctx.bitstream >>= 8;
- s->hdlctx.bitstream |= (*s->hdlctx.bp++) << 16;
- mask1 = 0x1f000;
- mask2 = 0x10000;
- mask3 = 0xffffffff >> (31-s->hdlctx.numbits);
- s->hdlctx.numbits += 8;
- for(i = 0; i < 8; i++, mask1 <<= 1, mask2 <<= 1,
- mask3 = (mask3 << 1) | 1) {
- if ((s->hdlctx.bitstream & mask1) != mask1)
- continue;
- s->hdlctx.bitstream &= ~mask2;
- s->hdlctx.bitbuf =
- (s->hdlctx.bitbuf & mask3) |
- ((s->hdlctx.bitbuf &
- (~mask3)) << 1);
- s->hdlctx.numbits++;
- mask3 = (mask3 << 1) | 1;
- }
- break;
- }
- }
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void start_tx(struct net_device *dev, struct hdlcdrv_state *s)
-{
- s->hdlctx.tx_state = 0;
- s->hdlctx.numflags = tenms_to_2flags(s, s->ch_params.tx_delay);
- s->hdlctx.bitbuf = s->hdlctx.bitstream = s->hdlctx.numbits = 0;
- hdlcdrv_transmitter(dev, s);
- s->hdlctx.ptt = 1;
- s->ptt_keyed++;
-}
-
-/* ---------------------------------------------------------------------- */
-
-void hdlcdrv_arbitrate(struct net_device *dev, struct hdlcdrv_state *s)
-{
- if (!s || s->magic != HDLCDRV_MAGIC || s->hdlctx.ptt || !s->skb)
- return;
- if (s->ch_params.fulldup) {
- start_tx(dev, s);
- return;
- }
- if (s->hdlcrx.dcd) {
- s->hdlctx.slotcnt = s->ch_params.slottime;
- return;
- }
- if ((--s->hdlctx.slotcnt) > 0)
- return;
- s->hdlctx.slotcnt = s->ch_params.slottime;
- if (get_random_u8() > s->ch_params.ppersist)
- return;
- start_tx(dev, s);
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * ===================== network driver interface =========================
- */
-
-static netdev_tx_t hdlcdrv_send_packet(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct hdlcdrv_state *sm = netdev_priv(dev);
-
- if (skb->protocol == htons(ETH_P_IP))
- return ax25_ip_xmit(skb);
-
- if (skb->data[0] != 0) {
- do_kiss_params(sm, skb->data, skb->len);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- if (sm->skb) {
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- netif_stop_queue(dev);
- sm->skb = skb;
- return NETDEV_TX_OK;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int hdlcdrv_set_mac_address(struct net_device *dev, void *addr)
-{
- struct sockaddr *sa = (struct sockaddr *)addr;
-
- /* addr is an AX.25 shifted ASCII mac address */
- dev_addr_set(dev, sa->sa_data);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
- */
-
-static int hdlcdrv_open(struct net_device *dev)
-{
- struct hdlcdrv_state *s = netdev_priv(dev);
- int i;
-
- if (!s->ops || !s->ops->open)
- return -ENODEV;
-
- /*
- * initialise some variables
- */
- s->opened = 1;
- s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0;
- s->hdlcrx.in_hdlc_rx = 0;
- s->hdlcrx.rx_state = 0;
-
- s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0;
- s->hdlctx.in_hdlc_tx = 0;
- s->hdlctx.tx_state = 1;
- s->hdlctx.numflags = 0;
- s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0;
- s->hdlctx.ptt = 0;
- s->hdlctx.slotcnt = s->ch_params.slottime;
- s->hdlctx.calibrate = 0;
-
- i = s->ops->open(dev);
- if (i)
- return i;
- netif_start_queue(dev);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * The inverse routine to hdlcdrv_open().
- */
-
-static int hdlcdrv_close(struct net_device *dev)
-{
- struct hdlcdrv_state *s = netdev_priv(dev);
- int i = 0;
-
- netif_stop_queue(dev);
-
- if (s->ops && s->ops->close)
- i = s->ops->close(dev);
- dev_kfree_skb(s->skb);
- s->skb = NULL;
- s->opened = 0;
- return i;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int hdlcdrv_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
- void __user *data, int cmd)
-{
- struct hdlcdrv_state *s = netdev_priv(dev);
- struct hdlcdrv_ioctl bi;
-
- if (cmd != SIOCDEVPRIVATE)
- return -ENOIOCTLCMD;
-
- if (in_compat_syscall()) /* to be implemented */
- return -ENOIOCTLCMD;
-
- if (copy_from_user(&bi, data, sizeof(bi)))
- return -EFAULT;
-
- switch (bi.cmd) {
- default:
- if (s->ops && s->ops->ioctl)
- return s->ops->ioctl(dev, data, &bi, cmd);
- return -ENOIOCTLCMD;
-
- case HDLCDRVCTL_GETCHANNELPAR:
- bi.data.cp.tx_delay = s->ch_params.tx_delay;
- bi.data.cp.tx_tail = s->ch_params.tx_tail;
- bi.data.cp.slottime = s->ch_params.slottime;
- bi.data.cp.ppersist = s->ch_params.ppersist;
- bi.data.cp.fulldup = s->ch_params.fulldup;
- break;
-
- case HDLCDRVCTL_SETCHANNELPAR:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- s->ch_params.tx_delay = bi.data.cp.tx_delay;
- s->ch_params.tx_tail = bi.data.cp.tx_tail;
- s->ch_params.slottime = bi.data.cp.slottime;
- s->ch_params.ppersist = bi.data.cp.ppersist;
- s->ch_params.fulldup = bi.data.cp.fulldup;
- s->hdlctx.slotcnt = 1;
- return 0;
-
- case HDLCDRVCTL_GETMODEMPAR:
- bi.data.mp.iobase = dev->base_addr;
- bi.data.mp.irq = dev->irq;
- bi.data.mp.dma = dev->dma;
- bi.data.mp.dma2 = s->ptt_out.dma2;
- bi.data.mp.seriobase = s->ptt_out.seriobase;
- bi.data.mp.pariobase = s->ptt_out.pariobase;
- bi.data.mp.midiiobase = s->ptt_out.midiiobase;
- break;
-
- case HDLCDRVCTL_SETMODEMPAR:
- if ((!capable(CAP_SYS_RAWIO)) || netif_running(dev))
- return -EACCES;
- dev->base_addr = bi.data.mp.iobase;
- dev->irq = bi.data.mp.irq;
- dev->dma = bi.data.mp.dma;
- s->ptt_out.dma2 = bi.data.mp.dma2;
- s->ptt_out.seriobase = bi.data.mp.seriobase;
- s->ptt_out.pariobase = bi.data.mp.pariobase;
- s->ptt_out.midiiobase = bi.data.mp.midiiobase;
- return 0;
-
- case HDLCDRVCTL_GETSTAT:
- bi.data.cs.ptt = hdlcdrv_ptt(s);
- bi.data.cs.dcd = s->hdlcrx.dcd;
- bi.data.cs.ptt_keyed = s->ptt_keyed;
- bi.data.cs.tx_packets = dev->stats.tx_packets;
- bi.data.cs.tx_errors = dev->stats.tx_errors;
- bi.data.cs.rx_packets = dev->stats.rx_packets;
- bi.data.cs.rx_errors = dev->stats.rx_errors;
- break;
-
- case HDLCDRVCTL_OLDGETSTAT:
- bi.data.ocs.ptt = hdlcdrv_ptt(s);
- bi.data.ocs.dcd = s->hdlcrx.dcd;
- bi.data.ocs.ptt_keyed = s->ptt_keyed;
- break;
-
- case HDLCDRVCTL_CALIBRATE:
- if(!capable(CAP_SYS_RAWIO))
- return -EPERM;
- if (s->par.bitrate <= 0)
- return -EINVAL;
- if (bi.data.calibrate > INT_MAX / s->par.bitrate)
- return -EINVAL;
- s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16;
- return 0;
-
- case HDLCDRVCTL_GETSAMPLES:
-#ifndef HDLCDRV_DEBUG
- return -EPERM;
-#else /* HDLCDRV_DEBUG */
- if (s->bitbuf_channel.rd == s->bitbuf_channel.wr)
- return -EAGAIN;
- bi.data.bits =
- s->bitbuf_channel.buffer[s->bitbuf_channel.rd];
- s->bitbuf_channel.rd = (s->bitbuf_channel.rd+1) %
- sizeof(s->bitbuf_channel.buffer);
- break;
-#endif /* HDLCDRV_DEBUG */
-
- case HDLCDRVCTL_GETBITS:
-#ifndef HDLCDRV_DEBUG
- return -EPERM;
-#else /* HDLCDRV_DEBUG */
- if (s->bitbuf_hdlc.rd == s->bitbuf_hdlc.wr)
- return -EAGAIN;
- bi.data.bits =
- s->bitbuf_hdlc.buffer[s->bitbuf_hdlc.rd];
- s->bitbuf_hdlc.rd = (s->bitbuf_hdlc.rd+1) %
- sizeof(s->bitbuf_hdlc.buffer);
- break;
-#endif /* HDLCDRV_DEBUG */
-
- case HDLCDRVCTL_DRIVERNAME:
- if (s->ops && s->ops->drvname) {
- strscpy(bi.data.drivername, s->ops->drvname,
- sizeof(bi.data.drivername));
- break;
- }
- bi.data.drivername[0] = '\0';
- break;
-
- }
- if (copy_to_user(data, &bi, sizeof(bi)))
- return -EFAULT;
- return 0;
-
-}
-
-/* --------------------------------------------------------------------- */
-
-static const struct net_device_ops hdlcdrv_netdev = {
- .ndo_open = hdlcdrv_open,
- .ndo_stop = hdlcdrv_close,
- .ndo_start_xmit = hdlcdrv_send_packet,
- .ndo_siocdevprivate = hdlcdrv_siocdevprivate,
- .ndo_set_mac_address = hdlcdrv_set_mac_address,
-};
-
-/*
- * Initialize fields in hdlcdrv
- */
-static void hdlcdrv_setup(struct net_device *dev)
-{
- static const struct hdlcdrv_channel_params dflt_ch_params = {
- 20, 2, 10, 40, 0
- };
- struct hdlcdrv_state *s = netdev_priv(dev);
-
- /*
- * initialize the hdlcdrv_state struct
- */
- s->ch_params = dflt_ch_params;
- s->ptt_keyed = 0;
-
- spin_lock_init(&s->hdlcrx.hbuf.lock);
- s->hdlcrx.hbuf.rd = s->hdlcrx.hbuf.wr = 0;
- s->hdlcrx.in_hdlc_rx = 0;
- s->hdlcrx.rx_state = 0;
-
- spin_lock_init(&s->hdlctx.hbuf.lock);
- s->hdlctx.hbuf.rd = s->hdlctx.hbuf.wr = 0;
- s->hdlctx.in_hdlc_tx = 0;
- s->hdlctx.tx_state = 1;
- s->hdlctx.numflags = 0;
- s->hdlctx.bitstream = s->hdlctx.bitbuf = s->hdlctx.numbits = 0;
- s->hdlctx.ptt = 0;
- s->hdlctx.slotcnt = s->ch_params.slottime;
- s->hdlctx.calibrate = 0;
-
-#ifdef HDLCDRV_DEBUG
- s->bitbuf_channel.rd = s->bitbuf_channel.wr = 0;
- s->bitbuf_channel.shreg = 0x80;
-
- s->bitbuf_hdlc.rd = s->bitbuf_hdlc.wr = 0;
- s->bitbuf_hdlc.shreg = 0x80;
-#endif /* HDLCDRV_DEBUG */
-
-
- /* Fill in the fields of the device structure */
-
- s->skb = NULL;
-
- dev->netdev_ops = &hdlcdrv_netdev;
- dev->header_ops = &ax25_header_ops;
-
- dev->type = ARPHRD_AX25; /* AF_AX25 device */
- dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
- dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */
- dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
- memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
- dev_addr_set(dev, (u8 *)&ax25_defaddr);
- dev->tx_queue_len = 16;
-}
-
-/* --------------------------------------------------------------------- */
-struct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops,
- unsigned int privsize, const char *ifname,
- unsigned int baseaddr, unsigned int irq,
- unsigned int dma)
-{
- struct net_device *dev;
- struct hdlcdrv_state *s;
- int err;
-
- if (privsize < sizeof(struct hdlcdrv_state))
- privsize = sizeof(struct hdlcdrv_state);
-
- dev = alloc_netdev(privsize, ifname, NET_NAME_UNKNOWN, hdlcdrv_setup);
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- /*
- * initialize part of the hdlcdrv_state struct
- */
- s = netdev_priv(dev);
- s->magic = HDLCDRV_MAGIC;
- s->ops = ops;
- dev->base_addr = baseaddr;
- dev->irq = irq;
- dev->dma = dma;
-
- err = register_netdev(dev);
- if (err < 0) {
- printk(KERN_WARNING "hdlcdrv: cannot register net "
- "device %s\n", dev->name);
- free_netdev(dev);
- dev = ERR_PTR(err);
- }
- return dev;
-}
-
-/* --------------------------------------------------------------------- */
-
-void hdlcdrv_unregister(struct net_device *dev)
-{
- struct hdlcdrv_state *s = netdev_priv(dev);
-
- BUG_ON(s->magic != HDLCDRV_MAGIC);
-
- if (s->opened && s->ops->close)
- s->ops->close(dev);
- unregister_netdev(dev);
-
- free_netdev(dev);
-}
-
-/* --------------------------------------------------------------------- */
-
-EXPORT_SYMBOL(hdlcdrv_receiver);
-EXPORT_SYMBOL(hdlcdrv_transmitter);
-EXPORT_SYMBOL(hdlcdrv_arbitrate);
-EXPORT_SYMBOL(hdlcdrv_register);
-EXPORT_SYMBOL(hdlcdrv_unregister);
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
deleted file mode 100644
index 5f38a002bd9e..000000000000
--- a/drivers/net/hamradio/mkiss.c
+++ /dev/null
@@ -1,980 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *
- * Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl>
- * Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org>
- * Copyright (C) 2004, 05 Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de>
- */
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/uaccess.h>
-#include <linux/crc16.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/major.h>
-#include <linux/init.h>
-#include <linux/rtnetlink.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/jiffies.h>
-#include <linux/refcount.h>
-
-#include <net/ax25.h>
-
-#define AX_MTU 236
-
-/* some arch define END as assembly function ending, just undef it */
-#undef END
-/* SLIP/KISS protocol characters. */
-#define END 0300 /* indicates end of frame */
-#define ESC 0333 /* indicates byte stuffing */
-#define ESC_END 0334 /* ESC ESC_END means END 'data' */
-#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
-
-struct mkiss {
- struct tty_struct *tty; /* ptr to TTY structure */
- struct net_device *dev; /* easy for intr handling */
-
- /* These are pointers to the malloc()ed frame buffers. */
- spinlock_t buflock;/* lock for rbuf and xbuf */
- unsigned char *rbuff; /* receiver buffer */
- int rcount; /* received chars counter */
- unsigned char *xbuff; /* transmitter buffer */
- unsigned char *xhead; /* pointer to next byte to XMIT */
- int xleft; /* bytes left in XMIT queue */
-
- /* Detailed SLIP statistics. */
- int mtu; /* Our mtu (to spot changes!) */
- int buffsize; /* Max buffers sizes */
-
- unsigned long flags; /* Flag values/ mode etc */
- /* long req'd: used by set_bit --RR */
-#define AXF_INUSE 0 /* Channel in use */
-#define AXF_ESCAPE 1 /* ESC received */
-#define AXF_ERROR 2 /* Parity, etc. error */
-#define AXF_KEEPTEST 3 /* Keepalive test flag */
-#define AXF_OUTWAIT 4 /* is outpacket was flag */
-
- int mode;
- int crcmode; /* MW: for FlexNet, SMACK etc. */
- int crcauto; /* CRC auto mode */
-
-#define CRC_MODE_NONE 0
-#define CRC_MODE_FLEX 1
-#define CRC_MODE_SMACK 2
-#define CRC_MODE_FLEX_TEST 3
-#define CRC_MODE_SMACK_TEST 4
-
- refcount_t refcnt;
- struct completion dead;
-};
-
-/*---------------------------------------------------------------------------*/
-
-static const unsigned short crc_flex_table[] = {
- 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38,
- 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770,
- 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9,
- 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1,
- 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a,
- 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672,
- 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb,
- 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3,
- 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c,
- 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574,
- 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd,
- 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5,
- 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e,
- 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476,
- 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf,
- 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7,
- 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30,
- 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378,
- 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1,
- 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9,
- 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32,
- 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a,
- 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3,
- 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb,
- 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34,
- 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c,
- 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5,
- 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd,
- 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36,
- 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e,
- 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7,
- 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff
-};
-
-static unsigned short calc_crc_flex(unsigned char *cp, int size)
-{
- unsigned short crc = 0xffff;
-
- while (size--)
- crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
-
- return crc;
-}
-
-static int check_crc_flex(unsigned char *cp, int size)
-{
- unsigned short crc = 0xffff;
-
- if (size < 3)
- return -1;
-
- while (size--)
- crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
-
- if ((crc & 0xffff) != 0x7070)
- return -1;
-
- return 0;
-}
-
-static int check_crc_16(unsigned char *cp, int size)
-{
- unsigned short crc = 0x0000;
-
- if (size < 3)
- return -1;
-
- crc = crc16(0, cp, size);
-
- if (crc != 0x0000)
- return -1;
-
- return 0;
-}
-
-/*
- * Standard encapsulation
- */
-
-static int kiss_esc(unsigned char *s, unsigned char *d, int len)
-{
- unsigned char *ptr = d;
- unsigned char c;
-
- /*
- * Send an initial END character to flush out any data that may have
- * accumulated in the receiver due to line noise.
- */
-
- *ptr++ = END;
-
- while (len-- > 0) {
- switch (c = *s++) {
- case END:
- *ptr++ = ESC;
- *ptr++ = ESC_END;
- break;
- case ESC:
- *ptr++ = ESC;
- *ptr++ = ESC_ESC;
- break;
- default:
- *ptr++ = c;
- break;
- }
- }
-
- *ptr++ = END;
-
- return ptr - d;
-}
-
-/*
- * MW:
- * OK its ugly, but tell me a better solution without copying the
- * packet to a temporary buffer :-)
- */
-static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc,
- int len)
-{
- unsigned char *ptr = d;
- unsigned char c=0;
-
- *ptr++ = END;
- while (len > 0) {
- if (len > 2)
- c = *s++;
- else if (len > 1)
- c = crc >> 8;
- else
- c = crc & 0xff;
-
- len--;
-
- switch (c) {
- case END:
- *ptr++ = ESC;
- *ptr++ = ESC_END;
- break;
- case ESC:
- *ptr++ = ESC;
- *ptr++ = ESC_ESC;
- break;
- default:
- *ptr++ = c;
- break;
- }
- }
- *ptr++ = END;
-
- return ptr - d;
-}
-
-/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */
-static void ax_bump(struct mkiss *ax)
-{
- struct sk_buff *skb;
- int count;
-
- spin_lock_bh(&ax->buflock);
- if (ax->rbuff[0] > 0x0f) {
- if (ax->rbuff[0] & 0x80) {
- if (check_crc_16(ax->rbuff, ax->rcount) < 0) {
- ax->dev->stats.rx_errors++;
- spin_unlock_bh(&ax->buflock);
-
- return;
- }
- if (ax->crcmode != CRC_MODE_SMACK && ax->crcauto) {
- printk(KERN_INFO
- "mkiss: %s: Switching to crc-smack\n",
- ax->dev->name);
- ax->crcmode = CRC_MODE_SMACK;
- }
- ax->rcount -= 2;
- *ax->rbuff &= ~0x80;
- } else if (ax->rbuff[0] & 0x20) {
- if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
- ax->dev->stats.rx_errors++;
- spin_unlock_bh(&ax->buflock);
- return;
- }
- if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) {
- printk(KERN_INFO
- "mkiss: %s: Switching to crc-flexnet\n",
- ax->dev->name);
- ax->crcmode = CRC_MODE_FLEX;
- }
- ax->rcount -= 2;
-
- /*
- * dl9sau bugfix: the trailling two bytes flexnet crc
- * will not be passed to the kernel. thus we have to
- * correct the kissparm signature, because it indicates
- * a crc but there's none
- */
- *ax->rbuff &= ~0x20;
- }
- }
-
- count = ax->rcount;
-
- if ((skb = dev_alloc_skb(count)) == NULL) {
- printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n",
- ax->dev->name);
- ax->dev->stats.rx_dropped++;
- spin_unlock_bh(&ax->buflock);
- return;
- }
-
- skb_put_data(skb, ax->rbuff, count);
- skb->protocol = ax25_type_trans(skb, ax->dev);
- netif_rx(skb);
- ax->dev->stats.rx_packets++;
- ax->dev->stats.rx_bytes += count;
- spin_unlock_bh(&ax->buflock);
-}
-
-static void kiss_unesc(struct mkiss *ax, unsigned char s)
-{
- switch (s) {
- case END:
- /* drop keeptest bit = VSV */
- if (test_bit(AXF_KEEPTEST, &ax->flags))
- clear_bit(AXF_KEEPTEST, &ax->flags);
-
- if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
- ax_bump(ax);
-
- clear_bit(AXF_ESCAPE, &ax->flags);
- ax->rcount = 0;
- return;
-
- case ESC:
- set_bit(AXF_ESCAPE, &ax->flags);
- return;
- case ESC_ESC:
- if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
- s = ESC;
- break;
- case ESC_END:
- if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
- s = END;
- break;
- }
-
- spin_lock_bh(&ax->buflock);
- if (!test_bit(AXF_ERROR, &ax->flags)) {
- if (ax->rcount < ax->buffsize) {
- ax->rbuff[ax->rcount++] = s;
- spin_unlock_bh(&ax->buflock);
- return;
- }
-
- ax->dev->stats.rx_over_errors++;
- set_bit(AXF_ERROR, &ax->flags);
- }
- spin_unlock_bh(&ax->buflock);
-}
-
-static int ax_set_mac_address(struct net_device *dev, void *addr)
-{
- struct sockaddr_ax25 *sa = addr;
-
- netif_tx_lock_bh(dev);
- netif_addr_lock(dev);
- __dev_addr_set(dev, &sa->sax25_call, AX25_ADDR_LEN);
- netif_addr_unlock(dev);
- netif_tx_unlock_bh(dev);
-
- return 0;
-}
-
-/*---------------------------------------------------------------------------*/
-
-static void ax_changedmtu(struct mkiss *ax)
-{
- struct net_device *dev = ax->dev;
- unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
- int len;
-
- len = dev->mtu * 2;
-
- /*
- * allow for arrival of larger UDP packets, even if we say not to
- * also fixes a bug in which SunOS sends 512-byte packets even with
- * an MSS of 128
- */
- if (len < 576 * 2)
- len = 576 * 2;
-
- xbuff = kmalloc(len + 4, GFP_ATOMIC);
- rbuff = kmalloc(len + 4, GFP_ATOMIC);
-
- if (xbuff == NULL || rbuff == NULL) {
- printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, "
- "MTU change cancelled.\n",
- ax->dev->name);
- dev->mtu = ax->mtu;
- kfree(xbuff);
- kfree(rbuff);
- return;
- }
-
- spin_lock_bh(&ax->buflock);
-
- oxbuff = ax->xbuff;
- ax->xbuff = xbuff;
- orbuff = ax->rbuff;
- ax->rbuff = rbuff;
-
- if (ax->xleft) {
- if (ax->xleft <= len) {
- memcpy(ax->xbuff, ax->xhead, ax->xleft);
- } else {
- ax->xleft = 0;
- dev->stats.tx_dropped++;
- }
- }
-
- ax->xhead = ax->xbuff;
-
- if (ax->rcount) {
- if (ax->rcount <= len) {
- memcpy(ax->rbuff, orbuff, ax->rcount);
- } else {
- ax->rcount = 0;
- dev->stats.rx_over_errors++;
- set_bit(AXF_ERROR, &ax->flags);
- }
- }
-
- ax->mtu = dev->mtu + 73;
- ax->buffsize = len;
-
- spin_unlock_bh(&ax->buflock);
-
- kfree(oxbuff);
- kfree(orbuff);
-}
-
-/* Encapsulate one AX.25 packet and stuff into a TTY queue. */
-static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
-{
- struct mkiss *ax = netdev_priv(dev);
- unsigned char *p;
- int actual, count;
-
- if (ax->mtu != ax->dev->mtu + 73) /* Someone has been ifconfigging */
- ax_changedmtu(ax);
-
- if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */
- printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name);
- dev->stats.tx_dropped++;
- netif_start_queue(dev);
- return;
- }
-
- p = icp;
-
- spin_lock_bh(&ax->buflock);
- if ((*p & 0x0f) != 0) {
- /* Configuration Command (kissparms(1).
- * Protocol spec says: never append CRC.
- * This fixes a very old bug in the linux
- * kiss driver. -- dl9sau */
- switch (*p & 0xff) {
- case 0x85:
- /* command from userspace especially for us,
- * not for delivery to the tnc */
- if (len > 1) {
- int cmd = (p[1] & 0xff);
- switch(cmd) {
- case 3:
- ax->crcmode = CRC_MODE_SMACK;
- break;
- case 2:
- ax->crcmode = CRC_MODE_FLEX;
- break;
- case 1:
- ax->crcmode = CRC_MODE_NONE;
- break;
- case 0:
- default:
- ax->crcmode = CRC_MODE_SMACK_TEST;
- cmd = 0;
- }
- ax->crcauto = (cmd ? 0 : 1);
- printk(KERN_INFO "mkiss: %s: crc mode set to %d\n",
- ax->dev->name, cmd);
- }
- spin_unlock_bh(&ax->buflock);
- netif_start_queue(dev);
-
- return;
- default:
- count = kiss_esc(p, ax->xbuff, len);
- }
- } else {
- unsigned short crc;
- switch (ax->crcmode) {
- case CRC_MODE_SMACK_TEST:
- ax->crcmode = CRC_MODE_FLEX_TEST;
- printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name);
- fallthrough;
- case CRC_MODE_SMACK:
- *p |= 0x80;
- crc = swab16(crc16(0, p, len));
- count = kiss_esc_crc(p, ax->xbuff, crc, len+2);
- break;
- case CRC_MODE_FLEX_TEST:
- ax->crcmode = CRC_MODE_NONE;
- printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name);
- fallthrough;
- case CRC_MODE_FLEX:
- *p |= 0x20;
- crc = calc_crc_flex(p, len);
- count = kiss_esc_crc(p, ax->xbuff, crc, len+2);
- break;
-
- default:
- count = kiss_esc(p, ax->xbuff, len);
- }
- }
- spin_unlock_bh(&ax->buflock);
-
- set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
- actual = ax->tty->ops->write(ax->tty, ax->xbuff, count);
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += actual;
-
- netif_trans_update(ax->dev);
- ax->xleft = count - actual;
- ax->xhead = ax->xbuff + actual;
-}
-
-/* Encapsulate an AX.25 packet and kick it into a TTY queue. */
-static netdev_tx_t ax_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct mkiss *ax = netdev_priv(dev);
-
- if (skb->protocol == htons(ETH_P_IP))
- return ax25_ip_xmit(skb);
-
- if (!netif_running(dev)) {
- printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (netif_queue_stopped(dev)) {
- /*
- * May be we must check transmitter timeout here ?
- * 14 Oct 1994 Dmitry Gorodchanin.
- */
- if (time_before(jiffies, dev_trans_start(dev) + 20 * HZ)) {
- /* 20 sec timeout not reached */
- return NETDEV_TX_BUSY;
- }
-
- printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name,
- (tty_chars_in_buffer(ax->tty) || ax->xleft) ?
- "bad line quality" : "driver error");
-
- ax->xleft = 0;
- clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
- netif_start_queue(dev);
- }
-
- /* We were not busy, so we are now... :-) */
- netif_stop_queue(dev);
- ax_encaps(dev, skb->data, skb->len);
- kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-static int ax_open_dev(struct net_device *dev)
-{
- struct mkiss *ax = netdev_priv(dev);
-
- if (ax->tty == NULL)
- return -ENODEV;
-
- return 0;
-}
-
-/* Open the low-level part of the AX25 channel. Easy! */
-static int ax_open(struct net_device *dev)
-{
- struct mkiss *ax = netdev_priv(dev);
- unsigned long len;
-
- if (ax->tty == NULL)
- return -ENODEV;
-
- /*
- * Allocate the frame buffers:
- *
- * rbuff Receive buffer.
- * xbuff Transmit buffer.
- */
- len = dev->mtu * 2;
-
- /*
- * allow for arrival of larger UDP packets, even if we say not to
- * also fixes a bug in which SunOS sends 512-byte packets even with
- * an MSS of 128
- */
- if (len < 576 * 2)
- len = 576 * 2;
-
- if ((ax->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL)
- goto norbuff;
-
- if ((ax->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL)
- goto noxbuff;
-
- ax->mtu = dev->mtu + 73;
- ax->buffsize = len;
- ax->rcount = 0;
- ax->xleft = 0;
-
- ax->flags &= (1 << AXF_INUSE); /* Clear ESCAPE & ERROR flags */
-
- spin_lock_init(&ax->buflock);
-
- return 0;
-
-noxbuff:
- kfree(ax->rbuff);
-
-norbuff:
- return -ENOMEM;
-}
-
-
-/* Close the low-level part of the AX25 channel. Easy! */
-static int ax_close(struct net_device *dev)
-{
- struct mkiss *ax = netdev_priv(dev);
-
- if (ax->tty)
- clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
-
- netif_stop_queue(dev);
-
- return 0;
-}
-
-static const struct net_device_ops ax_netdev_ops = {
- .ndo_open = ax_open_dev,
- .ndo_stop = ax_close,
- .ndo_start_xmit = ax_xmit,
- .ndo_set_mac_address = ax_set_mac_address,
-};
-
-static void ax_setup(struct net_device *dev)
-{
- /* Finish setting up the DEVICE info. */
- dev->mtu = AX_MTU;
- dev->hard_header_len = AX25_MAX_HEADER_LEN;
- dev->addr_len = AX25_ADDR_LEN;
- dev->type = ARPHRD_AX25;
- dev->tx_queue_len = 10;
- dev->header_ops = &ax25_header_ops;
- dev->netdev_ops = &ax_netdev_ops;
-
-
- memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
- dev_addr_set(dev, (u8 *)&ax25_defaddr);
-
- dev->flags = IFF_BROADCAST | IFF_MULTICAST;
-}
-
-/*
- * We have a potential race on dereferencing tty->disc_data, because the tty
- * layer provides no locking at all - thus one cpu could be running
- * sixpack_receive_buf while another calls sixpack_close, which zeroes
- * tty->disc_data and frees the memory that sixpack_receive_buf is using. The
- * best way to fix this is to use a rwlock in the tty struct, but for now we
- * use a single global rwlock for all ttys in ppp line discipline.
- */
-static DEFINE_RWLOCK(disc_data_lock);
-
-static struct mkiss *mkiss_get(struct tty_struct *tty)
-{
- struct mkiss *ax;
-
- read_lock(&disc_data_lock);
- ax = tty->disc_data;
- if (ax)
- refcount_inc(&ax->refcnt);
- read_unlock(&disc_data_lock);
-
- return ax;
-}
-
-static void mkiss_put(struct mkiss *ax)
-{
- if (refcount_dec_and_test(&ax->refcnt))
- complete(&ax->dead);
-}
-
-static int crc_force = 0; /* Can be overridden with insmod */
-
-static int mkiss_open(struct tty_struct *tty)
-{
- struct net_device *dev;
- struct mkiss *ax;
- int err;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (tty->ops->write == NULL)
- return -EOPNOTSUPP;
-
- dev = alloc_netdev(sizeof(struct mkiss), "ax%d", NET_NAME_UNKNOWN,
- ax_setup);
- if (!dev) {
- err = -ENOMEM;
- goto out;
- }
-
- ax = netdev_priv(dev);
- ax->dev = dev;
-
- spin_lock_init(&ax->buflock);
- refcount_set(&ax->refcnt, 1);
- init_completion(&ax->dead);
-
- ax->tty = tty;
- tty->disc_data = ax;
- tty->receive_room = 65535;
-
- tty_driver_flush_buffer(tty);
-
- /* Restore default settings */
- dev->type = ARPHRD_AX25;
-
- /* Perform the low-level AX25 initialization. */
- err = ax_open(ax->dev);
- if (err)
- goto out_free_netdev;
-
- err = register_netdev(dev);
- if (err)
- goto out_free_buffers;
-
- /* after register_netdev() - because else printk smashes the kernel */
- switch (crc_force) {
- case 3:
- ax->crcmode = CRC_MODE_SMACK;
- printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n",
- ax->dev->name);
- break;
- case 2:
- ax->crcmode = CRC_MODE_FLEX;
- printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n",
- ax->dev->name);
- break;
- case 1:
- ax->crcmode = CRC_MODE_NONE;
- printk(KERN_INFO "mkiss: %s: crc mode disabled.\n",
- ax->dev->name);
- break;
- case 0:
- default:
- crc_force = 0;
- printk(KERN_INFO "mkiss: %s: crc mode is auto.\n",
- ax->dev->name);
- ax->crcmode = CRC_MODE_SMACK_TEST;
- }
- ax->crcauto = (crc_force ? 0 : 1);
-
- netif_start_queue(dev);
-
- /* Done. We have linked the TTY line to a channel. */
- return 0;
-
-out_free_buffers:
- kfree(ax->rbuff);
- kfree(ax->xbuff);
-
-out_free_netdev:
- free_netdev(dev);
-
-out:
- return err;
-}
-
-static void mkiss_close(struct tty_struct *tty)
-{
- struct mkiss *ax;
-
- write_lock_irq(&disc_data_lock);
- ax = tty->disc_data;
- tty->disc_data = NULL;
- write_unlock_irq(&disc_data_lock);
-
- if (!ax)
- return;
-
- /*
- * We have now ensured that nobody can start using ap from now on, but
- * we have to wait for all existing users to finish.
- */
- if (!refcount_dec_and_test(&ax->refcnt))
- wait_for_completion(&ax->dead);
- /*
- * Halt the transmit queue so that a new transmit cannot scribble
- * on our buffers
- */
- netif_stop_queue(ax->dev);
-
- unregister_netdev(ax->dev);
-
- /* Free all AX25 frame buffers after unreg. */
- kfree(ax->rbuff);
- kfree(ax->xbuff);
-
- ax->tty = NULL;
-
- free_netdev(ax->dev);
-}
-
-/* Perform I/O control on an active ax25 channel. */
-static int mkiss_ioctl(struct tty_struct *tty, unsigned int cmd,
- unsigned long arg)
-{
- struct mkiss *ax = mkiss_get(tty);
- struct net_device *dev;
- unsigned int tmp, err;
-
- /* First make sure we're connected. */
- if (ax == NULL)
- return -ENXIO;
- dev = ax->dev;
-
- switch (cmd) {
- case SIOCGIFNAME:
- err = copy_to_user((void __user *) arg, ax->dev->name,
- strlen(ax->dev->name) + 1) ? -EFAULT : 0;
- break;
-
- case SIOCGIFENCAP:
- err = put_user(4, (int __user *) arg);
- break;
-
- case SIOCSIFENCAP:
- if (get_user(tmp, (int __user *) arg)) {
- err = -EFAULT;
- break;
- }
-
- ax->mode = tmp;
- dev->addr_len = AX25_ADDR_LEN;
- dev->hard_header_len = AX25_KISS_HEADER_LEN +
- AX25_MAX_HEADER_LEN + 3;
- dev->type = ARPHRD_AX25;
-
- err = 0;
- break;
-
- case SIOCSIFHWADDR: {
- char addr[AX25_ADDR_LEN];
-
- if (copy_from_user(&addr,
- (void __user *) arg, AX25_ADDR_LEN)) {
- err = -EFAULT;
- break;
- }
-
- netif_tx_lock_bh(dev);
- __dev_addr_set(dev, addr, AX25_ADDR_LEN);
- netif_tx_unlock_bh(dev);
-
- err = 0;
- break;
- }
- default:
- err = -ENOIOCTLCMD;
- }
-
- mkiss_put(ax);
-
- return err;
-}
-
-/*
- * Handle the 'receiver data ready' interrupt.
- * This function is called by the 'tty_io' module in the kernel when
- * a block of data has been received, which can now be decapsulated
- * and sent on to the AX.25 layer for further processing.
- */
-static void mkiss_receive_buf(struct tty_struct *tty, const u8 *cp,
- const u8 *fp, size_t count)
-{
- struct mkiss *ax = mkiss_get(tty);
-
- if (!ax)
- return;
-
- /*
- * Argh! mtu change time! - costs us the packet part received
- * at the change
- */
- if (ax->mtu != ax->dev->mtu + 73)
- ax_changedmtu(ax);
-
- /* Read the characters out of the buffer */
- while (count--) {
- if (fp != NULL && *fp++) {
- if (!test_and_set_bit(AXF_ERROR, &ax->flags))
- ax->dev->stats.rx_errors++;
- cp++;
- continue;
- }
-
- kiss_unesc(ax, *cp++);
- }
-
- mkiss_put(ax);
- tty_unthrottle(tty);
-}
-
-/*
- * Called by the driver when there's room for more data. If we have
- * more packets to send, we send them here.
- */
-static void mkiss_write_wakeup(struct tty_struct *tty)
-{
- struct mkiss *ax = mkiss_get(tty);
- int actual;
-
- if (!ax)
- return;
-
- if (ax->xleft <= 0) {
- /* Now serial buffer is almost free & we can start
- * transmission of another packet
- */
- clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-
- netif_wake_queue(ax->dev);
- goto out;
- }
-
- actual = tty->ops->write(tty, ax->xhead, ax->xleft);
- ax->xleft -= actual;
- ax->xhead += actual;
-
-out:
- mkiss_put(ax);
-}
-
-static struct tty_ldisc_ops ax_ldisc = {
- .owner = THIS_MODULE,
- .num = N_AX25,
- .name = "mkiss",
- .open = mkiss_open,
- .close = mkiss_close,
- .ioctl = mkiss_ioctl,
- .receive_buf = mkiss_receive_buf,
- .write_wakeup = mkiss_write_wakeup
-};
-
-static const char banner[] __initconst = KERN_INFO \
- "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n";
-static const char msg_regfail[] __initconst = KERN_ERR \
- "mkiss: can't register line discipline (err = %d)\n";
-
-static int __init mkiss_init_driver(void)
-{
- int status;
-
- printk(banner);
-
- status = tty_register_ldisc(&ax_ldisc);
- if (status != 0)
- printk(msg_regfail, status);
-
- return status;
-}
-
-static void __exit mkiss_exit_driver(void)
-{
- tty_unregister_ldisc(&ax_ldisc);
-}
-
-MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");
-MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");
-module_param(crc_force, int, 0);
-MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_AX25);
-
-module_init(mkiss_init_driver);
-module_exit(mkiss_exit_driver);
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
deleted file mode 100644
index 8569db4a7140..000000000000
--- a/drivers/net/hamradio/scc.c
+++ /dev/null
@@ -1,2179 +0,0 @@
-#define RCS_ID "$Id: scc.c,v 1.75 1998/11/04 15:15:01 jreuter Exp jreuter $"
-
-#define VERSION "3.0"
-
-/*
- * Please use z8530drv-utils-3.0 with this version.
- * ------------------
- *
- * You can find a subset of the documentation in
- * Documentation/networking/device_drivers/hamradio/z8530drv.rst.
- */
-
-/*
- ********************************************************************
- * SCC.C - Linux driver for Z8530 based HDLC cards for AX.25 *
- ********************************************************************
-
-
- ********************************************************************
-
- Copyright (c) 1993, 2000 Joerg Reuter DL1BKE
-
- portions (c) 1993 Guido ten Dolle PE1NNZ
-
- ********************************************************************
-
- The driver and the programs in the archive are UNDER CONSTRUCTION.
- The code is likely to fail, and so your kernel could --- even
- a whole network.
-
- This driver is intended for Amateur Radio use. If you are running it
- for commercial purposes, please drop me a note. I am nosy...
-
- ...BUT:
-
- ! You m u s t recognize the appropriate legislations of your country !
- ! before you connect a radio to the SCC board and start to transmit or !
- ! receive. The GPL allows you to use the d r i v e r, NOT the RADIO! !
-
- For non-Amateur-Radio use please note that you might need a special
- allowance/licence from the designer of the SCC Board and/or the
- MODEM.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the (modified) GNU General Public License
- delivered with the Linux kernel source.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should find a copy of the GNU General Public License in
- /usr/src/linux/COPYING;
-
- ********************************************************************
-
-
- Incomplete history of z8530drv:
- -------------------------------
-
- 1994-09-13 started to write the driver, rescued most of my own
- code (and Hans Alblas' memory buffer pool concept) from
- an earlier project "sccdrv" which was initiated by
- Guido ten Dolle. Not much of the old driver survived,
- though. The first version I put my hands on was sccdrv1.3
- from August 1993. The memory buffer pool concept
- appeared in an unauthorized sccdrv version (1.5) from
- August 1994.
-
- 1995-01-31 changed copyright notice to GPL without limitations.
-
- .
- . <SNIP>
- .
-
- 1996-10-05 New semester, new driver...
-
- * KISS TNC emulator removed (TTY driver)
- * Source moved to drivers/net/
- * Includes Z8530 defines from drivers/net/z8530.h
- * Uses sk_buffer memory management
- * Reduced overhead of /proc/net/z8530drv output
- * Streamlined quite a lot things
- * Invents brand new bugs... ;-)
-
- The move to version number 3.0 reflects theses changes.
- You can use 'kissbridge' if you need a KISS TNC emulator.
-
- 1996-12-13 Fixed for Linux networking changes. (G4KLX)
- 1997-01-08 Fixed the remaining problems.
- 1997-04-02 Hopefully fixed the problems with the new *_timer()
- routines, added calibration code.
- 1997-10-12 Made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO
- 1998-01-29 Small fix to avoid lock-up on initialization
- 1998-09-29 Fixed the "grouping" bugs, tx_inhibit works again,
- using dev->tx_queue_len now instead of MAXQUEUE now.
- 1998-10-21 Postponed the spinlock changes, would need a lot of
- testing I currently don't have the time to. Softdcd doesn't
- work.
- 1998-11-04 Softdcd does not work correctly in DPLL mode, in fact it
- never did. The DPLL locks on noise, the SYNC unit sees
- flags that aren't... Restarting the DPLL does not help
- either, it resynchronizes too slow and the first received
- frame gets lost.
- 2000-02-13 Fixed for new network driver interface changes, still
- does TX timeouts itself since it uses its own queue
- scheme.
-
- Thanks to all who contributed to this driver with ideas and bug
- reports!
-
- NB -- if you find errors, change something, please let me know
- first before you distribute it... And please don't touch
- the version number. Just replace my callsign in
- "v3.0.dl1bke" with your own. Just to avoid confusion...
-
- If you want to add your modification to the linux distribution
- please (!) contact me first.
-
- New versions of the driver will be announced on the linux-hams
- mailing list on vger.kernel.org. To subscribe send an e-mail
- to majordomo@vger.kernel.org with the following line in
- the body of the mail:
-
- subscribe linux-hams
-
- The content of the "Subject" field will be ignored.
-
- vy 73,
- Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org
- AX-25 : DL1BKE @ DB0ABH.#BAY.DEU.EU
- Internet: jreuter@yaina.de
- www : http://yaina.de/jreuter
-*/
-
-/* ----------------------------------------------------------------------- */
-
-#undef SCC_LDELAY /* slow it even a bit more down */
-#undef SCC_DONT_CHECK /* don't look if the SCCs you specified are available */
-
-#define SCC_MAXCHIPS 4 /* number of max. supported chips */
-#define SCC_BUFSIZE 384 /* must not exceed 4096 */
-#undef SCC_DEBUG
-
-#define SCC_DEFAULT_CLOCK 4915200
- /* default pclock if nothing is specified */
-
-/* ----------------------------------------------------------------------- */
-
-#include <linux/compat.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/in.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/rtnetlink.h>
-#include <linux/if_ether.h>
-#include <linux/if_arp.h>
-#include <linux/socket.h>
-#include <linux/init.h>
-#include <linux/scc.h>
-#include <linux/ctype.h>
-#include <linux/kernel.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/bitops.h>
-
-#include <net/net_namespace.h>
-#include <net/ax25.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <linux/uaccess.h>
-
-#include "z8530.h"
-
-static const char banner[] __initconst = KERN_INFO \
- "AX.25: Z8530 SCC driver version "VERSION".dl1bke\n";
-
-static void t_dwait(struct timer_list *t);
-static void t_txdelay(struct timer_list *t);
-static void t_tail(struct timer_list *t);
-static void t_busy(struct timer_list *);
-static void t_maxkeyup(struct timer_list *);
-static void t_idle(struct timer_list *t);
-static void scc_tx_done(struct scc_channel *);
-static void scc_start_tx_timer(struct scc_channel *,
- void (*)(struct timer_list *), unsigned long);
-static void scc_start_maxkeyup(struct scc_channel *);
-static void scc_start_defer(struct scc_channel *);
-
-static void z8530_init(void);
-
-static void init_channel(struct scc_channel *scc);
-static void scc_key_trx (struct scc_channel *scc, char tx);
-static void scc_init_timer(struct scc_channel *scc);
-
-static int scc_net_alloc(const char *name, struct scc_channel *scc);
-static void scc_net_setup(struct net_device *dev);
-static int scc_net_open(struct net_device *dev);
-static int scc_net_close(struct net_device *dev);
-static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb);
-static netdev_tx_t scc_net_tx(struct sk_buff *skb,
- struct net_device *dev);
-static int scc_net_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
- void __user *data, int cmd);
-static int scc_net_set_mac_address(struct net_device *dev, void *addr);
-static struct net_device_stats * scc_net_get_stats(struct net_device *dev);
-
-static unsigned char SCC_DriverName[] = "scc";
-
-static struct irqflags { unsigned char used : 1; } Ivec[NR_IRQS];
-
-static struct scc_channel SCC_Info[2 * SCC_MAXCHIPS]; /* information per channel */
-
-static struct scc_ctrl {
- io_port chan_A;
- io_port chan_B;
- int irq;
-} SCC_ctrl[SCC_MAXCHIPS+1];
-
-static unsigned char Driver_Initialized;
-static int Nchips;
-static io_port Vector_Latch;
-
-
-/* ******************************************************************** */
-/* * Port Access Functions * */
-/* ******************************************************************** */
-
-/* These provide interrupt save 2-step access to the Z8530 registers */
-
-static DEFINE_SPINLOCK(iolock); /* Guards paired accesses */
-
-static inline unsigned char InReg(io_port port, unsigned char reg)
-{
- unsigned long flags;
- unsigned char r;
-
- spin_lock_irqsave(&iolock, flags);
-#ifdef SCC_LDELAY
- Outb(port, reg);
- udelay(SCC_LDELAY);
- r=Inb(port);
- udelay(SCC_LDELAY);
-#else
- Outb(port, reg);
- r=Inb(port);
-#endif
- spin_unlock_irqrestore(&iolock, flags);
- return r;
-}
-
-static inline void OutReg(io_port port, unsigned char reg, unsigned char val)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&iolock, flags);
-#ifdef SCC_LDELAY
- Outb(port, reg); udelay(SCC_LDELAY);
- Outb(port, val); udelay(SCC_LDELAY);
-#else
- Outb(port, reg);
- Outb(port, val);
-#endif
- spin_unlock_irqrestore(&iolock, flags);
-}
-
-static inline void wr(struct scc_channel *scc, unsigned char reg,
- unsigned char val)
-{
- OutReg(scc->ctrl, reg, (scc->wreg[reg] = val));
-}
-
-static inline void or(struct scc_channel *scc, unsigned char reg, unsigned char val)
-{
- OutReg(scc->ctrl, reg, (scc->wreg[reg] |= val));
-}
-
-static inline void cl(struct scc_channel *scc, unsigned char reg, unsigned char val)
-{
- OutReg(scc->ctrl, reg, (scc->wreg[reg] &= ~val));
-}
-
-/* ******************************************************************** */
-/* * Some useful macros * */
-/* ******************************************************************** */
-
-static inline void scc_discard_buffers(struct scc_channel *scc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&scc->lock, flags);
- if (scc->tx_buff != NULL)
- {
- dev_kfree_skb_irq(scc->tx_buff);
- scc->tx_buff = NULL;
- }
-
- while (!skb_queue_empty(&scc->tx_queue))
- dev_kfree_skb_irq(skb_dequeue(&scc->tx_queue));
-
- spin_unlock_irqrestore(&scc->lock, flags);
-}
-
-
-
-/* ******************************************************************** */
-/* * Interrupt Service Routines * */
-/* ******************************************************************** */
-
-
-/* ----> subroutines for the interrupt handlers <---- */
-
-static inline void scc_notify(struct scc_channel *scc, int event)
-{
- struct sk_buff *skb;
- char *bp;
-
- if (scc->kiss.fulldup != KISS_DUPLEX_OPTIMA)
- return;
-
- skb = dev_alloc_skb(2);
- if (skb != NULL)
- {
- bp = skb_put(skb, 2);
- *bp++ = PARAM_HWEVENT;
- *bp++ = event;
- scc_net_rx(scc, skb);
- } else
- scc->stat.nospace++;
-}
-
-static inline void flush_rx_FIFO(struct scc_channel *scc)
-{
- int k;
-
- for (k=0; k<3; k++)
- Inb(scc->data);
-
- if(scc->rx_buff != NULL) /* did we receive something? */
- {
- scc->stat.rxerrs++; /* then count it as an error */
- dev_kfree_skb_irq(scc->rx_buff);
- scc->rx_buff = NULL;
- }
-}
-
-static void start_hunt(struct scc_channel *scc)
-{
- if ((scc->modem.clocksrc != CLK_EXTERNAL))
- OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
- or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
-}
-
-/* ----> four different interrupt handlers for Tx, Rx, changing of */
-/* DCD/CTS and Rx/Tx errors */
-
-/* Transmitter interrupt handler */
-static inline void scc_txint(struct scc_channel *scc)
-{
- struct sk_buff *skb;
-
- scc->stat.txints++;
- skb = scc->tx_buff;
-
- /* send first octet */
-
- if (skb == NULL)
- {
- skb = skb_dequeue(&scc->tx_queue);
- scc->tx_buff = skb;
- netif_wake_queue(scc->dev);
-
- if (skb == NULL)
- {
- scc_tx_done(scc);
- Outb(scc->ctrl, RES_Tx_P);
- return;
- }
-
- if (skb->len == 0) /* Paranoia... */
- {
- dev_kfree_skb_irq(skb);
- scc->tx_buff = NULL;
- scc_tx_done(scc);
- Outb(scc->ctrl, RES_Tx_P);
- return;
- }
-
- scc->stat.tx_state = TXS_ACTIVE;
-
- OutReg(scc->ctrl, R0, RES_Tx_CRC);
- /* reset CRC generator */
- or(scc,R10,ABUNDER); /* re-install underrun protection */
- Outb(scc->data,*skb->data); /* send byte */
- skb_pull(skb, 1);
-
- if (!scc->enhanced) /* reset EOM latch */
- Outb(scc->ctrl,RES_EOM_L);
- return;
- }
-
- /* End Of Frame... */
-
- if (skb->len == 0)
- {
- Outb(scc->ctrl, RES_Tx_P); /* reset pending int */
- cl(scc, R10, ABUNDER); /* send CRC */
- dev_kfree_skb_irq(skb);
- scc->tx_buff = NULL;
- scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */
- return;
- }
-
- /* send octet */
-
- Outb(scc->data,*skb->data);
- skb_pull(skb, 1);
-}
-
-
-/* External/Status interrupt handler */
-static inline void scc_exint(struct scc_channel *scc)
-{
- unsigned char status,changes,chg_and_stat;
-
- scc->stat.exints++;
-
- status = InReg(scc->ctrl,R0);
- changes = status ^ scc->status;
- chg_and_stat = changes & status;
-
- /* ABORT: generated whenever DCD drops while receiving */
-
- if (chg_and_stat & BRK_ABRT) /* Received an ABORT */
- flush_rx_FIFO(scc);
-
- /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */
-
- if ((changes & SYNC_HUNT) && scc->kiss.softdcd)
- {
- if (status & SYNC_HUNT)
- {
- scc->dcd = 0;
- flush_rx_FIFO(scc);
- if ((scc->modem.clocksrc != CLK_EXTERNAL))
- OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
- } else {
- scc->dcd = 1;
- }
-
- scc_notify(scc, scc->dcd? HWEV_DCD_OFF:HWEV_DCD_ON);
- }
-
- /* DCD: on = start to receive packet, off = ABORT condition */
- /* (a successfully received packet generates a special condition int) */
-
- if((changes & DCD) && !scc->kiss.softdcd) /* DCD input changed state */
- {
- if(status & DCD) /* DCD is now ON */
- {
- start_hunt(scc);
- scc->dcd = 1;
- } else { /* DCD is now OFF */
- cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */
- flush_rx_FIFO(scc);
- scc->dcd = 0;
- }
-
- scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
- }
-
-#ifdef notdef
- /* CTS: use external TxDelay (what's that good for?!)
- * Anyway: If we _could_ use it (BayCom USCC uses CTS for
- * own purposes) we _should_ use the "autoenable" feature
- * of the Z8530 and not this interrupt...
- */
-
- if (chg_and_stat & CTS) /* CTS is now ON */
- {
- if (scc->kiss.txdelay == 0) /* zero TXDELAY = wait for CTS */
- scc_start_tx_timer(scc, t_txdelay, 0);
- }
-#endif
-
- if (scc->stat.tx_state == TXS_ACTIVE && (status & TxEOM))
- {
- scc->stat.tx_under++; /* oops, an underrun! count 'em */
- Outb(scc->ctrl, RES_EXT_INT); /* reset ext/status interrupts */
-
- if (scc->tx_buff != NULL)
- {
- dev_kfree_skb_irq(scc->tx_buff);
- scc->tx_buff = NULL;
- }
-
- or(scc,R10,ABUNDER);
- scc_start_tx_timer(scc, t_txdelay, 0); /* restart transmission */
- }
-
- scc->status = status;
- Outb(scc->ctrl,RES_EXT_INT);
-}
-
-
-/* Receiver interrupt handler */
-static inline void scc_rxint(struct scc_channel *scc)
-{
- struct sk_buff *skb;
-
- scc->stat.rxints++;
-
- if((scc->wreg[5] & RTS) && scc->kiss.fulldup == KISS_DUPLEX_HALF)
- {
- Inb(scc->data); /* discard char */
- or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
- return;
- }
-
- skb = scc->rx_buff;
-
- if (skb == NULL)
- {
- skb = dev_alloc_skb(scc->stat.bufsize);
- if (skb == NULL)
- {
- scc->dev_stat.rx_dropped++;
- scc->stat.nospace++;
- Inb(scc->data);
- or(scc, R3, ENT_HM);
- return;
- }
-
- scc->rx_buff = skb;
- skb_put_u8(skb, 0); /* KISS data */
- }
-
- if (skb->len >= scc->stat.bufsize)
- {
-#ifdef notdef
- printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n");
-#endif
- dev_kfree_skb_irq(skb);
- scc->rx_buff = NULL;
- Inb(scc->data);
- or(scc, R3, ENT_HM);
- return;
- }
-
- skb_put_u8(skb, Inb(scc->data));
-}
-
-
-/* Receive Special Condition interrupt handler */
-static inline void scc_spint(struct scc_channel *scc)
-{
- unsigned char status;
- struct sk_buff *skb;
-
- scc->stat.spints++;
-
- status = InReg(scc->ctrl,R1); /* read receiver status */
-
- Inb(scc->data); /* throw away Rx byte */
- skb = scc->rx_buff;
-
- if(status & Rx_OVR) /* receiver overrun */
- {
- scc->stat.rx_over++; /* count them */
- or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
-
- if (skb != NULL)
- dev_kfree_skb_irq(skb);
- scc->rx_buff = skb = NULL;
- }
-
- if(status & END_FR && skb != NULL) /* end of frame */
- {
- /* CRC okay, frame ends on 8 bit boundary and received something ? */
-
- if (!(status & CRC_ERR) && (status & 0xe) == RES8 && skb->len > 0)
- {
- /* ignore last received byte (first of the CRC bytes) */
- skb_trim(skb, skb->len-1);
- scc_net_rx(scc, skb);
- scc->rx_buff = NULL;
- scc->stat.rxframes++;
- } else { /* a bad frame */
- dev_kfree_skb_irq(skb);
- scc->rx_buff = NULL;
- scc->stat.rxerrs++;
- }
- }
-
- Outb(scc->ctrl,ERR_RES);
-}
-
-
-/* ----> interrupt service routine for the Z8530 <---- */
-
-static void scc_isr_dispatch(struct scc_channel *scc, int vector)
-{
- spin_lock(&scc->lock);
- switch (vector & VECTOR_MASK)
- {
- case TXINT: scc_txint(scc); break;
- case EXINT: scc_exint(scc); break;
- case RXINT: scc_rxint(scc); break;
- case SPINT: scc_spint(scc); break;
- }
- spin_unlock(&scc->lock);
-}
-
-/* If the card has a latch for the interrupt vector (like the PA0HZP card)
- use it to get the number of the chip that generated the int.
- If not: poll all defined chips.
- */
-
-#define SCC_IRQTIMEOUT 30000
-
-static irqreturn_t scc_isr(int irq, void *dev_id)
-{
- int chip_irq = (long) dev_id;
- unsigned char vector;
- struct scc_channel *scc;
- struct scc_ctrl *ctrl;
- int k;
-
- if (Vector_Latch)
- {
- for(k=0; k < SCC_IRQTIMEOUT; k++)
- {
- Outb(Vector_Latch, 0); /* Generate INTACK */
-
- /* Read the vector */
- if((vector=Inb(Vector_Latch)) >= 16 * Nchips) break;
- if (vector & 0x01) break;
-
- scc=&SCC_Info[vector >> 3 ^ 0x01];
- if (!scc->dev) break;
-
- scc_isr_dispatch(scc, vector);
-
- OutReg(scc->ctrl,R0,RES_H_IUS); /* Reset Highest IUS */
- }
-
- if (k == SCC_IRQTIMEOUT)
- printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n");
-
- return IRQ_HANDLED;
- }
-
- /* Find the SCC generating the interrupt by polling all attached SCCs
- * reading RR3A (the interrupt pending register)
- */
-
- ctrl = SCC_ctrl;
- while (ctrl->chan_A)
- {
- if (ctrl->irq != chip_irq)
- {
- ctrl++;
- continue;
- }
-
- scc = NULL;
- for (k = 0; InReg(ctrl->chan_A,R3) && k < SCC_IRQTIMEOUT; k++)
- {
- vector=InReg(ctrl->chan_B,R2); /* Read the vector */
- if (vector & 0x01) break;
-
- scc = &SCC_Info[vector >> 3 ^ 0x01];
- if (!scc->dev) break;
-
- scc_isr_dispatch(scc, vector);
- }
-
- if (k == SCC_IRQTIMEOUT)
- {
- printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?!\n");
- break;
- }
-
- /* This looks weird and it is. At least the BayCom USCC doesn't
- * use the Interrupt Daisy Chain, thus we'll have to start
- * all over again to be sure not to miss an interrupt from
- * (any of) the other chip(s)...
- * Honestly, the situation *is* braindamaged...
- */
-
- if (scc != NULL)
- {
- OutReg(scc->ctrl,R0,RES_H_IUS);
- ctrl = SCC_ctrl;
- } else
- ctrl++;
- }
- return IRQ_HANDLED;
-}
-
-
-
-/* ******************************************************************** */
-/* * Init Channel */
-/* ******************************************************************** */
-
-
-/* ----> set SCC channel speed <---- */
-
-static inline void set_brg(struct scc_channel *scc, unsigned int tc)
-{
- cl(scc,R14,BRENABL); /* disable baudrate generator */
- wr(scc,R12,tc & 255); /* brg rate LOW */
- wr(scc,R13,tc >> 8); /* brg rate HIGH */
- or(scc,R14,BRENABL); /* enable baudrate generator */
-}
-
-static inline void set_speed(struct scc_channel *scc)
-{
- unsigned long flags;
- spin_lock_irqsave(&scc->lock, flags);
-
- if (scc->modem.speed > 0) /* paranoia... */
- set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2);
-
- spin_unlock_irqrestore(&scc->lock, flags);
-}
-
-
-/* ----> initialize a SCC channel <---- */
-
-static inline void init_brg(struct scc_channel *scc)
-{
- wr(scc, R14, BRSRC); /* BRG source = PCLK */
- OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]); /* DPLL source = BRG */
- OutReg(scc->ctrl, R14, SNRZI|scc->wreg[R14]); /* DPLL NRZI mode */
-}
-
-/*
- * Initialization according to the Z8530 manual (SGS-Thomson's version):
- *
- * 1. Modes and constants
- *
- * WR9 11000000 chip reset
- * WR4 XXXXXXXX Tx/Rx control, async or sync mode
- * WR1 0XX00X00 select W/REQ (optional)
- * WR2 XXXXXXXX program interrupt vector
- * WR3 XXXXXXX0 select Rx control
- * WR5 XXXX0XXX select Tx control
- * WR6 XXXXXXXX sync character
- * WR7 XXXXXXXX sync character
- * WR9 000X0XXX select interrupt control
- * WR10 XXXXXXXX miscellaneous control (optional)
- * WR11 XXXXXXXX clock control
- * WR12 XXXXXXXX time constant lower byte (optional)
- * WR13 XXXXXXXX time constant upper byte (optional)
- * WR14 XXXXXXX0 miscellaneous control
- * WR14 XXXSSSSS commands (optional)
- *
- * 2. Enables
- *
- * WR14 000SSSS1 baud rate enable
- * WR3 SSSSSSS1 Rx enable
- * WR5 SSSS1SSS Tx enable
- * WR0 10000000 reset Tx CRG (optional)
- * WR1 XSS00S00 DMA enable (optional)
- *
- * 3. Interrupt status
- *
- * WR15 XXXXXXXX enable external/status
- * WR0 00010000 reset external status
- * WR0 00010000 reset external status twice
- * WR1 SSSXXSXX enable Rx, Tx and Ext/status
- * WR9 000SXSSS enable master interrupt enable
- *
- * 1 = set to one, 0 = reset to zero
- * X = user defined, S = same as previous init
- *
- *
- * Note that the implementation differs in some points from above scheme.
- *
- */
-
-static void init_channel(struct scc_channel *scc)
-{
- timer_delete(&scc->tx_t);
- timer_delete(&scc->tx_wdog);
-
- disable_irq(scc->irq);
-
- wr(scc,R4,X1CLK|SDLC); /* *1 clock, SDLC mode */
- wr(scc,R1,0); /* no W/REQ operation */
- wr(scc,R3,Rx8|RxCRC_ENAB); /* RX 8 bits/char, CRC, disabled */
- wr(scc,R5,Tx8|DTR|TxCRC_ENAB); /* TX 8 bits/char, disabled, DTR */
- wr(scc,R6,0); /* SDLC address zero (not used) */
- wr(scc,R7,FLAG); /* SDLC flag value */
- wr(scc,R9,VIS); /* vector includes status */
- wr(scc,R10,(scc->modem.nrz? NRZ : NRZI)|CRCPS|ABUNDER); /* abort on underrun, preset CRC generator, NRZ(I) */
- wr(scc,R14, 0);
-
-
-/* set clock sources:
-
- CLK_DPLL: normal halfduplex operation
-
- RxClk: use DPLL
- TxClk: use DPLL
- TRxC mode DPLL output
-
- CLK_EXTERNAL: external clocking (G3RUH or DF9IC modem)
-
- BayCom: others:
-
- TxClk = pin RTxC TxClk = pin TRxC
- RxClk = pin TRxC RxClk = pin RTxC
-
-
- CLK_DIVIDER:
- RxClk = use DPLL
- TxClk = pin RTxC
-
- BayCom: others:
- pin TRxC = DPLL pin TRxC = BRG
- (RxClk * 1) (RxClk * 32)
-*/
-
-
- switch(scc->modem.clocksrc)
- {
- case CLK_DPLL:
- wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);
- init_brg(scc);
- break;
-
- case CLK_DIVIDER:
- wr(scc, R11, ((scc->brand & BAYCOM)? TRxCDP : TRxCBR) | RCDPLL|TCRTxCP|TRxCOI);
- init_brg(scc);
- break;
-
- case CLK_EXTERNAL:
- wr(scc, R11, (scc->brand & BAYCOM)? RCTRxCP|TCRTxCP : RCRTxCP|TCTRxCP);
- OutReg(scc->ctrl, R14, DISDPLL);
- break;
-
- }
-
- set_speed(scc); /* set baudrate */
-
- if(scc->enhanced)
- {
- or(scc,R15,SHDLCE|FIFOE); /* enable FIFO, SDLC/HDLC Enhancements (From now R7 is R7') */
- wr(scc,R7,AUTOEOM);
- }
-
- if(scc->kiss.softdcd || (InReg(scc->ctrl,R0) & DCD))
- /* DCD is now ON */
- {
- start_hunt(scc);
- }
-
- /* enable ABORT, DCD & SYNC/HUNT interrupts */
-
- wr(scc,R15, BRKIE|TxUIE|(scc->kiss.softdcd? SYNCIE:DCDIE));
-
- Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
- Outb(scc->ctrl,RES_EXT_INT); /* must be done twice */
-
- or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */
-
- scc->status = InReg(scc->ctrl,R0); /* read initial status */
-
- or(scc,R9,MIE); /* master interrupt enable */
-
- scc_init_timer(scc);
-
- enable_irq(scc->irq);
-}
-
-
-
-
-/* ******************************************************************** */
-/* * SCC timer functions * */
-/* ******************************************************************** */
-
-
-/* ----> scc_key_trx sets the time constant for the baudrate
- generator and keys the transmitter <---- */
-
-static void scc_key_trx(struct scc_channel *scc, char tx)
-{
- unsigned int time_const;
-
- if (scc->brand & PRIMUS)
- Outb(scc->ctrl + 4, scc->option | (tx? 0x80 : 0));
-
- if (scc->modem.speed < 300)
- scc->modem.speed = 1200;
-
- time_const = (unsigned) (scc->clock / (scc->modem.speed * (tx? 2:64))) - 2;
-
- disable_irq(scc->irq);
-
- if (tx)
- {
- or(scc, R1, TxINT_ENAB); /* t_maxkeyup may have reset these */
- or(scc, R15, TxUIE);
- }
-
- if (scc->modem.clocksrc == CLK_DPLL)
- { /* force simplex operation */
- if (tx)
- {
-#ifdef CONFIG_SCC_TRXECHO
- cl(scc, R3, RxENABLE|ENT_HM); /* switch off receiver */
- cl(scc, R15, DCDIE|SYNCIE); /* No DCD changes, please */
-#endif
- set_brg(scc, time_const); /* reprogram baudrate generator */
-
- /* DPLL -> Rx clk, BRG -> Tx CLK, TRxC mode output, TRxC = BRG */
- wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR);
-
- /* By popular demand: tx_inhibit */
- if (scc->kiss.tx_inhibit)
- {
- or(scc,R5, TxENAB);
- scc->wreg[R5] |= RTS;
- } else {
- or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */
- }
- } else {
- cl(scc,R5,RTS|TxENAB);
-
- set_brg(scc, time_const); /* reprogram baudrate generator */
-
- /* DPLL -> Rx clk, DPLL -> Tx CLK, TRxC mode output, TRxC = DPLL */
- wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);
-
-#ifndef CONFIG_SCC_TRXECHO
- if (scc->kiss.softdcd)
-#endif
- {
- or(scc,R15, scc->kiss.softdcd? SYNCIE:DCDIE);
- start_hunt(scc);
- }
- }
- } else {
- if (tx)
- {
-#ifdef CONFIG_SCC_TRXECHO
- if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
- {
- cl(scc, R3, RxENABLE);
- cl(scc, R15, DCDIE|SYNCIE);
- }
-#endif
-
- if (scc->kiss.tx_inhibit)
- {
- or(scc,R5, TxENAB);
- scc->wreg[R5] |= RTS;
- } else {
- or(scc,R5,RTS|TxENAB); /* enable tx */
- }
- } else {
- cl(scc,R5,RTS|TxENAB); /* disable tx */
-
- if ((scc->kiss.fulldup == KISS_DUPLEX_HALF) &&
-#ifndef CONFIG_SCC_TRXECHO
- scc->kiss.softdcd)
-#else
- 1)
-#endif
- {
- or(scc, R15, scc->kiss.softdcd? SYNCIE:DCDIE);
- start_hunt(scc);
- }
- }
- }
-
- enable_irq(scc->irq);
-}
-
-
-/* ----> SCC timer interrupt handler and friends. <---- */
-
-static void __scc_start_tx_timer(struct scc_channel *scc,
- void (*handler)(struct timer_list *t),
- unsigned long when)
-{
- timer_delete(&scc->tx_t);
-
- if (when == 0)
- {
- handler(&scc->tx_t);
- } else
- if (when != TIMER_OFF)
- {
- scc->tx_t.function = handler;
- scc->tx_t.expires = jiffies + (when*HZ)/100;
- add_timer(&scc->tx_t);
- }
-}
-
-static void scc_start_tx_timer(struct scc_channel *scc,
- void (*handler)(struct timer_list *t),
- unsigned long when)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&scc->lock, flags);
- __scc_start_tx_timer(scc, handler, when);
- spin_unlock_irqrestore(&scc->lock, flags);
-}
-
-static void scc_start_defer(struct scc_channel *scc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&scc->lock, flags);
- timer_delete(&scc->tx_wdog);
-
- if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF)
- {
- scc->tx_wdog.function = t_busy;
- scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer;
- add_timer(&scc->tx_wdog);
- }
- spin_unlock_irqrestore(&scc->lock, flags);
-}
-
-static void scc_start_maxkeyup(struct scc_channel *scc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&scc->lock, flags);
- timer_delete(&scc->tx_wdog);
-
- if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF)
- {
- scc->tx_wdog.function = t_maxkeyup;
- scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup;
- add_timer(&scc->tx_wdog);
- }
- spin_unlock_irqrestore(&scc->lock, flags);
-}
-
-/*
- * This is called from scc_txint() when there are no more frames to send.
- * Not exactly a timer function, but it is a close friend of the family...
- */
-
-static void scc_tx_done(struct scc_channel *scc)
-{
- /*
- * trx remains keyed in fulldup mode 2 until t_idle expires.
- */
-
- switch (scc->kiss.fulldup)
- {
- case KISS_DUPLEX_LINK:
- scc->stat.tx_state = TXS_IDLE2;
- if (scc->kiss.idletime != TIMER_OFF)
- scc_start_tx_timer(scc, t_idle,
- scc->kiss.idletime*100);
- break;
- case KISS_DUPLEX_OPTIMA:
- scc_notify(scc, HWEV_ALL_SENT);
- break;
- default:
- scc->stat.tx_state = TXS_BUSY;
- scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);
- }
-
- netif_wake_queue(scc->dev);
-}
-
-
-static unsigned char Rand = 17;
-
-static inline int is_grouped(struct scc_channel *scc)
-{
- int k;
- struct scc_channel *scc2;
- unsigned char grp1, grp2;
-
- grp1 = scc->kiss.group;
-
- for (k = 0; k < (Nchips * 2); k++)
- {
- scc2 = &SCC_Info[k];
- grp2 = scc2->kiss.group;
-
- if (scc2 == scc || !(scc2->dev && grp2))
- continue;
-
- if ((grp1 & 0x3f) == (grp2 & 0x3f))
- {
- if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) )
- return 1;
-
- if ( (grp1 & RXGROUP) && scc2->dcd )
- return 1;
- }
- }
- return 0;
-}
-
-/* DWAIT and SLOTTIME expired
- *
- * fulldup == 0: DCD is active or Rand > P-persistence: start t_busy timer
- * else key trx and start txdelay
- * fulldup == 1: key trx and start txdelay
- * fulldup == 2: mintime expired, reset status or key trx and start txdelay
- */
-
-static void t_dwait(struct timer_list *t)
-{
- struct scc_channel *scc = timer_container_of(scc, t, tx_t);
-
- if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */
- {
- if (skb_queue_empty(&scc->tx_queue)) { /* nothing to send */
- scc->stat.tx_state = TXS_IDLE;
- netif_wake_queue(scc->dev); /* t_maxkeyup locked it. */
- return;
- }
-
- scc->stat.tx_state = TXS_BUSY;
- }
-
- if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
- {
- Rand = Rand * 17 + 31;
-
- if (scc->dcd || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) )
- {
- scc_start_defer(scc);
- scc_start_tx_timer(scc, t_dwait, scc->kiss.slottime);
- return ;
- }
- }
-
- if ( !(scc->wreg[R5] & RTS) )
- {
- scc_key_trx(scc, TX_ON);
- scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay);
- } else {
- scc_start_tx_timer(scc, t_txdelay, 0);
- }
-}
-
-
-/* TXDELAY expired
- *
- * kick transmission by a fake scc_txint(scc), start 'maxkeyup' watchdog.
- */
-
-static void t_txdelay(struct timer_list *t)
-{
- struct scc_channel *scc = timer_container_of(scc, t, tx_t);
-
- scc_start_maxkeyup(scc);
-
- if (scc->tx_buff == NULL)
- {
- disable_irq(scc->irq);
- scc_txint(scc);
- enable_irq(scc->irq);
- }
-}
-
-
-/* TAILTIME expired
- *
- * switch off transmitter. If we were stopped by Maxkeyup restart
- * transmission after 'mintime' seconds
- */
-
-static void t_tail(struct timer_list *t)
-{
- struct scc_channel *scc = timer_container_of(scc, t, tx_t);
- unsigned long flags;
-
- spin_lock_irqsave(&scc->lock, flags);
- timer_delete(&scc->tx_wdog);
- scc_key_trx(scc, TX_OFF);
- spin_unlock_irqrestore(&scc->lock, flags);
-
- if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */
- {
- scc->stat.tx_state = TXS_WAIT;
- scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100);
- return;
- }
-
- scc->stat.tx_state = TXS_IDLE;
- netif_wake_queue(scc->dev);
-}
-
-
-/* BUSY timeout
- *
- * throw away send buffers if DCD remains active too long.
- */
-
-static void t_busy(struct timer_list *t)
-{
- struct scc_channel *scc = timer_container_of(scc, t, tx_wdog);
-
- timer_delete(&scc->tx_t);
- netif_stop_queue(scc->dev); /* don't pile on the wabbit! */
-
- scc_discard_buffers(scc);
- scc->stat.txerrs++;
- scc->stat.tx_state = TXS_IDLE;
-
- netif_wake_queue(scc->dev);
-}
-
-/* MAXKEYUP timeout
- *
- * this is our watchdog.
- */
-
-static void t_maxkeyup(struct timer_list *t)
-{
- struct scc_channel *scc = timer_container_of(scc, t, tx_wdog);
- unsigned long flags;
-
- spin_lock_irqsave(&scc->lock, flags);
- /*
- * let things settle down before we start to
- * accept new data.
- */
-
- netif_stop_queue(scc->dev);
- scc_discard_buffers(scc);
-
- timer_delete(&scc->tx_t);
-
- cl(scc, R1, TxINT_ENAB); /* force an ABORT, but don't */
- cl(scc, R15, TxUIE); /* count it. */
- OutReg(scc->ctrl, R0, RES_Tx_P);
-
- spin_unlock_irqrestore(&scc->lock, flags);
-
- scc->stat.txerrs++;
- scc->stat.tx_state = TXS_TIMEOUT;
- scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);
-}
-
-/* IDLE timeout
- *
- * in fulldup mode 2 it keys down the transmitter after 'idle' seconds
- * of inactivity. We will not restart transmission before 'mintime'
- * expires.
- */
-
-static void t_idle(struct timer_list *t)
-{
- struct scc_channel *scc = timer_container_of(scc, t, tx_t);
-
- timer_delete(&scc->tx_wdog);
-
- scc_key_trx(scc, TX_OFF);
- if(scc->kiss.mintime)
- scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100);
- scc->stat.tx_state = TXS_WAIT;
-}
-
-static void scc_init_timer(struct scc_channel *scc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&scc->lock, flags);
- scc->stat.tx_state = TXS_IDLE;
- spin_unlock_irqrestore(&scc->lock, flags);
-}
-
-
-/* ******************************************************************** */
-/* * Set/get L1 parameters * */
-/* ******************************************************************** */
-
-
-/*
- * this will set the "hardware" parameters through KISS commands or ioctl()
- */
-
-#define CAST(x) (unsigned long)(x)
-
-static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, unsigned int arg)
-{
- switch (cmd)
- {
- case PARAM_TXDELAY: scc->kiss.txdelay=arg; break;
- case PARAM_PERSIST: scc->kiss.persist=arg; break;
- case PARAM_SLOTTIME: scc->kiss.slottime=arg; break;
- case PARAM_TXTAIL: scc->kiss.tailtime=arg; break;
- case PARAM_FULLDUP: scc->kiss.fulldup=arg; break;
- case PARAM_DTR: break; /* does someone need this? */
- case PARAM_GROUP: scc->kiss.group=arg; break;
- case PARAM_IDLE: scc->kiss.idletime=arg; break;
- case PARAM_MIN: scc->kiss.mintime=arg; break;
- case PARAM_MAXKEY: scc->kiss.maxkeyup=arg; break;
- case PARAM_WAIT: scc->kiss.waittime=arg; break;
- case PARAM_MAXDEFER: scc->kiss.maxdefer=arg; break;
- case PARAM_TX: scc->kiss.tx_inhibit=arg; break;
-
- case PARAM_SOFTDCD:
- scc->kiss.softdcd=arg;
- if (arg)
- {
- or(scc, R15, SYNCIE);
- cl(scc, R15, DCDIE);
- start_hunt(scc);
- } else {
- or(scc, R15, DCDIE);
- cl(scc, R15, SYNCIE);
- }
- break;
-
- case PARAM_SPEED:
- if (arg < 256)
- scc->modem.speed=arg*100;
- else
- scc->modem.speed=arg;
-
- if (scc->stat.tx_state == 0) /* only switch baudrate on rx... ;-) */
- set_speed(scc);
- break;
-
- case PARAM_RTS:
- if ( !(scc->wreg[R5] & RTS) )
- {
- if (arg != TX_OFF) {
- scc_key_trx(scc, TX_ON);
- scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay);
- }
- } else {
- if (arg == TX_OFF)
- {
- scc->stat.tx_state = TXS_BUSY;
- scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);
- }
- }
- break;
-
- case PARAM_HWEVENT:
- scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
- break;
-
- default: return -EINVAL;
- }
-
- return 0;
-}
-
-
-
-static unsigned long scc_get_param(struct scc_channel *scc, unsigned int cmd)
-{
- switch (cmd)
- {
- case PARAM_TXDELAY: return CAST(scc->kiss.txdelay);
- case PARAM_PERSIST: return CAST(scc->kiss.persist);
- case PARAM_SLOTTIME: return CAST(scc->kiss.slottime);
- case PARAM_TXTAIL: return CAST(scc->kiss.tailtime);
- case PARAM_FULLDUP: return CAST(scc->kiss.fulldup);
- case PARAM_SOFTDCD: return CAST(scc->kiss.softdcd);
- case PARAM_DTR: return CAST((scc->wreg[R5] & DTR)? 1:0);
- case PARAM_RTS: return CAST((scc->wreg[R5] & RTS)? 1:0);
- case PARAM_SPEED: return CAST(scc->modem.speed);
- case PARAM_GROUP: return CAST(scc->kiss.group);
- case PARAM_IDLE: return CAST(scc->kiss.idletime);
- case PARAM_MIN: return CAST(scc->kiss.mintime);
- case PARAM_MAXKEY: return CAST(scc->kiss.maxkeyup);
- case PARAM_WAIT: return CAST(scc->kiss.waittime);
- case PARAM_MAXDEFER: return CAST(scc->kiss.maxdefer);
- case PARAM_TX: return CAST(scc->kiss.tx_inhibit);
- default: return NO_SUCH_PARAM;
- }
-
-}
-
-#undef CAST
-
-/* ******************************************************************* */
-/* * Send calibration pattern * */
-/* ******************************************************************* */
-
-static void scc_stop_calibrate(struct timer_list *t)
-{
- struct scc_channel *scc = timer_container_of(scc, t, tx_wdog);
- unsigned long flags;
-
- spin_lock_irqsave(&scc->lock, flags);
- timer_delete(&scc->tx_wdog);
- scc_key_trx(scc, TX_OFF);
- wr(scc, R6, 0);
- wr(scc, R7, FLAG);
- Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
- Outb(scc->ctrl,RES_EXT_INT);
-
- netif_wake_queue(scc->dev);
- spin_unlock_irqrestore(&scc->lock, flags);
-}
-
-
-static void
-scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&scc->lock, flags);
- netif_stop_queue(scc->dev);
- scc_discard_buffers(scc);
-
- timer_delete(&scc->tx_wdog);
-
- scc->tx_wdog.function = scc_stop_calibrate;
- scc->tx_wdog.expires = jiffies + HZ*duration;
- add_timer(&scc->tx_wdog);
-
- /* This doesn't seem to work. Why not? */
- wr(scc, R6, 0);
- wr(scc, R7, pattern);
-
- /*
- * Don't know if this works.
- * Damn, where is my Z8530 programming manual...?
- */
-
- Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
- Outb(scc->ctrl,RES_EXT_INT);
-
- scc_key_trx(scc, TX_ON);
- spin_unlock_irqrestore(&scc->lock, flags);
-}
-
-/* ******************************************************************* */
-/* * Init channel structures, special HW, etc... * */
-/* ******************************************************************* */
-
-/*
- * Reset the Z8530s and setup special hardware
- */
-
-static void z8530_init(void)
-{
- const unsigned int nr_irqs = irq_get_nr_irqs();
- struct scc_channel *scc;
- int chip, k;
- unsigned long flags;
- char *flag;
-
-
- printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2);
-
- flag=" ";
- for (k = 0; k < nr_irqs; k++)
- if (Ivec[k].used)
- {
- printk("%s%d", flag, k);
- flag=",";
- }
- printk("\n");
-
-
- /* reset and pre-init all chips in the system */
- for (chip = 0; chip < Nchips; chip++)
- {
- scc=&SCC_Info[2*chip];
- if (!scc->ctrl) continue;
-
- /* Special SCC cards */
-
- if(scc->brand & EAGLE) /* this is an EAGLE card */
- Outb(scc->special,0x08); /* enable interrupt on the board */
-
- if(scc->brand & (PC100 | PRIMUS)) /* this is a PC100/PRIMUS card */
- Outb(scc->special,scc->option); /* set the MODEM mode (0x22) */
-
-
- /* Reset and pre-init Z8530 */
-
- spin_lock_irqsave(&scc->lock, flags);
-
- Outb(scc->ctrl, 0);
- OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */
- udelay(100); /* give it 'a bit' more time than required */
- wr(scc, R2, chip*16); /* interrupt vector */
- wr(scc, R9, VIS); /* vector includes status */
- spin_unlock_irqrestore(&scc->lock, flags);
- }
-
-
- Driver_Initialized = 1;
-}
-
-/*
- * Allocate device structure, err, instance, and register driver
- */
-
-static int scc_net_alloc(const char *name, struct scc_channel *scc)
-{
- int err;
- struct net_device *dev;
-
- dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, scc_net_setup);
- if (!dev)
- return -ENOMEM;
-
- dev->ml_priv = scc;
- scc->dev = dev;
- spin_lock_init(&scc->lock);
- timer_setup(&scc->tx_t, NULL, 0);
- timer_setup(&scc->tx_wdog, NULL, 0);
-
- err = register_netdevice(dev);
- if (err) {
- printk(KERN_ERR "%s: can't register network device (%d)\n",
- name, err);
- free_netdev(dev);
- scc->dev = NULL;
- return err;
- }
-
- return 0;
-}
-
-
-
-/* ******************************************************************** */
-/* * Network driver methods * */
-/* ******************************************************************** */
-
-static const struct net_device_ops scc_netdev_ops = {
- .ndo_open = scc_net_open,
- .ndo_stop = scc_net_close,
- .ndo_start_xmit = scc_net_tx,
- .ndo_set_mac_address = scc_net_set_mac_address,
- .ndo_get_stats = scc_net_get_stats,
- .ndo_siocdevprivate = scc_net_siocdevprivate,
-};
-
-/* ----> Initialize device <----- */
-
-static void scc_net_setup(struct net_device *dev)
-{
- dev->tx_queue_len = 16; /* should be enough... */
-
- dev->netdev_ops = &scc_netdev_ops;
- dev->header_ops = &ax25_header_ops;
-
- dev->flags = 0;
-
- dev->type = ARPHRD_AX25;
- dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
- dev->mtu = AX25_DEF_PACLEN;
- dev->addr_len = AX25_ADDR_LEN;
-
- memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
- dev_addr_set(dev, (u8 *)&ax25_defaddr);
-}
-
-/* ----> open network device <---- */
-
-static int scc_net_open(struct net_device *dev)
-{
- struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
-
- if (!scc->init)
- return -EINVAL;
-
- scc->tx_buff = NULL;
- skb_queue_head_init(&scc->tx_queue);
-
- init_channel(scc);
-
- netif_start_queue(dev);
- return 0;
-}
-
-/* ----> close network device <---- */
-
-static int scc_net_close(struct net_device *dev)
-{
- struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
- unsigned long flags;
-
- netif_stop_queue(dev);
-
- spin_lock_irqsave(&scc->lock, flags);
- Outb(scc->ctrl,0); /* Make sure pointer is written */
- wr(scc,R1,0); /* disable interrupts */
- wr(scc,R3,0);
- spin_unlock_irqrestore(&scc->lock, flags);
-
- timer_delete_sync(&scc->tx_t);
- timer_delete_sync(&scc->tx_wdog);
-
- scc_discard_buffers(scc);
-
- return 0;
-}
-
-/* ----> receive frame, called from scc_rxint() <---- */
-
-static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb)
-{
- if (skb->len == 0) {
- dev_kfree_skb_irq(skb);
- return;
- }
-
- scc->dev_stat.rx_packets++;
- scc->dev_stat.rx_bytes += skb->len;
-
- skb->protocol = ax25_type_trans(skb, scc->dev);
-
- netif_rx(skb);
-}
-
-/* ----> transmit frame <---- */
-
-static netdev_tx_t scc_net_tx(struct sk_buff *skb, struct net_device *dev)
-{
- struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
- unsigned long flags;
- char kisscmd;
-
- if (skb->protocol == htons(ETH_P_IP))
- return ax25_ip_xmit(skb);
-
- if (skb->len > scc->stat.bufsize || skb->len < 2) {
- scc->dev_stat.tx_dropped++; /* bogus frame */
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- scc->dev_stat.tx_packets++;
- scc->dev_stat.tx_bytes += skb->len;
- scc->stat.txframes++;
-
- kisscmd = *skb->data & 0x1f;
- skb_pull(skb, 1);
-
- if (kisscmd) {
- scc_set_param(scc, kisscmd, *skb->data);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- spin_lock_irqsave(&scc->lock, flags);
-
- if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) {
- struct sk_buff *skb_del;
- skb_del = skb_dequeue(&scc->tx_queue);
- dev_kfree_skb_irq(skb_del);
- }
- skb_queue_tail(&scc->tx_queue, skb);
- netif_trans_update(dev);
-
-
- /*
- * Start transmission if the trx state is idle or
- * t_idle hasn't expired yet. Use dwait/persistence/slottime
- * algorithm for normal halfduplex operation.
- */
-
- if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2) {
- scc->stat.tx_state = TXS_BUSY;
- if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
- __scc_start_tx_timer(scc, t_dwait, scc->kiss.waittime);
- else
- __scc_start_tx_timer(scc, t_dwait, 0);
- }
- spin_unlock_irqrestore(&scc->lock, flags);
- return NETDEV_TX_OK;
-}
-
-/* ----> ioctl functions <---- */
-
-/*
- * SIOCSCCCFG - configure driver arg: (struct scc_hw_config *) arg
- * SIOCSCCINI - initialize driver arg: ---
- * SIOCSCCCHANINI - initialize channel arg: (struct scc_modem *) arg
- * SIOCSCCSMEM - set memory arg: (struct scc_mem_config *) arg
- * SIOCSCCGKISS - get level 1 parameter arg: (struct scc_kiss_cmd *) arg
- * SIOCSCCSKISS - set level 1 parameter arg: (struct scc_kiss_cmd *) arg
- * SIOCSCCGSTAT - get driver status arg: (struct scc_stat *) arg
- * SIOCSCCCAL - send calib. pattern arg: (struct scc_calibrate *) arg
- */
-
-static int scc_net_siocdevprivate(struct net_device *dev,
- struct ifreq *ifr, void __user *arg, int cmd)
-{
- struct scc_kiss_cmd kiss_cmd;
- struct scc_mem_config memcfg;
- struct scc_hw_config hwcfg;
- struct scc_calibrate cal;
- struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
- int chan;
- unsigned char device_name[IFNAMSIZ];
-
- if (!Driver_Initialized)
- {
- if (cmd == SIOCSCCCFG)
- {
- int found = 1;
-
- if (!capable(CAP_SYS_RAWIO)) return -EPERM;
- if (in_compat_syscall())
- return -EOPNOTSUPP;
-
- if (!arg) return -EFAULT;
-
- if (Nchips >= SCC_MAXCHIPS)
- return -EINVAL;
-
- if (copy_from_user(&hwcfg, arg, sizeof(hwcfg)))
- return -EFAULT;
-
- if (hwcfg.irq == 2) hwcfg.irq = 9;
-
- if (hwcfg.irq < 0 || hwcfg.irq >= irq_get_nr_irqs())
- return -EINVAL;
-
- if (!Ivec[hwcfg.irq].used && hwcfg.irq)
- {
- if (request_irq(hwcfg.irq, scc_isr,
- 0, "AX.25 SCC",
- (void *)(long) hwcfg.irq))
- printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq);
- else
- Ivec[hwcfg.irq].used = 1;
- }
-
- if (hwcfg.vector_latch && !Vector_Latch) {
- if (!request_region(hwcfg.vector_latch, 1, "scc vector latch"))
- printk(KERN_WARNING "z8530drv: warning, cannot reserve vector latch port 0x%lx\n, disabled.", hwcfg.vector_latch);
- else
- Vector_Latch = hwcfg.vector_latch;
- }
-
- if (hwcfg.clock == 0)
- hwcfg.clock = SCC_DEFAULT_CLOCK;
-
-#ifndef SCC_DONT_CHECK
-
- if(request_region(hwcfg.ctrl_a, 1, "scc-probe"))
- {
- disable_irq(hwcfg.irq);
- Outb(hwcfg.ctrl_a, 0);
- OutReg(hwcfg.ctrl_a, R9, FHWRES);
- udelay(100);
- OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */
- udelay(5);
-
- if (InReg(hwcfg.ctrl_a,R13) != 0x55)
- found = 0;
- enable_irq(hwcfg.irq);
- release_region(hwcfg.ctrl_a, 1);
- }
- else
- found = 0;
-#endif
-
- if (found)
- {
- SCC_Info[2*Nchips ].ctrl = hwcfg.ctrl_a;
- SCC_Info[2*Nchips ].data = hwcfg.data_a;
- SCC_Info[2*Nchips ].irq = hwcfg.irq;
- SCC_Info[2*Nchips+1].ctrl = hwcfg.ctrl_b;
- SCC_Info[2*Nchips+1].data = hwcfg.data_b;
- SCC_Info[2*Nchips+1].irq = hwcfg.irq;
-
- SCC_ctrl[Nchips].chan_A = hwcfg.ctrl_a;
- SCC_ctrl[Nchips].chan_B = hwcfg.ctrl_b;
- SCC_ctrl[Nchips].irq = hwcfg.irq;
- }
-
-
- for (chan = 0; chan < 2; chan++)
- {
- sprintf(device_name, "%s%i", SCC_DriverName, 2*Nchips+chan);
-
- SCC_Info[2*Nchips+chan].special = hwcfg.special;
- SCC_Info[2*Nchips+chan].clock = hwcfg.clock;
- SCC_Info[2*Nchips+chan].brand = hwcfg.brand;
- SCC_Info[2*Nchips+chan].option = hwcfg.option;
- SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc;
-
-#ifdef SCC_DONT_CHECK
- printk(KERN_INFO "%s: data port = 0x%3.3x control port = 0x%3.3x\n",
- device_name,
- SCC_Info[2*Nchips+chan].data,
- SCC_Info[2*Nchips+chan].ctrl);
-
-#else
- printk(KERN_INFO "%s: data port = 0x%3.3lx control port = 0x%3.3lx -- %s\n",
- device_name,
- chan? hwcfg.data_b : hwcfg.data_a,
- chan? hwcfg.ctrl_b : hwcfg.ctrl_a,
- found? "found" : "missing");
-#endif
-
- if (found)
- {
- request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl");
- request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data");
- if (Nchips+chan != 0 &&
- scc_net_alloc(device_name,
- &SCC_Info[2*Nchips+chan]))
- return -EINVAL;
- }
- }
-
- if (found) Nchips++;
-
- return 0;
- }
-
- if (cmd == SIOCSCCINI)
- {
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
-
- if (Nchips == 0)
- return -EINVAL;
-
- z8530_init();
- return 0;
- }
-
- return -EINVAL; /* confuse the user */
- }
-
- if (!scc->init)
- {
- if (cmd == SIOCSCCCHANINI)
- {
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (!arg) return -EINVAL;
-
- scc->stat.bufsize = SCC_BUFSIZE;
-
- if (copy_from_user(&scc->modem, arg, sizeof(struct scc_modem)))
- return -EINVAL;
-
- /* default KISS Params */
-
- if (scc->modem.speed < 4800)
- {
- scc->kiss.txdelay = 36; /* 360 ms */
- scc->kiss.persist = 42; /* 25% persistence */ /* was 25 */
- scc->kiss.slottime = 16; /* 160 ms */
- scc->kiss.tailtime = 4; /* minimal reasonable value */
- scc->kiss.fulldup = 0; /* CSMA */
- scc->kiss.waittime = 50; /* 500 ms */
- scc->kiss.maxkeyup = 10; /* 10 s */
- scc->kiss.mintime = 3; /* 3 s */
- scc->kiss.idletime = 30; /* 30 s */
- scc->kiss.maxdefer = 120; /* 2 min */
- scc->kiss.softdcd = 0; /* hardware dcd */
- } else {
- scc->kiss.txdelay = 10; /* 100 ms */
- scc->kiss.persist = 64; /* 25% persistence */ /* was 25 */
- scc->kiss.slottime = 8; /* 160 ms */
- scc->kiss.tailtime = 1; /* minimal reasonable value */
- scc->kiss.fulldup = 0; /* CSMA */
- scc->kiss.waittime = 50; /* 500 ms */
- scc->kiss.maxkeyup = 7; /* 7 s */
- scc->kiss.mintime = 3; /* 3 s */
- scc->kiss.idletime = 30; /* 30 s */
- scc->kiss.maxdefer = 120; /* 2 min */
- scc->kiss.softdcd = 0; /* hardware dcd */
- }
-
- scc->tx_buff = NULL;
- skb_queue_head_init(&scc->tx_queue);
- scc->init = 1;
-
- return 0;
- }
-
- return -EINVAL;
- }
-
- switch(cmd)
- {
- case SIOCSCCRESERVED:
- return -ENOIOCTLCMD;
-
- case SIOCSCCSMEM:
- if (!capable(CAP_SYS_RAWIO)) return -EPERM;
- if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg)))
- return -EINVAL;
- if (memcfg.bufsize < 16)
- return -EINVAL;
- scc->stat.bufsize = memcfg.bufsize;
- return 0;
-
- case SIOCSCCGSTAT:
- if (!arg || copy_to_user(arg, &scc->stat, sizeof(scc->stat)))
- return -EINVAL;
- return 0;
-
- case SIOCSCCGKISS:
- if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd)))
- return -EINVAL;
- kiss_cmd.param = scc_get_param(scc, kiss_cmd.command);
- if (copy_to_user(arg, &kiss_cmd, sizeof(kiss_cmd)))
- return -EINVAL;
- return 0;
-
- case SIOCSCCSKISS:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd)))
- return -EINVAL;
- return scc_set_param(scc, kiss_cmd.command, kiss_cmd.param);
-
- case SIOCSCCCAL:
- if (!capable(CAP_SYS_RAWIO)) return -EPERM;
- if (!arg || copy_from_user(&cal, arg, sizeof(cal)) || cal.time == 0)
- return -EINVAL;
-
- scc_start_calibrate(scc, cal.time, cal.pattern);
- return 0;
-
- default:
- return -ENOIOCTLCMD;
-
- }
-
- return -EINVAL;
-}
-
-/* ----> set interface callsign <---- */
-
-static int scc_net_set_mac_address(struct net_device *dev, void *addr)
-{
- struct sockaddr *sa = (struct sockaddr *) addr;
- dev_addr_set(dev, sa->sa_data);
- return 0;
-}
-
-/* ----> get statistics <---- */
-
-static struct net_device_stats *scc_net_get_stats(struct net_device *dev)
-{
- struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
-
- scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over;
- scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under;
- scc->dev_stat.rx_fifo_errors = scc->stat.rx_over;
- scc->dev_stat.tx_fifo_errors = scc->stat.tx_under;
-
- return &scc->dev_stat;
-}
-
-/* ******************************************************************** */
-/* * dump statistics to /proc/net/z8530drv * */
-/* ******************************************************************** */
-
-#ifdef CONFIG_PROC_FS
-
-static inline struct scc_channel *scc_net_seq_idx(loff_t pos)
-{
- int k;
-
- for (k = 0; k < Nchips*2; ++k) {
- if (!SCC_Info[k].init)
- continue;
- if (pos-- == 0)
- return &SCC_Info[k];
- }
- return NULL;
-}
-
-static void *scc_net_seq_start(struct seq_file *seq, loff_t *pos)
-{
- return *pos ? scc_net_seq_idx(*pos - 1) : SEQ_START_TOKEN;
-
-}
-
-static void *scc_net_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- unsigned k;
- struct scc_channel *scc = v;
- ++*pos;
-
- for (k = (v == SEQ_START_TOKEN) ? 0 : (scc - SCC_Info)+1;
- k < Nchips*2; ++k) {
- if (SCC_Info[k].init)
- return &SCC_Info[k];
- }
- return NULL;
-}
-
-static void scc_net_seq_stop(struct seq_file *seq, void *v)
-{
-}
-
-static int scc_net_seq_show(struct seq_file *seq, void *v)
-{
- if (v == SEQ_START_TOKEN) {
- seq_puts(seq, "z8530drv-"VERSION"\n");
- } else if (!Driver_Initialized) {
- seq_puts(seq, "not initialized\n");
- } else if (!Nchips) {
- seq_puts(seq, "chips missing\n");
- } else {
- const struct scc_channel *scc = v;
- const struct scc_stat *stat = &scc->stat;
- const struct scc_kiss *kiss = &scc->kiss;
-
-
- /* dev data ctrl irq clock brand enh vector special option
- * baud nrz clocksrc softdcd bufsize
- * rxints txints exints spints
- * rcvd rxerrs over / xmit txerrs under / nospace bufsize
- * txd pers slot tail ful wait min maxk idl defr txof grp
- * W ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
- * R ## ## XX ## ## ## ## ## XX ## ## ## ## ## ## ##
- */
-
- seq_printf(seq, "%s\t%3.3lx %3.3lx %d %lu %2.2x %d %3.3lx %3.3lx %d\n",
- scc->dev->name,
- scc->data, scc->ctrl, scc->irq, scc->clock, scc->brand,
- scc->enhanced, Vector_Latch, scc->special,
- scc->option);
- seq_printf(seq, "\t%lu %d %d %d %d\n",
- scc->modem.speed, scc->modem.nrz,
- scc->modem.clocksrc, kiss->softdcd,
- stat->bufsize);
- seq_printf(seq, "\t%lu %lu %lu %lu\n",
- stat->rxints, stat->txints, stat->exints, stat->spints);
- seq_printf(seq, "\t%lu %lu %d / %lu %lu %d / %d %d\n",
- stat->rxframes, stat->rxerrs, stat->rx_over,
- stat->txframes, stat->txerrs, stat->tx_under,
- stat->nospace, stat->tx_state);
-
-#define K(x) kiss->x
- seq_printf(seq, "\t%d %d %d %d %d %d %d %d %d %d %d %d\n",
- K(txdelay), K(persist), K(slottime), K(tailtime),
- K(fulldup), K(waittime), K(mintime), K(maxkeyup),
- K(idletime), K(maxdefer), K(tx_inhibit), K(group));
-#undef K
-#ifdef SCC_DEBUG
- {
- int reg;
-
- seq_printf(seq, "\tW ");
- for (reg = 0; reg < 16; reg++)
- seq_printf(seq, "%2.2x ", scc->wreg[reg]);
- seq_printf(seq, "\n");
-
- seq_printf(seq, "\tR %2.2x %2.2x XX ", InReg(scc->ctrl,R0), InReg(scc->ctrl,R1));
- for (reg = 3; reg < 8; reg++)
- seq_printf(seq, "%2.2x ", InReg(scc->ctrl, reg));
- seq_printf(seq, "XX ");
- for (reg = 9; reg < 16; reg++)
- seq_printf(seq, "%2.2x ", InReg(scc->ctrl, reg));
- seq_printf(seq, "\n");
- }
-#endif
- seq_putc(seq, '\n');
- }
-
- return 0;
-}
-
-static const struct seq_operations scc_net_seq_ops = {
- .start = scc_net_seq_start,
- .next = scc_net_seq_next,
- .stop = scc_net_seq_stop,
- .show = scc_net_seq_show,
-};
-#endif /* CONFIG_PROC_FS */
-
-
-/* ******************************************************************** */
-/* * Init SCC driver * */
-/* ******************************************************************** */
-
-static int __init scc_init_driver (void)
-{
- char devname[IFNAMSIZ];
-
- printk(banner);
-
- sprintf(devname,"%s0", SCC_DriverName);
-
- rtnl_lock();
- if (scc_net_alloc(devname, SCC_Info)) {
- rtnl_unlock();
- printk(KERN_ERR "z8530drv: cannot initialize module\n");
- return -EIO;
- }
- rtnl_unlock();
-
- proc_create_seq("z8530drv", 0, init_net.proc_net, &scc_net_seq_ops);
-
- return 0;
-}
-
-static void __exit scc_cleanup_driver(void)
-{
- const unsigned int nr_irqs = irq_get_nr_irqs();
- io_port ctrl;
- int k;
- struct scc_channel *scc;
- struct net_device *dev;
-
- if (Nchips == 0 && (dev = SCC_Info[0].dev))
- {
- unregister_netdev(dev);
- free_netdev(dev);
- }
-
- /* Guard against chip prattle */
- local_irq_disable();
-
- for (k = 0; k < Nchips; k++)
- if ( (ctrl = SCC_ctrl[k].chan_A) )
- {
- Outb(ctrl, 0);
- OutReg(ctrl,R9,FHWRES); /* force hardware reset */
- udelay(50);
- }
-
- /* To unload the port must be closed so no real IRQ pending */
- for (k = 0; k < nr_irqs ; k++)
- if (Ivec[k].used) free_irq(k, NULL);
-
- local_irq_enable();
-
- /* Now clean up */
- for (k = 0; k < Nchips*2; k++)
- {
- scc = &SCC_Info[k];
- if (scc->ctrl)
- {
- release_region(scc->ctrl, 1);
- release_region(scc->data, 1);
- }
- if (scc->dev)
- {
- unregister_netdev(scc->dev);
- free_netdev(scc->dev);
- }
- }
-
-
- if (Vector_Latch)
- release_region(Vector_Latch, 1);
-
- remove_proc_entry("z8530drv", init_net.proc_net);
-}
-
-MODULE_AUTHOR("Joerg Reuter <jreuter@yaina.de>");
-MODULE_DESCRIPTION("AX.25 Device Driver for Z8530 based HDLC cards");
-MODULE_LICENSE("GPL");
-module_init(scc_init_driver);
-module_exit(scc_cleanup_driver);
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
deleted file mode 100644
index 4106f0301ab4..000000000000
--- a/drivers/net/hamradio/yam.c
+++ /dev/null
@@ -1,1191 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*****************************************************************************/
-
-/*
- * yam.c -- YAM radio modem driver.
- *
- * Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr)
- * Adapted from baycom.c driver written by Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * Please note that the GPL allows you to use the driver, NOT the radio.
- * In order to use the radio, you need a license from the communications
- * authority of your country.
- *
- * History:
- * 0.0 F1OAT 06.06.98 Begin of work with baycom.c source code V 0.3
- * 0.1 F1OAT 07.06.98 Add timer polling routine for channel arbitration
- * 0.2 F6FBB 08.06.98 Added delay after FPGA programming
- * 0.3 F6FBB 29.07.98 Delayed PTT implementation for dupmode=2
- * 0.4 F6FBB 30.07.98 Added TxTail, Slottime and Persistence
- * 0.5 F6FBB 01.08.98 Shared IRQs, /proc/net and network statistics
- * 0.6 F6FBB 25.08.98 Added 1200Bds format
- * 0.7 F6FBB 12.09.98 Added to the kernel configuration
- * 0.8 F6FBB 14.10.98 Fixed slottime/persistence timing bug
- * OK1ZIA 2.09.01 Fixed "kfree_skb on hard IRQ"
- * using dev_kfree_skb_any(). (important in 2.4 kernel)
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/net.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/bitops.h>
-#include <linux/random.h>
-#include <asm/io.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/firmware.h>
-#include <linux/platform_device.h>
-
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <net/ax25.h>
-
-#include <linux/kernel.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <net/net_namespace.h>
-
-#include <linux/uaccess.h>
-#include <linux/init.h>
-
-#include <linux/yam.h>
-
-/* --------------------------------------------------------------------- */
-
-static const char yam_drvname[] = "yam";
-static const char yam_drvinfo[] __initconst = KERN_INFO \
- "YAM driver version 0.8 by F1OAT/F6FBB\n";
-
-/* --------------------------------------------------------------------- */
-
-#define FIRMWARE_9600 "yam/9600.bin"
-#define FIRMWARE_1200 "yam/1200.bin"
-
-#define YAM_9600 1
-#define YAM_1200 2
-
-#define NR_PORTS 4
-#define YAM_MAGIC 0xF10A7654
-
-/* Transmitter states */
-
-#define TX_OFF 0
-#define TX_HEAD 1
-#define TX_DATA 2
-#define TX_CRC1 3
-#define TX_CRC2 4
-#define TX_TAIL 5
-
-#define YAM_MAX_FRAME 1024
-
-#define DEFAULT_BITRATE 9600 /* bps */
-#define DEFAULT_HOLDD 10 /* sec */
-#define DEFAULT_TXD 300 /* ms */
-#define DEFAULT_TXTAIL 10 /* ms */
-#define DEFAULT_SLOT 100 /* ms */
-#define DEFAULT_PERS 64 /* 0->255 */
-
-struct yam_port {
- int magic;
- int bitrate;
- int baudrate;
- int iobase;
- int irq;
- int dupmode;
-
- struct net_device *dev;
-
- int nb_rxint;
- int nb_mdint;
-
- /* Parameters section */
-
- int txd; /* tx delay */
- int holdd; /* duplex ptt delay */
- int txtail; /* txtail delay */
- int slot; /* slottime */
- int pers; /* persistence */
-
- /* Tx section */
-
- int tx_state;
- int tx_count;
- int slotcnt;
- unsigned char tx_buf[YAM_MAX_FRAME];
- int tx_len;
- int tx_crcl, tx_crch;
- struct sk_buff_head send_queue; /* Packets awaiting transmission */
-
- /* Rx section */
-
- int dcd;
- unsigned char rx_buf[YAM_MAX_FRAME];
- int rx_len;
- int rx_crcl, rx_crch;
-};
-
-struct yam_mcs {
- unsigned char bits[YAM_FPGA_SIZE];
- int bitrate;
- struct yam_mcs *next;
-};
-
-static struct net_device *yam_devs[NR_PORTS];
-
-static struct yam_mcs *yam_data;
-
-static DEFINE_TIMER(yam_timer, NULL);
-
-/* --------------------------------------------------------------------- */
-
-#define RBR(iobase) (iobase+0)
-#define THR(iobase) (iobase+0)
-#define IER(iobase) (iobase+1)
-#define IIR(iobase) (iobase+2)
-#define FCR(iobase) (iobase+2)
-#define LCR(iobase) (iobase+3)
-#define MCR(iobase) (iobase+4)
-#define LSR(iobase) (iobase+5)
-#define MSR(iobase) (iobase+6)
-#define SCR(iobase) (iobase+7)
-#define DLL(iobase) (iobase+0)
-#define DLM(iobase) (iobase+1)
-
-#define YAM_EXTENT 8
-
-/* Interrupt Identification Register Bit Masks */
-#define IIR_NOPEND 1
-#define IIR_MSR 0
-#define IIR_TX 2
-#define IIR_RX 4
-#define IIR_LSR 6
-#define IIR_TIMEOUT 12 /* Fifo mode only */
-
-#define IIR_MASK 0x0F
-
-/* Interrupt Enable Register Bit Masks */
-#define IER_RX 1 /* enable rx interrupt */
-#define IER_TX 2 /* enable tx interrupt */
-#define IER_LSR 4 /* enable line status interrupts */
-#define IER_MSR 8 /* enable modem status interrupts */
-
-/* Modem Control Register Bit Masks */
-#define MCR_DTR 0x01 /* DTR output */
-#define MCR_RTS 0x02 /* RTS output */
-#define MCR_OUT1 0x04 /* OUT1 output (not accessible in RS232) */
-#define MCR_OUT2 0x08 /* Master Interrupt enable (must be set on PCs) */
-#define MCR_LOOP 0x10 /* Loopback enable */
-
-/* Modem Status Register Bit Masks */
-#define MSR_DCTS 0x01 /* Delta CTS input */
-#define MSR_DDSR 0x02 /* Delta DSR */
-#define MSR_DRIN 0x04 /* Delta RI */
-#define MSR_DDCD 0x08 /* Delta DCD */
-#define MSR_CTS 0x10 /* CTS input */
-#define MSR_DSR 0x20 /* DSR input */
-#define MSR_RING 0x40 /* RI input */
-#define MSR_DCD 0x80 /* DCD input */
-
-/* line status register bit mask */
-#define LSR_RXC 0x01
-#define LSR_OE 0x02
-#define LSR_PE 0x04
-#define LSR_FE 0x08
-#define LSR_BREAK 0x10
-#define LSR_THRE 0x20
-#define LSR_TSRE 0x40
-
-/* Line Control Register Bit Masks */
-#define LCR_DLAB 0x80
-#define LCR_BREAK 0x40
-#define LCR_PZERO 0x28
-#define LCR_PEVEN 0x18
-#define LCR_PODD 0x08
-#define LCR_STOP1 0x00
-#define LCR_STOP2 0x04
-#define LCR_BIT5 0x00
-#define LCR_BIT6 0x02
-#define LCR_BIT7 0x01
-#define LCR_BIT8 0x03
-
-/* YAM Modem <-> UART Port mapping */
-
-#define TX_RDY MSR_DCTS /* transmitter ready to send */
-#define RX_DCD MSR_DCD /* carrier detect */
-#define RX_FLAG MSR_RING /* hdlc flag received */
-#define FPGA_DONE MSR_DSR /* FPGA is configured */
-#define PTT_ON (MCR_RTS|MCR_OUT2) /* activate PTT */
-#define PTT_OFF (MCR_DTR|MCR_OUT2) /* release PTT */
-
-#define ENABLE_RXINT IER_RX /* enable uart rx interrupt during rx */
-#define ENABLE_TXINT IER_MSR /* enable uart ms interrupt during tx */
-#define ENABLE_RTXINT (IER_RX|IER_MSR) /* full duplex operations */
-
-
-/*************************************************************************
-* CRC Tables
-************************************************************************/
-
-static const unsigned char chktabl[256] =
-{0x00, 0x89, 0x12, 0x9b, 0x24, 0xad, 0x36, 0xbf, 0x48, 0xc1, 0x5a, 0xd3, 0x6c, 0xe5, 0x7e,
- 0xf7, 0x81, 0x08, 0x93, 0x1a, 0xa5, 0x2c, 0xb7, 0x3e, 0xc9, 0x40, 0xdb, 0x52, 0xed, 0x64,
- 0xff, 0x76, 0x02, 0x8b, 0x10, 0x99, 0x26, 0xaf, 0x34, 0xbd, 0x4a, 0xc3, 0x58, 0xd1, 0x6e,
- 0xe7, 0x7c, 0xf5, 0x83, 0x0a, 0x91, 0x18, 0xa7, 0x2e, 0xb5, 0x3c, 0xcb, 0x42, 0xd9, 0x50,
- 0xef, 0x66, 0xfd, 0x74, 0x04, 0x8d, 0x16, 0x9f, 0x20, 0xa9, 0x32, 0xbb, 0x4c, 0xc5, 0x5e,
- 0xd7, 0x68, 0xe1, 0x7a, 0xf3, 0x85, 0x0c, 0x97, 0x1e, 0xa1, 0x28, 0xb3, 0x3a, 0xcd, 0x44,
- 0xdf, 0x56, 0xe9, 0x60, 0xfb, 0x72, 0x06, 0x8f, 0x14, 0x9d, 0x22, 0xab, 0x30, 0xb9, 0x4e,
- 0xc7, 0x5c, 0xd5, 0x6a, 0xe3, 0x78, 0xf1, 0x87, 0x0e, 0x95, 0x1c, 0xa3, 0x2a, 0xb1, 0x38,
- 0xcf, 0x46, 0xdd, 0x54, 0xeb, 0x62, 0xf9, 0x70, 0x08, 0x81, 0x1a, 0x93, 0x2c, 0xa5, 0x3e,
- 0xb7, 0x40, 0xc9, 0x52, 0xdb, 0x64, 0xed, 0x76, 0xff, 0x89, 0x00, 0x9b, 0x12, 0xad, 0x24,
- 0xbf, 0x36, 0xc1, 0x48, 0xd3, 0x5a, 0xe5, 0x6c, 0xf7, 0x7e, 0x0a, 0x83, 0x18, 0x91, 0x2e,
- 0xa7, 0x3c, 0xb5, 0x42, 0xcb, 0x50, 0xd9, 0x66, 0xef, 0x74, 0xfd, 0x8b, 0x02, 0x99, 0x10,
- 0xaf, 0x26, 0xbd, 0x34, 0xc3, 0x4a, 0xd1, 0x58, 0xe7, 0x6e, 0xf5, 0x7c, 0x0c, 0x85, 0x1e,
- 0x97, 0x28, 0xa1, 0x3a, 0xb3, 0x44, 0xcd, 0x56, 0xdf, 0x60, 0xe9, 0x72, 0xfb, 0x8d, 0x04,
- 0x9f, 0x16, 0xa9, 0x20, 0xbb, 0x32, 0xc5, 0x4c, 0xd7, 0x5e, 0xe1, 0x68, 0xf3, 0x7a, 0x0e,
- 0x87, 0x1c, 0x95, 0x2a, 0xa3, 0x38, 0xb1, 0x46, 0xcf, 0x54, 0xdd, 0x62, 0xeb, 0x70, 0xf9,
- 0x8f, 0x06, 0x9d, 0x14, 0xab, 0x22, 0xb9, 0x30, 0xc7, 0x4e, 0xd5, 0x5c, 0xe3, 0x6a, 0xf1,
- 0x78};
-static const unsigned char chktabh[256] =
-{0x00, 0x11, 0x23, 0x32, 0x46, 0x57, 0x65, 0x74, 0x8c, 0x9d, 0xaf, 0xbe, 0xca, 0xdb, 0xe9,
- 0xf8, 0x10, 0x01, 0x33, 0x22, 0x56, 0x47, 0x75, 0x64, 0x9c, 0x8d, 0xbf, 0xae, 0xda, 0xcb,
- 0xf9, 0xe8, 0x21, 0x30, 0x02, 0x13, 0x67, 0x76, 0x44, 0x55, 0xad, 0xbc, 0x8e, 0x9f, 0xeb,
- 0xfa, 0xc8, 0xd9, 0x31, 0x20, 0x12, 0x03, 0x77, 0x66, 0x54, 0x45, 0xbd, 0xac, 0x9e, 0x8f,
- 0xfb, 0xea, 0xd8, 0xc9, 0x42, 0x53, 0x61, 0x70, 0x04, 0x15, 0x27, 0x36, 0xce, 0xdf, 0xed,
- 0xfc, 0x88, 0x99, 0xab, 0xba, 0x52, 0x43, 0x71, 0x60, 0x14, 0x05, 0x37, 0x26, 0xde, 0xcf,
- 0xfd, 0xec, 0x98, 0x89, 0xbb, 0xaa, 0x63, 0x72, 0x40, 0x51, 0x25, 0x34, 0x06, 0x17, 0xef,
- 0xfe, 0xcc, 0xdd, 0xa9, 0xb8, 0x8a, 0x9b, 0x73, 0x62, 0x50, 0x41, 0x35, 0x24, 0x16, 0x07,
- 0xff, 0xee, 0xdc, 0xcd, 0xb9, 0xa8, 0x9a, 0x8b, 0x84, 0x95, 0xa7, 0xb6, 0xc2, 0xd3, 0xe1,
- 0xf0, 0x08, 0x19, 0x2b, 0x3a, 0x4e, 0x5f, 0x6d, 0x7c, 0x94, 0x85, 0xb7, 0xa6, 0xd2, 0xc3,
- 0xf1, 0xe0, 0x18, 0x09, 0x3b, 0x2a, 0x5e, 0x4f, 0x7d, 0x6c, 0xa5, 0xb4, 0x86, 0x97, 0xe3,
- 0xf2, 0xc0, 0xd1, 0x29, 0x38, 0x0a, 0x1b, 0x6f, 0x7e, 0x4c, 0x5d, 0xb5, 0xa4, 0x96, 0x87,
- 0xf3, 0xe2, 0xd0, 0xc1, 0x39, 0x28, 0x1a, 0x0b, 0x7f, 0x6e, 0x5c, 0x4d, 0xc6, 0xd7, 0xe5,
- 0xf4, 0x80, 0x91, 0xa3, 0xb2, 0x4a, 0x5b, 0x69, 0x78, 0x0c, 0x1d, 0x2f, 0x3e, 0xd6, 0xc7,
- 0xf5, 0xe4, 0x90, 0x81, 0xb3, 0xa2, 0x5a, 0x4b, 0x79, 0x68, 0x1c, 0x0d, 0x3f, 0x2e, 0xe7,
- 0xf6, 0xc4, 0xd5, 0xa1, 0xb0, 0x82, 0x93, 0x6b, 0x7a, 0x48, 0x59, 0x2d, 0x3c, 0x0e, 0x1f,
- 0xf7, 0xe6, 0xd4, 0xc5, 0xb1, 0xa0, 0x92, 0x83, 0x7b, 0x6a, 0x58, 0x49, 0x3d, 0x2c, 0x1e,
- 0x0f};
-
-/*************************************************************************
-* FPGA functions
-************************************************************************/
-
-static void delay(int ms)
-{
- unsigned long timeout = jiffies + ((ms * HZ) / 1000);
- while (time_before(jiffies, timeout))
- cpu_relax();
-}
-
-/*
- * reset FPGA
- */
-
-static void fpga_reset(int iobase)
-{
- outb(0, IER(iobase));
- outb(LCR_DLAB | LCR_BIT5, LCR(iobase));
- outb(1, DLL(iobase));
- outb(0, DLM(iobase));
-
- outb(LCR_BIT5, LCR(iobase));
- inb(LSR(iobase));
- inb(MSR(iobase));
- /* turn off FPGA supply voltage */
- outb(MCR_OUT1 | MCR_OUT2, MCR(iobase));
- delay(100);
- /* turn on FPGA supply voltage again */
- outb(MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2, MCR(iobase));
- delay(100);
-}
-
-/*
- * send one byte to FPGA
- */
-
-static int fpga_write(int iobase, unsigned char wrd)
-{
- unsigned char bit;
- int k;
- unsigned long timeout = jiffies + HZ / 10;
-
- for (k = 0; k < 8; k++) {
- bit = (wrd & 0x80) ? (MCR_RTS | MCR_DTR) : MCR_DTR;
- outb(bit | MCR_OUT1 | MCR_OUT2, MCR(iobase));
- wrd <<= 1;
- outb(0xfc, THR(iobase));
- while ((inb(LSR(iobase)) & LSR_TSRE) == 0)
- if (time_after(jiffies, timeout))
- return -1;
- }
-
- return 0;
-}
-
-/*
- * predef should be 0 for loading user defined mcs
- * predef should be YAM_1200 for loading predef 1200 mcs
- * predef should be YAM_9600 for loading predef 9600 mcs
- */
-static unsigned char *add_mcs(unsigned char *bits, int bitrate,
- unsigned int predef)
-{
- const char *fw_name[2] = {FIRMWARE_9600, FIRMWARE_1200};
- const struct firmware *fw;
- struct platform_device *pdev;
- struct yam_mcs *p;
- int err;
-
- switch (predef) {
- case 0:
- fw = NULL;
- break;
- case YAM_1200:
- case YAM_9600:
- predef--;
- pdev = platform_device_register_simple("yam", 0, NULL, 0);
- if (IS_ERR(pdev)) {
- printk(KERN_ERR "yam: Failed to register firmware\n");
- return NULL;
- }
- err = request_firmware(&fw, fw_name[predef], &pdev->dev);
- platform_device_unregister(pdev);
- if (err) {
- printk(KERN_ERR "Failed to load firmware \"%s\"\n",
- fw_name[predef]);
- return NULL;
- }
- if (fw->size != YAM_FPGA_SIZE) {
- printk(KERN_ERR "Bogus length %zu in firmware \"%s\"\n",
- fw->size, fw_name[predef]);
- release_firmware(fw);
- return NULL;
- }
- bits = (unsigned char *)fw->data;
- break;
- default:
- printk(KERN_ERR "yam: Invalid predef number %u\n", predef);
- return NULL;
- }
-
- /* If it already exists, replace the bit data */
- p = yam_data;
- while (p) {
- if (p->bitrate == bitrate) {
- memcpy(p->bits, bits, YAM_FPGA_SIZE);
- goto out;
- }
- p = p->next;
- }
-
- /* Allocate a new mcs */
- if ((p = kmalloc_obj(struct yam_mcs)) == NULL) {
- release_firmware(fw);
- return NULL;
- }
- memcpy(p->bits, bits, YAM_FPGA_SIZE);
- p->bitrate = bitrate;
- p->next = yam_data;
- yam_data = p;
- out:
- release_firmware(fw);
- return p->bits;
-}
-
-static unsigned char *get_mcs(int bitrate)
-{
- struct yam_mcs *p;
-
- p = yam_data;
- while (p) {
- if (p->bitrate == bitrate)
- return p->bits;
- p = p->next;
- }
-
- /* Load predefined mcs data */
- switch (bitrate) {
- case 1200:
- /* setting predef as YAM_1200 for loading predef 1200 mcs */
- return add_mcs(NULL, bitrate, YAM_1200);
- default:
- /* setting predef as YAM_9600 for loading predef 9600 mcs */
- return add_mcs(NULL, bitrate, YAM_9600);
- }
-}
-
-/*
- * download bitstream to FPGA
- * data is contained in bits[] array in yam1200.h resp. yam9600.h
- */
-
-static int fpga_download(int iobase, int bitrate)
-{
- int i, rc;
- unsigned char *pbits;
-
- pbits = get_mcs(bitrate);
- if (pbits == NULL)
- return -1;
-
- fpga_reset(iobase);
- for (i = 0; i < YAM_FPGA_SIZE; i++) {
- if (fpga_write(iobase, pbits[i])) {
- printk(KERN_ERR "yam: error in write cycle\n");
- return -1; /* write... */
- }
- }
-
- fpga_write(iobase, 0xFF);
- rc = inb(MSR(iobase)); /* check DONE signal */
-
- /* Needed for some hardwares */
- delay(50);
-
- return (rc & MSR_DSR) ? 0 : -1;
-}
-
-
-/************************************************************************
-* Serial port init
-************************************************************************/
-
-static void yam_set_uart(struct net_device *dev)
-{
- struct yam_port *yp = netdev_priv(dev);
- int divisor = 115200 / yp->baudrate;
-
- outb(0, IER(dev->base_addr));
- outb(LCR_DLAB | LCR_BIT8, LCR(dev->base_addr));
- outb(divisor, DLL(dev->base_addr));
- outb(0, DLM(dev->base_addr));
- outb(LCR_BIT8, LCR(dev->base_addr));
- outb(PTT_OFF, MCR(dev->base_addr));
- outb(0x00, FCR(dev->base_addr));
-
- /* Flush pending irq */
-
- inb(RBR(dev->base_addr));
- inb(MSR(dev->base_addr));
-
- /* Enable rx irq */
-
- outb(ENABLE_RTXINT, IER(dev->base_addr));
-}
-
-
-/* --------------------------------------------------------------------- */
-
-enum uart {
- c_uart_unknown, c_uart_8250,
- c_uart_16450, c_uart_16550, c_uart_16550A
-};
-
-static const char *uart_str[] =
-{"unknown", "8250", "16450", "16550", "16550A"};
-
-static enum uart yam_check_uart(unsigned int iobase)
-{
- unsigned char b1, b2, b3;
- enum uart u;
- enum uart uart_tab[] =
- {c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A};
-
- b1 = inb(MCR(iobase));
- outb(b1 | 0x10, MCR(iobase)); /* loopback mode */
- b2 = inb(MSR(iobase));
- outb(0x1a, MCR(iobase));
- b3 = inb(MSR(iobase)) & 0xf0;
- outb(b1, MCR(iobase)); /* restore old values */
- outb(b2, MSR(iobase));
- if (b3 != 0x90)
- return c_uart_unknown;
- inb(RBR(iobase));
- inb(RBR(iobase));
- outb(0x01, FCR(iobase)); /* enable FIFOs */
- u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
- if (u == c_uart_16450) {
- outb(0x5a, SCR(iobase));
- b1 = inb(SCR(iobase));
- outb(0xa5, SCR(iobase));
- b2 = inb(SCR(iobase));
- if ((b1 != 0x5a) || (b2 != 0xa5))
- u = c_uart_8250;
- }
- return u;
-}
-
-/******************************************************************************
-* Rx Section
-******************************************************************************/
-static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp)
-{
- if (yp->dcd && yp->rx_len >= 3 && yp->rx_len < YAM_MAX_FRAME) {
- int pkt_len = yp->rx_len - 2 + 1; /* -CRC + kiss */
- struct sk_buff *skb;
-
- if ((yp->rx_crch & yp->rx_crcl) != 0xFF) {
- /* Bad crc */
- } else {
- if (!(skb = dev_alloc_skb(pkt_len))) {
- printk(KERN_WARNING "%s: memory squeeze, dropping packet\n", dev->name);
- ++dev->stats.rx_dropped;
- } else {
- unsigned char *cp;
- cp = skb_put(skb, pkt_len);
- *cp++ = 0; /* KISS kludge */
- memcpy(cp, yp->rx_buf, pkt_len - 1);
- skb->protocol = ax25_type_trans(skb, dev);
- netif_rx(skb);
- ++dev->stats.rx_packets;
- }
- }
- }
- yp->rx_len = 0;
- yp->rx_crcl = 0x21;
- yp->rx_crch = 0xf3;
-}
-
-static inline void yam_rx_byte(struct net_device *dev, struct yam_port *yp, unsigned char rxb)
-{
- if (yp->rx_len < YAM_MAX_FRAME) {
- unsigned char c = yp->rx_crcl;
- yp->rx_crcl = (chktabl[c] ^ yp->rx_crch);
- yp->rx_crch = (chktabh[c] ^ rxb);
- yp->rx_buf[yp->rx_len++] = rxb;
- }
-}
-
-/********************************************************************************
-* TX Section
-********************************************************************************/
-
-static void ptt_on(struct net_device *dev)
-{
- outb(PTT_ON, MCR(dev->base_addr));
-}
-
-static void ptt_off(struct net_device *dev)
-{
- outb(PTT_OFF, MCR(dev->base_addr));
-}
-
-static netdev_tx_t yam_send_packet(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct yam_port *yp = netdev_priv(dev);
-
- if (skb->protocol == htons(ETH_P_IP))
- return ax25_ip_xmit(skb);
-
- skb_queue_tail(&yp->send_queue, skb);
- netif_trans_update(dev);
- return NETDEV_TX_OK;
-}
-
-static void yam_start_tx(struct net_device *dev, struct yam_port *yp)
-{
- if ((yp->tx_state == TX_TAIL) || (yp->txd == 0))
- yp->tx_count = 1;
- else
- yp->tx_count = (yp->bitrate * yp->txd) / 8000;
- yp->tx_state = TX_HEAD;
- ptt_on(dev);
-}
-
-static void yam_arbitrate(struct net_device *dev)
-{
- struct yam_port *yp = netdev_priv(dev);
-
- if (yp->magic != YAM_MAGIC || yp->tx_state != TX_OFF ||
- skb_queue_empty(&yp->send_queue))
- return;
- /* tx_state is TX_OFF and there is data to send */
-
- if (yp->dupmode) {
- /* Full duplex mode, don't wait */
- yam_start_tx(dev, yp);
- return;
- }
- if (yp->dcd) {
- /* DCD on, wait slotime ... */
- yp->slotcnt = yp->slot / 10;
- return;
- }
- /* Is slottime passed ? */
- if ((--yp->slotcnt) > 0)
- return;
-
- yp->slotcnt = yp->slot / 10;
-
- /* is random > persist ? */
- if (get_random_u8() > yp->pers)
- return;
-
- yam_start_tx(dev, yp);
-}
-
-static void yam_dotimer(struct timer_list *unused)
-{
- int i;
-
- for (i = 0; i < NR_PORTS; i++) {
- struct net_device *dev = yam_devs[i];
- if (dev && netif_running(dev))
- yam_arbitrate(dev);
- }
- yam_timer.expires = jiffies + HZ / 100;
- add_timer(&yam_timer);
-}
-
-static void yam_tx_byte(struct net_device *dev, struct yam_port *yp)
-{
- struct sk_buff *skb;
- unsigned char b, temp;
-
- switch (yp->tx_state) {
- case TX_OFF:
- break;
- case TX_HEAD:
- if (--yp->tx_count <= 0) {
- if (!(skb = skb_dequeue(&yp->send_queue))) {
- ptt_off(dev);
- yp->tx_state = TX_OFF;
- break;
- }
- yp->tx_state = TX_DATA;
- if (skb->data[0] != 0) {
-/* do_kiss_params(s, skb->data, skb->len); */
- dev_kfree_skb_any(skb);
- break;
- }
- yp->tx_len = skb->len - 1; /* strip KISS byte */
- if (yp->tx_len >= YAM_MAX_FRAME || yp->tx_len < 2) {
- dev_kfree_skb_any(skb);
- break;
- }
- skb_copy_from_linear_data_offset(skb, 1,
- yp->tx_buf,
- yp->tx_len);
- dev_kfree_skb_any(skb);
- yp->tx_count = 0;
- yp->tx_crcl = 0x21;
- yp->tx_crch = 0xf3;
- yp->tx_state = TX_DATA;
- }
- break;
- case TX_DATA:
- b = yp->tx_buf[yp->tx_count++];
- outb(b, THR(dev->base_addr));
- temp = yp->tx_crcl;
- yp->tx_crcl = chktabl[temp] ^ yp->tx_crch;
- yp->tx_crch = chktabh[temp] ^ b;
- if (yp->tx_count >= yp->tx_len) {
- yp->tx_state = TX_CRC1;
- }
- break;
- case TX_CRC1:
- yp->tx_crch = chktabl[yp->tx_crcl] ^ yp->tx_crch;
- yp->tx_crcl = chktabh[yp->tx_crcl] ^ chktabl[yp->tx_crch] ^ 0xff;
- outb(yp->tx_crcl, THR(dev->base_addr));
- yp->tx_state = TX_CRC2;
- break;
- case TX_CRC2:
- outb(chktabh[yp->tx_crch] ^ 0xFF, THR(dev->base_addr));
- if (skb_queue_empty(&yp->send_queue)) {
- yp->tx_count = (yp->bitrate * yp->txtail) / 8000;
- if (yp->dupmode == 2)
- yp->tx_count += (yp->bitrate * yp->holdd) / 8;
- if (yp->tx_count == 0)
- yp->tx_count = 1;
- yp->tx_state = TX_TAIL;
- } else {
- yp->tx_count = 1;
- yp->tx_state = TX_HEAD;
- }
- ++dev->stats.tx_packets;
- break;
- case TX_TAIL:
- if (--yp->tx_count <= 0) {
- yp->tx_state = TX_OFF;
- ptt_off(dev);
- }
- break;
- }
-}
-
-/***********************************************************************************
-* ISR routine
-************************************************************************************/
-
-static irqreturn_t yam_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev;
- struct yam_port *yp;
- unsigned char iir;
- int counter = 100;
- int i;
- int handled = 0;
-
- for (i = 0; i < NR_PORTS; i++) {
- dev = yam_devs[i];
- yp = netdev_priv(dev);
-
- if (!netif_running(dev))
- continue;
-
- while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) {
- unsigned char msr = inb(MSR(dev->base_addr));
- unsigned char lsr = inb(LSR(dev->base_addr));
- unsigned char rxb;
-
- handled = 1;
-
- if (lsr & LSR_OE)
- ++dev->stats.rx_fifo_errors;
-
- yp->dcd = (msr & RX_DCD) ? 1 : 0;
-
- if (--counter <= 0) {
- printk(KERN_ERR "%s: too many irq iir=%d\n",
- dev->name, iir);
- goto out;
- }
- if (msr & TX_RDY) {
- ++yp->nb_mdint;
- yam_tx_byte(dev, yp);
- }
- if (lsr & LSR_RXC) {
- ++yp->nb_rxint;
- rxb = inb(RBR(dev->base_addr));
- if (msr & RX_FLAG)
- yam_rx_flag(dev, yp);
- else
- yam_rx_byte(dev, yp, rxb);
- }
- }
- }
-out:
- return IRQ_RETVAL(handled);
-}
-
-#ifdef CONFIG_PROC_FS
-
-static void *yam_seq_start(struct seq_file *seq, loff_t *pos)
-{
- return (*pos < NR_PORTS) ? yam_devs[*pos] : NULL;
-}
-
-static void *yam_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
- return (*pos < NR_PORTS) ? yam_devs[*pos] : NULL;
-}
-
-static void yam_seq_stop(struct seq_file *seq, void *v)
-{
-}
-
-static int yam_seq_show(struct seq_file *seq, void *v)
-{
- struct net_device *dev = v;
- const struct yam_port *yp = netdev_priv(dev);
-
- seq_printf(seq, "Device %s\n", dev->name);
- seq_printf(seq, " Up %d\n", netif_running(dev));
- seq_printf(seq, " Speed %u\n", yp->bitrate);
- seq_printf(seq, " IoBase 0x%x\n", yp->iobase);
- seq_printf(seq, " BaudRate %u\n", yp->baudrate);
- seq_printf(seq, " IRQ %u\n", yp->irq);
- seq_printf(seq, " TxState %u\n", yp->tx_state);
- seq_printf(seq, " Duplex %u\n", yp->dupmode);
- seq_printf(seq, " HoldDly %u\n", yp->holdd);
- seq_printf(seq, " TxDelay %u\n", yp->txd);
- seq_printf(seq, " TxTail %u\n", yp->txtail);
- seq_printf(seq, " SlotTime %u\n", yp->slot);
- seq_printf(seq, " Persist %u\n", yp->pers);
- seq_printf(seq, " TxFrames %lu\n", dev->stats.tx_packets);
- seq_printf(seq, " RxFrames %lu\n", dev->stats.rx_packets);
- seq_printf(seq, " TxInt %u\n", yp->nb_mdint);
- seq_printf(seq, " RxInt %u\n", yp->nb_rxint);
- seq_printf(seq, " RxOver %lu\n", dev->stats.rx_fifo_errors);
- seq_printf(seq, "\n");
- return 0;
-}
-
-static const struct seq_operations yam_seqops = {
- .start = yam_seq_start,
- .next = yam_seq_next,
- .stop = yam_seq_stop,
- .show = yam_seq_show,
-};
-#endif
-
-
-/* --------------------------------------------------------------------- */
-
-static int yam_open(struct net_device *dev)
-{
- struct yam_port *yp = netdev_priv(dev);
- enum uart u;
- int i;
- int ret=0;
-
- printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq);
-
- if (!yp->bitrate)
- return -ENXIO;
- if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT ||
- dev->irq < 2 || dev->irq > 15) {
- return -ENXIO;
- }
- if (!request_region(dev->base_addr, YAM_EXTENT, dev->name))
- {
- printk(KERN_ERR "%s: cannot 0x%lx busy\n", dev->name, dev->base_addr);
- return -EACCES;
- }
- if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) {
- printk(KERN_ERR "%s: cannot find uart type\n", dev->name);
- ret = -EIO;
- goto out_release_base;
- }
- if (fpga_download(dev->base_addr, yp->bitrate)) {
- printk(KERN_ERR "%s: cannot init FPGA\n", dev->name);
- ret = -EIO;
- goto out_release_base;
- }
- outb(0, IER(dev->base_addr));
- if (request_irq(dev->irq, yam_interrupt, IRQF_SHARED, dev->name, dev)) {
- printk(KERN_ERR "%s: irq %d busy\n", dev->name, dev->irq);
- ret = -EBUSY;
- goto out_release_base;
- }
-
- yam_set_uart(dev);
-
- netif_start_queue(dev);
-
- yp->slotcnt = yp->slot / 10;
-
- /* Reset overruns for all ports - FPGA programming makes overruns */
- for (i = 0; i < NR_PORTS; i++) {
- struct net_device *yam_dev = yam_devs[i];
-
- inb(LSR(yam_dev->base_addr));
- yam_dev->stats.rx_fifo_errors = 0;
- }
-
- printk(KERN_INFO "%s at iobase 0x%lx irq %u uart %s\n", dev->name, dev->base_addr, dev->irq,
- uart_str[u]);
- return 0;
-
-out_release_base:
- release_region(dev->base_addr, YAM_EXTENT);
- return ret;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int yam_close(struct net_device *dev)
-{
- struct sk_buff *skb;
- struct yam_port *yp = netdev_priv(dev);
-
- if (!dev)
- return -EINVAL;
-
- /*
- * disable interrupts
- */
- outb(0, IER(dev->base_addr));
- outb(1, MCR(dev->base_addr));
- /* Remove IRQ handler if last */
- free_irq(dev->irq,dev);
- release_region(dev->base_addr, YAM_EXTENT);
- netif_stop_queue(dev);
- while ((skb = skb_dequeue(&yp->send_queue)))
- dev_kfree_skb(skb);
-
- printk(KERN_INFO "%s: close yam at iobase 0x%lx irq %u\n",
- yam_drvname, dev->base_addr, dev->irq);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int yam_siocdevprivate(struct net_device *dev, struct ifreq *ifr, void __user *data, int cmd)
-{
- struct yam_port *yp = netdev_priv(dev);
- struct yamdrv_ioctl_cfg yi;
- struct yamdrv_ioctl_mcs *ym;
- int ioctl_cmd;
-
- if (copy_from_user(&ioctl_cmd, data, sizeof(int)))
- return -EFAULT;
-
- if (yp->magic != YAM_MAGIC)
- return -EINVAL;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (cmd != SIOCDEVPRIVATE)
- return -EINVAL;
-
- switch (ioctl_cmd) {
-
- case SIOCYAMRESERVED:
- return -EINVAL; /* unused */
-
- case SIOCYAMSMCS:
- if (netif_running(dev))
- return -EINVAL; /* Cannot change this parameter when up */
- ym = memdup_user(data, sizeof(struct yamdrv_ioctl_mcs));
- if (IS_ERR(ym))
- return PTR_ERR(ym);
- if (ym->cmd != SIOCYAMSMCS || ym->bitrate > YAM_MAXBITRATE) {
- kfree(ym);
- return -EINVAL;
- }
- /* setting predef as 0 for loading userdefined mcs data */
- add_mcs(ym->bits, ym->bitrate, 0);
- kfree(ym);
- break;
-
- case SIOCYAMSCFG:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- if (copy_from_user(&yi, data, sizeof(struct yamdrv_ioctl_cfg)))
- return -EFAULT;
-
- if (yi.cmd != SIOCYAMSCFG)
- return -EINVAL;
- if ((yi.cfg.mask & YAM_IOBASE) && netif_running(dev))
- return -EINVAL; /* Cannot change this parameter when up */
- if ((yi.cfg.mask & YAM_IRQ) && netif_running(dev))
- return -EINVAL; /* Cannot change this parameter when up */
- if ((yi.cfg.mask & YAM_BITRATE) && netif_running(dev))
- return -EINVAL; /* Cannot change this parameter when up */
- if ((yi.cfg.mask & YAM_BAUDRATE) && netif_running(dev))
- return -EINVAL; /* Cannot change this parameter when up */
-
- if (yi.cfg.mask & YAM_IOBASE) {
- yp->iobase = yi.cfg.iobase;
- dev->base_addr = yi.cfg.iobase;
- }
- if (yi.cfg.mask & YAM_IRQ) {
- if (yi.cfg.irq > 15)
- return -EINVAL;
- yp->irq = yi.cfg.irq;
- dev->irq = yi.cfg.irq;
- }
- if (yi.cfg.mask & YAM_BITRATE) {
- if (yi.cfg.bitrate > YAM_MAXBITRATE)
- return -EINVAL;
- yp->bitrate = yi.cfg.bitrate;
- }
- if (yi.cfg.mask & YAM_BAUDRATE) {
- if (yi.cfg.baudrate > YAM_MAXBAUDRATE)
- return -EINVAL;
- yp->baudrate = yi.cfg.baudrate;
- }
- if (yi.cfg.mask & YAM_MODE) {
- if (yi.cfg.mode > YAM_MAXMODE)
- return -EINVAL;
- yp->dupmode = yi.cfg.mode;
- }
- if (yi.cfg.mask & YAM_HOLDDLY) {
- if (yi.cfg.holddly > YAM_MAXHOLDDLY)
- return -EINVAL;
- yp->holdd = yi.cfg.holddly;
- }
- if (yi.cfg.mask & YAM_TXDELAY) {
- if (yi.cfg.txdelay > YAM_MAXTXDELAY)
- return -EINVAL;
- yp->txd = yi.cfg.txdelay;
- }
- if (yi.cfg.mask & YAM_TXTAIL) {
- if (yi.cfg.txtail > YAM_MAXTXTAIL)
- return -EINVAL;
- yp->txtail = yi.cfg.txtail;
- }
- if (yi.cfg.mask & YAM_PERSIST) {
- if (yi.cfg.persist > YAM_MAXPERSIST)
- return -EINVAL;
- yp->pers = yi.cfg.persist;
- }
- if (yi.cfg.mask & YAM_SLOTTIME) {
- if (yi.cfg.slottime > YAM_MAXSLOTTIME)
- return -EINVAL;
- yp->slot = yi.cfg.slottime;
- yp->slotcnt = yp->slot / 10;
- }
- break;
-
- case SIOCYAMGCFG:
- memset(&yi, 0, sizeof(yi));
- yi.cfg.mask = 0xffffffff;
- yi.cfg.iobase = yp->iobase;
- yi.cfg.irq = yp->irq;
- yi.cfg.bitrate = yp->bitrate;
- yi.cfg.baudrate = yp->baudrate;
- yi.cfg.mode = yp->dupmode;
- yi.cfg.txdelay = yp->txd;
- yi.cfg.holddly = yp->holdd;
- yi.cfg.txtail = yp->txtail;
- yi.cfg.persist = yp->pers;
- yi.cfg.slottime = yp->slot;
- if (copy_to_user(data, &yi, sizeof(struct yamdrv_ioctl_cfg)))
- return -EFAULT;
- break;
-
- default:
- return -EINVAL;
-
- }
-
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int yam_set_mac_address(struct net_device *dev, void *addr)
-{
- struct sockaddr *sa = (struct sockaddr *) addr;
-
- /* addr is an AX.25 shifted ASCII mac address */
- dev_addr_set(dev, sa->sa_data);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static const struct net_device_ops yam_netdev_ops = {
- .ndo_open = yam_open,
- .ndo_stop = yam_close,
- .ndo_start_xmit = yam_send_packet,
- .ndo_siocdevprivate = yam_siocdevprivate,
- .ndo_set_mac_address = yam_set_mac_address,
-};
-
-static void yam_setup(struct net_device *dev)
-{
- struct yam_port *yp = netdev_priv(dev);
-
- yp->magic = YAM_MAGIC;
- yp->bitrate = DEFAULT_BITRATE;
- yp->baudrate = DEFAULT_BITRATE * 2;
- yp->iobase = 0;
- yp->irq = 0;
- yp->dupmode = 0;
- yp->holdd = DEFAULT_HOLDD;
- yp->txd = DEFAULT_TXD;
- yp->txtail = DEFAULT_TXTAIL;
- yp->slot = DEFAULT_SLOT;
- yp->pers = DEFAULT_PERS;
- yp->dev = dev;
-
- dev->base_addr = yp->iobase;
- dev->irq = yp->irq;
-
- skb_queue_head_init(&yp->send_queue);
-
- dev->netdev_ops = &yam_netdev_ops;
- dev->header_ops = &ax25_header_ops;
-
- dev->type = ARPHRD_AX25;
- dev->hard_header_len = AX25_MAX_HEADER_LEN;
- dev->mtu = AX25_MTU;
- dev->addr_len = AX25_ADDR_LEN;
- memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
- dev_addr_set(dev, (u8 *)&ax25_defaddr);
-}
-
-static int __init yam_init_driver(void)
-{
- struct net_device *dev;
- int i, err;
- char name[IFNAMSIZ];
-
- printk(yam_drvinfo);
-
- for (i = 0; i < NR_PORTS; i++) {
- sprintf(name, "yam%d", i);
-
- dev = alloc_netdev(sizeof(struct yam_port), name,
- NET_NAME_UNKNOWN, yam_setup);
- if (!dev) {
- pr_err("yam: cannot allocate net device\n");
- err = -ENOMEM;
- goto error;
- }
-
- err = register_netdev(dev);
- if (err) {
- printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name);
- free_netdev(dev);
- goto error;
- }
- yam_devs[i] = dev;
-
- }
-
- timer_setup(&yam_timer, yam_dotimer, 0);
- yam_timer.expires = jiffies + HZ / 100;
- add_timer(&yam_timer);
-
- proc_create_seq("yam", 0444, init_net.proc_net, &yam_seqops);
- return 0;
- error:
- while (--i >= 0) {
- unregister_netdev(yam_devs[i]);
- free_netdev(yam_devs[i]);
- }
- return err;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void __exit yam_cleanup_driver(void)
-{
- struct yam_mcs *p;
- int i;
-
- timer_delete_sync(&yam_timer);
- for (i = 0; i < NR_PORTS; i++) {
- struct net_device *dev = yam_devs[i];
- if (dev) {
- unregister_netdev(dev);
- free_netdev(dev);
- }
- }
-
- while (yam_data) {
- p = yam_data;
- yam_data = yam_data->next;
- kfree(p);
- }
-
- remove_proc_entry("yam", init_net.proc_net);
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr");
-MODULE_DESCRIPTION("Yam amateur radio modem driver");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(FIRMWARE_1200);
-MODULE_FIRMWARE(FIRMWARE_9600);
-
-module_init(yam_init_driver);
-module_exit(yam_cleanup_driver);
-
-/* --------------------------------------------------------------------- */
-
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
deleted file mode 100644
index 9d236e64f5f5..000000000000
--- a/net/ax25/af_ax25.c
+++ /dev/null
@@ -1,2089 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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/capability.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/sched/signal.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/termios.h> /* For TIOCINQ/OUTQ */
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/sysctl.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <net/net_namespace.h>
-#include <net/tcp_states.h>
-#include <net/ip.h>
-#include <net/arp.h>
-
-
-
-HLIST_HEAD(ax25_list);
-DEFINE_SPINLOCK(ax25_list_lock);
-
-static const struct proto_ops ax25_proto_ops;
-
-static void ax25_free_sock(struct sock *sk)
-{
- ax25_cb_put(sk_to_ax25(sk));
-}
-
-/*
- * Socket removal during an interrupt is now safe.
- */
-static void ax25_cb_del(ax25_cb *ax25)
-{
- spin_lock_bh(&ax25_list_lock);
- if (!hlist_unhashed(&ax25->ax25_node)) {
- hlist_del_init(&ax25->ax25_node);
- ax25_cb_put(ax25);
- }
- spin_unlock_bh(&ax25_list_lock);
-}
-
-/*
- * Kill all bound sockets on a dropped device.
- */
-static void ax25_kill_by_device(struct net_device *dev)
-{
- ax25_dev *ax25_dev;
- ax25_cb *s;
- struct sock *sk;
-
- if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
- return;
- ax25_dev->device_up = false;
-
- spin_lock_bh(&ax25_list_lock);
-again:
- ax25_for_each(s, &ax25_list) {
- if (s->ax25_dev == ax25_dev) {
- sk = s->sk;
- if (!sk) {
- spin_unlock_bh(&ax25_list_lock);
- ax25_disconnect(s, ENETUNREACH);
- s->ax25_dev = NULL;
- ax25_cb_del(s);
- spin_lock_bh(&ax25_list_lock);
- goto again;
- }
- sock_hold(sk);
- spin_unlock_bh(&ax25_list_lock);
- lock_sock(sk);
- ax25_disconnect(s, ENETUNREACH);
- s->ax25_dev = NULL;
- if (sk->sk_socket) {
- netdev_put(ax25_dev->dev,
- &s->dev_tracker);
- ax25_dev_put(ax25_dev);
- }
- ax25_cb_del(s);
- release_sock(sk);
- spin_lock_bh(&ax25_list_lock);
- sock_put(sk);
- /* The entry could have been deleted from the
- * list meanwhile and thus the next pointer is
- * no longer valid. Play it safe and restart
- * the scan. Forward progress is ensured
- * because we set s->ax25_dev to NULL and we
- * are never passed a NULL 'dev' argument.
- */
- goto again;
- }
- }
- spin_unlock_bh(&ax25_list_lock);
-}
-
-/*
- * Handle device status changes.
- */
-static int ax25_device_event(struct notifier_block *this, unsigned long event,
- void *ptr)
-{
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
- /* Reject non AX.25 devices */
- if (dev->type != ARPHRD_AX25)
- 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;
- }
-
- return NOTIFY_DONE;
-}
-
-/*
- * Add a socket to the bound sockets list.
- */
-void ax25_cb_add(ax25_cb *ax25)
-{
- spin_lock_bh(&ax25_list_lock);
- ax25_cb_hold(ax25);
- hlist_add_head(&ax25->ax25_node, &ax25_list);
- 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)
-{
- ax25_cb *s;
-
- spin_lock(&ax25_list_lock);
- ax25_for_each(s, &ax25_list) {
- if ((s->iamdigi && !digi) || (!s->iamdigi && digi))
- continue;
- if (s->sk && !ax25cmp(&s->source_addr, addr) &&
- s->sk->sk_type == type && s->sk->sk_state == TCP_LISTEN) {
- /* If device is null we match any device */
- if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) {
- sock_hold(s->sk);
- spin_unlock(&ax25_list_lock);
- return s->sk;
- }
- }
- }
- spin_unlock(&ax25_list_lock);
-
- return NULL;
-}
-
-/*
- * Find an AX.25 socket given both ends.
- */
-struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr,
- int type)
-{
- struct sock *sk = NULL;
- ax25_cb *s;
-
- spin_lock(&ax25_list_lock);
- ax25_for_each(s, &ax25_list) {
- if (s->sk && !ax25cmp(&s->source_addr, my_addr) &&
- !ax25cmp(&s->dest_addr, dest_addr) &&
- s->sk->sk_type == type) {
- sk = s->sk;
- sock_hold(sk);
- break;
- }
- }
-
- spin_unlock(&ax25_list_lock);
-
- return sk;
-}
-
-/*
- * 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(const ax25_address *src_addr, ax25_address *dest_addr,
- ax25_digi *digi, struct net_device *dev)
-{
- ax25_cb *s;
-
- spin_lock_bh(&ax25_list_lock);
- ax25_for_each(s, &ax25_list) {
- if (s->sk && s->sk->sk_type != SOCK_SEQPACKET)
- continue;
- if (s->ax25_dev == NULL)
- continue;
- if (ax25cmp(&s->source_addr, src_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) {
- if (digi != NULL && digi->ndigi != 0) {
- if (s->digipeat == NULL)
- continue;
- if (ax25digicmp(s->digipeat, digi) != 0)
- continue;
- } else {
- if (s->digipeat != NULL && s->digipeat->ndigi != 0)
- continue;
- }
- ax25_cb_hold(s);
- spin_unlock_bh(&ax25_list_lock);
-
- return s;
- }
- }
- spin_unlock_bh(&ax25_list_lock);
-
- return NULL;
-}
-
-EXPORT_SYMBOL(ax25_find_cb);
-
-void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto)
-{
- ax25_cb *s;
- struct sk_buff *copy;
-
- spin_lock(&ax25_list_lock);
- ax25_for_each(s, &ax25_list) {
- if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 &&
- s->sk->sk_type == SOCK_RAW &&
- s->sk->sk_protocol == proto &&
- s->ax25_dev->dev == skb->dev &&
- atomic_read(&s->sk->sk_rmem_alloc) <= s->sk->sk_rcvbuf) {
- if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL)
- continue;
- if (sock_queue_rcv_skb(s->sk, copy) != 0)
- kfree_skb(copy);
- }
- }
- spin_unlock(&ax25_list_lock);
-}
-
-/*
- * Deferred destroy.
- */
-void ax25_destroy_socket(ax25_cb *);
-
-/*
- * Handler for deferred kills.
- */
-static void ax25_destroy_timer(struct timer_list *t)
-{
- ax25_cb *ax25 = timer_container_of(ax25, t, dtimer);
- struct sock *sk;
-
- sk=ax25->sk;
-
- bh_lock_sock(sk);
- sock_hold(sk);
- ax25_destroy_socket(ax25);
- bh_unlock_sock(sk);
- sock_put(sk);
-}
-
-/*
- * 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)
-{
- struct sk_buff *skb;
-
- ax25_cb_del(ax25);
-
- ax25_stop_heartbeat(ax25);
- ax25_stop_t1timer(ax25);
- ax25_stop_t2timer(ax25);
- ax25_stop_t3timer(ax25);
- ax25_stop_idletimer(ax25);
-
- ax25_clear_queues(ax25); /* Flush the queues */
-
- if (ax25->sk != NULL) {
- while ((skb = skb_dequeue(&ax25->sk->sk_receive_queue)) != NULL) {
- if (skb->sk != ax25->sk) {
- /* A pending connection */
- ax25_cb *sax25 = sk_to_ax25(skb->sk);
-
- /* Queue the unaccepted socket for death */
- sock_orphan(skb->sk);
-
- /* 9A4GL: hack to release unaccepted sockets */
- skb->sk->sk_state = TCP_LISTEN;
-
- ax25_start_heartbeat(sax25);
- sax25->state = AX25_STATE_0;
- }
-
- kfree_skb(skb);
- }
- skb_queue_purge(&ax25->sk->sk_write_queue);
- }
-
- if (ax25->sk != NULL) {
- if (sk_has_allocations(ax25->sk)) {
- /* Defer: outstanding buffers */
- timer_setup(&ax25->dtimer, ax25_destroy_timer, 0);
- ax25->dtimer.expires = jiffies + 2 * HZ;
- add_timer(&ax25->dtimer);
- } else {
- struct sock *sk=ax25->sk;
- ax25->sk=NULL;
- sock_put(sk);
- }
- } else {
- ax25_cb_put(ax25);
- }
-}
-
-/*
- * dl1bke 960311: set parameters for existing AX.25 connections,
- * includes a KILL command to abort any connection.
- * VERY useful for debugging ;-)
- */
-static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
-{
- struct ax25_ctl_struct ax25_ctl;
- ax25_digi digi;
- ax25_dev *ax25_dev;
- ax25_cb *ax25;
- unsigned int k;
- int ret = 0;
-
- if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
- return -EFAULT;
-
- if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
- return -EINVAL;
-
- if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL)
- return -EINVAL;
-
- ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr);
- if (!ax25_dev)
- return -ENODEV;
-
- digi.ndigi = ax25_ctl.digi_count;
- for (k = 0; k < digi.ndigi; k++)
- digi.calls[k] = ax25_ctl.digi_addr[k];
-
- ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev);
- if (!ax25) {
- ax25_dev_put(ax25_dev);
- return -ENOTCONN;
- }
-
- switch (ax25_ctl.cmd) {
- 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);
-#endif
- ax25_disconnect(ax25, ENETRESET);
- break;
-
- case AX25_WINDOW:
- if (ax25->modulus == AX25_MODULUS) {
- if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
- goto einval_put;
- } else {
- if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63)
- goto einval_put;
- }
- ax25->window = ax25_ctl.arg;
- break;
-
- case AX25_T1:
- if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ)
- goto einval_put;
- ax25->rtt = (ax25_ctl.arg * HZ) / 2;
- ax25->t1 = ax25_ctl.arg * HZ;
- break;
-
- case AX25_T2:
- if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ)
- goto einval_put;
- ax25->t2 = ax25_ctl.arg * HZ;
- break;
-
- case AX25_N2:
- if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
- goto einval_put;
- ax25->n2count = 0;
- ax25->n2 = ax25_ctl.arg;
- break;
-
- case AX25_T3:
- if (ax25_ctl.arg > ULONG_MAX / HZ)
- goto einval_put;
- ax25->t3 = ax25_ctl.arg * HZ;
- break;
-
- case AX25_IDLE:
- if (ax25_ctl.arg > ULONG_MAX / (60 * HZ))
- goto einval_put;
-
- ax25->idle = ax25_ctl.arg * 60 * HZ;
- break;
-
- case AX25_PACLEN:
- if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
- goto einval_put;
- ax25->paclen = ax25_ctl.arg;
- break;
-
- default:
- goto einval_put;
- }
-
-out_put:
- ax25_dev_put(ax25_dev);
- ax25_cb_put(ax25);
- return ret;
-
-einval_put:
- ret = -EINVAL;
- goto out_put;
-}
-
-static void ax25_fillin_cb_from_dev(ax25_cb *ax25, const ax25_dev *ax25_dev)
-{
- ax25->rtt = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]) / 2;
- ax25->t1 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]);
- ax25->t2 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T2]);
- ax25->t3 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T3]);
- ax25->n2 = ax25_dev->values[AX25_VALUES_N2];
- ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN];
- ax25->idle = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_IDLE]);
- ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF];
-
- if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) {
- ax25->modulus = AX25_EMODULUS;
- ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW];
- } else {
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25_dev->values[AX25_VALUES_WINDOW];
- }
-}
-
-/*
- * Fill in a created AX.25 created control block with the default
- * values for a particular device.
- */
-void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev)
-{
- ax25->ax25_dev = ax25_dev;
-
- if (ax25->ax25_dev != NULL) {
- ax25_fillin_cb_from_dev(ax25, ax25_dev);
- return;
- }
-
- /*
- * No device, use kernel / AX.25 spec default values
- */
- ax25->rtt = msecs_to_jiffies(AX25_DEF_T1) / 2;
- ax25->t1 = msecs_to_jiffies(AX25_DEF_T1);
- ax25->t2 = msecs_to_jiffies(AX25_DEF_T2);
- ax25->t3 = msecs_to_jiffies(AX25_DEF_T3);
- ax25->n2 = AX25_DEF_N2;
- ax25->paclen = AX25_DEF_PACLEN;
- ax25->idle = msecs_to_jiffies(AX25_DEF_IDLE);
- ax25->backoff = AX25_DEF_BACKOFF;
-
- if (AX25_DEF_AXDEFMODE) {
- ax25->modulus = AX25_EMODULUS;
- ax25->window = AX25_DEF_EWINDOW;
- } else {
- ax25->modulus = AX25_MODULUS;
- ax25->window = AX25_DEF_WINDOW;
- }
-}
-
-/*
- * Create an empty AX.25 control block.
- */
-ax25_cb *ax25_create_cb(void)
-{
- ax25_cb *ax25;
-
- if ((ax25 = kzalloc_obj(*ax25, GFP_ATOMIC)) == NULL)
- return NULL;
-
- refcount_set(&ax25->refcount, 1);
-
- skb_queue_head_init(&ax25->write_queue);
- skb_queue_head_init(&ax25->frag_queue);
- skb_queue_head_init(&ax25->ack_queue);
- skb_queue_head_init(&ax25->reseq_queue);
-
- ax25_setup_timers(ax25);
-
- ax25_fillin_cb(ax25, NULL);
-
- ax25->state = AX25_STATE_0;
-
- return ax25;
-}
-
-/*
- * Handling for system calls applied via the various interfaces to an
- * AX25 socket object
- */
-
-static int ax25_setsockopt(struct socket *sock, int level, int optname,
- sockptr_t optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- ax25_cb *ax25;
- struct net_device *dev;
- char devname[IFNAMSIZ];
- unsigned int opt;
- int res = 0;
-
- if (level != SOL_AX25)
- return -ENOPROTOOPT;
-
- if (optlen < sizeof(unsigned int))
- return -EINVAL;
-
- if (copy_from_sockptr(&opt, optval, sizeof(unsigned int)))
- return -EFAULT;
-
- lock_sock(sk);
- ax25 = sk_to_ax25(sk);
-
- switch (optname) {
- case AX25_WINDOW:
- if (ax25->modulus == AX25_MODULUS) {
- if (opt < 1 || opt > 7) {
- res = -EINVAL;
- break;
- }
- } else {
- if (opt < 1 || opt > 63) {
- res = -EINVAL;
- break;
- }
- }
- ax25->window = opt;
- break;
-
- case AX25_T1:
- if (opt < 1 || opt > UINT_MAX / HZ) {
- res = -EINVAL;
- break;
- }
- ax25->rtt = (opt * HZ) >> 1;
- ax25->t1 = opt * HZ;
- break;
-
- case AX25_T2:
- if (opt < 1 || opt > UINT_MAX / HZ) {
- 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 || opt > UINT_MAX / HZ) {
- res = -EINVAL;
- break;
- }
- ax25->t3 = opt * HZ;
- break;
-
- case AX25_IDLE:
- if (opt > UINT_MAX / (60 * HZ)) {
- res = -EINVAL;
- break;
- }
- ax25->idle = opt * 60 * HZ;
- break;
-
- case AX25_BACKOFF:
- if (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 - 1)
- optlen = IFNAMSIZ - 1;
-
- memset(devname, 0, sizeof(devname));
-
- if (copy_from_sockptr(devname, optval, optlen)) {
- res = -EFAULT;
- break;
- }
-
- if (sk->sk_type == SOCK_SEQPACKET &&
- (sock->state != SS_UNCONNECTED ||
- sk->sk_state == TCP_LISTEN)) {
- res = -EADDRNOTAVAIL;
- break;
- }
-
- rcu_read_lock();
- dev = dev_get_by_name_rcu(&init_net, devname);
- if (!dev) {
- rcu_read_unlock();
- res = -ENODEV;
- break;
- }
-
- if (ax25->ax25_dev) {
- if (dev == ax25->ax25_dev->dev) {
- rcu_read_unlock();
- break;
- }
- netdev_put(ax25->ax25_dev->dev, &ax25->dev_tracker);
- ax25_dev_put(ax25->ax25_dev);
- }
-
- ax25->ax25_dev = ax25_dev_ax25dev(dev);
- if (!ax25->ax25_dev) {
- rcu_read_unlock();
- res = -ENODEV;
- break;
- }
- ax25_fillin_cb(ax25, ax25->ax25_dev);
- netdev_hold(dev, &ax25->dev_tracker, GFP_ATOMIC);
- ax25_dev_hold(ax25->ax25_dev);
- rcu_read_unlock();
- break;
-
- default:
- res = -ENOPROTOOPT;
- }
- release_sock(sk);
-
- return res;
-}
-
-static int ax25_getsockopt(struct socket *sock, int level, int optname,
- char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- ax25_cb *ax25;
- struct ax25_dev *ax25_dev;
- char devname[IFNAMSIZ];
- void *valptr;
- int val = 0;
- int maxlen, length;
-
- if (level != SOL_AX25)
- return -ENOPROTOOPT;
-
- if (get_user(maxlen, optlen))
- return -EFAULT;
-
- if (maxlen < 1)
- return -EFAULT;
-
- valptr = &val;
- length = min_t(unsigned int, maxlen, sizeof(int));
-
- lock_sock(sk);
- ax25 = sk_to_ax25(sk);
-
- switch (optname) {
- case AX25_WINDOW:
- val = ax25->window;
- break;
-
- case AX25_T1:
- val = ax25->t1 / HZ;
- break;
-
- case AX25_T2:
- val = ax25->t2 / HZ;
- break;
-
- case AX25_N2:
- val = ax25->n2;
- break;
-
- case AX25_T3:
- val = ax25->t3 / HZ;
- break;
-
- case AX25_IDLE:
- val = ax25->idle / (60 * HZ);
- break;
-
- case AX25_BACKOFF:
- val = ax25->backoff;
- break;
-
- case AX25_EXTSEQ:
- val = (ax25->modulus == AX25_EMODULUS);
- break;
-
- case AX25_PIDINCL:
- val = ax25->pidincl;
- 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) {
- strscpy(devname, ax25_dev->dev->name, sizeof(devname));
- length = strlen(devname) + 1;
- } else {
- *devname = '\0';
- length = 1;
- }
-
- valptr = devname;
- break;
-
- default:
- release_sock(sk);
- return -ENOPROTOOPT;
- }
- release_sock(sk);
-
- if (put_user(length, optlen))
- return -EFAULT;
-
- return copy_to_user(optval, valptr, length) ? -EFAULT : 0;
-}
-
-static int ax25_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = sock->sk;
- int res = 0;
-
- lock_sock(sk);
- if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_LISTEN) {
- sk->sk_max_ack_backlog = backlog;
- sk->sk_state = TCP_LISTEN;
- goto out;
- }
- res = -EOPNOTSUPP;
-
-out:
- release_sock(sk);
-
- return res;
-}
-
-/*
- * XXX: when creating ax25_sock we should update the .obj_size setting
- * below.
- */
-static struct proto ax25_proto = {
- .name = "AX25",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct ax25_sock),
-};
-
-static int ax25_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
- ax25_cb *ax25;
-
- if (protocol < 0 || protocol > U8_MAX)
- return -EINVAL;
-
- if (!net_eq(net, &init_net))
- return -EAFNOSUPPORT;
-
- switch (sock->type) {
- 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 AX25_P_SEGMENT:
-#ifdef CONFIG_INET
- case AX25_P_ARP:
- case AX25_P_IP:
-#endif
-#ifdef CONFIG_NETROM
- case AX25_P_NETROM:
-#endif
-#ifdef CONFIG_ROSE
- case AX25_P_ROSE:
-#endif
- return -ESOCKTNOSUPPORT;
-#ifdef CONFIG_NETROM_MODULE
- case AX25_P_NETROM:
- if (ax25_protocol_is_registered(AX25_P_NETROM))
- return -ESOCKTNOSUPPORT;
- break;
-#endif
-#ifdef CONFIG_ROSE_MODULE
- case AX25_P_ROSE:
- if (ax25_protocol_is_registered(AX25_P_ROSE))
- return -ESOCKTNOSUPPORT;
- break;
-#endif
- default:
- break;
- }
- break;
-
- case SOCK_RAW:
- if (!capable(CAP_NET_RAW))
- return -EPERM;
- break;
- default:
- return -ESOCKTNOSUPPORT;
- }
-
- sk = sk_alloc(net, PF_AX25, GFP_ATOMIC, &ax25_proto, kern);
- if (sk == NULL)
- return -ENOMEM;
-
- ax25 = ax25_sk(sk)->cb = ax25_create_cb();
- if (!ax25) {
- sk_free(sk);
- return -ENOMEM;
- }
-
- sock_init_data(sock, sk);
-
- sk->sk_destruct = ax25_free_sock;
- sock->ops = &ax25_proto_ops;
- sk->sk_protocol = protocol;
-
- ax25->sk = sk;
-
- return 0;
-}
-
-struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
-{
- struct sock *sk;
- ax25_cb *ax25, *oax25;
-
- sk = sk_alloc(sock_net(osk), PF_AX25, GFP_ATOMIC, osk->sk_prot, 0);
- if (sk == NULL)
- return NULL;
-
- if ((ax25 = ax25_create_cb()) == NULL) {
- sk_free(sk);
- return NULL;
- }
-
- switch (osk->sk_type) {
- case SOCK_DGRAM:
- break;
- case SOCK_SEQPACKET:
- break;
- default:
- sk_free(sk);
- ax25_cb_put(ax25);
- return NULL;
- }
-
- sock_init_data(NULL, sk);
-
- sk->sk_type = osk->sk_type;
- sk->sk_priority = READ_ONCE(osk->sk_priority);
- sk->sk_protocol = osk->sk_protocol;
- sk->sk_rcvbuf = osk->sk_rcvbuf;
- sk->sk_sndbuf = osk->sk_sndbuf;
- sk->sk_state = TCP_ESTABLISHED;
- sock_copy_flags(sk, osk);
-
- oax25 = sk_to_ax25(osk);
-
- ax25->modulus = oax25->modulus;
- ax25->backoff = oax25->backoff;
- ax25->pidincl = oax25->pidincl;
- ax25->iamdigi = oax25->iamdigi;
- ax25->rtt = oax25->rtt;
- ax25->t1 = oax25->t1;
- ax25->t2 = oax25->t2;
- ax25->t3 = oax25->t3;
- ax25->n2 = oax25->n2;
- ax25->idle = oax25->idle;
- ax25->paclen = oax25->paclen;
- ax25->window = oax25->window;
-
- ax25->ax25_dev = ax25_dev;
- ax25->source_addr = oax25->source_addr;
-
- if (oax25->digipeat != NULL) {
- ax25->digipeat = kmemdup(oax25->digipeat, sizeof(ax25_digi),
- GFP_ATOMIC);
- if (ax25->digipeat == NULL) {
- sk_free(sk);
- ax25_cb_put(ax25);
- return NULL;
- }
- }
-
- ax25_sk(sk)->cb = ax25;
- sk->sk_destruct = ax25_free_sock;
- ax25->sk = sk;
-
- return sk;
-}
-
-static int ax25_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
- ax25_cb *ax25;
- ax25_dev *ax25_dev;
-
- if (sk == NULL)
- return 0;
-
- sock_hold(sk);
- lock_sock(sk);
- sock_orphan(sk);
- ax25 = sk_to_ax25(sk);
- ax25_dev = ax25->ax25_dev;
-
- if (sk->sk_type == SOCK_SEQPACKET) {
- switch (ax25->state) {
- case AX25_STATE_0:
- if (!sock_flag(ax25->sk, SOCK_DEAD)) {
- release_sock(sk);
- ax25_disconnect(ax25, 0);
- lock_sock(sk);
- }
- ax25_destroy_socket(ax25);
- break;
-
- case AX25_STATE_1:
- case AX25_STATE_2:
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- release_sock(sk);
- ax25_disconnect(ax25, 0);
- lock_sock(sk);
- if (!sock_flag(ax25->sk, SOCK_DESTROY))
- 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;
-#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->sk_state = TCP_CLOSE;
- sk->sk_shutdown |= SEND_SHUTDOWN;
- sk->sk_state_change(sk);
- sock_set_flag(sk, SOCK_DESTROY);
- break;
-
- default:
- break;
- }
- } else {
- sk->sk_state = TCP_CLOSE;
- sk->sk_shutdown |= SEND_SHUTDOWN;
- sk->sk_state_change(sk);
- ax25_destroy_socket(ax25);
- }
- if (ax25_dev) {
- if (!ax25_dev->device_up) {
- timer_delete_sync(&ax25->timer);
- timer_delete_sync(&ax25->t1timer);
- timer_delete_sync(&ax25->t2timer);
- timer_delete_sync(&ax25->t3timer);
- timer_delete_sync(&ax25->idletimer);
- }
- netdev_put(ax25_dev->dev, &ax25->dev_tracker);
- ax25_dev_put(ax25_dev);
- }
-
- sock->sk = NULL;
- release_sock(sk);
- sock_put(sk);
-
- return 0;
-}
-
-/*
- * 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
- * and trivially backward compatible.
- */
-static int ax25_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len)
-{
- struct sock *sk = sock->sk;
- struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
- ax25_dev *ax25_dev = NULL;
- ax25_uid_assoc *user;
- ax25_address call;
- ax25_cb *ax25;
- int err = 0;
-
- if (addr_len != sizeof(struct sockaddr_ax25) &&
- addr_len != sizeof(struct full_sockaddr_ax25))
- /* support for old structure may go away some time
- * ax25_bind(): uses old (6 digipeater) socket structure.
- */
- if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
- (addr_len > sizeof(struct full_sockaddr_ax25)))
- return -EINVAL;
-
- if (addr->fsa_ax25.sax25_family != AF_AX25)
- return -EINVAL;
-
- user = ax25_findbyuid(current_euid());
- if (user) {
- call = user->call;
- ax25_uid_put(user);
- } else {
- if (ax25_uid_policy && !capable(CAP_NET_ADMIN))
- return -EACCES;
-
- call = addr->fsa_ax25.sax25_call;
- }
-
- lock_sock(sk);
-
- ax25 = sk_to_ax25(sk);
- if (!sock_flag(sk, SOCK_ZAPPED)) {
- err = -EINVAL;
- goto out;
- }
-
- ax25->source_addr = call;
-
- /*
- * 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) {
- err = -EADDRNOTAVAIL;
- goto out;
- }
- } else {
- if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) {
- err = -EADDRNOTAVAIL;
- goto out;
- }
- }
-
- if (ax25_dev) {
- ax25_fillin_cb(ax25, ax25_dev);
- netdev_hold(ax25_dev->dev, &ax25->dev_tracker, GFP_ATOMIC);
- }
-
-done:
- ax25_cb_add(ax25);
- sock_reset_flag(sk, SOCK_ZAPPED);
-
-out:
- release_sock(sk);
-
- return err;
-}
-
-/*
- * FIXME: nonblock behaviour looks like it may have a bug.
- */
-static int __must_check ax25_connect(struct socket *sock,
- struct sockaddr_unsized *uaddr, int addr_len, int flags)
-{
- struct sock *sk = sock->sk;
- ax25_cb *ax25 = sk_to_ax25(sk), *ax25t;
- struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
- ax25_digi *digi = NULL;
- int ct = 0, err = 0;
-
- /*
- * some sanity checks. code further down depends on this
- */
-
- if (addr_len == sizeof(struct sockaddr_ax25))
- /* support for this will go away in early 2.5.x
- * ax25_connect(): uses obsolete socket structure
- */
- ;
- else if (addr_len != sizeof(struct full_sockaddr_ax25))
- /* support for old structure may go away some time
- * ax25_connect(): uses old (6 digipeater) socket structure.
- */
- if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
- (addr_len > sizeof(struct full_sockaddr_ax25)))
- return -EINVAL;
-
-
- if (fsa->fsa_ax25.sax25_family != AF_AX25)
- return -EINVAL;
-
- lock_sock(sk);
-
- /* deal with restarts */
- if (sock->state == SS_CONNECTING) {
- switch (sk->sk_state) {
- case TCP_SYN_SENT: /* still trying */
- err = -EINPROGRESS;
- goto out_release;
-
- case TCP_ESTABLISHED: /* connection established */
- sock->state = SS_CONNECTED;
- goto out_release;
-
- case TCP_CLOSE: /* connection refused */
- sock->state = SS_UNCONNECTED;
- err = -ECONNREFUSED;
- goto out_release;
- }
- }
-
- if (sk->sk_state == TCP_ESTABLISHED && sk->sk_type == SOCK_SEQPACKET) {
- err = -EISCONN; /* No reconnect on a seqpacket socket */
- goto out_release;
- }
-
- sk->sk_state = TCP_CLOSE;
- sock->state = SS_UNCONNECTED;
-
- 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) {
- /* Valid number of digipeaters ? */
- if (fsa->fsa_ax25.sax25_ndigis < 1 ||
- fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS ||
- addr_len < sizeof(struct sockaddr_ax25) +
- sizeof(ax25_address) * fsa->fsa_ax25.sax25_ndigis) {
- err = -EINVAL;
- goto out_release;
- }
-
- if ((digi = kmalloc_obj(ax25_digi)) == NULL) {
- err = -ENOBUFS;
- goto out_release;
- }
-
- digi->ndigi = fsa->fsa_ax25.sax25_ndigis;
- digi->lastrepeat = -1;
-
- while (ct < fsa->fsa_ax25.sax25_ndigis) {
- if ((fsa->fsa_digipeater[ct].ax25_call[6] &
- AX25_HBIT) && ax25->iamdigi) {
- digi->repeated[ct] = 1;
- digi->lastrepeat = ct;
- } else {
- digi->repeated[ct] = 0;
- }
- digi->calls[ct] = fsa->fsa_digipeater[ct];
- ct++;
- }
- }
-
- /* Must bind first - autobinding does not work. */
- if (sock_flag(sk, SOCK_ZAPPED)) {
- kfree(digi);
- err = -EINVAL;
- goto out_release;
- }
-
- /* Check to see if the device has been filled in, error if it hasn't. */
- if (ax25->ax25_dev == NULL) {
- kfree(digi);
- err = -EHOSTUNREACH;
- goto out_release;
- }
-
- if (sk->sk_type == SOCK_SEQPACKET &&
- (ax25t=ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi,
- ax25->ax25_dev->dev))) {
- kfree(digi);
- err = -EADDRINUSE; /* Already such a connection */
- ax25_cb_put(ax25t);
- goto out_release;
- }
-
- ax25->dest_addr = fsa->fsa_ax25.sax25_call;
- ax25->digipeat = digi;
-
- /* First the easy one */
- if (sk->sk_type != SOCK_SEQPACKET) {
- sock->state = SS_CONNECTED;
- sk->sk_state = TCP_ESTABLISHED;
- goto out_release;
- }
-
- /* Move to connecting socket, ax.25 lapb WAIT_UA.. */
- sock->state = SS_CONNECTING;
- sk->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;
-
-#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;
-#endif
- }
-
- ax25->state = AX25_STATE_1;
-
- ax25_start_heartbeat(ax25);
-
- /* Now the loop */
- if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
- err = -EINPROGRESS;
- goto out_release;
- }
-
- if (sk->sk_state == TCP_SYN_SENT) {
- DEFINE_WAIT(wait);
-
- for (;;) {
- prepare_to_wait(sk_sleep(sk), &wait,
- TASK_INTERRUPTIBLE);
- if (sk->sk_state != TCP_SYN_SENT)
- break;
- if (!signal_pending(current)) {
- release_sock(sk);
- schedule();
- lock_sock(sk);
- continue;
- }
- err = -ERESTARTSYS;
- break;
- }
- finish_wait(sk_sleep(sk), &wait);
-
- if (err)
- goto out_release;
- }
-
- if (sk->sk_state != TCP_ESTABLISHED) {
- /* Not in ABM, not in WAIT_UA -> failed */
- sock->state = SS_UNCONNECTED;
- err = sock_error(sk); /* Always set at this point */
- goto out_release;
- }
-
- sock->state = SS_CONNECTED;
-
- err = 0;
-out_release:
- release_sock(sk);
-
- return err;
-}
-
-static int ax25_accept(struct socket *sock, struct socket *newsock,
- struct proto_accept_arg *arg)
-{
- struct sk_buff *skb;
- struct sock *newsk;
- ax25_dev *ax25_dev;
- DEFINE_WAIT(wait);
- struct sock *sk;
- ax25_cb *ax25;
- int err = 0;
-
- if (sock->state != SS_UNCONNECTED)
- return -EINVAL;
-
- if ((sk = sock->sk) == NULL)
- return -EINVAL;
-
- lock_sock(sk);
- if (sk->sk_type != SOCK_SEQPACKET) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (sk->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
- */
- for (;;) {
- prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
- skb = skb_dequeue(&sk->sk_receive_queue);
- if (skb)
- break;
-
- if (arg->flags & O_NONBLOCK) {
- err = -EWOULDBLOCK;
- break;
- }
- if (!signal_pending(current)) {
- release_sock(sk);
- schedule();
- lock_sock(sk);
- continue;
- }
- err = -ERESTARTSYS;
- break;
- }
- finish_wait(sk_sleep(sk), &wait);
-
- if (err)
- goto out;
-
- newsk = skb->sk;
- sock_graft(newsk, newsock);
-
- /* Now attach up the new socket */
- kfree_skb(skb);
- sk_acceptq_removed(sk);
- newsock->state = SS_CONNECTED;
- ax25 = sk_to_ax25(newsk);
- ax25_dev = ax25->ax25_dev;
- netdev_hold(ax25_dev->dev, &ax25->dev_tracker, GFP_ATOMIC);
- ax25_dev_hold(ax25_dev);
-
-out:
- release_sock(sk);
-
- return err;
-}
-
-static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
- int peer)
-{
- 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;
-
- memset(fsa, 0, sizeof(*fsa));
- lock_sock(sk);
- ax25 = sk_to_ax25(sk);
-
- if (peer != 0) {
- if (sk->sk_state != TCP_ESTABLISHED) {
- err = -ENOTCONN;
- goto out;
- }
-
- fsa->fsa_ax25.sax25_family = AF_AX25;
- fsa->fsa_ax25.sax25_call = ax25->dest_addr;
-
- if (ax25->digipeat != NULL) {
- ndigi = ax25->digipeat->ndigi;
- fsa->fsa_ax25.sax25_ndigis = ndigi;
- for (i = 0; i < ndigi; i++)
- fsa->fsa_digipeater[i] =
- ax25->digipeat->calls[i];
- }
- } else {
- fsa->fsa_ax25.sax25_family = AF_AX25;
- fsa->fsa_ax25.sax25_call = ax25->source_addr;
- fsa->fsa_ax25.sax25_ndigis = 1;
- if (ax25->ax25_dev != NULL) {
- memcpy(&fsa->fsa_digipeater[0],
- ax25->ax25_dev->dev->dev_addr, AX25_ADDR_LEN);
- } else {
- fsa->fsa_digipeater[0] = null_ax25_address;
- }
- }
- err = sizeof (struct full_sockaddr_ax25);
-
-out:
- release_sock(sk);
-
- return err;
-}
-
-static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
-{
- DECLARE_SOCKADDR(struct sockaddr_ax25 *, usax, msg->msg_name);
- struct sock *sk = sock->sk;
- struct sockaddr_ax25 sax;
- struct sk_buff *skb;
- ax25_digi dtmp, *dp;
- ax25_cb *ax25;
- size_t size;
- int lv, err, addr_len = msg->msg_namelen;
-
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT))
- return -EINVAL;
-
- lock_sock(sk);
- ax25 = sk_to_ax25(sk);
-
- if (sock_flag(sk, SOCK_ZAPPED)) {
- err = -EADDRNOTAVAIL;
- goto out;
- }
-
- if (sk->sk_shutdown & SEND_SHUTDOWN) {
- send_sig(SIGPIPE, current, 0);
- err = -EPIPE;
- goto out;
- }
-
- if (ax25->ax25_dev == NULL) {
- err = -ENETUNREACH;
- goto out;
- }
-
- if (len > ax25->ax25_dev->dev->mtu) {
- err = -EMSGSIZE;
- goto out;
- }
-
- if (usax != NULL) {
- if (usax->sax25_family != AF_AX25) {
- err = -EINVAL;
- goto out;
- }
-
- if (addr_len == sizeof(struct sockaddr_ax25))
- /* ax25_sendmsg(): uses obsolete socket structure */
- ;
- else if (addr_len != sizeof(struct full_sockaddr_ax25))
- /* support for old structure may go away some time
- * ax25_sendmsg(): uses old (6 digipeater)
- * socket structure.
- */
- if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
- (addr_len > sizeof(struct full_sockaddr_ax25))) {
- err = -EINVAL;
- goto out;
- }
-
-
- if (addr_len > sizeof(struct sockaddr_ax25) && usax->sax25_ndigis != 0) {
- int ct = 0;
- 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 ||
- addr_len < sizeof(struct sockaddr_ax25) +
- sizeof(ax25_address) * usax->sax25_ndigis) {
- err = -EINVAL;
- goto out;
- }
-
- dtmp.ndigi = usax->sax25_ndigis;
-
- while (ct < usax->sax25_ndigis) {
- dtmp.repeated[ct] = 0;
- dtmp.calls[ct] = fsa->fsa_digipeater[ct];
- ct++;
- }
-
- dtmp.lastrepeat = 0;
- }
-
- sax = *usax;
- if (sk->sk_type == SOCK_SEQPACKET &&
- ax25cmp(&ax25->dest_addr, &sax.sax25_call)) {
- err = -EISCONN;
- goto out;
- }
- if (usax->sax25_ndigis == 0)
- dp = NULL;
- else
- dp = &dtmp;
- } else {
- /*
- * FIXME: 1003.1g - if the socket is like this because
- * it has become closed (not started closed) and is VC
- * we ought to SIGPIPE, EPIPE
- */
- if (sk->sk_state != TCP_ESTABLISHED) {
- err = -ENOTCONN;
- goto out;
- }
- sax.sax25_family = AF_AX25;
- sax.sax25_call = ax25->dest_addr;
- dp = ax25->digipeat;
- }
-
- /* Build a packet */
- /* Assume the worst case */
- size = len + ax25->ax25_dev->dev->hard_header_len;
-
- skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, &err);
- if (skb == NULL)
- goto out;
-
- skb_reserve(skb, size - len);
-
- /* User data follows immediately after the AX.25 data */
- if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
- err = -EFAULT;
- kfree_skb(skb);
- goto out;
- }
-
- skb_reset_network_header(skb);
-
- /* Add the PID if one is not supplied by the user in the skb */
- if (!ax25->pidincl)
- *(u8 *)skb_push(skb, 1) = sk->sk_protocol;
-
- if (sk->sk_type == SOCK_SEQPACKET) {
- /* Connected mode sockets go via the LAPB machine */
- if (sk->sk_state != TCP_ESTABLISHED) {
- kfree_skb(skb);
- err = -ENOTCONN;
- goto out;
- }
-
- /* Shove it onto the queue and kick */
- ax25_output(ax25, ax25->paclen, skb);
-
- err = len;
- goto out;
- }
-
- skb_push(skb, 1 + ax25_addr_size(dp));
-
- /* Building AX.25 Header */
-
- /* Build an AX.25 header */
- lv = ax25_addr_build(skb->data, &ax25->source_addr, &sax.sax25_call,
- dp, AX25_COMMAND, AX25_MODULUS);
-
- skb_set_transport_header(skb, lv);
-
- *skb_transport_header(skb) = AX25_UI;
-
- /* Datagram frames go straight out of the door as UI */
- ax25_queue_xmit(skb, ax25->ax25_dev->dev);
-
- err = len;
-
-out:
- release_sock(sk);
-
- return err;
-}
-
-static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
- int flags)
-{
- struct sock *sk = sock->sk;
- struct sk_buff *skb, *last;
- struct sk_buff_head *sk_queue;
- int copied;
- int err = 0;
- int off = 0;
- long timeo;
-
- 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->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_ESTABLISHED) {
- err = -ENOTCONN;
- goto out;
- }
-
- /* We need support for non-blocking reads. */
- sk_queue = &sk->sk_receive_queue;
- skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off, &err, &last);
- /* If no packet is available, release_sock(sk) and try again. */
- if (!skb) {
- if (err != -EAGAIN)
- goto out;
- release_sock(sk);
- timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
- while (timeo && !__skb_wait_for_more_packets(sk, sk_queue, &err,
- &timeo, last)) {
- skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off,
- &err, &last);
- if (skb)
- break;
-
- if (err != -EAGAIN)
- goto done;
- }
- if (!skb)
- goto done;
- lock_sock(sk);
- }
-
- if (!sk_to_ax25(sk)->pidincl)
- skb_pull(skb, 1); /* Remove PID */
-
- skb_reset_transport_header(skb);
- copied = skb->len;
-
- if (copied > size) {
- copied = size;
- msg->msg_flags |= MSG_TRUNC;
- }
-
- skb_copy_datagram_msg(skb, 0, msg, copied);
-
- if (msg->msg_name) {
- ax25_digi digi;
- ax25_address src;
- const unsigned char *mac = skb_mac_header(skb);
- DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name);
-
- memset(sax, 0, sizeof(struct full_sockaddr_ax25));
- ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL,
- &digi, NULL, NULL);
- sax->sax25_family = AF_AX25;
- /* We set this correctly, even though we may not let the
- application know the digi calls further down (because it
- did NOT ask to know them). This could get political... **/
- sax->sax25_ndigis = digi.ndigi;
- sax->sax25_call = src;
-
- if (sax->sax25_ndigis != 0) {
- int ct;
- struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)sax;
-
- for (ct = 0; ct < digi.ndigi; ct++)
- fsa->fsa_digipeater[ct] = digi.calls[ct];
- }
- msg->msg_namelen = sizeof(struct full_sockaddr_ax25);
- }
-
- skb_free_datagram(sk, skb);
- err = copied;
-
-out:
- release_sock(sk);
-
-done:
- return err;
-}
-
-static int ax25_shutdown(struct socket *sk, int how)
-{
- /* FIXME - generate DM and RNR states */
- return -EOPNOTSUPP;
-}
-
-static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk = sock->sk;
- void __user *argp = (void __user *)arg;
- int res = 0;
-
- lock_sock(sk);
- switch (cmd) {
- case TIOCOUTQ: {
- long amount;
-
- amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
- if (amount < 0)
- amount = 0;
- res = put_user(amount, (int __user *)argp);
- 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->sk_receive_queue)) != NULL)
- amount = skb->len;
- res = put_user(amount, (int __user *) argp);
- 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, argp, sizeof(sax25))) {
- res = -EFAULT;
- break;
- }
- res = ax25_uid_ioctl(cmd, &sax25);
- break;
- }
-
- case SIOCAX25NOUID: { /* Set the default policy (default/bar) */
- long amount;
- if (!capable(CAP_NET_ADMIN)) {
- res = -EPERM;
- break;
- }
- if (get_user(amount, (long __user *)argp)) {
- res = -EFAULT;
- break;
- }
- if (amount < 0 || amount > AX25_NOUID_BLOCK) {
- res = -EINVAL;
- break;
- }
- ax25_uid_policy = amount;
- res = 0;
- break;
- }
-
- case SIOCADDRT:
- case SIOCDELRT:
- case SIOCAX25OPTRT:
- if (!capable(CAP_NET_ADMIN)) {
- res = -EPERM;
- break;
- }
- res = ax25_rt_ioctl(cmd, argp);
- break;
-
- case SIOCAX25CTLCON:
- if (!capable(CAP_NET_ADMIN)) {
- res = -EPERM;
- break;
- }
- res = ax25_ctl_ioctl(cmd, argp);
- break;
-
- case SIOCAX25GETINFO:
- case SIOCAX25GETINFOOLD: {
- ax25_cb *ax25 = sk_to_ax25(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 = sk_rmem_alloc_get(sk);
- ax25_info.snd_q = sk_wmem_alloc_get(sk);
- 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(argp, &ax25_info, sizeof(struct ax25_info_struct_deprecated))) {
- res = -EFAULT;
- break;
- }
- } else {
- if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct))) {
- res = -EINVAL;
- break;
- }
- }
- res = 0;
- break;
- }
-
- case SIOCAX25ADDFWD:
- case SIOCAX25DELFWD: {
- struct ax25_fwd_struct ax25_fwd;
- if (!capable(CAP_NET_ADMIN)) {
- res = -EPERM;
- break;
- }
- if (copy_from_user(&ax25_fwd, argp, sizeof(ax25_fwd))) {
- res = -EFAULT;
- break;
- }
- res = ax25_fwd_ioctl(cmd, &ax25_fwd);
- break;
- }
-
- 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 = -ENOIOCTLCMD;
- break;
- }
- release_sock(sk);
-
- return res;
-}
-
-#ifdef CONFIG_PROC_FS
-
-static void *ax25_info_start(struct seq_file *seq, loff_t *pos)
- __acquires(ax25_list_lock)
-{
- spin_lock_bh(&ax25_list_lock);
- return seq_hlist_start(&ax25_list, *pos);
-}
-
-static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- return seq_hlist_next(v, &ax25_list, pos);
-}
-
-static void ax25_info_stop(struct seq_file *seq, void *v)
- __releases(ax25_list_lock)
-{
- spin_unlock_bh(&ax25_list_lock);
-}
-
-static int ax25_info_show(struct seq_file *seq, void *v)
-{
- ax25_cb *ax25 = hlist_entry(v, struct ax25_cb, ax25_node);
- char buf[11];
- int k;
-
-
- /*
- * 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
- */
-
- seq_printf(seq, "%p %s %s%s ",
- ax25,
- ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name,
- ax2asc(buf, &ax25->source_addr),
- ax25->iamdigi? "*":"");
- seq_printf(seq, "%s", ax2asc(buf, &ax25->dest_addr));
-
- for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) {
- seq_printf(seq, ",%s%s",
- ax2asc(buf, &ax25->digipeat->calls[k]),
- ax25->digipeat->repeated[k]? "*":"");
- }
-
- seq_printf(seq, " %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,
- ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ,
- ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ,
- ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ,
- ax25_display_timer(&ax25->idletimer) / (60 * HZ),
- ax25->idle / (60 * HZ),
- ax25->n2count, ax25->n2,
- ax25->rtt / HZ,
- ax25->window,
- ax25->paclen);
-
- if (ax25->sk != NULL) {
- seq_printf(seq, " %d %d %llu\n",
- sk_wmem_alloc_get(ax25->sk),
- sk_rmem_alloc_get(ax25->sk),
- sock_i_ino(ax25->sk));
- } else {
- seq_puts(seq, " * * *\n");
- }
- return 0;
-}
-
-static const struct seq_operations ax25_info_seqops = {
- .start = ax25_info_start,
- .next = ax25_info_next,
- .stop = ax25_info_stop,
- .show = ax25_info_show,
-};
-#endif
-
-static const struct net_proto_family ax25_family_ops = {
- .family = PF_AX25,
- .create = ax25_create,
- .owner = THIS_MODULE,
-};
-
-static const struct proto_ops ax25_proto_ops = {
- .family = PF_AX25,
- .owner = THIS_MODULE,
- .release = ax25_release,
- .bind = ax25_bind,
- .connect = ax25_connect,
- .socketpair = sock_no_socketpair,
- .accept = ax25_accept,
- .getname = ax25_getname,
- .poll = datagram_poll,
- .ioctl = ax25_ioctl,
- .gettstamp = sock_gettstamp,
- .listen = ax25_listen,
- .shutdown = ax25_shutdown,
- .setsockopt = ax25_setsockopt,
- .getsockopt = ax25_getsockopt,
- .sendmsg = ax25_sendmsg,
- .recvmsg = ax25_recvmsg,
- .mmap = sock_no_mmap,
-};
-
-/*
- * Called by socket.c on kernel start up
- */
-static struct packet_type ax25_packet_type __read_mostly = {
- .type = cpu_to_be16(ETH_P_AX25),
- .func = ax25_kiss_rcv,
-};
-
-static struct notifier_block ax25_dev_notifier = {
- .notifier_call = ax25_device_event,
-};
-
-static int __init ax25_init(void)
-{
- int rc = proto_register(&ax25_proto, 0);
-
- if (rc != 0)
- goto out;
-
- sock_register(&ax25_family_ops);
- dev_add_pack(&ax25_packet_type);
- register_netdevice_notifier(&ax25_dev_notifier);
-
- proc_create_seq("ax25_route", 0444, init_net.proc_net, &ax25_rt_seqops);
- proc_create_seq("ax25", 0444, init_net.proc_net, &ax25_info_seqops);
- proc_create_seq("ax25_calls", 0444, init_net.proc_net,
- &ax25_uid_seqops);
-out:
- return rc;
-}
-module_init(ax25_init);
-
-
-MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
-MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NETPROTO(PF_AX25);
-
-static void __exit ax25_exit(void)
-{
- remove_proc_entry("ax25_route", init_net.proc_net);
- remove_proc_entry("ax25", init_net.proc_net);
- remove_proc_entry("ax25_calls", init_net.proc_net);
-
- unregister_netdevice_notifier(&ax25_dev_notifier);
-
- dev_remove_pack(&ax25_packet_type);
-
- sock_unregister(PF_AX25);
- proto_unregister(&ax25_proto);
-
- ax25_rt_free();
- ax25_uid_free();
- ax25_dev_free();
-}
-module_exit(ax25_exit);
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
deleted file mode 100644
index f68865a4d0ab..000000000000
--- a/net/ax25/ax25_addr.c
+++ /dev/null
@@ -1,303 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-/*
- * The default broadcast address of an interface is QST-0; the default address
- * is LINUX-1. The null address is defined as a callsign of all spaces with
- * an SSID of zero.
- */
-
-const ax25_address ax25_bcast =
- {{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}};
-const ax25_address ax25_defaddr =
- {{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, 1 << 1}};
-const ax25_address null_ax25_address =
- {{' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}};
-
-EXPORT_SYMBOL_GPL(ax25_bcast);
-EXPORT_SYMBOL_GPL(ax25_defaddr);
-EXPORT_SYMBOL(null_ax25_address);
-
-/*
- * ax25 -> ascii conversion
- */
-char *ax2asc(char *buf, const ax25_address *a)
-{
- char c, *s;
- int n;
-
- for (n = 0, s = buf; n < 6; n++) {
- c = (a->ax25_call[n] >> 1) & 0x7F;
-
- if (c != ' ') *s++ = c;
- }
-
- *s++ = '-';
-
- if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) {
- *s++ = '1';
- n -= 10;
- }
-
- *s++ = n + '0';
- *s++ = '\0';
-
- if (*buf == '\0' || *buf == '-')
- return "*";
-
- return buf;
-
-}
-
-EXPORT_SYMBOL(ax2asc);
-
-/*
- * ascii -> ax25 conversion
- */
-void asc2ax(ax25_address *addr, const char *callsign)
-{
- const char *s;
- int n;
-
- for (s = callsign, n = 0; n < 6; n++) {
- if (*s != '\0' && *s != '-')
- addr->ax25_call[n] = *s++;
- else
- addr->ax25_call[n] = ' ';
- addr->ax25_call[n] <<= 1;
- addr->ax25_call[n] &= 0xFE;
- }
-
- if (*s++ == '\0') {
- addr->ax25_call[6] = 0x00;
- return;
- }
-
- addr->ax25_call[6] = *s++ - '0';
-
- if (*s != '\0') {
- addr->ax25_call[6] *= 10;
- addr->ax25_call[6] += *s++ - '0';
- }
-
- addr->ax25_call[6] <<= 1;
- addr->ax25_call[6] &= 0x1E;
-}
-
-EXPORT_SYMBOL(asc2ax);
-
-/*
- * Compare two ax.25 addresses
- */
-int ax25cmp(const ax25_address *a, const ax25_address *b)
-{
- int ct = 0;
-
- while (ct < 6) {
- if ((a->ax25_call[ct] & 0xFE) != (b->ax25_call[ct] & 0xFE)) /* Clean off repeater bits */
- return 1;
- ct++;
- }
-
- if ((a->ax25_call[ct] & 0x1E) == (b->ax25_call[ct] & 0x1E)) /* SSID without control bit */
- return 0;
-
- return 2; /* Partial match */
-}
-
-EXPORT_SYMBOL(ax25cmp);
-
-/*
- * Compare two AX.25 digipeater paths.
- */
-int ax25digicmp(const ax25_digi *digi1, const ax25_digi *digi2)
-{
- int i;
-
- if (digi1->ndigi != digi2->ndigi)
- return 1;
-
- if (digi1->lastrepeat != digi2->lastrepeat)
- return 1;
-
- for (i = 0; i < digi1->ndigi; i++)
- if (ax25cmp(&digi1->calls[i], &digi2->calls[i]) != 0)
- return 1;
-
- return 0;
-}
-
-/*
- * Given an AX.25 address pull of to, from, digi list, command/response and the start of data
- *
- */
-const unsigned char *ax25_addr_parse(const unsigned char *buf, int len,
- ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags,
- int *dama)
-{
- int d = 0;
-
- if (len < 14) return NULL;
-
- if (flags != NULL) {
- *flags = 0;
-
- if (buf[6] & AX25_CBIT)
- *flags = AX25_COMMAND;
- if (buf[13] & AX25_CBIT)
- *flags = AX25_RESPONSE;
- }
-
- if (dama != NULL)
- *dama = ~buf[13] & AX25_DAMA_FLAG;
-
- /* Copy to, from */
- if (dest != NULL)
- memcpy(dest, buf + 0, AX25_ADDR_LEN);
- if (src != NULL)
- memcpy(src, buf + 7, AX25_ADDR_LEN);
-
- buf += 2 * AX25_ADDR_LEN;
- len -= 2 * AX25_ADDR_LEN;
-
- digi->lastrepeat = -1;
- digi->ndigi = 0;
-
- while (!(buf[-1] & AX25_EBIT)) {
- if (d >= AX25_MAX_DIGIS)
- return NULL;
- if (len < AX25_ADDR_LEN)
- return NULL;
-
- memcpy(&digi->calls[d], buf, AX25_ADDR_LEN);
- digi->ndigi = d + 1;
-
- if (buf[6] & AX25_HBIT) {
- digi->repeated[d] = 1;
- digi->lastrepeat = d;
- } else {
- digi->repeated[d] = 0;
- }
-
- buf += AX25_ADDR_LEN;
- len -= AX25_ADDR_LEN;
- d++;
- }
-
- return buf;
-}
-
-/*
- * Assemble an AX.25 header from the bits
- */
-int ax25_addr_build(unsigned char *buf, const ax25_address *src,
- const ax25_address *dest, const ax25_digi *d, int flag, int modulus)
-{
- int len = 0;
- int ct = 0;
-
- memcpy(buf, dest, AX25_ADDR_LEN);
- buf[6] &= ~(AX25_EBIT | AX25_CBIT);
- buf[6] |= AX25_SSSID_SPARE;
-
- if (flag == AX25_COMMAND) buf[6] |= AX25_CBIT;
-
- buf += AX25_ADDR_LEN;
- len += AX25_ADDR_LEN;
-
- memcpy(buf, src, AX25_ADDR_LEN);
- buf[6] &= ~(AX25_EBIT | AX25_CBIT);
- buf[6] &= ~AX25_SSSID_SPARE;
-
- if (modulus == AX25_MODULUS)
- buf[6] |= AX25_SSSID_SPARE;
- else
- buf[6] |= AX25_ESSID_SPARE;
-
- if (flag == AX25_RESPONSE) buf[6] |= AX25_CBIT;
-
- /*
- * Fast path the normal digiless path
- */
- if (d == NULL || d->ndigi == 0) {
- buf[6] |= AX25_EBIT;
- return 2 * AX25_ADDR_LEN;
- }
-
- buf += AX25_ADDR_LEN;
- len += AX25_ADDR_LEN;
-
- while (ct < d->ndigi) {
- memcpy(buf, &d->calls[ct], AX25_ADDR_LEN);
-
- if (d->repeated[ct])
- buf[6] |= AX25_HBIT;
- else
- buf[6] &= ~AX25_HBIT;
-
- buf[6] &= ~AX25_EBIT;
- buf[6] |= AX25_SSSID_SPARE;
-
- buf += AX25_ADDR_LEN;
- len += AX25_ADDR_LEN;
- ct++;
- }
-
- buf[-1] |= AX25_EBIT;
-
- return len;
-}
-
-int ax25_addr_size(const ax25_digi *dp)
-{
- if (dp == NULL)
- return 2 * AX25_ADDR_LEN;
-
- return AX25_ADDR_LEN * (2 + dp->ndigi);
-}
-
-/*
- * Reverse Digipeat List. May not pass both parameters as same struct
- */
-void ax25_digi_invert(const ax25_digi *in, ax25_digi *out)
-{
- int ct;
-
- out->ndigi = in->ndigi;
- out->lastrepeat = in->ndigi - in->lastrepeat - 2;
-
- /* Invert the digipeaters */
- for (ct = 0; ct < in->ndigi; ct++) {
- out->calls[ct] = in->calls[in->ndigi - ct - 1];
-
- if (ct <= out->lastrepeat) {
- out->calls[ct].ax25_call[6] |= AX25_HBIT;
- out->repeated[ct] = 1;
- } else {
- out->calls[ct].ax25_call[6] &= ~AX25_HBIT;
- out->repeated[ct] = 0;
- }
- }
-}
diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c
deleted file mode 100644
index 3c0544fc4ad5..000000000000
--- a/net/ax25/ax25_dev.c
+++ /dev/null
@@ -1,200 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/slab.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#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>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-
-static LIST_HEAD(ax25_dev_list);
-DEFINE_SPINLOCK(ax25_dev_lock);
-
-ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
-{
- ax25_dev *ax25_dev, *res = NULL;
-
- spin_lock_bh(&ax25_dev_lock);
- list_for_each_entry(ax25_dev, &ax25_dev_list, list)
- if (ax25cmp(addr, (const ax25_address *)ax25_dev->dev->dev_addr) == 0) {
- res = ax25_dev;
- ax25_dev_hold(ax25_dev);
- break;
- }
- spin_unlock_bh(&ax25_dev_lock);
-
- return res;
-}
-
-/*
- * This is called when an interface is brought up. These are
- * reasonable defaults.
- */
-void ax25_dev_device_up(struct net_device *dev)
-{
- ax25_dev *ax25_dev;
-
- ax25_dev = kzalloc_obj(*ax25_dev);
- if (!ax25_dev) {
- printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n");
- return;
- }
-
- refcount_set(&ax25_dev->refcount, 1);
- ax25_dev->dev = dev;
- netdev_hold(dev, &ax25_dev->dev_tracker, GFP_KERNEL);
- ax25_dev->forward = NULL;
- ax25_dev->device_up = true;
-
- ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
- ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE;
- ax25_dev->values[AX25_VALUES_BACKOFF] = AX25_DEF_BACKOFF;
- ax25_dev->values[AX25_VALUES_CONMODE] = AX25_DEF_CONMODE;
- ax25_dev->values[AX25_VALUES_WINDOW] = AX25_DEF_WINDOW;
- ax25_dev->values[AX25_VALUES_EWINDOW] = AX25_DEF_EWINDOW;
- ax25_dev->values[AX25_VALUES_T1] = AX25_DEF_T1;
- ax25_dev->values[AX25_VALUES_T2] = AX25_DEF_T2;
- ax25_dev->values[AX25_VALUES_T3] = AX25_DEF_T3;
- ax25_dev->values[AX25_VALUES_IDLE] = AX25_DEF_IDLE;
- ax25_dev->values[AX25_VALUES_N2] = AX25_DEF_N2;
- ax25_dev->values[AX25_VALUES_PACLEN] = AX25_DEF_PACLEN;
- ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL;
-
-#ifdef CONFIG_AX25_DAMA_SLAVE
- ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT;
-
- ax25_ds_setup_timer(ax25_dev);
-#endif
-
- spin_lock_bh(&ax25_dev_lock);
- list_add(&ax25_dev->list, &ax25_dev_list);
- rcu_assign_pointer(dev->ax25_ptr, ax25_dev);
- spin_unlock_bh(&ax25_dev_lock);
-
- ax25_register_dev_sysctl(ax25_dev);
-}
-
-void ax25_dev_device_down(struct net_device *dev)
-{
- ax25_dev *s, *ax25_dev;
-
- if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
- return;
-
- ax25_unregister_dev_sysctl(ax25_dev);
-
- spin_lock_bh(&ax25_dev_lock);
-
-#ifdef CONFIG_AX25_DAMA_SLAVE
- timer_shutdown_sync(&ax25_dev->dama.slave_timer);
-#endif
-
- /*
- * Remove any packet forwarding that points to this device.
- */
- list_for_each_entry(s, &ax25_dev_list, list)
- if (s->forward == dev)
- s->forward = NULL;
-
- list_for_each_entry(s, &ax25_dev_list, list) {
- if (s == ax25_dev) {
- list_del(&s->list);
- break;
- }
- }
-
- RCU_INIT_POINTER(dev->ax25_ptr, NULL);
- spin_unlock_bh(&ax25_dev_lock);
- netdev_put(dev, &ax25_dev->dev_tracker);
- ax25_dev_put(ax25_dev);
-}
-
-int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
-{
- ax25_dev *ax25_dev, *fwd_dev;
-
- if ((ax25_dev = ax25_addr_ax25dev(&fwd->port_from)) == NULL)
- return -EINVAL;
-
- switch (cmd) {
- case SIOCAX25ADDFWD:
- fwd_dev = ax25_addr_ax25dev(&fwd->port_to);
- if (!fwd_dev) {
- ax25_dev_put(ax25_dev);
- return -EINVAL;
- }
- if (ax25_dev->forward) {
- ax25_dev_put(fwd_dev);
- ax25_dev_put(ax25_dev);
- return -EINVAL;
- }
- ax25_dev->forward = fwd_dev->dev;
- ax25_dev_put(fwd_dev);
- ax25_dev_put(ax25_dev);
- break;
-
- case SIOCAX25DELFWD:
- if (!ax25_dev->forward) {
- ax25_dev_put(ax25_dev);
- return -EINVAL;
- }
- ax25_dev->forward = NULL;
- ax25_dev_put(ax25_dev);
- break;
-
- default:
- ax25_dev_put(ax25_dev);
- return -EINVAL;
- }
-
- return 0;
-}
-
-struct net_device *ax25_fwd_dev(struct net_device *dev)
-{
- ax25_dev *ax25_dev;
-
- if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
- return dev;
-
- if (ax25_dev->forward == NULL)
- return dev;
-
- return ax25_dev->forward;
-}
-
-/*
- * Free all memory associated with device structures.
- */
-void __exit ax25_dev_free(void)
-{
- ax25_dev *s, *n;
-
- spin_lock_bh(&ax25_dev_lock);
- list_for_each_entry_safe(s, n, &ax25_dev_list, list) {
- netdev_put(s->dev, &s->dev_tracker);
- list_del(&s->list);
- ax25_dev_put(s);
- }
- spin_unlock_bh(&ax25_dev_lock);
-}
diff --git a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c
deleted file mode 100644
index c62f8fb06189..000000000000
--- a/net/ax25/ax25_ds_in.c
+++ /dev/null
@@ -1,298 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-/*
- * State machine for state 1, Awaiting Connection State.
- * The handling of the timer(s) is in file ax25_ds_timer.c.
- * Handling of state 0 and connection release is in ax25.c.
- */
-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) {
- bh_lock_sock(ax25->sk);
- ax25->sk->sk_state = TCP_ESTABLISHED;
- /*
- * For WAIT_SABM connections we will produce an accept
- * ready socket here
- */
- if (!sock_flag(ax25->sk, SOCK_DEAD))
- ax25->sk->sk_state_change(ax25->sk);
- bh_unlock_sock(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;
-}
-
-/*
- * State machine for state 2, Awaiting Release State.
- * The handling of the timer(s) is in file ax25_ds_timer.c
- * Handling of state 0 and connection release is in ax25.c.
- */
-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);
- 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;
-
- default:
- break;
- }
-
- return 0;
-}
-
-/*
- * State machine for state 3, Connected State.
- * The handling of the timer(s) is in file ax25_timer.c
- * Handling of state 0 and connection release is in ax25.c.
- */
-static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type)
-{
- 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_RR:
- case AX25_RNR:
- if (frametype == AX25_RR)
- ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
- else
- ax25->condition |= AX25_COND_PEER_RX_BUSY;
-
- if (ax25_validate_nr(ax25, nr)) {
- if (ax25_check_iframes_acked(ax25, nr))
- ax25->n2count=0;
- if (type == AX25_COMMAND && pf)
- ax25_ds_enquiry_response(ax25);
- } else {
- ax25_ds_nr_error_recovery(ax25);
- ax25->state = AX25_STATE_1;
- }
- break;
-
- case AX25_REJ:
- ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-
- if (ax25_validate_nr(ax25, nr)) {
- if (ax25->va != nr)
- ax25->n2count=0;
-
- ax25_frames_acked(ax25, nr);
- ax25_calculate_rtt(ax25);
- ax25_stop_t1timer(ax25);
- ax25_start_t3timer(ax25);
- ax25_requeue_frames(ax25);
-
- 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_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);
- 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->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;
- }
- }
- break;
-
- case AX25_FRMR:
- case AX25_ILLEGAL:
- ax25_ds_establish_data_link(ax25);
- ax25->state = AX25_STATE_1;
- break;
-
- default:
- break;
- }
-
- return queued;
-}
-
-/*
- * Higher level upcall for a LAPB frame
- */
-int ax25_ds_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
-{
- int queued = 0, frametype, ns, nr, pf;
-
- 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;
- }
-
- return queued;
-}
diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c
deleted file mode 100644
index f00e27df3c76..000000000000
--- a/net/ax25/ax25_ds_subr.c
+++ /dev/null
@@ -1,204 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/spinlock.h>
-#include <linux/net.h>
-#include <linux/gfp.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-void ax25_ds_nr_error_recovery(ax25_cb *ax25)
-{
- ax25_ds_establish_data_link(ax25);
-}
-
-/*
- * dl1bke 960114: transmit I frames on DAMA poll
- */
-void ax25_ds_enquiry_response(ax25_cb *ax25)
-{
- ax25_cb *ax25o;
-
- /* Please note that neither DK4EG's nor DG2FEF's
- * DAMA spec mention the following behaviour as seen
- * with TheFirmware:
- *
- * DB0ACH->DL1BKE <RR C P R0> [DAMA]
- * DL1BKE->DB0ACH <I NR=0 NS=0>
- * DL1BKE-7->DB0PRA-6 DB0ACH <I C S3 R5>
- * DL1BKE->DB0ACH <RR R F R0>
- *
- * The Flexnet DAMA Master implementation apparently
- * insists on the "proper" AX.25 behaviour:
- *
- * DB0ACH->DL1BKE <RR C P R0> [DAMA]
- * DL1BKE->DB0ACH <RR R F R0>
- * DL1BKE->DB0ACH <I NR=0 NS=0>
- * 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
- * this mode anyway (a RR or RNR invokes the retransmission).
- * Is this a Flexnet bug?
- */
-
- ax25_std_enquiry_response(ax25);
-
- if (!(ax25->condition & AX25_COND_PEER_RX_BUSY)) {
- ax25_requeue_frames(ax25);
- ax25_kick(ax25);
- }
-
- if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2 || skb_peek(&ax25->ack_queue) != NULL)
- ax25_ds_t1_timeout(ax25);
- else
- ax25->n2count = 0;
-
- ax25_start_t3timer(ax25);
- ax25_ds_set_timer(ax25->ax25_dev);
-
- spin_lock(&ax25_list_lock);
- ax25_for_each(ax25o, &ax25_list) {
- if (ax25o == ax25)
- continue;
-
- if (ax25o->ax25_dev != ax25->ax25_dev)
- continue;
-
- if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2) {
- ax25_ds_t1_timeout(ax25o);
- continue;
- }
-
- if (!(ax25o->condition & AX25_COND_PEER_RX_BUSY) && ax25o->state == AX25_STATE_3) {
- ax25_requeue_frames(ax25o);
- ax25_kick(ax25o);
- }
-
- if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2 || skb_peek(&ax25o->ack_queue) != NULL)
- ax25_ds_t1_timeout(ax25o);
-
- /* do not start T3 for listening sockets (tnx DD8NE) */
-
- if (ax25o->state != AX25_STATE_0)
- ax25_start_t3timer(ax25o);
- }
- spin_unlock(&ax25_list_lock);
-}
-
-void ax25_ds_establish_data_link(ax25_cb *ax25)
-{
- ax25->condition &= AX25_COND_DAMA_MODE;
- ax25->n2count = 0;
- ax25_calculate_t1(ax25);
- ax25_start_t1timer(ax25);
- ax25_stop_t2timer(ax25);
- ax25_start_t3timer(ax25);
-}
-
-/*
- * :::FIXME:::
- * 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.
- */
-static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char param)
-{
- struct sk_buff *skb;
- unsigned char *p;
-
- if (ax25_dev->dev == NULL)
- return;
-
- if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL)
- return;
-
- skb_reset_network_header(skb);
- p = skb_put(skb, 2);
-
- *p++ = cmd;
- *p++ = param;
-
- skb->protocol = ax25_type_trans(skb, ax25_dev->dev);
-
- dev_queue_xmit(skb);
-}
-
-/*
- * 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
- * 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(&ax25_list_lock);
- ax25_for_each(ax25, &ax25_list)
- if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) {
- res = 1;
- break;
- }
- spin_unlock(&ax25_list_lock);
-
- return res;
-}
-
-static void ax25_dev_dama_on(ax25_dev *ax25_dev)
-{
- if (ax25_dev == NULL)
- return;
-
- if (ax25_dev->dama.slave == 0)
- ax25_kiss_cmd(ax25_dev, 5, 1);
-
- ax25_dev->dama.slave = 1;
- ax25_ds_set_timer(ax25_dev);
-}
-
-void ax25_dev_dama_off(ax25_dev *ax25_dev)
-{
- if (ax25_dev == NULL)
- return;
-
- if (ax25_dev->dama.slave && !ax25_check_dama_slave(ax25_dev)) {
- ax25_kiss_cmd(ax25_dev, 5, 0);
- ax25_dev->dama.slave = 0;
- ax25_ds_del_timer(ax25_dev);
- }
-}
-
-void ax25_dama_on(ax25_cb *ax25)
-{
- ax25_dev_dama_on(ax25->ax25_dev);
- ax25->condition |= AX25_COND_DAMA_MODE;
-}
-
-void ax25_dama_off(ax25_cb *ax25)
-{
- ax25->condition &= ~AX25_COND_DAMA_MODE;
- ax25_dev_dama_off(ax25->ax25_dev);
-}
diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c
deleted file mode 100644
index 0c9e7775aa54..000000000000
--- a/net/ax25/ax25_ds_timer.c
+++ /dev/null
@@ -1,235 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <net/tcp_states.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-static void ax25_ds_timeout(struct timer_list *);
-
-/*
- * Add DAMA slave timeout timer to timer list.
- * 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.
- */
-
-void ax25_ds_setup_timer(ax25_dev *ax25_dev)
-{
- timer_setup(&ax25_dev->dama.slave_timer, ax25_ds_timeout, 0);
-}
-
-void ax25_ds_del_timer(ax25_dev *ax25_dev)
-{
- if (ax25_dev)
- timer_delete(&ax25_dev->dama.slave_timer);
-}
-
-void ax25_ds_set_timer(ax25_dev *ax25_dev)
-{
- if (ax25_dev == NULL) /* paranoia */
- return;
-
- ax25_dev->dama.slave_timeout =
- msecs_to_jiffies(ax25_dev->values[AX25_VALUES_DS_TIMEOUT]) / 10;
- mod_timer(&ax25_dev->dama.slave_timer, jiffies + HZ);
-}
-
-/*
- * DAMA Slave Timeout
- * Silently discard all (slave) connections in case our master forgot us...
- */
-
-static void ax25_ds_timeout(struct timer_list *t)
-{
- ax25_dev *ax25_dev = timer_container_of(ax25_dev, t, dama.slave_timer);
- 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(&ax25_list_lock);
- ax25_for_each(ax25, &ax25_list) {
- if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
- continue;
-
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- ax25_disconnect(ax25, ETIMEDOUT);
- }
- spin_unlock(&ax25_list_lock);
-
- ax25_dev_dama_off(ax25_dev);
-}
-
-void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
-{
- struct sock *sk=ax25->sk;
-
- if (sk)
- bh_lock_sock(sk);
-
- switch (ax25->state) {
-
- case AX25_STATE_0:
- case AX25_STATE_2:
- /* 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 || sock_flag(sk, SOCK_DESTROY) ||
- (sk->sk_state == TCP_LISTEN &&
- sock_flag(sk, SOCK_DEAD))) {
- if (sk) {
- sock_hold(sk);
- ax25_destroy_socket(ax25);
- bh_unlock_sock(sk);
- /* Ungrab socket and destroy it */
- sock_put(sk);
- } else
- ax25_destroy_socket(ax25);
- return;
- }
- break;
-
- case AX25_STATE_3:
- /*
- * Check the state of the receive buffer.
- */
- if (sk != NULL) {
- if (atomic_read(&sk->sk_rmem_alloc) <
- (sk->sk_rcvbuf >> 1) &&
- (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
- ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
- ax25->condition &= ~AX25_COND_ACK_PENDING;
- break;
- }
- }
- break;
- }
-
- if (sk)
- bh_unlock_sock(sk);
-
- ax25_start_heartbeat(ax25);
-}
-
-/* dl1bke 960114: T3 works much like the IDLE timeout, but
- * gets reloaded with every frame for this
- * connection.
- */
-void ax25_ds_t3timer_expiry(ax25_cb *ax25)
-{
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- ax25_dama_off(ax25);
- ax25_disconnect(ax25, ETIMEDOUT);
-}
-
-/* dl1bke 960228: close the connection when IDLE expires.
- * unlike T3 this timer gets reloaded only on
- * I frames.
- */
-void ax25_ds_idletimer_expiry(ax25_cb *ax25)
-{
- ax25_clear_queues(ax25);
-
- ax25->n2count = 0;
- ax25->state = AX25_STATE_2;
-
- ax25_calculate_t1(ax25);
- ax25_start_t1timer(ax25);
- ax25_stop_t3timer(ax25);
-
- if (ax25->sk != NULL) {
- bh_lock_sock(ax25->sk);
- ax25->sk->sk_state = TCP_CLOSE;
- ax25->sk->sk_err = 0;
- ax25->sk->sk_shutdown |= SEND_SHUTDOWN;
- if (!sock_flag(ax25->sk, SOCK_DEAD)) {
- ax25->sk->sk_state_change(ax25->sk);
- sock_set_flag(ax25->sk, SOCK_DEAD);
- }
- bh_unlock_sock(ax25->sk);
- }
-}
-
-/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC
- * within the poll of any connected channel. Remember
- * that we are not allowed to send anything unless we
- * get polled by the Master.
- *
- * Thus we'll have to do parts of our T1 handling in
- * 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);
- if (!sock_flag(ax25->sk, SOCK_DESTROY))
- ax25_disconnect(ax25, ETIMEDOUT);
- return;
- } else {
- ax25->n2count++;
- }
- break;
-
- case AX25_STATE_3:
- if (ax25->n2count == ax25->n2) {
- ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
- ax25_disconnect(ax25, ETIMEDOUT);
- return;
- } else {
- ax25->n2count++;
- }
- break;
- }
-
- ax25_calculate_t1(ax25);
- ax25_start_t1timer(ax25);
-}
diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c
deleted file mode 100644
index 3ad454416a5c..000000000000
--- a/net/ax25/ax25_iface.c
+++ /dev/null
@@ -1,214 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-static struct ax25_protocol *protocol_list;
-static DEFINE_RWLOCK(protocol_list_lock);
-
-static HLIST_HEAD(ax25_linkfail_list);
-static DEFINE_SPINLOCK(linkfail_lock);
-
-static struct listen_struct {
- struct listen_struct *next;
- ax25_address callsign;
- struct net_device *dev;
-} *listen_list = NULL;
-static DEFINE_SPINLOCK(listen_lock);
-
-/*
- * Do not register the internal protocols AX25_P_TEXT, AX25_P_SEGMENT,
- * AX25_P_IP or AX25_P_ARP ...
- */
-void ax25_register_pid(struct ax25_protocol *ap)
-{
- write_lock_bh(&protocol_list_lock);
- ap->next = protocol_list;
- protocol_list = ap;
- write_unlock_bh(&protocol_list_lock);
-}
-
-EXPORT_SYMBOL_GPL(ax25_register_pid);
-
-void ax25_protocol_release(unsigned int pid)
-{
- struct ax25_protocol *protocol;
-
- write_lock_bh(&protocol_list_lock);
- protocol = protocol_list;
- if (protocol == NULL)
- goto out;
-
- if (protocol->pid == pid) {
- protocol_list = protocol->next;
- goto out;
- }
-
- while (protocol != NULL && protocol->next != NULL) {
- if (protocol->next->pid == pid) {
- protocol->next = protocol->next->next;
- goto out;
- }
-
- protocol = protocol->next;
- }
-out:
- write_unlock_bh(&protocol_list_lock);
-}
-
-EXPORT_SYMBOL(ax25_protocol_release);
-
-void ax25_linkfail_register(struct ax25_linkfail *lf)
-{
- spin_lock_bh(&linkfail_lock);
- hlist_add_head(&lf->lf_node, &ax25_linkfail_list);
- spin_unlock_bh(&linkfail_lock);
-}
-
-EXPORT_SYMBOL(ax25_linkfail_register);
-
-void ax25_linkfail_release(struct ax25_linkfail *lf)
-{
- spin_lock_bh(&linkfail_lock);
- hlist_del_init(&lf->lf_node);
- spin_unlock_bh(&linkfail_lock);
-}
-
-EXPORT_SYMBOL(ax25_linkfail_release);
-
-int ax25_listen_register(const ax25_address *callsign, struct net_device *dev)
-{
- struct listen_struct *listen;
-
- if (ax25_listen_mine(callsign, dev))
- return 0;
-
- if ((listen = kmalloc_obj(*listen, GFP_ATOMIC)) == NULL)
- return -ENOMEM;
-
- listen->callsign = *callsign;
- listen->dev = dev;
-
- spin_lock_bh(&listen_lock);
- listen->next = listen_list;
- listen_list = listen;
- spin_unlock_bh(&listen_lock);
-
- return 0;
-}
-
-EXPORT_SYMBOL(ax25_listen_register);
-
-void ax25_listen_release(const ax25_address *callsign, struct net_device *dev)
-{
- struct listen_struct *s, *listen;
-
- spin_lock_bh(&listen_lock);
- listen = listen_list;
- if (listen == NULL) {
- spin_unlock_bh(&listen_lock);
- return;
- }
-
- if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
- listen_list = listen->next;
- spin_unlock_bh(&listen_lock);
- kfree(listen);
- return;
- }
-
- while (listen != NULL && listen->next != NULL) {
- if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) {
- s = listen->next;
- listen->next = listen->next->next;
- spin_unlock_bh(&listen_lock);
- kfree(s);
- return;
- }
-
- listen = listen->next;
- }
- spin_unlock_bh(&listen_lock);
-}
-
-EXPORT_SYMBOL(ax25_listen_release);
-
-int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
-{
- int (*res)(struct sk_buff *, ax25_cb *) = NULL;
- struct ax25_protocol *protocol;
-
- read_lock(&protocol_list_lock);
- for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
- if (protocol->pid == pid) {
- res = protocol->func;
- break;
- }
- read_unlock(&protocol_list_lock);
-
- return res;
-}
-
-int ax25_listen_mine(const 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)) {
- spin_unlock_bh(&listen_lock);
- return 1;
- }
- spin_unlock_bh(&listen_lock);
-
- return 0;
-}
-
-void ax25_link_failed(ax25_cb *ax25, int reason)
-{
- struct ax25_linkfail *lf;
-
- spin_lock_bh(&linkfail_lock);
- hlist_for_each_entry(lf, &ax25_linkfail_list, lf_node)
- lf->func(ax25, reason);
- spin_unlock_bh(&linkfail_lock);
-}
-
-int ax25_protocol_is_registered(unsigned int pid)
-{
- struct ax25_protocol *protocol;
- int res = 0;
-
- read_lock_bh(&protocol_list_lock);
- for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
- if (protocol->pid == pid) {
- res = 1;
- break;
- }
- read_unlock_bh(&protocol_list_lock);
-
- return res;
-}
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
deleted file mode 100644
index d75b3e9ed93d..000000000000
--- a/net/ax25/ax25_in.c
+++ /dev/null
@@ -1,455 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-/*
- * Given a fragment, queue it on the fragment queue and if the fragment
- * is complete, send it back to ax25_rx_iframe.
- */
-static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb)
-{
- struct sk_buff *skbn, *skbo;
-
- if (ax25->fragno != 0) {
- if (!(*skb->data & AX25_SEG_FIRST)) {
- if ((ax25->fragno - 1) == (*skb->data & AX25_SEG_REM)) {
- /* Enqueue fragment */
- ax25->fragno = *skb->data & AX25_SEG_REM;
- skb_pull(skb, 1); /* skip fragno */
- ax25->fraglen += skb->len;
- skb_queue_tail(&ax25->frag_queue, skb);
-
- /* Last fragment received ? */
- if (ax25->fragno == 0) {
- skbn = alloc_skb(AX25_MAX_HEADER_LEN +
- ax25->fraglen,
- GFP_ATOMIC);
- if (!skbn) {
- skb_queue_purge(&ax25->frag_queue);
- return 1;
- }
-
- skb_reserve(skbn, AX25_MAX_HEADER_LEN);
-
- skbn->dev = ax25->ax25_dev->dev;
- skb_reset_network_header(skbn);
- skb_reset_transport_header(skbn);
-
- /* Copy data from the fragments */
- while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) {
- skb_copy_from_linear_data(skbo,
- skb_put(skbn, skbo->len),
- skbo->len);
- kfree_skb(skbo);
- }
-
- ax25->fraglen = 0;
-
- if (ax25_rx_iframe(ax25, skbn) == 0)
- kfree_skb(skbn);
- }
-
- return 1;
- }
- }
- } else {
- /* First fragment received */
- if (*skb->data & AX25_SEG_FIRST) {
- skb_queue_purge(&ax25->frag_queue);
- ax25->fragno = *skb->data & AX25_SEG_REM;
- skb_pull(skb, 1); /* skip fragno */
- ax25->fraglen = skb->len;
- skb_queue_tail(&ax25->frag_queue, skb);
- return 1;
- }
- }
-
- return 0;
-}
-
-/*
- * This is where all valid I frames are sent to, to be dispatched to
- * whichever protocol requires them.
- */
-int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
-{
- int (*func)(struct sk_buff *, ax25_cb *);
- unsigned char pid;
- int queued = 0;
-
- if (skb == NULL) return 0;
-
- ax25_start_idletimer(ax25);
-
- pid = *skb->data;
-
- if (pid == AX25_P_IP) {
- /* working around a TCP bug to keep additional listeners
- * happy. TCP re-uses the buffer and destroys the original
- * content.
- */
- struct sk_buff *skbn = skb_copy(skb, GFP_ATOMIC);
- if (skbn != NULL) {
- kfree_skb(skb);
- skb = skbn;
- }
-
- skb_pull(skb, 1); /* Remove PID */
- skb->mac_header = skb->network_header;
- skb_reset_network_header(skb);
- skb->dev = ax25->ax25_dev->dev;
- skb->pkt_type = PACKET_HOST;
- skb->protocol = htons(ETH_P_IP);
- netif_rx(skb);
- return 1;
- }
- if (pid == AX25_P_SEGMENT) {
- skb_pull(skb, 1); /* Remove PID */
- return ax25_rx_fragment(ax25, skb);
- }
-
- if ((func = ax25_protocol_function(pid)) != NULL) {
- skb_pull(skb, 1); /* Remove PID */
- return (*func)(skb, ax25);
- }
-
- if (ax25->sk != NULL && ax25->ax25_dev->values[AX25_VALUES_CONMODE] == 2) {
- if ((!ax25->pidincl && ax25->sk->sk_protocol == pid) ||
- ax25->pidincl) {
- if (sock_queue_rcv_skb(ax25->sk, skb) == 0)
- queued = 1;
- else
- ax25->condition |= AX25_COND_OWN_RX_BUSY;
- }
- }
-
- return queued;
-}
-
-/*
- * Higher level upcall for a LAPB frame
- */
-static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, int dama)
-{
- int queued = 0;
-
- if (ax25->state == AX25_STATE_0)
- 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;
-
-#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;
-#endif
- }
-
- return queued;
-}
-
-static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
- const ax25_address *dev_addr, struct packet_type *ptype)
-{
- ax25_address src, dest, *next_digi = NULL;
- int type = 0, mine = 0, dama;
- struct sock *make, *sk;
- ax25_digi dp, reverse_dp;
- ax25_cb *ax25;
- ax25_dev *ax25_dev;
-
- /*
- * Process the AX.25/LAPB frame.
- */
-
- skb_reset_transport_header(skb);
-
- if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
- goto free;
-
- /*
- * Parse the address header.
- */
-
- if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL)
- goto free;
-
- /*
- * Ours perhaps ?
- */
- if (dp.lastrepeat + 1 < dp.ndigi) /* Not yet digipeated completely */
- next_digi = &dp.calls[dp.lastrepeat + 1];
-
- /*
- * Pull of the AX.25 headers leaving the CTRL/PID bytes
- */
- skb_pull(skb, ax25_addr_size(&dp));
-
- /* For our port addresses ? */
- if (ax25cmp(&dest, dev_addr) == 0 && dp.lastrepeat + 1 == dp.ndigi)
- mine = 1;
-
- /* Also match on any registered callsign from L3/4 */
- if (!mine && ax25_listen_mine(&dest, dev) && dp.lastrepeat + 1 == dp.ndigi)
- mine = 1;
-
- /* UI frame - bypass LAPB processing */
- if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
- skb_set_transport_header(skb, 2); /* skip control and pid */
-
- ax25_send_to_raw(&dest, skb, skb->data[1]);
-
- if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0)
- goto free;
-
- /* Now we are pointing at the pid byte */
- switch (skb->data[1]) {
- case AX25_P_IP:
- skb_pull(skb,2); /* drop PID/CTRL */
- skb_reset_transport_header(skb);
- skb_reset_network_header(skb);
- skb->dev = dev;
- skb->pkt_type = PACKET_HOST;
- skb->protocol = htons(ETH_P_IP);
- netif_rx(skb);
- break;
-
- case AX25_P_ARP:
- skb_pull(skb,2);
- skb_reset_transport_header(skb);
- skb_reset_network_header(skb);
- skb->dev = dev;
- skb->pkt_type = PACKET_HOST;
- skb->protocol = htons(ETH_P_ARP);
- netif_rx(skb);
- break;
- case AX25_P_TEXT:
- /* Now find a suitable dgram socket */
- sk = ax25_get_socket(&dest, &src, SOCK_DGRAM);
- if (sk != NULL) {
- bh_lock_sock(sk);
- if (atomic_read(&sk->sk_rmem_alloc) >=
- sk->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);
- }
- bh_unlock_sock(sk);
- sock_put(sk);
- } else {
- kfree_skb(skb);
- }
- break;
-
- default:
- kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */
- break;
- }
-
- return 0;
- }
-
- /*
- * Is connected mode supported on this device ?
- * If not, should we DM the incoming frame (except DMs) or
- * silently ignore them. For now we stay quiet.
- */
- if (ax25_dev->values[AX25_VALUES_CONMODE] == 0)
- goto free;
-
- /* LAPB */
-
- /* AX.25 state 1-4 */
-
- ax25_digi_invert(&dp, &reverse_dp);
-
- 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
- */
- if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
- kfree_skb(skb);
-
- ax25_cb_put(ax25);
- return 0;
- }
-
- /* AX.25 state 0 (disconnected) */
-
- /* a) received not a SABM(E) */
-
- 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.
- */
- if ((*skb->data & ~AX25_PF) != AX25_DM && mine)
- ax25_return_dm(dev, &src, &dest, &dp);
-
- goto free;
- }
-
- /* b) received SABM(E) */
-
- if (dp.lastrepeat + 1 == dp.ndigi)
- sk = ax25_find_listener(&dest, 0, dev, SOCK_SEQPACKET);
- else
- sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET);
-
- if (sk != NULL) {
- bh_lock_sock(sk);
- if (sk_acceptq_is_full(sk) ||
- (make = ax25_make_new(sk, ax25_dev)) == NULL) {
- if (mine)
- ax25_return_dm(dev, &src, &dest, &dp);
- kfree_skb(skb);
- bh_unlock_sock(sk);
- sock_put(sk);
-
- return 0;
- }
-
- ax25 = sk_to_ax25(make);
- skb_set_owner_r(skb, make);
- skb_queue_head(&sk->sk_receive_queue, skb);
-
- make->sk_state = TCP_ESTABLISHED;
-
- sk_acceptq_added(sk);
- bh_unlock_sock(sk);
- } else {
- if (!mine)
- goto free;
-
- if ((ax25 = ax25_create_cb()) == NULL) {
- ax25_return_dm(dev, &src, &dest, &dp);
- goto free;
- }
-
- ax25_fillin_cb(ax25, ax25_dev);
- }
-
- ax25->source_addr = dest;
- ax25->dest_addr = src;
-
- /*
- * Sort out any digipeated paths.
- */
- if (dp.ndigi && !ax25->digipeat &&
- (ax25->digipeat = kmalloc_obj(ax25_digi, GFP_ATOMIC)) == NULL) {
- kfree_skb(skb);
- ax25_destroy_socket(ax25);
- if (sk)
- sock_put(sk);
- return 0;
- }
-
- if (dp.ndigi == 0) {
- kfree(ax25->digipeat);
- ax25->digipeat = NULL;
- } else {
- /* Reverse the source SABM's path */
- memcpy(ax25->digipeat, &reverse_dp, sizeof(ax25_digi));
- }
-
- if ((*skb->data & ~AX25_PF) == AX25_SABME) {
- ax25->modulus = AX25_EMODULUS;
- ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW];
- } else {
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25_dev->values[AX25_VALUES_WINDOW];
- }
-
- ax25_send_control(ax25, AX25_UA, AX25_POLLON, AX25_RESPONSE);
-
-#ifdef CONFIG_AX25_DAMA_SLAVE
- if (dama && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
- ax25_dama_on(ax25);
-#endif
-
- ax25->state = AX25_STATE_3;
-
- ax25_cb_add(ax25);
-
- ax25_start_heartbeat(ax25);
- ax25_start_t3timer(ax25);
- ax25_start_idletimer(ax25);
-
- if (sk) {
- if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_data_ready(sk);
- sock_put(sk);
- } else {
-free:
- kfree_skb(skb);
- }
- return 0;
-}
-
-/*
- * Receive an AX.25 frame via a SLIP interface.
- */
-int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev)
-{
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (!skb)
- return NET_RX_DROP;
-
- skb_orphan(skb);
-
- if (!net_eq(dev_net(dev), &init_net)) {
- kfree_skb(skb);
- return 0;
- }
-
- if ((*skb->data & 0x0F) != 0) {
- kfree_skb(skb); /* Not a KISS data frame */
- return 0;
- }
-
- skb_pull(skb, AX25_KISS_HEADER_LEN); /* Remove the KISS byte */
-
- return ax25_rcv(skb, dev, (const ax25_address *)dev->dev_addr, ptype);
-}
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
deleted file mode 100644
index 215d4ccf12b9..000000000000
--- a/net/ax25/ax25_ip.c
+++ /dev/null
@@ -1,247 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/termios.h> /* For TIOCINQ/OUTQ */
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/sysctl.h>
-#include <net/ip.h>
-#include <net/arp.h>
-
-/*
- * IP over AX.25 encapsulation.
- */
-
-/*
- * Shove an AX.25 UI header on an IP packet and handle ARP
- */
-
-#ifdef CONFIG_INET
-
-static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *daddr,
- const void *saddr, unsigned int len)
-{
- unsigned char *buff;
-
- /* they sometimes come back to us... */
- if (type == ETH_P_AX25)
- return 0;
-
- /* header is an AX.25 UI frame from us to them */
- buff = skb_push(skb, AX25_HEADER_LEN);
- *buff++ = 0x00; /* KISS DATA */
-
- if (daddr != NULL)
- memcpy(buff, daddr, dev->addr_len); /* Address specified */
-
- buff[6] &= ~AX25_CBIT;
- buff[6] &= ~AX25_EBIT;
- buff[6] |= AX25_SSSID_SPARE;
- buff += AX25_ADDR_LEN;
-
- if (saddr != NULL)
- memcpy(buff, saddr, dev->addr_len);
- else
- memcpy(buff, dev->dev_addr, dev->addr_len);
-
- buff[6] &= ~AX25_CBIT;
- buff[6] |= AX25_EBIT;
- buff[6] |= AX25_SSSID_SPARE;
- buff += AX25_ADDR_LEN;
-
- *buff++ = AX25_UI; /* UI */
-
- /* 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_hard_header - wrong protocol type 0x%2.2x\n", type);
- *buff++ = 0;
- break;
- }
-
- if (daddr != NULL)
- return AX25_HEADER_LEN;
-
- return -AX25_HEADER_LEN; /* Unfinished header */
-}
-
-netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
-{
- struct sk_buff *ourskb;
- unsigned char *bp = skb->data;
- ax25_route *route;
- struct net_device *dev = NULL;
- ax25_address *src, *dst;
- ax25_digi *digipeat = NULL;
- ax25_dev *ax25_dev;
- ax25_cb *ax25;
- char ip_mode = ' ';
-
- dst = (ax25_address *)(bp + 1);
- src = (ax25_address *)(bp + 8);
-
- ax25_route_lock_use();
- route = ax25_get_route(dst, NULL);
- if (route) {
- digipeat = route->digipeat;
- dev = route->dev;
- ip_mode = route->ip_mode;
- }
-
- if (dev == NULL)
- dev = skb->dev;
-
- rcu_read_lock();
- if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
- kfree_skb(skb);
- goto put;
- }
-
- if (bp[16] == AX25_P_IP) {
- if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
- /*
- * We copy the buffer and release the original thereby
- * keeping it straight
- *
- * Note: we report 1 back so the caller will
- * not feed the frame direct to the physical device
- * We don't want that to happen. (It won't be upset
- * as we have pulled the frame from the queue by
- * freeing it).
- *
- * NB: TCP modifies buffers that are still
- * on a device queue, thus we use skb_copy()
- * instead of using skb_clone() unless this
- * gets fixed.
- */
-
- ax25_address src_c;
- ax25_address dst_c;
-
- if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
- kfree_skb(skb);
- goto put;
- }
-
- if (skb->sk != NULL)
- skb_set_owner_w(ourskb, skb->sk);
-
- kfree_skb(skb);
- /* dl9sau: bugfix
- * after kfree_skb(), dst and src which were pointer
- * to bp which is part of skb->data would not be valid
- * anymore hope that after skb_pull(ourskb, ..) our
- * dsc_c and src_c will not become invalid
- */
- bp = ourskb->data;
- dst_c = *(ax25_address *)(bp + 1);
- src_c = *(ax25_address *)(bp + 8);
-
- skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */
- skb_reset_network_header(ourskb);
-
- ax25=ax25_send_frame(
- ourskb,
- ax25_dev->values[AX25_VALUES_PACLEN],
- &src_c,
- &dst_c, digipeat, dev);
- if (ax25) {
- ax25_cb_put(ax25);
- }
- goto put;
- }
- }
-
- bp[7] &= ~AX25_CBIT;
- bp[7] &= ~AX25_EBIT;
- bp[7] |= AX25_SSSID_SPARE;
-
- bp[14] &= ~AX25_CBIT;
- bp[14] |= AX25_EBIT;
- bp[14] |= AX25_SSSID_SPARE;
-
- skb_pull(skb, AX25_KISS_HEADER_LEN);
-
- if (digipeat != NULL) {
- if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL)
- goto put;
-
- skb = ourskb;
- }
-
- ax25_queue_xmit(skb, dev);
-
-put:
- rcu_read_unlock();
- ax25_route_lock_unuse();
- return NETDEV_TX_OK;
-}
-
-#else /* INET */
-
-static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *daddr,
- const void *saddr, unsigned int len)
-{
- return -AX25_HEADER_LEN;
-}
-
-netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-#endif
-
-static bool ax25_validate_header(const char *header, unsigned int len)
-{
- ax25_digi digi;
-
- if (!len)
- return false;
-
- if (header[0])
- return true;
-
- return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL,
- NULL);
-}
-
-const struct header_ops ax25_header_ops = {
- .create = ax25_hard_header,
- .validate = ax25_validate_header,
-};
-
-EXPORT_SYMBOL(ax25_header_ops);
-EXPORT_SYMBOL(ax25_ip_xmit);
diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c
deleted file mode 100644
index 8bca2ace98e5..000000000000
--- a/net/ax25/ax25_out.c
+++ /dev/null
@@ -1,398 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/spinlock.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-static DEFINE_SPINLOCK(ax25_frag_lock);
-
-ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, const ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev)
-{
- ax25_dev *ax25_dev;
- ax25_cb *ax25;
-
- /*
- * Take the default packet length for the device if zero is
- * specified.
- */
- if (paclen == 0) {
- rcu_read_lock();
- ax25_dev = ax25_dev_ax25dev(dev);
- if (!ax25_dev) {
- rcu_read_unlock();
- return NULL;
- }
- paclen = ax25_dev->values[AX25_VALUES_PACLEN];
- rcu_read_unlock();
- }
-
- /*
- * Look for an existing connection.
- */
- if ((ax25 = ax25_find_cb(src, dest, digi, dev)) != NULL) {
- ax25_output(ax25, paclen, skb);
- return ax25; /* It already existed */
- }
-
- rcu_read_lock();
- ax25_dev = ax25_dev_ax25dev(dev);
- if (!ax25_dev) {
- rcu_read_unlock();
- return NULL;
- }
-
- if ((ax25 = ax25_create_cb()) == NULL) {
- rcu_read_unlock();
- return NULL;
- }
- ax25_fillin_cb(ax25, ax25_dev);
- rcu_read_unlock();
-
- ax25->source_addr = *src;
- ax25->dest_addr = *dest;
-
- if (digi != NULL) {
- ax25->digipeat = kmemdup(digi, sizeof(*digi), GFP_ATOMIC);
- if (ax25->digipeat == NULL) {
- ax25_cb_put(ax25);
- return NULL;
- }
- }
-
- 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;
-
-#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;
-#endif
- }
-
- /*
- * There is one ref for the state machine; a caller needs
- * one more to put it back, just like with the existing one.
- */
- ax25_cb_hold(ax25);
-
- ax25_cb_add(ax25);
-
- ax25->state = AX25_STATE_1;
-
- ax25_start_heartbeat(ax25);
-
- ax25_output(ax25, paclen, skb);
-
- return ax25; /* We had to create it */
-}
-
-EXPORT_SYMBOL(ax25_send_frame);
-
-/*
- * All outgoing AX.25 I frames pass via this routine. Therefore this is
- * where the fragmentation of frames takes place. If fragment is set to
- * zero then we are not allowed to do fragmentation, even if the frame
- * is too large.
- */
-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;
-
- if (paclen < 16) {
- WARN_ON_ONCE(1);
- kfree_skb(skb);
- return;
- }
-
- if ((skb->len - 1) > paclen) {
- if (*skb->data == AX25_P_TEXT) {
- skb_pull(skb, 1); /* skip PID */
- ka9qfrag = 0;
- } else {
- paclen -= 2; /* Allow for fragment control info */
- ka9qfrag = 1;
- }
-
- fragno = skb->len / paclen;
- if (skb->len % paclen == 0) fragno--;
-
- frontlen = skb_headroom(skb); /* Address space + CTRL */
-
- while (skb->len > 0) {
- spin_lock_bh(&ax25_frag_lock);
- if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) {
- 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);
-
- spin_unlock_bh(&ax25_frag_lock);
-
- len = (paclen > skb->len) ? skb->len : paclen;
-
- if (ka9qfrag == 1) {
- skb_reserve(skbn, frontlen + 2);
- skb_set_network_header(skbn,
- skb_network_offset(skb));
- skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
- p = skb_push(skbn, 2);
-
- *p++ = AX25_P_SEGMENT;
-
- *p = fragno--;
- if (first) {
- *p |= AX25_SEG_FIRST;
- first = 0;
- }
- } else {
- skb_reserve(skbn, frontlen + 1);
- skb_set_network_header(skbn,
- skb_network_offset(skb));
- skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
- p = skb_push(skbn, 1);
- *p = AX25_P_TEXT;
- }
-
- skb_pull(skb, len);
- skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */
- }
-
- kfree_skb(skb);
- } else {
- skb_queue_tail(&ax25->write_queue, skb); /* Throw it on the queue */
- }
-
- switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- 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;
-#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.
- */
-static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit)
-{
- unsigned char *frame;
-
- if (skb == NULL)
- return;
-
- skb_reset_network_header(skb);
-
- if (ax25->modulus == AX25_MODULUS) {
- frame = skb_push(skb, 1);
-
- *frame = AX25_I;
- *frame |= (poll_bit) ? AX25_PF : 0;
- *frame |= (ax25->vr << 5);
- *frame |= (ax25->vs << 1);
- } else {
- frame = skb_push(skb, 2);
-
- frame[0] = AX25_I;
- frame[0] |= (ax25->vs << 1);
- frame[1] = (poll_bit) ? AX25_EPF : 0;
- frame[1] |= (ax25->vr << 1);
- }
-
- ax25_start_idletimer(ax25);
-
- ax25_transmit_buffer(ax25, skb, AX25_COMMAND);
-}
-
-void ax25_kick(ax25_cb *ax25)
-{
- struct sk_buff *skb, *skbn;
- int last = 1;
- unsigned short start, end, next;
-
- if (ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4)
- return;
-
- if (ax25->condition & AX25_COND_PEER_RX_BUSY)
- return;
-
- if (skb_peek(&ax25->write_queue) == NULL)
- return;
-
- start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs;
- end = (ax25->va + ax25->window) % ax25->modulus;
-
- if (start == end)
- return;
-
- /*
- * Transmit data until either we're out of data to send or
- * the window is full. Send a poll on the final I frame if
- * the window is filled.
- */
-
- /*
- * Dequeue the frame and copy it.
- * Check for race with ax25_clear_queues().
- */
- skb = skb_dequeue(&ax25->write_queue);
- if (!skb)
- return;
-
- ax25->vs = start;
-
- do {
- if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
- skb_queue_head(&ax25->write_queue, skb);
- break;
- }
-
- if (skb->sk != NULL)
- skb_set_owner_w(skbn, skb->sk);
-
- next = (ax25->vs + 1) % ax25->modulus;
- last = (next == end);
-
- /*
- * Transmit the frame copy.
- * bke 960114: do not set the Poll bit on the last frame
- * 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;
-
-#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
- break;
-#endif
- }
-
- ax25->vs = next;
-
- /*
- * Requeue the original data frame.
- */
- skb_queue_tail(&ax25->ack_queue, skb);
-
- } while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL);
-
- ax25->condition &= ~AX25_COND_ACK_PENDING;
-
- if (!ax25_t1timer_running(ax25)) {
- ax25_stop_t3timer(ax25);
- ax25_calculate_t1(ax25);
- ax25_start_t1timer(ax25);
- }
-}
-
-void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
-{
- unsigned char *ptr;
- int headroom;
-
- if (ax25->ax25_dev == NULL) {
- ax25_disconnect(ax25, ENETUNREACH);
- return;
- }
-
- headroom = ax25_addr_size(ax25->digipeat);
-
- if (unlikely(skb_headroom(skb) < headroom)) {
- skb = skb_expand_head(skb, headroom);
- if (!skb) {
- printk(KERN_CRIT "AX.25: ax25_transmit_buffer - out of memory\n");
- return;
- }
- }
-
- ptr = skb_push(skb, headroom);
-
- ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
-
- ax25_queue_xmit(skb, ax25->ax25_dev->dev);
-}
-
-/*
- * A small shim to dev_queue_xmit to add the KISS control byte, and do
- * any packet forwarding in operation.
- */
-void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- unsigned char *ptr;
-
- rcu_read_lock();
- skb->protocol = ax25_type_trans(skb, ax25_fwd_dev(dev));
- rcu_read_unlock();
-
- ptr = skb_push(skb, 1);
- *ptr = 0x00; /* KISS */
-
- dev_queue_xmit(skb);
-}
-
-int ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr)
-{
- if (ax25->vs == nr) {
- ax25_frames_acked(ax25, nr);
- ax25_calculate_rtt(ax25);
- ax25_stop_t1timer(ax25);
- ax25_start_t3timer(ax25);
- return 1;
- } else {
- if (ax25->va != nr) {
- ax25_frames_acked(ax25, nr);
- ax25_calculate_t1(ax25);
- ax25_start_t1timer(ax25);
- return 1;
- }
- }
- return 0;
-}
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
deleted file mode 100644
index 1d5c59ccf142..000000000000
--- a/net/ax25/ax25_route.c
+++ /dev/null
@@ -1,416 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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/capability.h>
-#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>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/seq_file.h>
-#include <linux/export.h>
-
-static ax25_route *ax25_route_list;
-DEFINE_RWLOCK(ax25_route_lock);
-
-void ax25_rt_device_down(struct net_device *dev)
-{
- ax25_route *s, *t, *ax25_rt;
-
- write_lock_bh(&ax25_route_lock);
- ax25_rt = ax25_route_list;
- while (ax25_rt != NULL) {
- s = ax25_rt;
- ax25_rt = ax25_rt->next;
-
- if (s->dev == dev) {
- if (ax25_route_list == s) {
- ax25_route_list = s->next;
- kfree(s->digipeat);
- kfree(s);
- } else {
- for (t = ax25_route_list; t != NULL; t = t->next) {
- if (t->next == s) {
- t->next = s->next;
- kfree(s->digipeat);
- kfree(s);
- break;
- }
- }
- }
- }
- }
- write_unlock_bh(&ax25_route_lock);
-}
-
-static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
-{
- ax25_route *ax25_rt;
- ax25_dev *ax25_dev;
- int i;
-
- if (route->digi_count > AX25_MAX_DIGIS)
- return -EINVAL;
-
- ax25_dev = ax25_addr_ax25dev(&route->port_addr);
- if (!ax25_dev)
- return -EINVAL;
-
- write_lock_bh(&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) {
- kfree(ax25_rt->digipeat);
- ax25_rt->digipeat = NULL;
- if (route->digi_count != 0) {
- if ((ax25_rt->digipeat = kmalloc_obj(ax25_digi, GFP_ATOMIC)) == NULL) {
- write_unlock_bh(&ax25_route_lock);
- ax25_dev_put(ax25_dev);
- 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];
- }
- }
- write_unlock_bh(&ax25_route_lock);
- ax25_dev_put(ax25_dev);
- return 0;
- }
- ax25_rt = ax25_rt->next;
- }
-
- if ((ax25_rt = kmalloc_obj(ax25_route, GFP_ATOMIC)) == NULL) {
- write_unlock_bh(&ax25_route_lock);
- ax25_dev_put(ax25_dev);
- 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 ((ax25_rt->digipeat = kmalloc_obj(ax25_digi, GFP_ATOMIC)) == NULL) {
- write_unlock_bh(&ax25_route_lock);
- kfree(ax25_rt);
- ax25_dev_put(ax25_dev);
- 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_bh(&ax25_route_lock);
- ax25_dev_put(ax25_dev);
-
- return 0;
-}
-
-void __ax25_put_route(ax25_route *ax25_rt)
-{
- kfree(ax25_rt->digipeat);
- kfree(ax25_rt);
-}
-
-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_bh(&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_put_route(s);
- } else {
- for (t = ax25_route_list; t != NULL; t = t->next) {
- if (t->next == s) {
- t->next = s->next;
- __ax25_put_route(s);
- break;
- }
- }
- }
- }
- }
- write_unlock_bh(&ax25_route_lock);
- ax25_dev_put(ax25_dev);
-
- 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_bh(&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;
- }
- }
- ax25_rt = ax25_rt->next;
- }
-
-out:
- write_unlock_bh(&ax25_route_lock);
- ax25_dev_put(ax25_dev);
- return err;
-}
-
-int ax25_rt_ioctl(unsigned int cmd, void __user *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;
- }
-}
-
-#ifdef CONFIG_PROC_FS
-
-static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(ax25_route_lock)
-{
- struct ax25_route *ax25_rt;
- int i = 1;
-
- read_lock(&ax25_route_lock);
- if (*pos == 0)
- return SEQ_START_TOKEN;
-
- for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
- if (i == *pos)
- return ax25_rt;
- ++i;
- }
-
- return NULL;
-}
-
-static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
- return (v == SEQ_START_TOKEN) ? ax25_route_list :
- ((struct ax25_route *) v)->next;
-}
-
-static void ax25_rt_seq_stop(struct seq_file *seq, void *v)
- __releases(ax25_route_lock)
-{
- read_unlock(&ax25_route_lock);
-}
-
-static int ax25_rt_seq_show(struct seq_file *seq, void *v)
-{
- char buf[11];
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, "callsign dev mode digipeaters\n");
- else {
- struct ax25_route *ax25_rt = v;
- const char *callsign;
- int i;
-
- if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
- callsign = "default";
- else
- callsign = ax2asc(buf, &ax25_rt->callsign);
-
- seq_printf(seq, "%-9s %-4s",
- callsign,
- ax25_rt->dev ? ax25_rt->dev->name : "???");
-
- switch (ax25_rt->ip_mode) {
- case 'V':
- seq_puts(seq, " vc");
- break;
- case 'D':
- seq_puts(seq, " dg");
- break;
- default:
- seq_puts(seq, " *");
- break;
- }
-
- if (ax25_rt->digipeat != NULL)
- for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
- seq_printf(seq, " %s",
- ax2asc(buf, &ax25_rt->digipeat->calls[i]));
-
- seq_puts(seq, "\n");
- }
- return 0;
-}
-
-const struct seq_operations ax25_rt_seqops = {
- .start = ax25_rt_seq_start,
- .next = ax25_rt_seq_next,
- .stop = ax25_rt_seq_stop,
- .show = ax25_rt_seq_show,
-};
-#endif
-
-/*
- * Find AX.25 route
- *
- * Only routes with a reference count of zero can be destroyed.
- * Must be called with ax25_route_lock read locked.
- */
-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;
-
- /*
- * Bind to the physical interface we heard them on, or the default
- * route if none is found;
- */
- for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
- if (dev == NULL) {
- if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
- ax25_spe_rt = ax25_rt;
- if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
- ax25_def_rt = ax25_rt;
- } else {
- if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev)
- ax25_spe_rt = ax25_rt;
- if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev)
- ax25_def_rt = ax25_rt;
- }
- }
-
- ax25_rt = ax25_def_rt;
- if (ax25_spe_rt != NULL)
- ax25_rt = ax25_spe_rt;
-
- return ax25_rt;
-}
-
-
-struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
- ax25_address *dest, ax25_digi *digi)
-{
- unsigned char *bp;
- int len;
-
- len = digi->ndigi * AX25_ADDR_LEN;
-
- if (unlikely(skb_headroom(skb) < len)) {
- skb = skb_expand_head(skb, len);
- if (!skb) {
- printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memory\n");
- return NULL;
- }
- }
-
- bp = skb_push(skb, len);
-
- ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
-
- return skb;
-}
-
-/*
- * Free all memory associated with routing structures.
- */
-void __exit ax25_rt_free(void)
-{
- ax25_route *s, *ax25_rt = ax25_route_list;
-
- write_lock_bh(&ax25_route_lock);
- while (ax25_rt != NULL) {
- s = ax25_rt;
- ax25_rt = ax25_rt->next;
-
- kfree(s->digipeat);
- kfree(s);
- }
- write_unlock_bh(&ax25_route_lock);
-}
diff --git a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c
deleted file mode 100644
index ba176196ae06..000000000000
--- a/net/ax25/ax25_std_in.c
+++ /dev/null
@@ -1,443 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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)
- *
- * 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>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-/*
- * State machine for state 1, Awaiting Connection State.
- * The handling of the timer(s) is in file ax25_std_timer.c.
- * Handling of state 0 and connection release is in ax25.c.
- */
-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) {
- bh_lock_sock(ax25->sk);
- ax25->sk->sk_state = TCP_ESTABLISHED;
- /* For WAIT_SABM connections we will produce an accept ready socket here */
- if (!sock_flag(ax25->sk, SOCK_DEAD))
- ax25->sk->sk_state_change(ax25->sk);
- bh_unlock_sock(ax25->sk);
- }
- }
- 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];
- }
- }
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-/*
- * State machine for state 2, Awaiting Release State.
- * The handling of the timer(s) is in file ax25_std_timer.c
- * Handling of state 0 and connection release is in ax25.c.
- */
-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);
- ax25_disconnect(ax25, 0);
- 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;
-
- default:
- break;
- }
-
- return 0;
-}
-
-/*
- * State machine for state 3, Connected State.
- * The handling of the timer(s) is in file ax25_std_timer.c
- * Handling of state 0 and connection release is in ax25.c.
- */
-static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type)
-{
- 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_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_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_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);
- }
- }
- } 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;
- }
- }
- break;
-
- case AX25_FRMR:
- case AX25_ILLEGAL:
- ax25_std_establish_data_link(ax25);
- ax25->state = AX25_STATE_1;
- break;
-
- default:
- break;
- }
-
- return queued;
-}
-
-/*
- * State machine for state 4, Timer Recovery State.
- * The handling of the timer(s) is in file ax25_std_timer.c
- * Handling of state 0 and connection release is in ax25.c.
- */
-static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type)
-{
- 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_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);
- 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);
- 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;
- }
- 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);
- }
- }
- } 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;
- }
- }
- break;
-
- case AX25_FRMR:
- case AX25_ILLEGAL:
- ax25_std_establish_data_link(ax25);
- ax25->state = AX25_STATE_1;
- break;
-
- default:
- break;
- }
-
- return queued;
-}
-
-/*
- * Higher level upcall for a LAPB frame
- */
-int ax25_std_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
-{
- int queued = 0, frametype, ns, nr, pf;
-
- 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;
- }
-
- ax25_kick(ax25);
-
- return queued;
-}
diff --git a/net/ax25/ax25_std_subr.c b/net/ax25/ax25_std_subr.c
deleted file mode 100644
index 4c36f1342558..000000000000
--- a/net/ax25/ax25_std_subr.c
+++ /dev/null
@@ -1,83 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-/*
- * The following routines are taken from page 170 of the 7th ARRL Computer
- * Networking Conference paper, as is the whole state machine.
- */
-
-void ax25_std_nr_error_recovery(ax25_cb *ax25)
-{
- ax25_std_establish_data_link(ax25);
-}
-
-void ax25_std_establish_data_link(ax25_cb *ax25)
-{
- ax25->condition = 0x00;
- ax25->n2count = 0;
-
- 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);
-
- ax25_calculate_t1(ax25);
- ax25_stop_idletimer(ax25);
- ax25_stop_t3timer(ax25);
- ax25_stop_t2timer(ax25);
- ax25_start_t1timer(ax25);
-}
-
-void ax25_std_transmit_enquiry(ax25_cb *ax25)
-{
- if (ax25->condition & AX25_COND_OWN_RX_BUSY)
- ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_COMMAND);
- else
- ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_COMMAND);
-
- ax25->condition &= ~AX25_COND_ACK_PENDING;
-
- ax25_calculate_t1(ax25);
- ax25_start_t1timer(ax25);
-}
-
-void ax25_std_enquiry_response(ax25_cb *ax25)
-{
- if (ax25->condition & AX25_COND_OWN_RX_BUSY)
- ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_RESPONSE);
- else
- ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_RESPONSE);
-
- ax25->condition &= ~AX25_COND_ACK_PENDING;
-}
-
-void ax25_std_timeout_response(ax25_cb *ax25)
-{
- if (ax25->condition & AX25_COND_OWN_RX_BUSY)
- ax25_send_control(ax25, AX25_RNR, AX25_POLLOFF, AX25_RESPONSE);
- else
- ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
-
- ax25->condition &= ~AX25_COND_ACK_PENDING;
-}
diff --git a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c
deleted file mode 100644
index b17da41210cb..000000000000
--- a/net/ax25/ax25_std_timer.c
+++ /dev/null
@@ -1,175 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-void ax25_std_heartbeat_expiry(ax25_cb *ax25)
-{
- struct sock *sk = ax25->sk;
-
- if (sk)
- bh_lock_sock(sk);
-
- switch (ax25->state) {
- case AX25_STATE_0:
- case AX25_STATE_2:
- /* 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 || sock_flag(sk, SOCK_DESTROY) ||
- (sk->sk_state == TCP_LISTEN &&
- sock_flag(sk, SOCK_DEAD))) {
- if (sk) {
- sock_hold(sk);
- ax25_destroy_socket(ax25);
- bh_unlock_sock(sk);
- /* Ungrab socket and destroy it */
- sock_put(sk);
- } else
- ax25_destroy_socket(ax25);
- return;
- }
- break;
-
- case AX25_STATE_3:
- case AX25_STATE_4:
- /*
- * Check the state of the receive buffer.
- */
- if (sk != NULL) {
- if (atomic_read(&sk->sk_rmem_alloc) <
- (sk->sk_rcvbuf >> 1) &&
- (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;
- }
- }
- }
-
- if (sk)
- bh_unlock_sock(sk);
-
- ax25_start_heartbeat(ax25);
-}
-
-void ax25_std_t2timer_expiry(ax25_cb *ax25)
-{
- if (ax25->condition & AX25_COND_ACK_PENDING) {
- ax25->condition &= ~AX25_COND_ACK_PENDING;
- ax25_std_timeout_response(ax25);
- }
-}
-
-void ax25_std_t3timer_expiry(ax25_cb *ax25)
-{
- ax25->n2count = 0;
- ax25_std_transmit_enquiry(ax25);
- ax25->state = AX25_STATE_4;
-}
-
-void ax25_std_idletimer_expiry(ax25_cb *ax25)
-{
- ax25_clear_queues(ax25);
-
- ax25->n2count = 0;
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- ax25->state = AX25_STATE_2;
-
- ax25_calculate_t1(ax25);
- ax25_start_t1timer(ax25);
- ax25_stop_t2timer(ax25);
- ax25_stop_t3timer(ax25);
-
- if (ax25->sk != NULL) {
- bh_lock_sock(ax25->sk);
- ax25->sk->sk_state = TCP_CLOSE;
- ax25->sk->sk_err = 0;
- ax25->sk->sk_shutdown |= SEND_SHUTDOWN;
- if (!sock_flag(ax25->sk, SOCK_DEAD)) {
- ax25->sk->sk_state_change(ax25->sk);
- sock_set_flag(ax25->sk, SOCK_DEAD);
- }
- bh_unlock_sock(ax25->sk);
- }
-}
-
-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);
- if (!sock_flag(ax25->sk, SOCK_DESTROY))
- 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);
- }
- break;
- }
-
- ax25_calculate_t1(ax25);
- ax25_start_t1timer(ax25);
-}
diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c
deleted file mode 100644
index bff4b203a893..000000000000
--- a/net/ax25/ax25_subr.c
+++ /dev/null
@@ -1,296 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-/*
- * This routine purges all the queues of frames.
- */
-void ax25_clear_queues(ax25_cb *ax25)
-{
- skb_queue_purge(&ax25->write_queue);
- skb_queue_purge(&ax25->ack_queue);
- skb_queue_purge(&ax25->reseq_queue);
- skb_queue_purge(&ax25->frag_queue);
-}
-
-/*
- * This routine purges the input queue of those frames that have been
- * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
- * SDL diagram.
- */
-void ax25_frames_acked(ax25_cb *ax25, unsigned short nr)
-{
- struct sk_buff *skb;
-
- /*
- * Remove all the ack-ed frames from the ack queue.
- */
- if (ax25->va != nr) {
- while (skb_peek(&ax25->ack_queue) != NULL && ax25->va != nr) {
- skb = skb_dequeue(&ax25->ack_queue);
- kfree_skb(skb);
- ax25->va = (ax25->va + 1) % ax25->modulus;
- }
- }
-}
-
-void ax25_requeue_frames(ax25_cb *ax25)
-{
- struct sk_buff *skb;
-
- /*
- * Requeue all the un-ack-ed frames on the output queue to be picked
- * up by ax25_kick called from the timer. This arrangement handles the
- * possibility of an empty output queue.
- */
- while ((skb = skb_dequeue_tail(&ax25->ack_queue)) != NULL)
- skb_queue_head(&ax25->write_queue, skb);
-}
-
-/*
- * Validate that the value of nr is between va and vs. Return true or
- * false for testing.
- */
-int ax25_validate_nr(ax25_cb *ax25, unsigned short nr)
-{
- unsigned short vc = ax25->va;
-
- while (vc != ax25->vs) {
- if (nr == vc) return 1;
- vc = (vc + 1) % ax25->modulus;
- }
-
- if (nr == ax25->vs) return 1;
-
- return 0;
-}
-
-/*
- * This routine is the centralised routine for parsing the control
- * information for the different frame formats.
- */
-int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
-{
- unsigned char *frame;
- int frametype = AX25_ILLEGAL;
-
- frame = skb->data;
- *ns = *nr = *pf = 0;
-
- if (ax25->modulus == AX25_MODULUS) {
- if ((frame[0] & AX25_S) == 0) {
- frametype = AX25_I; /* I frame - carries NR/NS/PF */
- *ns = (frame[0] >> 1) & 0x07;
- *nr = (frame[0] >> 5) & 0x07;
- *pf = frame[0] & AX25_PF;
- } else if ((frame[0] & AX25_U) == 1) { /* S frame - take out PF/NR */
- frametype = frame[0] & 0x0F;
- *nr = (frame[0] >> 5) & 0x07;
- *pf = frame[0] & AX25_PF;
- } else if ((frame[0] & AX25_U) == 3) { /* U frame - take out PF */
- frametype = frame[0] & ~AX25_PF;
- *pf = frame[0] & AX25_PF;
- }
- skb_pull(skb, 1);
- } else {
- if ((frame[0] & AX25_S) == 0) {
- frametype = AX25_I; /* I frame - carries NR/NS/PF */
- *ns = (frame[0] >> 1) & 0x7F;
- *nr = (frame[1] >> 1) & 0x7F;
- *pf = frame[1] & AX25_EPF;
- skb_pull(skb, 2);
- } else if ((frame[0] & AX25_U) == 1) { /* S frame - take out PF/NR */
- frametype = frame[0] & 0x0F;
- *nr = (frame[1] >> 1) & 0x7F;
- *pf = frame[1] & AX25_EPF;
- skb_pull(skb, 2);
- } else if ((frame[0] & AX25_U) == 3) { /* U frame - take out PF */
- frametype = frame[0] & ~AX25_PF;
- *pf = frame[0] & AX25_PF;
- skb_pull(skb, 1);
- }
- }
-
- return frametype;
-}
-
-/*
- * This routine is called when the HDLC layer internally generates a
- * 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)
-{
- struct sk_buff *skb;
- unsigned char *dptr;
-
- if ((skb = alloc_skb(ax25->ax25_dev->dev->hard_header_len + 2, GFP_ATOMIC)) == NULL)
- return;
-
- skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len);
-
- skb_reset_network_header(skb);
-
- /* Assume a response - address structure for DTE */
- if (ax25->modulus == AX25_MODULUS) {
- dptr = skb_put(skb, 1);
- *dptr = frametype;
- *dptr |= (poll_bit) ? AX25_PF : 0;
- if ((frametype & AX25_U) == AX25_S) /* S frames carry NR */
- *dptr |= (ax25->vr << 5);
- } else {
- if ((frametype & AX25_U) == AX25_U) {
- dptr = skb_put(skb, 1);
- *dptr = frametype;
- *dptr |= (poll_bit) ? AX25_PF : 0;
- } else {
- dptr = skb_put(skb, 2);
- dptr[0] = frametype;
- dptr[1] = (ax25->vr << 1);
- dptr[1] |= (poll_bit) ? AX25_EPF : 0;
- }
- }
-
- ax25_transmit_buffer(ax25, skb, type);
-}
-
-/*
- * Send a 'DM' to an unknown connection attempt, or an invalid caller.
- *
- * Note: src here is the sender, thus it's the target of the DM
- */
-void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi)
-{
- struct sk_buff *skb;
- char *dptr;
- ax25_digi retdigi;
-
- if (dev == NULL)
- return;
-
- if ((skb = alloc_skb(dev->hard_header_len + 1, GFP_ATOMIC)) == NULL)
- return; /* Next SABM will get DM'd */
-
- skb_reserve(skb, dev->hard_header_len);
- skb_reset_network_header(skb);
-
- ax25_digi_invert(digi, &retdigi);
-
- dptr = skb_put(skb, 1);
-
- *dptr = AX25_DM | AX25_PF;
-
- /*
- * Do the address ourselves
- */
- dptr = skb_push(skb, ax25_addr_size(digi));
- dptr += ax25_addr_build(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS);
-
- ax25_queue_xmit(skb, dev);
-}
-
-/*
- * Exponential backoff for AX.25
- */
-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;
- }
-
- ax25->t1 = t * ax25->rtt;
-}
-
-/*
- * Calculate the Round Trip Time
- */
-void ax25_calculate_rtt(ax25_cb *ax25)
-{
- if (ax25->backoff == 0)
- return;
-
- if (ax25_t1timer_running(ax25) && ax25->n2count == 0)
- ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25_display_timer(&ax25->t1timer)) / 10;
-
- if (ax25->rtt < AX25_T1CLAMPLO)
- ax25->rtt = AX25_T1CLAMPLO;
-
- if (ax25->rtt > AX25_T1CLAMPHI)
- ax25->rtt = AX25_T1CLAMPHI;
-}
-
-void ax25_disconnect(ax25_cb *ax25, int reason)
-{
- ax25_clear_queues(ax25);
-
- if (reason == ENETUNREACH) {
- timer_delete_sync(&ax25->timer);
- timer_delete_sync(&ax25->t1timer);
- timer_delete_sync(&ax25->t2timer);
- timer_delete_sync(&ax25->t3timer);
- timer_delete_sync(&ax25->idletimer);
- } else {
- if (ax25->sk && !sock_flag(ax25->sk, SOCK_DESTROY))
- ax25_stop_heartbeat(ax25);
- ax25_stop_t1timer(ax25);
- ax25_stop_t2timer(ax25);
- ax25_stop_t3timer(ax25);
- ax25_stop_idletimer(ax25);
- }
-
- ax25->state = AX25_STATE_0;
-
- ax25_link_failed(ax25, reason);
-
- if (ax25->sk != NULL) {
- local_bh_disable();
- bh_lock_sock(ax25->sk);
- ax25->sk->sk_state = TCP_CLOSE;
- ax25->sk->sk_err = reason;
- ax25->sk->sk_shutdown |= SEND_SHUTDOWN;
- if (!sock_flag(ax25->sk, SOCK_DEAD)) {
- ax25->sk->sk_state_change(ax25->sk);
- sock_set_flag(ax25->sk, SOCK_DEAD);
- }
- bh_unlock_sock(ax25->sk);
- local_bh_enable();
- }
-}
diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c
deleted file mode 100644
index a69bfbc8b679..000000000000
--- a/net/ax25/ax25_timer.c
+++ /dev/null
@@ -1,224 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-static void ax25_heartbeat_expiry(struct timer_list *);
-static void ax25_t1timer_expiry(struct timer_list *);
-static void ax25_t2timer_expiry(struct timer_list *);
-static void ax25_t3timer_expiry(struct timer_list *);
-static void ax25_idletimer_expiry(struct timer_list *);
-
-void ax25_setup_timers(ax25_cb *ax25)
-{
- timer_setup(&ax25->timer, ax25_heartbeat_expiry, 0);
- timer_setup(&ax25->t1timer, ax25_t1timer_expiry, 0);
- timer_setup(&ax25->t2timer, ax25_t2timer_expiry, 0);
- timer_setup(&ax25->t3timer, ax25_t3timer_expiry, 0);
- timer_setup(&ax25->idletimer, ax25_idletimer_expiry, 0);
-}
-
-void ax25_start_heartbeat(ax25_cb *ax25)
-{
- mod_timer(&ax25->timer, jiffies + 5 * HZ);
-}
-
-void ax25_start_t1timer(ax25_cb *ax25)
-{
- mod_timer(&ax25->t1timer, jiffies + ax25->t1);
-}
-
-void ax25_start_t2timer(ax25_cb *ax25)
-{
- mod_timer(&ax25->t2timer, jiffies + ax25->t2);
-}
-
-void ax25_start_t3timer(ax25_cb *ax25)
-{
- if (ax25->t3 > 0)
- mod_timer(&ax25->t3timer, jiffies + ax25->t3);
- else
- timer_delete(&ax25->t3timer);
-}
-
-void ax25_start_idletimer(ax25_cb *ax25)
-{
- if (ax25->idle > 0)
- mod_timer(&ax25->idletimer, jiffies + ax25->idle);
- else
- timer_delete(&ax25->idletimer);
-}
-
-void ax25_stop_heartbeat(ax25_cb *ax25)
-{
- timer_delete(&ax25->timer);
-}
-
-void ax25_stop_t1timer(ax25_cb *ax25)
-{
- timer_delete(&ax25->t1timer);
-}
-
-void ax25_stop_t2timer(ax25_cb *ax25)
-{
- timer_delete(&ax25->t2timer);
-}
-
-void ax25_stop_t3timer(ax25_cb *ax25)
-{
- timer_delete(&ax25->t3timer);
-}
-
-void ax25_stop_idletimer(ax25_cb *ax25)
-{
- timer_delete(&ax25->idletimer);
-}
-
-int ax25_t1timer_running(ax25_cb *ax25)
-{
- return timer_pending(&ax25->t1timer);
-}
-
-unsigned long ax25_display_timer(struct timer_list *timer)
-{
- long delta = timer->expires - jiffies;
-
- if (!timer_pending(timer))
- return 0;
-
- return max(0L, delta);
-}
-
-EXPORT_SYMBOL(ax25_display_timer);
-
-static void ax25_heartbeat_expiry(struct timer_list *t)
-{
- int proto = AX25_PROTO_STD_SIMPLEX;
- ax25_cb *ax25 = timer_container_of(ax25, t, timer);
-
- if (ax25->ax25_dev)
- proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL];
-
- switch (proto) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_std_heartbeat_expiry(ax25);
- break;
-
-#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;
-#endif
- }
-}
-
-static void ax25_t1timer_expiry(struct timer_list *t)
-{
- ax25_cb *ax25 = timer_container_of(ax25, t, t1timer);
-
- switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- 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;
-#endif
- }
-}
-
-static void ax25_t2timer_expiry(struct timer_list *t)
-{
- ax25_cb *ax25 = timer_container_of(ax25, t, t2timer);
-
- switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- 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;
-#endif
- }
-}
-
-static void ax25_t3timer_expiry(struct timer_list *t)
-{
- ax25_cb *ax25 = timer_container_of(ax25, t, t3timer);
-
- switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- 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;
-#endif
- }
-}
-
-static void ax25_idletimer_expiry(struct timer_list *t)
-{
- ax25_cb *ax25 = timer_container_of(ax25, t, idletimer);
-
- switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- 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;
-#endif
- }
-}
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c
deleted file mode 100644
index 159ce74273f0..000000000000
--- a/net/ax25/ax25_uid.c
+++ /dev/null
@@ -1,204 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/notifier.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/stat.h>
-#include <linux/sysctl.h>
-#include <linux/export.h>
-#include <net/ip.h>
-#include <net/arp.h>
-
-/*
- * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines.
- */
-
-static HLIST_HEAD(ax25_uid_list);
-static DEFINE_RWLOCK(ax25_uid_lock);
-
-int ax25_uid_policy;
-
-EXPORT_SYMBOL(ax25_uid_policy);
-
-ax25_uid_assoc *ax25_findbyuid(kuid_t uid)
-{
- ax25_uid_assoc *ax25_uid, *res = NULL;
-
- read_lock(&ax25_uid_lock);
- ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
- if (uid_eq(ax25_uid->uid, uid)) {
- ax25_uid_hold(ax25_uid);
- res = ax25_uid;
- break;
- }
- }
- read_unlock(&ax25_uid_lock);
-
- return res;
-}
-
-EXPORT_SYMBOL(ax25_findbyuid);
-
-int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
-{
- ax25_uid_assoc *ax25_uid;
- ax25_uid_assoc *user;
- unsigned long res;
-
- switch (cmd) {
- case SIOCAX25GETUID:
- res = -ENOENT;
- read_lock(&ax25_uid_lock);
- ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
- if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
- res = from_kuid_munged(current_user_ns(), ax25_uid->uid);
- break;
- }
- }
- read_unlock(&ax25_uid_lock);
-
- return res;
-
- case SIOCAX25ADDUID:
- {
- kuid_t sax25_kuid;
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- sax25_kuid = make_kuid(current_user_ns(), sax->sax25_uid);
- if (!uid_valid(sax25_kuid))
- return -EINVAL;
- user = ax25_findbyuid(sax25_kuid);
- if (user) {
- ax25_uid_put(user);
- return -EEXIST;
- }
- if (sax->sax25_uid == 0)
- return -EINVAL;
- if ((ax25_uid = kmalloc_obj(*ax25_uid)) == NULL)
- return -ENOMEM;
-
- refcount_set(&ax25_uid->refcount, 1);
- ax25_uid->uid = sax25_kuid;
- ax25_uid->call = sax->sax25_call;
-
- write_lock(&ax25_uid_lock);
- hlist_add_head(&ax25_uid->uid_node, &ax25_uid_list);
- write_unlock(&ax25_uid_lock);
-
- return 0;
- }
- case SIOCAX25DELUID:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- ax25_uid = NULL;
- write_lock(&ax25_uid_lock);
- ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
- if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
- break;
- }
- if (ax25_uid == NULL) {
- write_unlock(&ax25_uid_lock);
- return -ENOENT;
- }
- hlist_del_init(&ax25_uid->uid_node);
- ax25_uid_put(ax25_uid);
- write_unlock(&ax25_uid_lock);
-
- return 0;
-
- default:
- return -EINVAL;
- }
-
- return -EINVAL; /*NOTREACHED */
-}
-
-#ifdef CONFIG_PROC_FS
-
-static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(ax25_uid_lock)
-{
- read_lock(&ax25_uid_lock);
- return seq_hlist_start_head(&ax25_uid_list, *pos);
-}
-
-static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- return seq_hlist_next(v, &ax25_uid_list, pos);
-}
-
-static void ax25_uid_seq_stop(struct seq_file *seq, void *v)
- __releases(ax25_uid_lock)
-{
- read_unlock(&ax25_uid_lock);
-}
-
-static int ax25_uid_seq_show(struct seq_file *seq, void *v)
-{
- char buf[11];
-
- if (v == SEQ_START_TOKEN)
- seq_printf(seq, "Policy: %d\n", ax25_uid_policy);
- else {
- struct ax25_uid_assoc *pt;
-
- pt = hlist_entry(v, struct ax25_uid_assoc, uid_node);
- seq_printf(seq, "%6d %s\n",
- from_kuid_munged(seq_user_ns(seq), pt->uid),
- ax2asc(buf, &pt->call));
- }
- return 0;
-}
-
-const struct seq_operations ax25_uid_seqops = {
- .start = ax25_uid_seq_start,
- .next = ax25_uid_seq_next,
- .stop = ax25_uid_seq_stop,
- .show = ax25_uid_seq_show,
-};
-#endif
-
-/*
- * Free all memory associated with UID/Callsign structures.
- */
-void __exit ax25_uid_free(void)
-{
- ax25_uid_assoc *ax25_uid;
-
- write_lock(&ax25_uid_lock);
-again:
- ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
- hlist_del_init(&ax25_uid->uid_node);
- ax25_uid_put(ax25_uid);
- goto again;
- }
- write_unlock(&ax25_uid_lock);
-}
diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c
deleted file mode 100644
index 68753aa30334..000000000000
--- a/net/ax25/sysctl_net_ax25.c
+++ /dev/null
@@ -1,181 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
- */
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/sysctl.h>
-#include <linux/spinlock.h>
-#include <net/ax25.h>
-
-static int min_ipdefmode[1], max_ipdefmode[] = {1};
-static int min_axdefmode[1], max_axdefmode[] = {1};
-static int min_backoff[1], max_backoff[] = {2};
-static int min_conmode[1], max_conmode[] = {2};
-static int min_window[] = {1}, max_window[] = {7};
-static int min_ewindow[] = {1}, max_ewindow[] = {63};
-static int min_t1[] = {1}, max_t1[] = {30000};
-static int min_t2[] = {1}, max_t2[] = {20000};
-static int min_t3[1], max_t3[] = {3600000};
-static int min_idle[1], max_idle[] = {65535000};
-static int min_n2[] = {1}, max_n2[] = {31};
-static int min_paclen[] = {1}, max_paclen[] = {512};
-static int min_proto[1], max_proto[] = { AX25_PROTO_MAX };
-#ifdef CONFIG_AX25_DAMA_SLAVE
-static int min_ds_timeout[1], max_ds_timeout[] = {65535000};
-#endif
-
-static const struct ctl_table ax25_param_table[] = {
- {
- .procname = "ip_default_mode",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_ipdefmode,
- .extra2 = &max_ipdefmode
- },
- {
- .procname = "ax25_default_mode",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_axdefmode,
- .extra2 = &max_axdefmode
- },
- {
- .procname = "backoff_type",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_backoff,
- .extra2 = &max_backoff
- },
- {
- .procname = "connect_mode",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_conmode,
- .extra2 = &max_conmode
- },
- {
- .procname = "standard_window_size",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_window,
- .extra2 = &max_window
- },
- {
- .procname = "extended_window_size",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_ewindow,
- .extra2 = &max_ewindow
- },
- {
- .procname = "t1_timeout",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_t1,
- .extra2 = &max_t1
- },
- {
- .procname = "t2_timeout",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_t2,
- .extra2 = &max_t2
- },
- {
- .procname = "t3_timeout",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_t3,
- .extra2 = &max_t3
- },
- {
- .procname = "idle_timeout",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_idle,
- .extra2 = &max_idle
- },
- {
- .procname = "maximum_retry_count",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_n2,
- .extra2 = &max_n2
- },
- {
- .procname = "maximum_packet_length",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_paclen,
- .extra2 = &max_paclen
- },
- {
- .procname = "protocol",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_proto,
- .extra2 = &max_proto
- },
-#ifdef CONFIG_AX25_DAMA_SLAVE
- {
- .procname = "dama_slave_timeout",
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_ds_timeout,
- .extra2 = &max_ds_timeout
- },
-#endif
-};
-
-int ax25_register_dev_sysctl(ax25_dev *ax25_dev)
-{
- char path[sizeof("net/ax25/") + IFNAMSIZ];
- int k;
- struct ctl_table *table;
-
- table = kmemdup(ax25_param_table, sizeof(ax25_param_table), GFP_KERNEL);
- if (!table)
- return -ENOMEM;
-
- BUILD_BUG_ON(ARRAY_SIZE(ax25_param_table) != AX25_MAX_VALUES);
- for (k = 0; k < AX25_MAX_VALUES; k++)
- table[k].data = &ax25_dev->values[k];
-
- snprintf(path, sizeof(path), "net/ax25/%s", ax25_dev->dev->name);
- ax25_dev->sysheader = register_net_sysctl_sz(&init_net, path, table,
- ARRAY_SIZE(ax25_param_table));
- if (!ax25_dev->sysheader) {
- kfree(table);
- return -ENOMEM;
- }
- return 0;
-}
-
-void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev)
-{
- struct ctl_table_header *header = ax25_dev->sysheader;
- const struct ctl_table *table;
-
- if (header) {
- ax25_dev->sysheader = NULL;
- table = header->ctl_table_arg;
- unregister_net_sysctl_table(header);
- kfree(table);
- }
-}
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 51d70180e1cc..d409f606aec0 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -109,7 +109,6 @@
#include <net/sock.h>
#include <net/arp.h>
#include <net/ax25.h>
-#include <net/netrom.h>
#include <net/dst_metadata.h>
#include <net/ip_tunnels.h>
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
deleted file mode 100644
index 5fc54836dfa8..000000000000
--- a/net/netrom/af_netrom.c
+++ /dev/null
@@ -1,1536 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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/module.h>
-#include <linux/moduleparam.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/sched/signal.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/stat.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/net_namespace.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/termios.h> /* For TIOCINQ/OUTQ */
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <net/netrom.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <net/ip.h>
-#include <net/tcp_states.h>
-#include <net/arp.h>
-#include <linux/init.h>
-
-static int nr_ndevs = 4;
-
-int sysctl_netrom_default_path_quality = NR_DEFAULT_QUAL;
-int sysctl_netrom_obsolescence_count_initialiser = NR_DEFAULT_OBS;
-int sysctl_netrom_network_ttl_initialiser = NR_DEFAULT_TTL;
-int sysctl_netrom_transport_timeout = NR_DEFAULT_T1;
-int sysctl_netrom_transport_maximum_tries = NR_DEFAULT_N2;
-int sysctl_netrom_transport_acknowledge_delay = NR_DEFAULT_T2;
-int sysctl_netrom_transport_busy_delay = NR_DEFAULT_T4;
-int sysctl_netrom_transport_requested_window_size = NR_DEFAULT_WINDOW;
-int sysctl_netrom_transport_no_activity_timeout = NR_DEFAULT_IDLE;
-int sysctl_netrom_routing_control = NR_DEFAULT_ROUTING;
-int sysctl_netrom_link_fails_count = NR_DEFAULT_FAILS;
-int sysctl_netrom_reset_circuit = NR_DEFAULT_RESET;
-
-static unsigned short circuit = 0x101;
-
-static HLIST_HEAD(nr_list);
-static DEFINE_SPINLOCK(nr_list_lock);
-
-static const struct proto_ops nr_proto_ops;
-
-/*
- * NETROM network devices are virtual network devices encapsulating NETROM
- * frames into AX.25 which will be sent through an AX.25 device, so form a
- * special "super class" of normal net devices; split their locks off into a
- * separate class since they always nest.
- */
-static struct lock_class_key nr_netdev_xmit_lock_key;
-static struct lock_class_key nr_netdev_addr_lock_key;
-
-static void nr_set_lockdep_one(struct net_device *dev,
- struct netdev_queue *txq,
- void *_unused)
-{
- lockdep_set_class(&txq->_xmit_lock, &nr_netdev_xmit_lock_key);
-}
-
-static void nr_set_lockdep_key(struct net_device *dev)
-{
- lockdep_set_class(&dev->addr_list_lock, &nr_netdev_addr_lock_key);
- netdev_for_each_tx_queue(dev, nr_set_lockdep_one, NULL);
-}
-
-/*
- * Socket removal during an interrupt is now safe.
- */
-static void nr_remove_socket(struct sock *sk)
-{
- spin_lock_bh(&nr_list_lock);
- sk_del_node_init(sk);
- spin_unlock_bh(&nr_list_lock);
-}
-
-/*
- * Kill all bound sockets on a dropped device.
- */
-static void nr_kill_by_device(struct net_device *dev)
-{
- struct sock *s;
-
- spin_lock_bh(&nr_list_lock);
- sk_for_each(s, &nr_list)
- if (nr_sk(s)->device == dev)
- nr_disconnect(s, ENETUNREACH);
- spin_unlock_bh(&nr_list_lock);
-}
-
-/*
- * Handle device status changes.
- */
-static int nr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
- if (event != NETDEV_DOWN)
- return NOTIFY_DONE;
-
- nr_kill_by_device(dev);
- nr_rt_device_down(dev);
-
- return NOTIFY_DONE;
-}
-
-/*
- * Add a socket to the bound sockets list.
- */
-static void nr_insert_socket(struct sock *sk)
-{
- spin_lock_bh(&nr_list_lock);
- sk_add_node(sk, &nr_list);
- spin_unlock_bh(&nr_list_lock);
-}
-
-/*
- * Find a socket that wants to accept the Connect Request we just
- * received.
- */
-static struct sock *nr_find_listener(ax25_address *addr)
-{
- struct sock *s;
-
- spin_lock_bh(&nr_list_lock);
- sk_for_each(s, &nr_list)
- if (!ax25cmp(&nr_sk(s)->source_addr, addr) &&
- s->sk_state == TCP_LISTEN) {
- sock_hold(s);
- goto found;
- }
- s = NULL;
-found:
- spin_unlock_bh(&nr_list_lock);
- return s;
-}
-
-/*
- * Find a connected NET/ROM socket given my circuit IDs.
- */
-static struct sock *nr_find_socket(unsigned char index, unsigned char id)
-{
- struct sock *s;
-
- spin_lock_bh(&nr_list_lock);
- sk_for_each(s, &nr_list) {
- struct nr_sock *nr = nr_sk(s);
-
- if (nr->my_index == index && nr->my_id == id) {
- sock_hold(s);
- goto found;
- }
- }
- s = NULL;
-found:
- spin_unlock_bh(&nr_list_lock);
- return s;
-}
-
-/*
- * 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)
-{
- struct sock *s;
-
- spin_lock_bh(&nr_list_lock);
- sk_for_each(s, &nr_list) {
- struct nr_sock *nr = nr_sk(s);
-
- if (nr->your_index == index && nr->your_id == id &&
- !ax25cmp(&nr->dest_addr, dest)) {
- sock_hold(s);
- goto found;
- }
- }
- s = NULL;
-found:
- spin_unlock_bh(&nr_list_lock);
- return s;
-}
-
-/*
- * Find next free circuit ID.
- */
-static unsigned short nr_find_next_circuit(void)
-{
- unsigned short id = circuit;
- unsigned char i, j;
- struct sock *sk;
-
- for (;;) {
- i = id / 256;
- j = id % 256;
-
- if (i != 0 && j != 0) {
- if ((sk=nr_find_socket(i, j)) == NULL)
- break;
- sock_put(sk);
- }
-
- id++;
- }
-
- return id;
-}
-
-/*
- * Deferred destroy.
- */
-void nr_destroy_socket(struct sock *);
-
-/*
- * Handler for deferred kills.
- */
-static void nr_destroy_timer(struct timer_list *t)
-{
- struct sock *sk = timer_container_of(sk, t, sk_timer);
- bh_lock_sock(sk);
- sock_hold(sk);
- nr_destroy_socket(sk);
- bh_unlock_sock(sk);
- sock_put(sk);
-}
-
-/*
- * 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)
-{
- struct sk_buff *skb;
-
- nr_remove_socket(sk);
-
- nr_stop_heartbeat(sk);
- nr_stop_t1timer(sk);
- nr_stop_t2timer(sk);
- nr_stop_t4timer(sk);
- nr_stop_idletimer(sk);
-
- nr_clear_queues(sk); /* Flush the queues */
-
- while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
- if (skb->sk != sk) { /* A pending connection */
- /* Queue the unaccepted socket for death */
- sock_set_flag(skb->sk, SOCK_DEAD);
- nr_start_heartbeat(skb->sk);
- nr_sk(skb->sk)->state = NR_STATE_0;
- }
-
- kfree_skb(skb);
- }
-
- if (sk_has_allocations(sk)) {
- /* Defer: outstanding buffers */
- sk->sk_timer.function = nr_destroy_timer;
- sk->sk_timer.expires = jiffies + 2 * HZ;
- add_timer(&sk->sk_timer);
- } else
- sock_put(sk);
-}
-
-/*
- * Handling for system calls applied via the various interfaces to a
- * NET/ROM socket object.
- */
-
-static int nr_setsockopt(struct socket *sock, int level, int optname,
- sockptr_t optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- struct nr_sock *nr = nr_sk(sk);
- unsigned int opt;
-
- if (level != SOL_NETROM)
- return -ENOPROTOOPT;
-
- if (optlen < sizeof(unsigned int))
- return -EINVAL;
-
- if (copy_from_sockptr(&opt, optval, sizeof(opt)))
- return -EFAULT;
-
- switch (optname) {
- case NETROM_T1:
- if (opt < 1 || opt > UINT_MAX / HZ)
- return -EINVAL;
- nr->t1 = opt * HZ;
- return 0;
-
- case NETROM_T2:
- if (opt < 1 || opt > UINT_MAX / HZ)
- 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 || opt > UINT_MAX / HZ)
- return -EINVAL;
- nr->t4 = opt * HZ;
- return 0;
-
- case NETROM_IDLE:
- if (opt > UINT_MAX / (60 * HZ))
- return -EINVAL;
- nr->idle = opt * 60 * HZ;
- return 0;
-
- default:
- return -ENOPROTOOPT;
- }
-}
-
-static int nr_getsockopt(struct socket *sock, int level, int optname,
- char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- struct nr_sock *nr = nr_sk(sk);
- int val = 0;
- int len;
-
- if (level != SOL_NETROM)
- return -ENOPROTOOPT;
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- if (len < 0)
- return -EINVAL;
-
- switch (optname) {
- case NETROM_T1:
- val = nr->t1 / HZ;
- break;
-
- case NETROM_T2:
- val = nr->t2 / HZ;
- break;
-
- case NETROM_N2:
- val = nr->n2;
- break;
-
- case NETROM_T4:
- val = nr->t4 / HZ;
- break;
-
- case NETROM_IDLE:
- val = nr->idle / (60 * HZ);
- break;
-
- default:
- return -ENOPROTOOPT;
- }
-
- len = min_t(unsigned int, len, sizeof(int));
-
- if (put_user(len, optlen))
- return -EFAULT;
-
- return copy_to_user(optval, &val, len) ? -EFAULT : 0;
-}
-
-static int nr_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = sock->sk;
-
- lock_sock(sk);
- if (sock->state != SS_UNCONNECTED) {
- release_sock(sk);
- return -EINVAL;
- }
-
- if (sk->sk_state != TCP_LISTEN) {
- memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
- sk->sk_max_ack_backlog = backlog;
- sk->sk_state = TCP_LISTEN;
- release_sock(sk);
- return 0;
- }
- release_sock(sk);
-
- return -EOPNOTSUPP;
-}
-
-static struct proto nr_proto = {
- .name = "NETROM",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct nr_sock),
-};
-
-static int nr_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
- struct nr_sock *nr;
-
- if (!net_eq(net, &init_net))
- return -EAFNOSUPPORT;
-
- if (sock->type != SOCK_SEQPACKET || protocol != 0)
- return -ESOCKTNOSUPPORT;
-
- sk = sk_alloc(net, PF_NETROM, GFP_ATOMIC, &nr_proto, kern);
- if (sk == NULL)
- return -ENOMEM;
-
- nr = nr_sk(sk);
-
- sock_init_data(sock, sk);
-
- sock->ops = &nr_proto_ops;
- sk->sk_protocol = protocol;
-
- skb_queue_head_init(&nr->ack_queue);
- skb_queue_head_init(&nr->reseq_queue);
- skb_queue_head_init(&nr->frag_queue);
-
- nr_init_timers(sk);
-
- nr->t1 =
- msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_timeout));
- nr->t2 =
- msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_acknowledge_delay));
- nr->n2 =
- msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_maximum_tries));
- nr->t4 =
- msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_busy_delay));
- nr->idle =
- msecs_to_jiffies(READ_ONCE(sysctl_netrom_transport_no_activity_timeout));
- nr->window = READ_ONCE(sysctl_netrom_transport_requested_window_size);
-
- nr->bpqext = 1;
- nr->state = NR_STATE_0;
-
- return 0;
-}
-
-static struct sock *nr_make_new(struct sock *osk)
-{
- struct sock *sk;
- struct nr_sock *nr, *onr;
-
- if (osk->sk_type != SOCK_SEQPACKET)
- return NULL;
-
- sk = sk_alloc(sock_net(osk), PF_NETROM, GFP_ATOMIC, osk->sk_prot, 0);
- if (sk == NULL)
- return NULL;
-
- nr = nr_sk(sk);
-
- sock_init_data(NULL, sk);
-
- sk->sk_type = osk->sk_type;
- sk->sk_priority = READ_ONCE(osk->sk_priority);
- sk->sk_protocol = osk->sk_protocol;
- sk->sk_rcvbuf = osk->sk_rcvbuf;
- sk->sk_sndbuf = osk->sk_sndbuf;
- sk->sk_state = TCP_ESTABLISHED;
- sock_copy_flags(sk, osk);
-
- skb_queue_head_init(&nr->ack_queue);
- skb_queue_head_init(&nr->reseq_queue);
- skb_queue_head_init(&nr->frag_queue);
-
- nr_init_timers(sk);
-
- onr = nr_sk(osk);
-
- nr->t1 = onr->t1;
- nr->t2 = onr->t2;
- nr->n2 = onr->n2;
- nr->t4 = onr->t4;
- nr->idle = onr->idle;
- nr->window = onr->window;
-
- nr->device = onr->device;
- nr->bpqext = onr->bpqext;
-
- return sk;
-}
-
-static int nr_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
- struct nr_sock *nr;
-
- if (sk == NULL) return 0;
-
- sock_hold(sk);
- sock_orphan(sk);
- lock_sock(sk);
- 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->sk_state = TCP_CLOSE;
- sk->sk_shutdown |= SEND_SHUTDOWN;
- sk->sk_state_change(sk);
- sock_set_flag(sk, SOCK_DESTROY);
- break;
-
- default:
- break;
- }
-
- sock->sk = NULL;
- release_sock(sk);
- sock_put(sk);
-
- return 0;
-}
-
-static int nr_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len)
-{
- struct sock *sk = sock->sk;
- struct nr_sock *nr = nr_sk(sk);
- struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
- struct net_device *dev;
- ax25_uid_assoc *user;
- ax25_address *source;
-
- lock_sock(sk);
- if (!sock_flag(sk, SOCK_ZAPPED)) {
- release_sock(sk);
- return -EINVAL;
- }
- if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25)) {
- release_sock(sk);
- return -EINVAL;
- }
- if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) {
- release_sock(sk);
- return -EINVAL;
- }
- if (addr->fsa_ax25.sax25_family != AF_NETROM) {
- release_sock(sk);
- return -EINVAL;
- }
- if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) {
- release_sock(sk);
- return -EADDRNOTAVAIL;
- }
-
- /*
- * Only the super user can set an arbitrary user callsign.
- */
- if (addr->fsa_ax25.sax25_ndigis == 1) {
- if (!capable(CAP_NET_BIND_SERVICE)) {
- dev_put(dev);
- release_sock(sk);
- return -EPERM;
- }
- nr->user_addr = addr->fsa_digipeater[0];
- nr->source_addr = addr->fsa_ax25.sax25_call;
- } else {
- source = &addr->fsa_ax25.sax25_call;
-
- user = ax25_findbyuid(current_euid());
- if (user) {
- nr->user_addr = user->call;
- ax25_uid_put(user);
- } else {
- if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
- release_sock(sk);
- dev_put(dev);
- return -EPERM;
- }
- nr->user_addr = *source;
- }
-
- nr->source_addr = *source;
- }
-
- nr->device = dev;
- nr_insert_socket(sk);
-
- sock_reset_flag(sk, SOCK_ZAPPED);
- dev_put(dev);
- release_sock(sk);
-
- return 0;
-}
-
-static int nr_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
- int addr_len, int flags)
-{
- struct sock *sk = sock->sk;
- struct nr_sock *nr = nr_sk(sk);
- struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;
- const ax25_address *source = NULL;
- ax25_uid_assoc *user;
- struct net_device *dev;
- int err = 0;
-
- lock_sock(sk);
- if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
- sock->state = SS_CONNECTED;
- goto out_release; /* Connect completed during a ERESTARTSYS event */
- }
-
- if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
- sock->state = SS_UNCONNECTED;
- err = -ECONNREFUSED;
- goto out_release;
- }
-
- if (sk->sk_state == TCP_ESTABLISHED) {
- err = -EISCONN; /* No reconnect on a seqpacket socket */
- goto out_release;
- }
-
- if (sock->state == SS_CONNECTING) {
- err = -EALREADY;
- goto out_release;
- }
-
- sk->sk_state = TCP_CLOSE;
- sock->state = SS_UNCONNECTED;
-
- if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) {
- err = -EINVAL;
- goto out_release;
- }
- if (addr->sax25_family != AF_NETROM) {
- err = -EINVAL;
- goto out_release;
- }
- if (sock_flag(sk, SOCK_ZAPPED)) { /* Must bind first - autobinding in this may or may not work */
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- if ((dev = nr_dev_first()) == NULL) {
- err = -ENETUNREACH;
- goto out_release;
- }
- source = (const ax25_address *)dev->dev_addr;
-
- user = ax25_findbyuid(current_euid());
- if (user) {
- nr->user_addr = user->call;
- ax25_uid_put(user);
- } else {
- if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
- dev_put(dev);
- err = -EPERM;
- goto out_release;
- }
- nr->user_addr = *source;
- }
-
- nr->source_addr = *source;
- nr->device = dev;
-
- dev_put(dev);
- nr_insert_socket(sk); /* Finish the bind */
- }
-
- nr->dest_addr = addr->sax25_call;
-
- release_sock(sk);
- circuit = nr_find_next_circuit();
- lock_sock(sk);
-
- nr->my_index = circuit / 256;
- nr->my_id = circuit % 256;
-
- circuit++;
-
- /* Move to connecting socket, start sending Connect Requests */
- sock->state = SS_CONNECTING;
- sk->sk_state = TCP_SYN_SENT;
-
- nr_establish_data_link(sk);
-
- nr->state = NR_STATE_1;
-
- nr_start_heartbeat(sk);
-
- /* Now the loop */
- if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
- err = -EINPROGRESS;
- goto out_release;
- }
-
- /*
- * A Connect Ack with Choke or timeout or failed routing will go to
- * closed.
- */
- if (sk->sk_state == TCP_SYN_SENT) {
- DEFINE_WAIT(wait);
-
- for (;;) {
- prepare_to_wait(sk_sleep(sk), &wait,
- TASK_INTERRUPTIBLE);
- if (sk->sk_state != TCP_SYN_SENT)
- break;
- if (!signal_pending(current)) {
- release_sock(sk);
- schedule();
- lock_sock(sk);
- continue;
- }
- err = -ERESTARTSYS;
- break;
- }
- finish_wait(sk_sleep(sk), &wait);
- if (err)
- goto out_release;
- }
-
- if (sk->sk_state != TCP_ESTABLISHED) {
- sock->state = SS_UNCONNECTED;
- err = sock_error(sk); /* Always set at this point */
- goto out_release;
- }
-
- sock->state = SS_CONNECTED;
-
-out_release:
- release_sock(sk);
-
- return err;
-}
-
-static int nr_accept(struct socket *sock, struct socket *newsock,
- struct proto_accept_arg *arg)
-{
- struct sk_buff *skb;
- struct sock *newsk;
- DEFINE_WAIT(wait);
- struct sock *sk;
- int err = 0;
-
- if ((sk = sock->sk) == NULL)
- return -EINVAL;
-
- lock_sock(sk);
- if (sk->sk_type != SOCK_SEQPACKET) {
- err = -EOPNOTSUPP;
- goto out_release;
- }
-
- if (sk->sk_state != TCP_LISTEN) {
- err = -EINVAL;
- goto out_release;
- }
-
- /*
- * The write queue this time is holding sockets ready to use
- * hooked into the SABM we saved
- */
- for (;;) {
- prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
- skb = skb_dequeue(&sk->sk_receive_queue);
- if (skb)
- break;
-
- if (arg->flags & O_NONBLOCK) {
- err = -EWOULDBLOCK;
- break;
- }
- if (!signal_pending(current)) {
- release_sock(sk);
- schedule();
- lock_sock(sk);
- continue;
- }
- err = -ERESTARTSYS;
- break;
- }
- finish_wait(sk_sleep(sk), &wait);
- if (err)
- goto out_release;
-
- newsk = skb->sk;
- sock_graft(newsk, newsock);
-
- /* Now attach up the new socket */
- kfree_skb(skb);
- sk_acceptq_removed(sk);
-
-out_release:
- release_sock(sk);
-
- return err;
-}
-
-static int nr_getname(struct socket *sock, struct sockaddr *uaddr,
- int peer)
-{
- struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr;
- struct sock *sk = sock->sk;
- struct nr_sock *nr = nr_sk(sk);
- int uaddr_len;
-
- memset(&sax->fsa_ax25, 0, sizeof(struct sockaddr_ax25));
-
- lock_sock(sk);
- if (peer != 0) {
- if (sk->sk_state != TCP_ESTABLISHED) {
- release_sock(sk);
- return -ENOTCONN;
- }
- sax->fsa_ax25.sax25_family = AF_NETROM;
- sax->fsa_ax25.sax25_ndigis = 1;
- sax->fsa_ax25.sax25_call = nr->user_addr;
- memset(sax->fsa_digipeater, 0, sizeof(sax->fsa_digipeater));
- sax->fsa_digipeater[0] = nr->dest_addr;
- uaddr_len = sizeof(struct full_sockaddr_ax25);
- } else {
- sax->fsa_ax25.sax25_family = AF_NETROM;
- sax->fsa_ax25.sax25_ndigis = 0;
- sax->fsa_ax25.sax25_call = nr->source_addr;
- uaddr_len = sizeof(struct sockaddr_ax25);
- }
- release_sock(sk);
-
- return uaddr_len;
-}
-
-int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
-{
- struct sock *sk;
- struct sock *make;
- struct nr_sock *nr_make;
- ax25_address *src, *dest, *user;
- unsigned short circuit_index, circuit_id;
- unsigned short peer_circuit_index, peer_circuit_id;
- unsigned short frametype, flags, window, timeout;
- int ret;
-
- skb_orphan(skb);
-
- /*
- * skb->data points to the netrom frame start
- */
-
- src = (ax25_address *)(skb->data + 0);
- dest = (ax25_address *)(skb->data + 7);
-
- circuit_index = skb->data[15];
- circuit_id = skb->data[16];
- peer_circuit_index = skb->data[17];
- peer_circuit_id = skb->data[18];
- frametype = skb->data[19] & 0x0F;
- flags = skb->data[19] & 0xF0;
-
- /*
- * Check for an incoming IP over NET/ROM frame.
- */
- if (frametype == NR_PROTOEXT &&
- circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
- skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
- skb_reset_transport_header(skb);
-
- return nr_rx_ip(skb, dev);
- }
-
- /*
- * Find an existing socket connection, based on circuit ID, if it's
- * a Connect Request base it on their circuit ID.
- *
- * Circuit ID 0/0 is not valid but it could still be a "reset" for a
- * circuit that no longer exists at the other end ...
- */
-
- sk = NULL;
-
- if (circuit_index == 0 && circuit_id == 0) {
- if (frametype == NR_CONNACK && flags == NR_CHOKE_FLAG)
- sk = nr_find_peer(peer_circuit_index, peer_circuit_id, src);
- } else {
- if (frametype == NR_CONNREQ)
- sk = nr_find_peer(circuit_index, circuit_id, src);
- else
- sk = nr_find_socket(circuit_index, circuit_id);
- }
-
- if (sk != NULL) {
- bh_lock_sock(sk);
- skb_reset_transport_header(skb);
-
- if (frametype == NR_CONNACK && skb->len == 22)
- nr_sk(sk)->bpqext = 1;
- else
- nr_sk(sk)->bpqext = 0;
-
- ret = nr_process_rx_frame(sk, skb);
- bh_unlock_sock(sk);
- sock_put(sk);
- return ret;
- }
-
- /*
- * Now it should be a CONNREQ.
- */
- if (frametype != NR_CONNREQ) {
- /*
- * Here it would be nice to be able to send a reset but
- * NET/ROM doesn't have one. We've tried to extend the protocol
- * by sending NR_CONNACK | NR_CHOKE_FLAGS replies but that
- * apparently kills BPQ boxes... :-(
- * So now we try to follow the established behaviour of
- * G8PZT's Xrouter which is sending packets with command type 7
- * as an extension of the protocol.
- */
- if (READ_ONCE(sysctl_netrom_reset_circuit) &&
- (frametype != NR_RESET || flags != 0))
- nr_transmit_reset(skb, 1);
-
- return 0;
- }
-
- sk = nr_find_listener(dest);
-
- user = (ax25_address *)(skb->data + 21);
-
- if (sk == NULL || sk_acceptq_is_full(sk) ||
- (make = nr_make_new(sk)) == NULL) {
- nr_transmit_refusal(skb, 0);
- if (sk)
- sock_put(sk);
- return 0;
- }
-
- bh_lock_sock(sk);
-
- window = skb->data[20];
-
- sock_hold(make);
- skb->sk = make;
- skb->destructor = sock_efree;
- make->sk_state = TCP_ESTABLISHED;
-
- /* Fill in his circuit details */
- nr_make = nr_sk(make);
- nr_make->source_addr = *dest;
- nr_make->dest_addr = *src;
- nr_make->user_addr = *user;
-
- nr_make->your_index = circuit_index;
- nr_make->your_id = circuit_id;
-
- bh_unlock_sock(sk);
- circuit = nr_find_next_circuit();
- bh_lock_sock(sk);
-
- nr_make->my_index = circuit / 256;
- nr_make->my_id = circuit % 256;
-
- circuit++;
-
- /* Window negotiation */
- if (window < nr_make->window)
- nr_make->window = window;
-
- /* L4 timeout negotiation */
- if (skb->len == 37) {
- timeout = skb->data[36] * 256 + skb->data[35];
- if (timeout * HZ < nr_make->t1)
- nr_make->t1 = timeout * HZ;
- nr_make->bpqext = 1;
- } else {
- nr_make->bpqext = 0;
- }
-
- nr_write_internal(make, NR_CONNACK);
-
- nr_make->condition = 0x00;
- nr_make->vs = 0;
- nr_make->va = 0;
- nr_make->vr = 0;
- nr_make->vl = 0;
- nr_make->state = NR_STATE_3;
- sk_acceptq_added(sk);
- skb_queue_head(&sk->sk_receive_queue, skb);
-
- if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_data_ready(sk);
-
- bh_unlock_sock(sk);
- sock_put(sk);
-
- nr_insert_socket(make);
-
- nr_start_heartbeat(make);
- nr_start_idletimer(make);
-
- return 1;
-}
-
-static int nr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
-{
- struct sock *sk = sock->sk;
- struct nr_sock *nr = nr_sk(sk);
- DECLARE_SOCKADDR(struct sockaddr_ax25 *, usax, msg->msg_name);
- int err;
- struct sockaddr_ax25 sax;
- struct sk_buff *skb;
- unsigned char *asmptr;
- int size;
-
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT))
- return -EINVAL;
-
- lock_sock(sk);
- if (sock_flag(sk, SOCK_ZAPPED)) {
- err = -EADDRNOTAVAIL;
- goto out;
- }
-
- if (sk->sk_shutdown & SEND_SHUTDOWN) {
- send_sig(SIGPIPE, current, 0);
- err = -EPIPE;
- goto out;
- }
-
- if (nr->device == NULL) {
- err = -ENETUNREACH;
- goto out;
- }
-
- if (usax) {
- if (msg->msg_namelen < sizeof(sax)) {
- err = -EINVAL;
- goto out;
- }
- sax = *usax;
- if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0) {
- err = -EISCONN;
- goto out;
- }
- if (sax.sax25_family != AF_NETROM) {
- err = -EINVAL;
- goto out;
- }
- } else {
- if (sk->sk_state != TCP_ESTABLISHED) {
- err = -ENOTCONN;
- goto out;
- }
- sax.sax25_family = AF_NETROM;
- sax.sax25_call = nr->dest_addr;
- }
-
- /* Build a packet - the conventional user limit is 236 bytes. We can
- do ludicrously large NetROM frames but must not overflow */
- if (len > 65536) {
- err = -EMSGSIZE;
- goto out;
- }
-
- size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
-
- if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
- goto out;
-
- skb_reserve(skb, size - len);
- skb_reset_transport_header(skb);
-
- /*
- * Push down the NET/ROM header
- */
-
- asmptr = skb_push(skb, NR_TRANSPORT_LEN);
-
- /* Build a NET/ROM Transport header */
-
- *asmptr++ = nr->your_index;
- *asmptr++ = nr->your_id;
- *asmptr++ = 0; /* To be filled in later */
- *asmptr++ = 0; /* Ditto */
- *asmptr++ = NR_INFO;
-
- /*
- * Put the data on the end
- */
- skb_put(skb, len);
-
- /* User data follows immediately after the NET/ROM transport header */
- if (memcpy_from_msg(skb_transport_header(skb), msg, len)) {
- kfree_skb(skb);
- err = -EFAULT;
- goto out;
- }
-
- if (sk->sk_state != TCP_ESTABLISHED) {
- kfree_skb(skb);
- err = -ENOTCONN;
- goto out;
- }
-
- nr_output(sk, skb); /* Shove it onto the queue */
-
- err = len;
-out:
- release_sock(sk);
- return err;
-}
-
-static int nr_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
- int flags)
-{
- struct sock *sk = sock->sk;
- DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name);
- size_t copied;
- struct sk_buff *skb;
- int er;
-
- /*
- * This works for seqpacket too. The receiver has ordered the queue for
- * us! We do one quick check first though
- */
-
- lock_sock(sk);
- if (sk->sk_state != TCP_ESTABLISHED) {
- release_sock(sk);
- return -ENOTCONN;
- }
-
- /* Now we can treat all alike */
- skb = skb_recv_datagram(sk, flags, &er);
- if (!skb) {
- release_sock(sk);
- return er;
- }
-
- skb_reset_transport_header(skb);
- copied = skb->len;
-
- if (copied > size) {
- copied = size;
- msg->msg_flags |= MSG_TRUNC;
- }
-
- er = skb_copy_datagram_msg(skb, 0, msg, copied);
- if (er < 0) {
- skb_free_datagram(sk, skb);
- release_sock(sk);
- return er;
- }
-
- if (sax != NULL) {
- memset(sax, 0, sizeof(*sax));
- sax->sax25_family = AF_NETROM;
- skb_copy_from_linear_data_offset(skb, 7, sax->sax25_call.ax25_call,
- AX25_ADDR_LEN);
- msg->msg_namelen = sizeof(*sax);
- }
-
- skb_free_datagram(sk, skb);
-
- release_sock(sk);
- return copied;
-}
-
-
-static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk = sock->sk;
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
- case TIOCOUTQ: {
- long amount;
-
- lock_sock(sk);
- amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
- if (amount < 0)
- amount = 0;
- release_sock(sk);
- return put_user(amount, (int __user *)argp);
- }
-
- case TIOCINQ: {
- struct sk_buff *skb;
- long amount = 0L;
-
- lock_sock(sk);
- /* These two are safe on a single CPU system as only user tasks fiddle here */
- if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
- amount = skb->len;
- release_sock(sk);
- return put_user(amount, (int __user *)argp);
- }
-
- 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, argp);
-
- default:
- return -ENOIOCTLCMD;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_PROC_FS
-
-static void *nr_info_start(struct seq_file *seq, loff_t *pos)
- __acquires(&nr_list_lock)
-{
- spin_lock_bh(&nr_list_lock);
- return seq_hlist_start_head(&nr_list, *pos);
-}
-
-static void *nr_info_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- return seq_hlist_next(v, &nr_list, pos);
-}
-
-static void nr_info_stop(struct seq_file *seq, void *v)
- __releases(&nr_list_lock)
-{
- spin_unlock_bh(&nr_list_lock);
-}
-
-static int nr_info_show(struct seq_file *seq, void *v)
-{
- struct sock *s = sk_entry(v);
- struct net_device *dev;
- struct nr_sock *nr;
- const char *devname;
- char buf[11];
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq,
-"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");
-
- else {
-
- bh_lock_sock(s);
- nr = nr_sk(s);
-
- if ((dev = nr->device) == NULL)
- devname = "???";
- else
- devname = dev->name;
-
- seq_printf(seq, "%-9s ", ax2asc(buf, &nr->user_addr));
- seq_printf(seq, "%-9s ", ax2asc(buf, &nr->dest_addr));
- seq_printf(seq,
-"%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %llu\n",
- ax2asc(buf, &nr->source_addr),
- devname,
- nr->my_index,
- nr->my_id,
- nr->your_index,
- nr->your_id,
- nr->state,
- nr->vs,
- nr->vr,
- nr->va,
- ax25_display_timer(&nr->t1timer) / HZ,
- nr->t1 / HZ,
- ax25_display_timer(&nr->t2timer) / HZ,
- nr->t2 / HZ,
- ax25_display_timer(&nr->t4timer) / HZ,
- nr->t4 / HZ,
- ax25_display_timer(&nr->idletimer) / (60 * HZ),
- nr->idle / (60 * HZ),
- nr->n2count,
- nr->n2,
- nr->window,
- sk_wmem_alloc_get(s),
- sk_rmem_alloc_get(s),
- s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : (u64)0);
-
- bh_unlock_sock(s);
- }
- return 0;
-}
-
-static const struct seq_operations nr_info_seqops = {
- .start = nr_info_start,
- .next = nr_info_next,
- .stop = nr_info_stop,
- .show = nr_info_show,
-};
-#endif /* CONFIG_PROC_FS */
-
-static const struct net_proto_family nr_family_ops = {
- .family = PF_NETROM,
- .create = nr_create,
- .owner = THIS_MODULE,
-};
-
-static const struct proto_ops nr_proto_ops = {
- .family = PF_NETROM,
- .owner = THIS_MODULE,
- .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,
- .gettstamp = sock_gettstamp,
- .listen = nr_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = nr_setsockopt,
- .getsockopt = nr_getsockopt,
- .sendmsg = nr_sendmsg,
- .recvmsg = nr_recvmsg,
- .mmap = sock_no_mmap,
-};
-
-static struct notifier_block nr_dev_notifier = {
- .notifier_call = nr_device_event,
-};
-
-static struct net_device **dev_nr;
-
-static struct ax25_protocol nr_pid = {
- .pid = AX25_P_NETROM,
- .func = nr_route_frame
-};
-
-static struct ax25_linkfail nr_linkfail_notifier = {
- .func = nr_link_failed,
-};
-
-static int __init nr_proto_init(void)
-{
- int i;
- int rc = proto_register(&nr_proto, 0);
-
- if (rc)
- return rc;
-
- if (nr_ndevs > 0x7fffffff/sizeof(struct net_device *)) {
- pr_err("NET/ROM: %s - nr_ndevs parameter too large\n",
- __func__);
- rc = -EINVAL;
- goto unregister_proto;
- }
-
- dev_nr = kzalloc_objs(struct net_device *, nr_ndevs);
- if (!dev_nr) {
- pr_err("NET/ROM: %s - unable to allocate device array\n",
- __func__);
- rc = -ENOMEM;
- goto unregister_proto;
- }
-
- for (i = 0; i < nr_ndevs; i++) {
- char name[IFNAMSIZ];
- struct net_device *dev;
-
- sprintf(name, "nr%d", i);
- dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, nr_setup);
- if (!dev) {
- rc = -ENOMEM;
- goto fail;
- }
-
- dev->base_addr = i;
- rc = register_netdev(dev);
- if (rc) {
- free_netdev(dev);
- goto fail;
- }
- nr_set_lockdep_key(dev);
- dev_nr[i] = dev;
- }
-
- rc = sock_register(&nr_family_ops);
- if (rc)
- goto fail;
-
- rc = register_netdevice_notifier(&nr_dev_notifier);
- if (rc)
- goto out_sock;
-
- ax25_register_pid(&nr_pid);
- ax25_linkfail_register(&nr_linkfail_notifier);
-
-#ifdef CONFIG_SYSCTL
- rc = nr_register_sysctl();
- if (rc)
- goto out_sysctl;
-#endif
-
- nr_loopback_init();
-
- rc = -ENOMEM;
- if (!proc_create_seq("nr", 0444, init_net.proc_net, &nr_info_seqops))
- goto proc_remove1;
- if (!proc_create_seq("nr_neigh", 0444, init_net.proc_net,
- &nr_neigh_seqops))
- goto proc_remove2;
- if (!proc_create_seq("nr_nodes", 0444, init_net.proc_net,
- &nr_node_seqops))
- goto proc_remove3;
-
- return 0;
-
-proc_remove3:
- remove_proc_entry("nr_neigh", init_net.proc_net);
-proc_remove2:
- remove_proc_entry("nr", init_net.proc_net);
-proc_remove1:
-
- nr_loopback_clear();
- nr_rt_free();
-
-#ifdef CONFIG_SYSCTL
- nr_unregister_sysctl();
-out_sysctl:
-#endif
- ax25_linkfail_release(&nr_linkfail_notifier);
- ax25_protocol_release(AX25_P_NETROM);
- unregister_netdevice_notifier(&nr_dev_notifier);
-out_sock:
- sock_unregister(PF_NETROM);
-fail:
- while (--i >= 0) {
- unregister_netdev(dev_nr[i]);
- free_netdev(dev_nr[i]);
- }
- kfree(dev_nr);
-unregister_proto:
- proto_unregister(&nr_proto);
- return rc;
-}
-
-module_init(nr_proto_init);
-
-module_param(nr_ndevs, int, 0);
-MODULE_PARM_DESC(nr_ndevs, "number of NET/ROM devices");
-
-MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
-MODULE_DESCRIPTION("The amateur radio NET/ROM network and transport layer protocol");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NETPROTO(PF_NETROM);
-
-static void __exit nr_exit(void)
-{
- int i;
-
- remove_proc_entry("nr", init_net.proc_net);
- remove_proc_entry("nr_neigh", init_net.proc_net);
- remove_proc_entry("nr_nodes", init_net.proc_net);
- nr_loopback_clear();
-
- nr_rt_free();
-
-#ifdef CONFIG_SYSCTL
- nr_unregister_sysctl();
-#endif
-
- ax25_linkfail_release(&nr_linkfail_notifier);
- ax25_protocol_release(AX25_P_NETROM);
-
- unregister_netdevice_notifier(&nr_dev_notifier);
-
- sock_unregister(PF_NETROM);
-
- for (i = 0; i < nr_ndevs; i++) {
- struct net_device *dev = dev_nr[i];
- if (dev) {
- unregister_netdev(dev);
- free_netdev(dev);
- }
- }
-
- kfree(dev_nr);
- proto_unregister(&nr_proto);
-}
-module_exit(nr_exit);
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
deleted file mode 100644
index 2c34389c3ce6..000000000000
--- a/net/netrom/nr_dev.c
+++ /dev/null
@@ -1,178 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/types.h>
-#include <linux/sysctl.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/in.h>
-#include <linux/if_ether.h> /* For the statistics structure. */
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-#include <asm/io.h>
-
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-
-#include <net/ip.h>
-#include <net/arp.h>
-
-#include <net/ax25.h>
-#include <net/netrom.h>
-
-/*
- * Only allow IP over NET/ROM frames through if the netrom device is up.
- */
-
-int nr_rx_ip(struct sk_buff *skb, struct net_device *dev)
-{
- struct net_device_stats *stats = &dev->stats;
-
- if (!netif_running(dev)) {
- stats->rx_dropped++;
- return 0;
- }
-
- stats->rx_packets++;
- stats->rx_bytes += skb->len;
-
- skb->protocol = htons(ETH_P_IP);
-
- /* Spoof incoming device */
- skb->dev = dev;
- skb->mac_header = skb->network_header;
- skb_reset_network_header(skb);
- skb->pkt_type = PACKET_HOST;
-
- netif_rx(skb);
-
- return 1;
-}
-
-static int nr_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type,
- const void *daddr, const void *saddr, unsigned int len)
-{
- unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
-
- memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len);
- buff[6] &= ~AX25_CBIT;
- buff[6] &= ~AX25_EBIT;
- buff[6] |= AX25_SSSID_SPARE;
- buff += AX25_ADDR_LEN;
-
- if (daddr != NULL)
- memcpy(buff, daddr, dev->addr_len);
- buff[6] &= ~AX25_CBIT;
- buff[6] |= AX25_EBIT;
- buff[6] |= AX25_SSSID_SPARE;
- buff += AX25_ADDR_LEN;
-
- *buff++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser);
-
- *buff++ = NR_PROTO_IP;
- *buff++ = NR_PROTO_IP;
- *buff++ = 0;
- *buff++ = 0;
- *buff++ = NR_PROTOEXT;
-
- if (daddr != NULL)
- return 37;
-
- return -37;
-}
-
-static int __must_check nr_set_mac_address(struct net_device *dev, void *addr)
-{
- struct sockaddr *sa = addr;
- int err;
-
- if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len))
- return 0;
-
- if (dev->flags & IFF_UP) {
- err = ax25_listen_register((ax25_address *)sa->sa_data, NULL);
- if (err)
- return err;
-
- ax25_listen_release((const ax25_address *)dev->dev_addr, NULL);
- }
-
- dev_addr_set(dev, sa->sa_data);
-
- return 0;
-}
-
-static int nr_open(struct net_device *dev)
-{
- int err;
-
- err = ax25_listen_register((const ax25_address *)dev->dev_addr, NULL);
- if (err)
- return err;
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-static int nr_close(struct net_device *dev)
-{
- ax25_listen_release((const ax25_address *)dev->dev_addr, NULL);
- netif_stop_queue(dev);
- return 0;
-}
-
-static netdev_tx_t nr_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct net_device_stats *stats = &dev->stats;
- unsigned int len = skb->len;
-
- if (!nr_route_frame(skb, NULL)) {
- kfree_skb(skb);
- stats->tx_errors++;
- return NETDEV_TX_OK;
- }
-
- stats->tx_packets++;
- stats->tx_bytes += len;
-
- return NETDEV_TX_OK;
-}
-
-static const struct header_ops nr_header_ops = {
- .create = nr_header,
-};
-
-static const struct net_device_ops nr_netdev_ops = {
- .ndo_open = nr_open,
- .ndo_stop = nr_close,
- .ndo_start_xmit = nr_xmit,
- .ndo_set_mac_address = nr_set_mac_address,
-};
-
-void nr_setup(struct net_device *dev)
-{
- dev->mtu = NR_MAX_PACKET_SIZE;
- dev->netdev_ops = &nr_netdev_ops;
- dev->header_ops = &nr_header_ops;
- dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
- dev->addr_len = AX25_ADDR_LEN;
- dev->type = ARPHRD_NETROM;
-
- /* New-style flags. */
- dev->flags = IFF_NOARP;
-}
diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c
deleted file mode 100644
index 97944db6b5ac..000000000000
--- a/net/netrom/nr_in.c
+++ /dev/null
@@ -1,301 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <net/netrom.h>
-
-static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
-{
- struct sk_buff *skbo, *skbn = skb;
- struct nr_sock *nr = nr_sk(sk);
-
- skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
-
- nr_start_idletimer(sk);
-
- if (more) {
- nr->fraglen += skb->len;
- skb_queue_tail(&nr->frag_queue, skb);
- return 0;
- }
-
- if (!more && nr->fraglen > 0) { /* End of fragment */
- nr->fraglen += skb->len;
- skb_queue_tail(&nr->frag_queue, skb);
-
- if ((skbn = alloc_skb(nr->fraglen, GFP_ATOMIC)) == NULL)
- return 1;
-
- skb_reset_transport_header(skbn);
-
- while ((skbo = skb_dequeue(&nr->frag_queue)) != NULL) {
- skb_copy_from_linear_data(skbo,
- skb_put(skbn, skbo->len),
- skbo->len);
- kfree_skb(skbo);
- }
-
- nr->fraglen = 0;
- }
-
- return sock_queue_rcv_skb(sk, skbn);
-}
-
-/*
- * State machine for state 1, Awaiting Connection State.
- * 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)
-{
- switch (frametype) {
- case NR_CONNACK: {
- struct nr_sock *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->sk_state = TCP_ESTABLISHED;
- if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_state_change(sk);
- break;
- }
-
- case NR_CONNACK | NR_CHOKE_FLAG:
- nr_disconnect(sk, ECONNREFUSED);
- break;
-
- case NR_RESET:
- if (READ_ONCE(sysctl_netrom_reset_circuit))
- nr_disconnect(sk, ECONNRESET);
- break;
-
- default:
- break;
- }
- return 0;
-}
-
-/*
- * State machine for state 2, Awaiting Release State.
- * 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)
-{
- switch (frametype) {
- case NR_CONNACK | NR_CHOKE_FLAG:
- nr_disconnect(sk, ECONNRESET);
- break;
-
- case NR_DISCREQ:
- nr_write_internal(sk, NR_DISCACK);
- fallthrough;
- case NR_DISCACK:
- nr_disconnect(sk, 0);
- break;
-
- case NR_RESET:
- if (READ_ONCE(sysctl_netrom_reset_circuit))
- nr_disconnect(sk, ECONNRESET);
- break;
-
- default:
- break;
- }
- return 0;
-}
-
-/*
- * State machine for state 3, Connected State.
- * 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_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype)
-{
- struct nr_sock *nrom = nr_sk(sk);
- struct sk_buff_head temp_queue;
- struct sk_buff *skbn;
- unsigned short save_vr;
- unsigned short nr, ns;
- int queued = 0;
-
- nr = skb->data[18];
-
- 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);
- 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;
- }
- 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 {
- 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);
- } else {
- if (nrom->condition & NR_COND_PEER_RX_BUSY) {
- nr_frames_acked(sk, nr);
- } 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)) {
- 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);
- }
- }
- break;
-
- case NR_RESET:
- if (READ_ONCE(sysctl_netrom_reset_circuit))
- nr_disconnect(sk, ECONNRESET);
- break;
-
- default:
- break;
- }
- return queued;
-}
-
-/* Higher level upcall for a LAPB frame - called with sk locked */
-int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
-{
- struct nr_sock *nr = nr_sk(sk);
- int queued = 0, frametype;
-
- if (nr->state == NR_STATE_0)
- return 0;
-
- 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;
- }
-
- nr_kick(sk);
-
- return queued;
-}
diff --git a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c
deleted file mode 100644
index 7a9d765b30c0..000000000000
--- a/net/netrom/nr_loopback.c
+++ /dev/null
@@ -1,73 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
- */
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/socket.h>
-#include <linux/timer.h>
-#include <net/ax25.h>
-#include <linux/skbuff.h>
-#include <net/netrom.h>
-#include <linux/init.h>
-
-static void nr_loopback_timer(struct timer_list *);
-
-static struct sk_buff_head loopback_queue;
-static DEFINE_TIMER(loopback_timer, nr_loopback_timer);
-
-void __init nr_loopback_init(void)
-{
- skb_queue_head_init(&loopback_queue);
-}
-
-static inline int nr_loopback_running(void)
-{
- return timer_pending(&loopback_timer);
-}
-
-int nr_loopback_queue(struct sk_buff *skb)
-{
- struct sk_buff *skbn;
-
- if ((skbn = alloc_skb(skb->len, GFP_ATOMIC)) != NULL) {
- skb_copy_from_linear_data(skb, skb_put(skbn, skb->len), skb->len);
- skb_reset_transport_header(skbn);
-
- skb_queue_tail(&loopback_queue, skbn);
-
- if (!nr_loopback_running())
- mod_timer(&loopback_timer, jiffies + 10);
- }
-
- kfree_skb(skb);
- return 1;
-}
-
-static void nr_loopback_timer(struct timer_list *unused)
-{
- struct sk_buff *skb;
- ax25_address *nr_dest;
- struct net_device *dev;
-
- if ((skb = skb_dequeue(&loopback_queue)) != NULL) {
- nr_dest = (ax25_address *)(skb->data + 7);
-
- dev = nr_dev_get(nr_dest);
-
- if (dev == NULL || nr_rx_frame(skb, dev) == 0)
- kfree_skb(skb);
-
- dev_put(dev);
-
- if (!skb_queue_empty(&loopback_queue) && !nr_loopback_running())
- mod_timer(&loopback_timer, jiffies + 10);
- }
-}
-
-void nr_loopback_clear(void)
-{
- timer_delete_sync(&loopback_timer);
- skb_queue_purge(&loopback_queue);
-}
diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c
deleted file mode 100644
index 2b3cbceb0b52..000000000000
--- a/net/netrom/nr_out.c
+++ /dev/null
@@ -1,272 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <net/netrom.h>
-
-/*
- * This is where all NET/ROM frames pass, except for IP-over-NET/ROM which
- * cannot be fragmented in this manner.
- */
-void nr_output(struct sock *sk, struct sk_buff *skb)
-{
- struct sk_buff *skbn;
- unsigned char transport[NR_TRANSPORT_LEN];
- int err, frontlen, len;
-
- if (skb->len - NR_TRANSPORT_LEN > NR_MAX_PACKET_SIZE) {
- /* Save a copy of the Transport Header */
- skb_copy_from_linear_data(skb, transport, NR_TRANSPORT_LEN);
- skb_pull(skb, NR_TRANSPORT_LEN);
-
- frontlen = skb_headroom(skb);
-
- while (skb->len > 0) {
- if ((skbn = sock_alloc_send_skb(sk, frontlen + NR_MAX_PACKET_SIZE, 0, &err)) == NULL) {
- kfree_skb(skb);
- return;
- }
-
- skb_reserve(skbn, frontlen);
-
- len = (NR_MAX_PACKET_SIZE > skb->len) ? skb->len : NR_MAX_PACKET_SIZE;
-
- /* Copy the user data */
- skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
- skb_pull(skb, len);
-
- /* Duplicate the Transport Header */
- skb_push(skbn, NR_TRANSPORT_LEN);
- skb_copy_to_linear_data(skbn, transport,
- NR_TRANSPORT_LEN);
- if (skb->len > 0)
- skbn->data[4] |= NR_MORE_FLAG;
-
- skb_queue_tail(&sk->sk_write_queue, skbn); /* Throw it on the queue */
- }
-
- kfree_skb(skb);
- } else {
- skb_queue_tail(&sk->sk_write_queue, skb); /* Throw it on the queue */
- }
-
- 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.
- */
-static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
-{
- struct nr_sock *nr = nr_sk(sk);
-
- if (skb == NULL)
- return;
-
- skb->data[2] = nr->vs;
- skb->data[3] = nr->vr;
-
- if (nr->condition & NR_COND_OWN_RX_BUSY)
- skb->data[4] |= NR_CHOKE_FLAG;
-
- nr_start_idletimer(sk);
-
- nr_transmit_buffer(sk, skb);
-}
-
-void nr_send_nak_frame(struct sock *sk)
-{
- struct sk_buff *skb, *skbn;
- struct nr_sock *nr = nr_sk(sk);
-
- if ((skb = skb_peek(&nr->ack_queue)) == NULL)
- return;
-
- if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL)
- return;
-
- skbn->data[2] = nr->va;
- skbn->data[3] = nr->vr;
-
- if (nr->condition & NR_COND_OWN_RX_BUSY)
- skbn->data[4] |= NR_CHOKE_FLAG;
-
- nr_transmit_buffer(sk, skbn);
-
- nr->condition &= ~NR_COND_ACK_PENDING;
- nr->vl = nr->vr;
-
- nr_stop_t1timer(sk);
-}
-
-void nr_kick(struct sock *sk)
-{
- struct nr_sock *nr = nr_sk(sk);
- struct sk_buff *skb, *skbn;
- unsigned short start, end;
-
- if (nr->state != NR_STATE_3)
- return;
-
- if (nr->condition & NR_COND_PEER_RX_BUSY)
- return;
-
- if (!skb_peek(&sk->sk_write_queue))
- return;
-
- start = (skb_peek(&nr->ack_queue) == NULL) ? nr->va : nr->vs;
- end = (nr->va + nr->window) % NR_MODULUS;
-
- if (start == end)
- return;
-
- nr->vs = start;
-
- /*
- * Transmit data until either we're out of data to send or
- * the window is full.
- */
-
- /*
- * Dequeue the frame and copy it.
- */
- skb = skb_dequeue(&sk->sk_write_queue);
-
- do {
- if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
- skb_queue_head(&sk->sk_write_queue, skb);
- break;
- }
-
- skb_set_owner_w(skbn, sk);
-
- /*
- * Transmit the frame copy.
- */
- nr_send_iframe(sk, skbn);
-
- nr->vs = (nr->vs + 1) % NR_MODULUS;
-
- /*
- * Requeue the original data frame.
- */
- skb_queue_tail(&nr->ack_queue, skb);
-
- } while (nr->vs != end &&
- (skb = skb_dequeue(&sk->sk_write_queue)) != NULL);
-
- nr->vl = nr->vr;
- nr->condition &= ~NR_COND_ACK_PENDING;
-
- if (!nr_t1timer_running(sk))
- nr_start_t1timer(sk);
-}
-
-void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
-{
- struct nr_sock *nr = nr_sk(sk);
- unsigned char *dptr;
-
- /*
- * Add the protocol byte and network header.
- */
- dptr = skb_push(skb, NR_NETWORK_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;
-
- memcpy(dptr, &nr->dest_addr, AX25_ADDR_LEN);
- dptr[6] &= ~AX25_CBIT;
- dptr[6] |= AX25_EBIT;
- dptr[6] |= AX25_SSSID_SPARE;
- dptr += AX25_ADDR_LEN;
-
- *dptr++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser);
-
- if (!nr_route_frame(skb, NULL)) {
- kfree_skb(skb);
- nr_disconnect(sk, ENETUNREACH);
- }
-}
-
-/*
- * The following routines are taken from page 170 of the 7th ARRL Computer
- * Networking Conference paper, as is the whole state machine.
- */
-
-void nr_establish_data_link(struct sock *sk)
-{
- struct nr_sock *nr = nr_sk(sk);
-
- nr->condition = 0x00;
- nr->n2count = 0;
-
- nr_write_internal(sk, NR_CONNREQ);
-
- nr_stop_t2timer(sk);
- nr_stop_t4timer(sk);
- nr_stop_idletimer(sk);
- nr_start_t1timer(sk);
-}
-
-/*
- * Never send a NAK when we are CHOKEd.
- */
-void nr_enquiry_response(struct sock *sk)
-{
- struct nr_sock *nr = nr_sk(sk);
- int frametype = NR_INFOACK;
-
- if (nr->condition & NR_COND_OWN_RX_BUSY) {
- frametype |= NR_CHOKE_FLAG;
- } else {
- if (skb_peek(&nr->reseq_queue) != NULL)
- frametype |= NR_NAK_FLAG;
- }
-
- nr_write_internal(sk, frametype);
-
- nr->vl = nr->vr;
- nr->condition &= ~NR_COND_ACK_PENDING;
-}
-
-void nr_check_iframes_acked(struct sock *sk, unsigned short nr)
-{
- struct nr_sock *nrom = nr_sk(sk);
-
- if (nrom->vs == nr) {
- nr_frames_acked(sk, nr);
- nr_stop_t1timer(sk);
- nrom->n2count = 0;
- } else {
- if (nrom->va != nr) {
- nr_frames_acked(sk, nr);
- nr_start_t1timer(sk);
- }
- }
-}
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
deleted file mode 100644
index 9cc29ae85b06..000000000000
--- a/net/netrom/nr_route.c
+++ /dev/null
@@ -1,989 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <net/arp.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/termios.h> /* For TIOCINQ/OUTQ */
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <net/netrom.h>
-#include <linux/seq_file.h>
-#include <linux/export.h>
-
-static unsigned int nr_neigh_no = 1;
-
-static HLIST_HEAD(nr_node_list);
-static DEFINE_SPINLOCK(nr_node_list_lock);
-static HLIST_HEAD(nr_neigh_list);
-static DEFINE_SPINLOCK(nr_neigh_list_lock);
-
-static struct nr_node *nr_node_get(ax25_address *callsign)
-{
- struct nr_node *found = NULL;
- struct nr_node *nr_node;
-
- spin_lock_bh(&nr_node_list_lock);
- nr_node_for_each(nr_node, &nr_node_list)
- if (ax25cmp(callsign, &nr_node->callsign) == 0) {
- nr_node_hold(nr_node);
- found = nr_node;
- break;
- }
- spin_unlock_bh(&nr_node_list_lock);
- return found;
-}
-
-static struct nr_neigh *nr_neigh_get_dev(ax25_address *callsign,
- struct net_device *dev)
-{
- struct nr_neigh *found = NULL;
- struct nr_neigh *nr_neigh;
-
- spin_lock_bh(&nr_neigh_list_lock);
- nr_neigh_for_each(nr_neigh, &nr_neigh_list)
- if (ax25cmp(callsign, &nr_neigh->callsign) == 0 &&
- nr_neigh->dev == dev) {
- nr_neigh_hold(nr_neigh);
- found = nr_neigh;
- break;
- }
- spin_unlock_bh(&nr_neigh_list_lock);
- return found;
-}
-
-static void nr_remove_neigh(struct nr_neigh *);
-
-/* re-sort the routes in quality order. */
-static void re_sort_routes(struct nr_node *nr_node, int x, int y)
-{
- if (nr_node->routes[y].quality > nr_node->routes[x].quality) {
- if (nr_node->which == x)
- nr_node->which = y;
- else if (nr_node->which == y)
- nr_node->which = x;
-
- swap(nr_node->routes[x], nr_node->routes[y]);
- }
-}
-
-/*
- * Add a new route to a node, and in the process add the node and the
- * neighbour if it is new.
- */
-static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
- ax25_address *ax25, ax25_digi *ax25_digi, struct net_device *dev,
- int quality, int obs_count)
-{
- struct nr_node *nr_node;
- struct nr_neigh *nr_neigh;
- int i, found;
- struct net_device *odev;
-
- if ((odev=nr_dev_get(nr)) != NULL) { /* Can't add routes to ourself */
- dev_put(odev);
- return -EINVAL;
- }
-
- nr_node = nr_node_get(nr);
-
- nr_neigh = nr_neigh_get_dev(ax25, dev);
-
- /*
- * The L2 link to a neighbour has failed in the past
- * and now a frame comes from this neighbour. We assume
- * it was a temporary trouble with the link and reset the
- * routes now (and not wait for a node broadcast).
- */
- if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) {
- struct nr_node *nr_nodet;
-
- spin_lock_bh(&nr_node_list_lock);
- nr_node_for_each(nr_nodet, &nr_node_list) {
- nr_node_lock(nr_nodet);
- for (i = 0; i < nr_nodet->count; i++)
- if (nr_nodet->routes[i].neighbour == nr_neigh)
- if (i < nr_nodet->which)
- nr_nodet->which = i;
- nr_node_unlock(nr_nodet);
- }
- spin_unlock_bh(&nr_node_list_lock);
- }
-
- if (nr_neigh != NULL)
- nr_neigh->failed = 0;
-
- if (quality == 0 && nr_neigh != NULL && nr_node != NULL) {
- nr_neigh_put(nr_neigh);
- nr_node_put(nr_node);
- return 0;
- }
-
- if (nr_neigh == NULL) {
- if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) {
- if (nr_node)
- nr_node_put(nr_node);
- return -ENOMEM;
- }
-
- nr_neigh->callsign = *ax25;
- nr_neigh->digipeat = NULL;
- nr_neigh->ax25 = NULL;
- nr_neigh->dev = dev;
- nr_neigh->quality = READ_ONCE(sysctl_netrom_default_path_quality);
- nr_neigh->locked = 0;
- nr_neigh->count = 0;
- nr_neigh->number = nr_neigh_no++;
- nr_neigh->failed = 0;
- refcount_set(&nr_neigh->refcount, 1);
-
- if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
- nr_neigh->digipeat = kmemdup(ax25_digi,
- sizeof(*ax25_digi),
- GFP_KERNEL);
- if (nr_neigh->digipeat == NULL) {
- kfree(nr_neigh);
- if (nr_node)
- nr_node_put(nr_node);
- return -ENOMEM;
- }
- }
-
- spin_lock_bh(&nr_neigh_list_lock);
- hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
- nr_neigh_hold(nr_neigh);
- spin_unlock_bh(&nr_neigh_list_lock);
- }
-
- if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
- nr_neigh->quality = quality;
-
- if (nr_node == NULL) {
- if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) {
- if (nr_neigh)
- nr_neigh_put(nr_neigh);
- return -ENOMEM;
- }
-
- nr_node->callsign = *nr;
- strscpy(nr_node->mnemonic, mnemonic);
-
- nr_node->which = 0;
- nr_node->count = 1;
- refcount_set(&nr_node->refcount, 1);
- spin_lock_init(&nr_node->node_lock);
-
- nr_node->routes[0].quality = quality;
- nr_node->routes[0].obs_count = obs_count;
- nr_node->routes[0].neighbour = nr_neigh;
-
- nr_neigh_hold(nr_neigh);
- nr_neigh->count++;
-
- spin_lock_bh(&nr_node_list_lock);
- hlist_add_head(&nr_node->node_node, &nr_node_list);
- /* refcount initialized at 1 */
- spin_unlock_bh(&nr_node_list_lock);
-
- nr_neigh_put(nr_neigh);
- return 0;
- }
- nr_node_lock(nr_node);
-
- if (quality != 0)
- strscpy(nr_node->mnemonic, mnemonic);
-
- for (found = 0, i = 0; i < nr_node->count; i++) {
- if (nr_node->routes[i].neighbour == nr_neigh) {
- nr_node->routes[i].quality = quality;
- nr_node->routes[i].obs_count = obs_count;
- found = 1;
- break;
- }
- }
-
- if (!found) {
- /* We have space at the bottom, slot it in */
- if (nr_node->count < 3) {
- nr_node->routes[2] = nr_node->routes[1];
- nr_node->routes[1] = nr_node->routes[0];
-
- nr_node->routes[0].quality = quality;
- nr_node->routes[0].obs_count = obs_count;
- nr_node->routes[0].neighbour = nr_neigh;
-
- nr_node->which++;
- nr_node->count++;
- nr_neigh_hold(nr_neigh);
- nr_neigh->count++;
- } else {
- /* It must be better than the worst */
- if (quality > nr_node->routes[2].quality) {
- nr_node->routes[2].neighbour->count--;
- nr_neigh_put(nr_node->routes[2].neighbour);
-
- if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
- nr_remove_neigh(nr_node->routes[2].neighbour);
-
- nr_node->routes[2].quality = quality;
- nr_node->routes[2].obs_count = obs_count;
- nr_node->routes[2].neighbour = nr_neigh;
-
- nr_neigh_hold(nr_neigh);
- nr_neigh->count++;
- }
- }
- }
-
- /* Now re-sort the routes in quality order */
- switch (nr_node->count) {
- case 3:
- re_sort_routes(nr_node, 0, 1);
- re_sort_routes(nr_node, 1, 2);
- fallthrough;
- case 2:
- re_sort_routes(nr_node, 0, 1);
- break;
- case 1:
- break;
- }
-
- for (i = 0; i < nr_node->count; i++) {
- if (nr_node->routes[i].neighbour == nr_neigh) {
- if (i < nr_node->which)
- nr_node->which = i;
- break;
- }
- }
-
- nr_neigh_put(nr_neigh);
- nr_node_unlock(nr_node);
- nr_node_put(nr_node);
- return 0;
-}
-
-static void nr_remove_node_locked(struct nr_node *nr_node)
-{
- lockdep_assert_held(&nr_node_list_lock);
-
- hlist_del_init(&nr_node->node_node);
- nr_node_put(nr_node);
-}
-
-static inline void __nr_remove_neigh(struct nr_neigh *nr_neigh)
-{
- hlist_del_init(&nr_neigh->neigh_node);
- nr_neigh_put(nr_neigh);
-}
-
-#define nr_remove_neigh_locked(__neigh) \
- __nr_remove_neigh(__neigh)
-
-static void nr_remove_neigh(struct nr_neigh *nr_neigh)
-{
- spin_lock_bh(&nr_neigh_list_lock);
- __nr_remove_neigh(nr_neigh);
- spin_unlock_bh(&nr_neigh_list_lock);
-}
-
-/*
- * "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 nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct net_device *dev)
-{
- struct nr_node *nr_node;
- struct nr_neigh *nr_neigh;
- int i;
-
- nr_node = nr_node_get(callsign);
-
- if (nr_node == NULL)
- return -EINVAL;
-
- nr_neigh = nr_neigh_get_dev(neighbour, dev);
-
- if (nr_neigh == NULL) {
- nr_node_put(nr_node);
- return -EINVAL;
- }
-
- spin_lock_bh(&nr_node_list_lock);
- nr_node_lock(nr_node);
- for (i = 0; i < nr_node->count; i++) {
- if (nr_node->routes[i].neighbour == nr_neigh) {
- nr_neigh->count--;
- nr_neigh_put(nr_neigh);
-
- if (nr_neigh->count == 0 && !nr_neigh->locked)
- nr_remove_neigh(nr_neigh);
- nr_neigh_put(nr_neigh);
-
- nr_node->count--;
-
- if (nr_node->count == 0) {
- nr_remove_node_locked(nr_node);
- } else {
- switch (i) {
- case 0:
- nr_node->routes[0] = nr_node->routes[1];
- fallthrough;
- case 1:
- nr_node->routes[1] = nr_node->routes[2];
- fallthrough;
- case 2:
- break;
- }
- nr_node_put(nr_node);
- }
- nr_node_unlock(nr_node);
- spin_unlock_bh(&nr_node_list_lock);
-
- return 0;
- }
- }
- nr_neigh_put(nr_neigh);
- nr_node_unlock(nr_node);
- spin_unlock_bh(&nr_node_list_lock);
- nr_node_put(nr_node);
-
- return -EINVAL;
-}
-
-/*
- * Lock a neighbour with a quality.
- */
-static int __must_check nr_add_neigh(ax25_address *callsign,
- ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
-{
- struct nr_neigh *nr_neigh;
-
- nr_neigh = nr_neigh_get_dev(callsign, dev);
- if (nr_neigh) {
- nr_neigh->quality = quality;
- nr_neigh->locked = 1;
- nr_neigh_put(nr_neigh);
- return 0;
- }
-
- if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
-
- nr_neigh->callsign = *callsign;
- nr_neigh->digipeat = NULL;
- nr_neigh->ax25 = NULL;
- nr_neigh->dev = dev;
- nr_neigh->quality = quality;
- nr_neigh->locked = 1;
- nr_neigh->count = 0;
- nr_neigh->number = nr_neigh_no++;
- nr_neigh->failed = 0;
- refcount_set(&nr_neigh->refcount, 1);
-
- if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
- nr_neigh->digipeat = kmemdup(ax25_digi, sizeof(*ax25_digi),
- GFP_KERNEL);
- if (nr_neigh->digipeat == NULL) {
- kfree(nr_neigh);
- return -ENOMEM;
- }
- }
-
- spin_lock_bh(&nr_neigh_list_lock);
- hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
- /* refcount is initialized at 1 */
- spin_unlock_bh(&nr_neigh_list_lock);
-
- return 0;
-}
-
-/*
- * "Delete" a neighbour. The neighbour is only removed if the number
- * of nodes that may use it is zero.
- */
-static int nr_del_neigh(ax25_address *callsign, struct net_device *dev, unsigned int quality)
-{
- struct nr_neigh *nr_neigh;
-
- nr_neigh = nr_neigh_get_dev(callsign, dev);
-
- if (nr_neigh == NULL) return -EINVAL;
-
- nr_neigh->quality = quality;
- nr_neigh->locked = 0;
-
- if (nr_neigh->count == 0)
- nr_remove_neigh(nr_neigh);
- nr_neigh_put(nr_neigh);
-
- return 0;
-}
-
-/*
- * Decrement the obsolescence count by one. If a route is reduced to a
- * count of zero, remove it. Also remove any unlocked neighbours with
- * zero nodes routing via it.
- */
-static int nr_dec_obs(void)
-{
- struct nr_neigh *nr_neigh;
- struct nr_node *s;
- struct hlist_node *nodet;
- int i;
-
- spin_lock_bh(&nr_node_list_lock);
- nr_node_for_each_safe(s, nodet, &nr_node_list) {
- nr_node_lock(s);
- for (i = 0; i < s->count; i++) {
- switch (s->routes[i].obs_count) {
- case 0: /* A locked entry */
- break;
-
- case 1: /* From 1 -> 0 */
- nr_neigh = s->routes[i].neighbour;
-
- nr_neigh->count--;
- nr_neigh_put(nr_neigh);
-
- if (nr_neigh->count == 0 && !nr_neigh->locked)
- nr_remove_neigh(nr_neigh);
-
- s->count--;
-
- switch (i) {
- case 0:
- s->routes[0] = s->routes[1];
- fallthrough;
- case 1:
- s->routes[1] = s->routes[2];
- break;
- case 2:
- break;
- }
- break;
-
- default:
- s->routes[i].obs_count--;
- break;
-
- }
- }
-
- if (s->count <= 0)
- nr_remove_node_locked(s);
- nr_node_unlock(s);
- }
- spin_unlock_bh(&nr_node_list_lock);
-
- return 0;
-}
-
-/*
- * A device has been removed. Remove its routes and neighbours.
- */
-void nr_rt_device_down(struct net_device *dev)
-{
- struct nr_neigh *s;
- struct hlist_node *nodet, *node2t;
- struct nr_node *t;
- int i;
-
- spin_lock_bh(&nr_neigh_list_lock);
- nr_neigh_for_each_safe(s, nodet, &nr_neigh_list) {
- if (s->dev == dev) {
- spin_lock_bh(&nr_node_list_lock);
- nr_node_for_each_safe(t, node2t, &nr_node_list) {
- nr_node_lock(t);
- for (i = 0; i < t->count; i++) {
- if (t->routes[i].neighbour == s) {
- t->count--;
-
- switch (i) {
- case 0:
- t->routes[0] = t->routes[1];
- fallthrough;
- case 1:
- t->routes[1] = t->routes[2];
- break;
- case 2:
- break;
- }
- }
- }
-
- if (t->count <= 0)
- nr_remove_node_locked(t);
- nr_node_unlock(t);
- }
- spin_unlock_bh(&nr_node_list_lock);
-
- nr_remove_neigh_locked(s);
- }
- }
- spin_unlock_bh(&nr_neigh_list_lock);
-}
-
-/*
- * Check that the device given is a valid AX.25 interface that is "up".
- * Or a valid ethernet interface with an AX.25 callsign binding.
- */
-static struct net_device *nr_ax25_dev_get(char *devname)
-{
- struct net_device *dev;
-
- if ((dev = dev_get_by_name(&init_net, devname)) == NULL)
- return NULL;
-
- if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
- return dev;
-
- dev_put(dev);
- return NULL;
-}
-
-/*
- * Find the first active NET/ROM device, usually "nr0".
- */
-struct net_device *nr_dev_first(void)
-{
- struct net_device *dev, *first = NULL;
-
- rcu_read_lock();
- for_each_netdev_rcu(&init_net, dev) {
- if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
- if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
- first = dev;
- }
- dev_hold(first);
- rcu_read_unlock();
-
- return first;
-}
-
-/*
- * Find the NET/ROM device for the given callsign.
- */
-struct net_device *nr_dev_get(ax25_address *addr)
-{
- struct net_device *dev;
-
- rcu_read_lock();
- for_each_netdev_rcu(&init_net, dev) {
- if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM &&
- ax25cmp(addr, (const ax25_address *)dev->dev_addr) == 0) {
- dev_hold(dev);
- goto out;
- }
- }
- dev = NULL;
-out:
- rcu_read_unlock();
- return dev;
-}
-
-static ax25_digi *nr_call_to_digi(ax25_digi *digi, int ndigis,
- ax25_address *digipeaters)
-{
- int i;
-
- if (ndigis == 0)
- return NULL;
-
- for (i = 0; i < ndigis; i++) {
- digi->calls[i] = digipeaters[i];
- digi->repeated[i] = 0;
- }
-
- digi->ndigi = ndigis;
- digi->lastrepeat = -1;
-
- return digi;
-}
-
-/*
- * Handle the ioctls that control the routing functions.
- */
-int nr_rt_ioctl(unsigned int cmd, void __user *arg)
-{
- struct nr_route_struct nr_route;
- struct net_device *dev;
- ax25_digi digi;
- int ret;
-
- switch (cmd) {
- case SIOCADDRT:
- if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
- return -EFAULT;
- if (nr_route.ndigis > AX25_MAX_DIGIS)
- return -EINVAL;
- if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
- return -EINVAL;
- switch (nr_route.type) {
- case NETROM_NODE:
- if (strnlen(nr_route.mnemonic, 7) == 7) {
- ret = -EINVAL;
- break;
- }
-
- ret = nr_add_node(&nr_route.callsign,
- nr_route.mnemonic,
- &nr_route.neighbour,
- nr_call_to_digi(&digi, nr_route.ndigis,
- nr_route.digipeaters),
- dev, nr_route.quality,
- nr_route.obs_count);
- break;
- case NETROM_NEIGH:
- ret = nr_add_neigh(&nr_route.callsign,
- nr_call_to_digi(&digi, nr_route.ndigis,
- nr_route.digipeaters),
- dev, nr_route.quality);
- break;
- default:
- ret = -EINVAL;
- }
- dev_put(dev);
- return ret;
-
- 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:
- ret = nr_del_node(&nr_route.callsign,
- &nr_route.neighbour, dev);
- break;
- case NETROM_NEIGH:
- ret = nr_del_neigh(&nr_route.callsign,
- dev, nr_route.quality);
- break;
- default:
- ret = -EINVAL;
- }
- dev_put(dev);
- return ret;
-
- case SIOCNRDECOBS:
- return nr_dec_obs();
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * A level 2 link has timed out, therefore it appears to be a poor link,
- * then don't use that neighbour until it is reset.
- */
-void nr_link_failed(ax25_cb *ax25, int reason)
-{
- struct nr_neigh *s, *nr_neigh = NULL;
- struct nr_node *nr_node = NULL;
-
- spin_lock_bh(&nr_neigh_list_lock);
- nr_neigh_for_each(s, &nr_neigh_list) {
- if (s->ax25 == ax25) {
- nr_neigh_hold(s);
- nr_neigh = s;
- break;
- }
- }
- spin_unlock_bh(&nr_neigh_list_lock);
-
- if (nr_neigh == NULL)
- return;
-
- nr_neigh->ax25 = NULL;
- ax25_cb_put(ax25);
-
- if (++nr_neigh->failed < READ_ONCE(sysctl_netrom_link_fails_count)) {
- nr_neigh_put(nr_neigh);
- return;
- }
- spin_lock_bh(&nr_node_list_lock);
- nr_node_for_each(nr_node, &nr_node_list) {
- nr_node_lock(nr_node);
- if (nr_node->which < nr_node->count &&
- nr_node->routes[nr_node->which].neighbour == nr_neigh)
- nr_node->which++;
- nr_node_unlock(nr_node);
- }
- spin_unlock_bh(&nr_node_list_lock);
- nr_neigh_put(nr_neigh);
-}
-
-/*
- * Route a frame to an appropriate AX.25 connection. A NULL ax25_cb
- * indicates an internally generated frame.
- */
-int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
-{
- ax25_address *nr_src, *nr_dest;
- struct nr_neigh *nr_neigh;
- struct nr_node *nr_node;
- struct net_device *dev;
- unsigned char *dptr;
- ax25_cb *ax25s;
- int ret;
- struct sk_buff *nskb, *oskb;
-
- /*
- * Reject malformed packets early. Check that it contains at least 2
- * addresses and 1 byte more for Time-To-Live
- */
- if (skb->len < 2 * sizeof(ax25_address) + 1)
- return 0;
-
- nr_src = (ax25_address *)(skb->data + 0);
- nr_dest = (ax25_address *)(skb->data + 7);
-
- if (ax25 != NULL) {
- ret = nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat,
- ax25->ax25_dev->dev, 0,
- READ_ONCE(sysctl_netrom_obsolescence_count_initialiser));
- if (ret)
- return ret;
- }
-
- if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */
- if (ax25 == NULL) /* Its from me */
- ret = nr_loopback_queue(skb);
- else
- ret = nr_rx_frame(skb, dev);
- dev_put(dev);
- return ret;
- }
-
- if (!READ_ONCE(sysctl_netrom_routing_control) && ax25 != NULL)
- return 0;
-
- /* Its Time-To-Live has expired */
- if (skb->data[14] == 1) {
- return 0;
- }
-
- nr_node = nr_node_get(nr_dest);
- if (nr_node == NULL)
- return 0;
- nr_node_lock(nr_node);
-
- if (nr_node->which >= nr_node->count) {
- nr_node_unlock(nr_node);
- nr_node_put(nr_node);
- return 0;
- }
-
- nr_neigh = nr_node->routes[nr_node->which].neighbour;
-
- if ((dev = nr_dev_first()) == NULL) {
- nr_node_unlock(nr_node);
- nr_node_put(nr_node);
- return 0;
- }
-
- /* We are going to change the netrom headers so we should get our
- own skb, we also did not know until now how much header space
- we had to reserve... - RXQ */
- nskb = skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC);
-
- if (!nskb) {
- nr_node_unlock(nr_node);
- nr_node_put(nr_node);
- dev_put(dev);
- return 0;
- }
- oskb = skb;
- skb = nskb;
- skb->data[14]--;
-
- dptr = skb_push(skb, 1);
- *dptr = AX25_P_NETROM;
-
- ax25s = nr_neigh->ax25;
- nr_neigh->ax25 = ax25_send_frame(skb, 256,
- (const ax25_address *)dev->dev_addr,
- &nr_neigh->callsign,
- nr_neigh->digipeat, nr_neigh->dev);
- if (ax25s)
- ax25_cb_put(ax25s);
-
- dev_put(dev);
- ret = (nr_neigh->ax25 != NULL);
- nr_node_unlock(nr_node);
- nr_node_put(nr_node);
-
- if (ret)
- kfree_skb(oskb);
-
- return ret;
-}
-
-#ifdef CONFIG_PROC_FS
-
-static void *nr_node_start(struct seq_file *seq, loff_t *pos)
- __acquires(&nr_node_list_lock)
-{
- spin_lock_bh(&nr_node_list_lock);
- return seq_hlist_start_head(&nr_node_list, *pos);
-}
-
-static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- return seq_hlist_next(v, &nr_node_list, pos);
-}
-
-static void nr_node_stop(struct seq_file *seq, void *v)
- __releases(&nr_node_list_lock)
-{
- spin_unlock_bh(&nr_node_list_lock);
-}
-
-static int nr_node_show(struct seq_file *seq, void *v)
-{
- char buf[11];
- int i;
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq,
- "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
- else {
- struct nr_node *nr_node = hlist_entry(v, struct nr_node,
- node_node);
-
- nr_node_lock(nr_node);
- seq_printf(seq, "%-9s %-7s %d %d",
- ax2asc(buf, &nr_node->callsign),
- (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
- nr_node->which + 1,
- nr_node->count);
-
- for (i = 0; i < nr_node->count; i++) {
- seq_printf(seq, " %3d %d %05d",
- nr_node->routes[i].quality,
- nr_node->routes[i].obs_count,
- nr_node->routes[i].neighbour->number);
- }
- nr_node_unlock(nr_node);
-
- seq_puts(seq, "\n");
- }
- return 0;
-}
-
-const struct seq_operations nr_node_seqops = {
- .start = nr_node_start,
- .next = nr_node_next,
- .stop = nr_node_stop,
- .show = nr_node_show,
-};
-
-static void *nr_neigh_start(struct seq_file *seq, loff_t *pos)
- __acquires(&nr_neigh_list_lock)
-{
- spin_lock_bh(&nr_neigh_list_lock);
- return seq_hlist_start_head(&nr_neigh_list, *pos);
-}
-
-static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- return seq_hlist_next(v, &nr_neigh_list, pos);
-}
-
-static void nr_neigh_stop(struct seq_file *seq, void *v)
- __releases(&nr_neigh_list_lock)
-{
- spin_unlock_bh(&nr_neigh_list_lock);
-}
-
-static int nr_neigh_show(struct seq_file *seq, void *v)
-{
- char buf[11];
- int i;
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, "addr callsign dev qual lock count failed digipeaters\n");
- else {
- struct nr_neigh *nr_neigh;
-
- nr_neigh = hlist_entry(v, struct nr_neigh, neigh_node);
- seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d",
- nr_neigh->number,
- ax2asc(buf, &nr_neigh->callsign),
- nr_neigh->dev ? nr_neigh->dev->name : "???",
- nr_neigh->quality,
- nr_neigh->locked,
- nr_neigh->count,
- nr_neigh->failed);
-
- if (nr_neigh->digipeat != NULL) {
- for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
- seq_printf(seq, " %s",
- ax2asc(buf, &nr_neigh->digipeat->calls[i]));
- }
-
- seq_puts(seq, "\n");
- }
- return 0;
-}
-
-const struct seq_operations nr_neigh_seqops = {
- .start = nr_neigh_start,
- .next = nr_neigh_next,
- .stop = nr_neigh_stop,
- .show = nr_neigh_show,
-};
-#endif
-
-/*
- * Free all memory associated with the nodes and routes lists.
- */
-void nr_rt_free(void)
-{
- struct nr_neigh *s = NULL;
- struct nr_node *t = NULL;
- struct hlist_node *nodet;
-
- spin_lock_bh(&nr_neigh_list_lock);
- spin_lock_bh(&nr_node_list_lock);
- nr_node_for_each_safe(t, nodet, &nr_node_list) {
- nr_node_lock(t);
- nr_remove_node_locked(t);
- nr_node_unlock(t);
- }
- nr_neigh_for_each_safe(s, nodet, &nr_neigh_list) {
- while(s->count) {
- s->count--;
- nr_neigh_put(s);
- }
- nr_remove_neigh_locked(s);
- }
- spin_unlock_bh(&nr_node_list_lock);
- spin_unlock_bh(&nr_neigh_list_lock);
-}
diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c
deleted file mode 100644
index c3bbd5880850..000000000000
--- a/net/netrom/nr_subr.c
+++ /dev/null
@@ -1,280 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <net/netrom.h>
-
-/*
- * This routine purges all of the queues of frames.
- */
-void nr_clear_queues(struct sock *sk)
-{
- struct nr_sock *nr = nr_sk(sk);
-
- skb_queue_purge(&sk->sk_write_queue);
- skb_queue_purge(&nr->ack_queue);
- skb_queue_purge(&nr->reseq_queue);
- skb_queue_purge(&nr->frag_queue);
-}
-
-/*
- * This routine purges the input queue of those frames that have been
- * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
- * SDL diagram.
- */
-void nr_frames_acked(struct sock *sk, unsigned short nr)
-{
- struct nr_sock *nrom = nr_sk(sk);
- struct sk_buff *skb;
-
- /*
- * Remove all the ack-ed frames from the ack queue.
- */
- if (nrom->va != nr) {
- while (skb_peek(&nrom->ack_queue) != NULL && nrom->va != nr) {
- skb = skb_dequeue(&nrom->ack_queue);
- kfree_skb(skb);
- nrom->va = (nrom->va + 1) % NR_MODULUS;
- }
- }
-}
-
-/*
- * Requeue all the un-ack-ed frames on the output queue to be picked
- * up by nr_kick called from the timer. This arrangement handles the
- * possibility of an empty output queue.
- */
-void nr_requeue_frames(struct sock *sk)
-{
- struct sk_buff *skb, *skb_prev = NULL;
-
- while ((skb = skb_dequeue(&nr_sk(sk)->ack_queue)) != NULL) {
- if (skb_prev == NULL)
- skb_queue_head(&sk->sk_write_queue, skb);
- else
- skb_append(skb_prev, skb, &sk->sk_write_queue);
- skb_prev = skb;
- }
-}
-
-/*
- * Validate that the value of nr is between va and vs. Return true or
- * false for testing.
- */
-int nr_validate_nr(struct sock *sk, unsigned short nr)
-{
- struct nr_sock *nrom = nr_sk(sk);
- unsigned short vc = nrom->va;
-
- while (vc != nrom->vs) {
- if (nr == vc) return 1;
- vc = (vc + 1) % NR_MODULUS;
- }
-
- return nr == nrom->vs;
-}
-
-/*
- * Check that ns is within the receive window.
- */
-int nr_in_rx_window(struct sock *sk, unsigned short ns)
-{
- struct nr_sock *nr = nr_sk(sk);
- unsigned short vc = nr->vr;
- unsigned short vt = (nr->vl + nr->window) % NR_MODULUS;
-
- while (vc != vt) {
- if (ns == vc) return 1;
- vc = (vc + 1) % NR_MODULUS;
- }
-
- return 0;
-}
-
-/*
- * This routine is called when the HDLC layer internally generates a
- * control frame.
- */
-void nr_write_internal(struct sock *sk, int frametype)
-{
- struct nr_sock *nr = nr_sk(sk);
- struct sk_buff *skb;
- unsigned char *dptr;
- int len, timeout;
-
- 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;
- }
-
- skb = alloc_skb(NR_NETWORK_LEN + len, GFP_ATOMIC);
- if (!skb)
- return;
-
- /*
- * Space for AX.25 and NET/ROM network header
- */
- skb_reserve(skb, NR_NETWORK_LEN);
-
- dptr = skb_put(skb, len);
-
- 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++ = READ_ONCE(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;
- }
-
- nr_transmit_buffer(sk, skb);
-}
-
-/*
- * This routine is called to send an error reply.
- */
-void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags)
-{
- struct sk_buff *skbn;
- unsigned char *dptr;
- int len;
-
- len = NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1;
-
- if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL)
- return;
-
- skb_reserve(skbn, 0);
-
- dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
-
- skb_copy_from_linear_data_offset(skb, 7, dptr, AX25_ADDR_LEN);
- dptr[6] &= ~AX25_CBIT;
- dptr[6] &= ~AX25_EBIT;
- dptr[6] |= AX25_SSSID_SPARE;
- dptr += AX25_ADDR_LEN;
-
- skb_copy_from_linear_data(skb, dptr, AX25_ADDR_LEN);
- dptr[6] &= ~AX25_CBIT;
- dptr[6] |= AX25_EBIT;
- dptr[6] |= AX25_SSSID_SPARE;
- dptr += AX25_ADDR_LEN;
-
- *dptr++ = READ_ONCE(sysctl_netrom_network_ttl_initialiser);
-
- if (mine) {
- *dptr++ = 0;
- *dptr++ = 0;
- *dptr++ = skb->data[15];
- *dptr++ = skb->data[16];
- } else {
- *dptr++ = skb->data[15];
- *dptr++ = skb->data[16];
- *dptr++ = 0;
- *dptr++ = 0;
- }
-
- *dptr++ = cmdflags;
- *dptr++ = 0;
-
- if (!nr_route_frame(skbn, NULL))
- kfree_skb(skbn);
-}
-
-void nr_disconnect(struct sock *sk, int reason)
-{
- nr_stop_t1timer(sk);
- nr_stop_t2timer(sk);
- nr_stop_t4timer(sk);
- nr_stop_idletimer(sk);
-
- nr_clear_queues(sk);
-
- nr_sk(sk)->state = NR_STATE_0;
-
- sk->sk_state = TCP_CLOSE;
- sk->sk_err = reason;
- sk->sk_shutdown |= SEND_SHUTDOWN;
-
- if (!sock_flag(sk, SOCK_DEAD)) {
- sk->sk_state_change(sk);
- sock_set_flag(sk, SOCK_DEAD);
- }
-}
diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c
deleted file mode 100644
index b3a62b1f3a09..000000000000
--- a/net/netrom/nr_timer.c
+++ /dev/null
@@ -1,249 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <net/netrom.h>
-
-static void nr_heartbeat_expiry(struct timer_list *);
-static void nr_t1timer_expiry(struct timer_list *);
-static void nr_t2timer_expiry(struct timer_list *);
-static void nr_t4timer_expiry(struct timer_list *);
-static void nr_idletimer_expiry(struct timer_list *);
-
-void nr_init_timers(struct sock *sk)
-{
- struct nr_sock *nr = nr_sk(sk);
-
- timer_setup(&nr->t1timer, nr_t1timer_expiry, 0);
- timer_setup(&nr->t2timer, nr_t2timer_expiry, 0);
- timer_setup(&nr->t4timer, nr_t4timer_expiry, 0);
- timer_setup(&nr->idletimer, nr_idletimer_expiry, 0);
-
- /* initialized by sock_init_data */
- sk->sk_timer.function = nr_heartbeat_expiry;
-}
-
-void nr_start_t1timer(struct sock *sk)
-{
- struct nr_sock *nr = nr_sk(sk);
-
- sk_reset_timer(sk, &nr->t1timer, jiffies + nr->t1);
-}
-
-void nr_start_t2timer(struct sock *sk)
-{
- struct nr_sock *nr = nr_sk(sk);
-
- sk_reset_timer(sk, &nr->t2timer, jiffies + nr->t2);
-}
-
-void nr_start_t4timer(struct sock *sk)
-{
- struct nr_sock *nr = nr_sk(sk);
-
- sk_reset_timer(sk, &nr->t4timer, jiffies + nr->t4);
-}
-
-void nr_start_idletimer(struct sock *sk)
-{
- struct nr_sock *nr = nr_sk(sk);
-
- if (nr->idle > 0)
- sk_reset_timer(sk, &nr->idletimer, jiffies + nr->idle);
-}
-
-void nr_start_heartbeat(struct sock *sk)
-{
- sk_reset_timer(sk, &sk->sk_timer, jiffies + 5 * HZ);
-}
-
-void nr_stop_t1timer(struct sock *sk)
-{
- sk_stop_timer(sk, &nr_sk(sk)->t1timer);
-}
-
-void nr_stop_t2timer(struct sock *sk)
-{
- sk_stop_timer(sk, &nr_sk(sk)->t2timer);
-}
-
-void nr_stop_t4timer(struct sock *sk)
-{
- sk_stop_timer(sk, &nr_sk(sk)->t4timer);
-}
-
-void nr_stop_idletimer(struct sock *sk)
-{
- sk_stop_timer(sk, &nr_sk(sk)->idletimer);
-}
-
-void nr_stop_heartbeat(struct sock *sk)
-{
- sk_stop_timer(sk, &sk->sk_timer);
-}
-
-int nr_t1timer_running(struct sock *sk)
-{
- return timer_pending(&nr_sk(sk)->t1timer);
-}
-
-static void nr_heartbeat_expiry(struct timer_list *t)
-{
- struct sock *sk = timer_container_of(sk, t, sk_timer);
- struct nr_sock *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 (sock_flag(sk, SOCK_DESTROY) ||
- (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
- if (sk->sk_state == TCP_LISTEN)
- sock_hold(sk);
- bh_unlock_sock(sk);
- nr_destroy_socket(sk);
- goto out;
- }
- break;
-
- case NR_STATE_3:
- /*
- * Check for the state of the receive buffer.
- */
- if (atomic_read(&sk->sk_rmem_alloc) < (sk->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);
-out:
- sock_put(sk);
-}
-
-static void nr_t2timer_expiry(struct timer_list *t)
-{
- struct nr_sock *nr = timer_container_of(nr, t, t2timer);
- struct sock *sk = &nr->sock;
-
- 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);
- sock_put(sk);
-}
-
-static void nr_t4timer_expiry(struct timer_list *t)
-{
- struct nr_sock *nr = timer_container_of(nr, t, t4timer);
- struct sock *sk = &nr->sock;
-
- bh_lock_sock(sk);
- nr_sk(sk)->condition &= ~NR_COND_PEER_RX_BUSY;
- bh_unlock_sock(sk);
- sock_put(sk);
-}
-
-static void nr_idletimer_expiry(struct timer_list *t)
-{
- struct nr_sock *nr = timer_container_of(nr, t, idletimer);
- struct sock *sk = &nr->sock;
-
- bh_lock_sock(sk);
-
- nr_clear_queues(sk);
-
- nr->n2count = 0;
- nr_write_internal(sk, NR_DISCREQ);
- nr->state = NR_STATE_2;
-
- nr_start_t1timer(sk);
- nr_stop_t2timer(sk);
- nr_stop_t4timer(sk);
-
- sk->sk_state = TCP_CLOSE;
- sk->sk_err = 0;
- sk->sk_shutdown |= SEND_SHUTDOWN;
-
- if (!sock_flag(sk, SOCK_DEAD)) {
- sk->sk_state_change(sk);
- sock_set_flag(sk, SOCK_DEAD);
- }
- bh_unlock_sock(sk);
- sock_put(sk);
-}
-
-static void nr_t1timer_expiry(struct timer_list *t)
-{
- struct nr_sock *nr = timer_container_of(nr, t, t1timer);
- struct sock *sk = &nr->sock;
-
- bh_lock_sock(sk);
- switch (nr->state) {
- case NR_STATE_1:
- if (nr->n2count == nr->n2) {
- nr_disconnect(sk, ETIMEDOUT);
- goto out;
- } else {
- nr->n2count++;
- nr_write_internal(sk, NR_CONNREQ);
- }
- break;
-
- case NR_STATE_2:
- if (nr->n2count == nr->n2) {
- nr_disconnect(sk, ETIMEDOUT);
- goto out;
- } else {
- nr->n2count++;
- nr_write_internal(sk, NR_DISCREQ);
- }
- break;
-
- case NR_STATE_3:
- if (nr->n2count == nr->n2) {
- nr_disconnect(sk, ETIMEDOUT);
- goto out;
- } else {
- nr->n2count++;
- nr_requeue_frames(sk);
- }
- break;
- }
-
- nr_start_t1timer(sk);
-out:
- bh_unlock_sock(sk);
- sock_put(sk);
-}
diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c
deleted file mode 100644
index 7dc0fa628f2e..000000000000
--- a/net/netrom/sysctl_net_netrom.c
+++ /dev/null
@@ -1,156 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
- */
-#include <linux/mm.h>
-#include <linux/sysctl.h>
-#include <linux/init.h>
-#include <net/ax25.h>
-#include <net/netrom.h>
-
-/*
- * Values taken from NET/ROM documentation.
- */
-static int min_quality[] = {0}, max_quality[] = {255};
-static int min_obs[] = {0}, max_obs[] = {255};
-static int min_ttl[] = {0}, max_ttl[] = {255};
-static int min_t1[] = {5 * HZ};
-static int max_t1[] = {600 * HZ};
-static int min_n2[] = {2}, max_n2[] = {127};
-static int min_t2[] = {1 * HZ};
-static int max_t2[] = {60 * HZ};
-static int min_t4[] = {1 * HZ};
-static int max_t4[] = {1000 * HZ};
-static int min_window[] = {1}, max_window[] = {127};
-static int min_idle[] = {0 * HZ};
-static int max_idle[] = {65535 * HZ};
-static int min_route[] = {0}, max_route[] = {1};
-static int min_fails[] = {1}, max_fails[] = {10};
-static int min_reset[] = {0}, max_reset[] = {1};
-
-static struct ctl_table_header *nr_table_header;
-
-static struct ctl_table nr_table[] = {
- {
- .procname = "default_path_quality",
- .data = &sysctl_netrom_default_path_quality,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_quality,
- .extra2 = &max_quality
- },
- {
- .procname = "obsolescence_count_initialiser",
- .data = &sysctl_netrom_obsolescence_count_initialiser,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_obs,
- .extra2 = &max_obs
- },
- {
- .procname = "network_ttl_initialiser",
- .data = &sysctl_netrom_network_ttl_initialiser,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_ttl,
- .extra2 = &max_ttl
- },
- {
- .procname = "transport_timeout",
- .data = &sysctl_netrom_transport_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_t1,
- .extra2 = &max_t1
- },
- {
- .procname = "transport_maximum_tries",
- .data = &sysctl_netrom_transport_maximum_tries,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_n2,
- .extra2 = &max_n2
- },
- {
- .procname = "transport_acknowledge_delay",
- .data = &sysctl_netrom_transport_acknowledge_delay,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_t2,
- .extra2 = &max_t2
- },
- {
- .procname = "transport_busy_delay",
- .data = &sysctl_netrom_transport_busy_delay,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_t4,
- .extra2 = &max_t4
- },
- {
- .procname = "transport_requested_window_size",
- .data = &sysctl_netrom_transport_requested_window_size,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_window,
- .extra2 = &max_window
- },
- {
- .procname = "transport_no_activity_timeout",
- .data = &sysctl_netrom_transport_no_activity_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_idle,
- .extra2 = &max_idle
- },
- {
- .procname = "routing_control",
- .data = &sysctl_netrom_routing_control,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_route,
- .extra2 = &max_route
- },
- {
- .procname = "link_fails_count",
- .data = &sysctl_netrom_link_fails_count,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_fails,
- .extra2 = &max_fails
- },
- {
- .procname = "reset",
- .data = &sysctl_netrom_reset_circuit,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_reset,
- .extra2 = &max_reset
- },
-};
-
-int __init nr_register_sysctl(void)
-{
- nr_table_header = register_net_sysctl(&init_net, "net/netrom", nr_table);
- if (!nr_table_header)
- return -ENOMEM;
- return 0;
-}
-
-void nr_unregister_sysctl(void)
-{
- unregister_net_sysctl_table(nr_table_header);
-}
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
deleted file mode 100644
index d5032840ee48..000000000000
--- a/net/rose/af_rose.c
+++ /dev/null
@@ -1,1687 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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/capability.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/sched/signal.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/stat.h>
-#include <net/net_namespace.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/termios.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <net/rose.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <net/tcp_states.h>
-#include <net/ip.h>
-#include <net/arp.h>
-
-static int rose_ndevs = 10;
-
-int sysctl_rose_restart_request_timeout = ROSE_DEFAULT_T0;
-int sysctl_rose_call_request_timeout = ROSE_DEFAULT_T1;
-int sysctl_rose_reset_request_timeout = ROSE_DEFAULT_T2;
-int sysctl_rose_clear_request_timeout = ROSE_DEFAULT_T3;
-int sysctl_rose_no_activity_timeout = ROSE_DEFAULT_IDLE;
-int sysctl_rose_ack_hold_back_timeout = ROSE_DEFAULT_HB;
-int sysctl_rose_routing_control = ROSE_DEFAULT_ROUTING;
-int sysctl_rose_link_fail_timeout = ROSE_DEFAULT_FAIL_TIMEOUT;
-int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC;
-int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE;
-
-static HLIST_HEAD(rose_list);
-static DEFINE_SPINLOCK(rose_list_lock);
-
-static const struct proto_ops rose_proto_ops;
-
-ax25_address rose_callsign;
-
-/*
- * ROSE network devices are virtual network devices encapsulating ROSE
- * frames into AX.25 which will be sent through an AX.25 device, so form a
- * special "super class" of normal net devices; split their locks off into a
- * separate class since they always nest.
- */
-static struct lock_class_key rose_netdev_xmit_lock_key;
-static struct lock_class_key rose_netdev_addr_lock_key;
-
-static void rose_set_lockdep_one(struct net_device *dev,
- struct netdev_queue *txq,
- void *_unused)
-{
- lockdep_set_class(&txq->_xmit_lock, &rose_netdev_xmit_lock_key);
-}
-
-static void rose_set_lockdep_key(struct net_device *dev)
-{
- lockdep_set_class(&dev->addr_list_lock, &rose_netdev_addr_lock_key);
- netdev_for_each_tx_queue(dev, rose_set_lockdep_one, NULL);
-}
-
-/*
- * Convert a ROSE address into text.
- */
-char *rose2asc(char *buf, const rose_address *addr)
-{
- if (addr->rose_addr[0] == 0x00 && addr->rose_addr[1] == 0x00 &&
- addr->rose_addr[2] == 0x00 && addr->rose_addr[3] == 0x00 &&
- addr->rose_addr[4] == 0x00) {
- strcpy(buf, "*");
- } else {
- sprintf(buf, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF,
- addr->rose_addr[1] & 0xFF,
- addr->rose_addr[2] & 0xFF,
- addr->rose_addr[3] & 0xFF,
- addr->rose_addr[4] & 0xFF);
- }
-
- return buf;
-}
-
-/*
- * Compare two ROSE addresses, 0 == equal.
- */
-int rosecmp(const rose_address *addr1, const rose_address *addr2)
-{
- int i;
-
- for (i = 0; i < 5; i++)
- if (addr1->rose_addr[i] != addr2->rose_addr[i])
- return 1;
-
- return 0;
-}
-
-/*
- * Compare two ROSE addresses for only mask digits, 0 == equal.
- */
-int rosecmpm(const rose_address *addr1, const rose_address *addr2,
- unsigned short mask)
-{
- unsigned int i, j;
-
- if (mask > 10)
- return 1;
-
- for (i = 0; i < mask; i++) {
- j = i / 2;
-
- if ((i % 2) != 0) {
- if ((addr1->rose_addr[j] & 0x0F) != (addr2->rose_addr[j] & 0x0F))
- return 1;
- } else {
- if ((addr1->rose_addr[j] & 0xF0) != (addr2->rose_addr[j] & 0xF0))
- return 1;
- }
- }
-
- return 0;
-}
-
-/*
- * Socket removal during an interrupt is now safe.
- */
-static void rose_remove_socket(struct sock *sk)
-{
- spin_lock_bh(&rose_list_lock);
- sk_del_node_init(sk);
- spin_unlock_bh(&rose_list_lock);
-}
-
-/*
- * Kill all bound sockets on a broken link layer connection to a
- * particular neighbour.
- */
-void rose_kill_by_neigh(struct rose_neigh *neigh)
-{
- struct sock *s;
-
- spin_lock_bh(&rose_list_lock);
- sk_for_each(s, &rose_list) {
- struct rose_sock *rose = rose_sk(s);
-
- if (rose->neighbour == neigh) {
- rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
- rose_neigh_put(rose->neighbour);
- rose->neighbour = NULL;
- }
- }
- spin_unlock_bh(&rose_list_lock);
-}
-
-/*
- * Kill all bound sockets on a dropped device.
- */
-static void rose_kill_by_device(struct net_device *dev)
-{
- struct sock *sk, *array[16];
- struct rose_sock *rose;
- bool rescan;
- int i, cnt;
-
-start:
- rescan = false;
- cnt = 0;
- spin_lock_bh(&rose_list_lock);
- sk_for_each(sk, &rose_list) {
- rose = rose_sk(sk);
- if (rose->device == dev) {
- if (cnt == ARRAY_SIZE(array)) {
- rescan = true;
- break;
- }
- sock_hold(sk);
- array[cnt++] = sk;
- }
- }
- spin_unlock_bh(&rose_list_lock);
-
- for (i = 0; i < cnt; i++) {
- sk = array[i];
- rose = rose_sk(sk);
- lock_sock(sk);
- spin_lock_bh(&rose_list_lock);
- if (rose->device == dev) {
- rose_disconnect(sk, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
- if (rose->neighbour)
- rose_neigh_put(rose->neighbour);
- netdev_put(rose->device, &rose->dev_tracker);
- rose->device = NULL;
- }
- spin_unlock_bh(&rose_list_lock);
- release_sock(sk);
- sock_put(sk);
- cond_resched();
- }
- if (rescan)
- goto start;
-}
-
-/*
- * Handle device status changes.
- */
-static int rose_device_event(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
- if (event != NETDEV_DOWN)
- 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;
- }
-
- return NOTIFY_DONE;
-}
-
-/*
- * Add a socket to the bound sockets list.
- */
-static void rose_insert_socket(struct sock *sk)
-{
-
- spin_lock_bh(&rose_list_lock);
- sk_add_node(sk, &rose_list);
- spin_unlock_bh(&rose_list_lock);
-}
-
-/*
- * Find a socket that wants to accept the Call Request we just
- * received.
- */
-static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
-{
- struct sock *s;
-
- spin_lock_bh(&rose_list_lock);
- sk_for_each(s, &rose_list) {
- struct rose_sock *rose = rose_sk(s);
-
- if (!rosecmp(&rose->source_addr, addr) &&
- !ax25cmp(&rose->source_call, call) &&
- !rose->source_ndigis && s->sk_state == TCP_LISTEN)
- goto found;
- }
-
- sk_for_each(s, &rose_list) {
- struct rose_sock *rose = rose_sk(s);
-
- if (!rosecmp(&rose->source_addr, addr) &&
- !ax25cmp(&rose->source_call, &null_ax25_address) &&
- s->sk_state == TCP_LISTEN)
- goto found;
- }
- s = NULL;
-found:
- spin_unlock_bh(&rose_list_lock);
- return s;
-}
-
-/*
- * Find a connected ROSE socket given my LCI and device.
- */
-struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh)
-{
- struct sock *s;
-
- spin_lock_bh(&rose_list_lock);
- sk_for_each(s, &rose_list) {
- struct rose_sock *rose = rose_sk(s);
-
- if (rose->lci == lci && rose->neighbour == neigh)
- goto found;
- }
- s = NULL;
-found:
- spin_unlock_bh(&rose_list_lock);
- return s;
-}
-
-/*
- * Find a unique LCI for a given device.
- */
-unsigned int rose_new_lci(struct rose_neigh *neigh)
-{
- int lci;
-
- if (neigh->dce_mode) {
- for (lci = 1; lci <= sysctl_rose_maximum_vcs; lci++)
- if (rose_find_socket(lci, neigh) == NULL && rose_route_free_lci(lci, neigh) == NULL)
- return lci;
- } else {
- for (lci = sysctl_rose_maximum_vcs; lci > 0; lci--)
- if (rose_find_socket(lci, neigh) == NULL && rose_route_free_lci(lci, neigh) == NULL)
- return lci;
- }
-
- return 0;
-}
-
-/*
- * Deferred destroy.
- */
-void rose_destroy_socket(struct sock *);
-
-/*
- * Handler for deferred kills.
- */
-static void rose_destroy_timer(struct timer_list *t)
-{
- struct sock *sk = timer_container_of(sk, t, sk_timer);
-
- rose_destroy_socket(sk);
-}
-
-/*
- * 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)
-{
- struct sk_buff *skb;
-
- rose_remove_socket(sk);
- rose_stop_heartbeat(sk);
- rose_stop_idletimer(sk);
- rose_stop_timer(sk);
-
- rose_clear_queues(sk); /* Flush the queues */
-
- while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
- if (skb->sk != sk) { /* A pending connection */
- /* Queue the unaccepted socket for death */
- sock_set_flag(skb->sk, SOCK_DEAD);
- rose_start_heartbeat(skb->sk);
- rose_sk(skb->sk)->state = ROSE_STATE_0;
- }
-
- kfree_skb(skb);
- }
-
- if (sk_has_allocations(sk)) {
- /* Defer: outstanding buffers */
- timer_setup(&sk->sk_timer, rose_destroy_timer, 0);
- sk->sk_timer.expires = jiffies + 10 * HZ;
- add_timer(&sk->sk_timer);
- } else
- sock_put(sk);
-}
-
-/*
- * Handling for system calls applied via the various interfaces to a
- * ROSE socket object.
- */
-
-static int rose_setsockopt(struct socket *sock, int level, int optname,
- sockptr_t optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- struct rose_sock *rose = rose_sk(sk);
- unsigned int opt;
-
- if (level != SOL_ROSE)
- return -ENOPROTOOPT;
-
- if (optlen < sizeof(unsigned int))
- return -EINVAL;
-
- if (copy_from_sockptr(&opt, optval, sizeof(unsigned int)))
- return -EFAULT;
-
- switch (optname) {
- case ROSE_DEFER:
- rose->defer = opt ? 1 : 0;
- return 0;
-
- case ROSE_T1:
- if (opt < 1 || opt > UINT_MAX / HZ)
- return -EINVAL;
- rose->t1 = opt * HZ;
- return 0;
-
- case ROSE_T2:
- if (opt < 1 || opt > UINT_MAX / HZ)
- return -EINVAL;
- rose->t2 = opt * HZ;
- return 0;
-
- case ROSE_T3:
- if (opt < 1 || opt > UINT_MAX / HZ)
- return -EINVAL;
- rose->t3 = opt * HZ;
- return 0;
-
- case ROSE_HOLDBACK:
- if (opt < 1 || opt > UINT_MAX / HZ)
- return -EINVAL;
- rose->hb = opt * HZ;
- return 0;
-
- case ROSE_IDLE:
- if (opt > UINT_MAX / (60 * HZ))
- return -EINVAL;
- rose->idle = opt * 60 * HZ;
- return 0;
-
- case ROSE_QBITINCL:
- rose->qbitincl = opt ? 1 : 0;
- return 0;
-
- default:
- return -ENOPROTOOPT;
- }
-}
-
-static int rose_getsockopt(struct socket *sock, int level, int optname,
- char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- struct rose_sock *rose = rose_sk(sk);
- int val = 0;
- int len;
-
- 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_T1:
- val = rose->t1 / HZ;
- break;
-
- case ROSE_T2:
- val = rose->t2 / HZ;
- break;
-
- case ROSE_T3:
- val = rose->t3 / HZ;
- break;
-
- case ROSE_HOLDBACK:
- val = rose->hb / HZ;
- break;
-
- case ROSE_IDLE:
- val = rose->idle / (60 * HZ);
- break;
-
- case ROSE_QBITINCL:
- val = rose->qbitincl;
- break;
-
- default:
- return -ENOPROTOOPT;
- }
-
- len = min_t(unsigned int, len, sizeof(int));
-
- if (put_user(len, optlen))
- return -EFAULT;
-
- return copy_to_user(optval, &val, len) ? -EFAULT : 0;
-}
-
-static int rose_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = sock->sk;
-
- lock_sock(sk);
- if (sock->state != SS_UNCONNECTED) {
- release_sock(sk);
- return -EINVAL;
- }
-
- if (sk->sk_state != TCP_LISTEN) {
- struct rose_sock *rose = rose_sk(sk);
-
- rose->dest_ndigis = 0;
- memset(&rose->dest_addr, 0, ROSE_ADDR_LEN);
- memset(&rose->dest_call, 0, AX25_ADDR_LEN);
- memset(rose->dest_digis, 0, AX25_ADDR_LEN * ROSE_MAX_DIGIS);
- sk->sk_max_ack_backlog = backlog;
- sk->sk_state = TCP_LISTEN;
- release_sock(sk);
- return 0;
- }
- release_sock(sk);
-
- return -EOPNOTSUPP;
-}
-
-static struct proto rose_proto = {
- .name = "ROSE",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct rose_sock),
-};
-
-static int rose_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
- struct rose_sock *rose;
-
- if (!net_eq(net, &init_net))
- return -EAFNOSUPPORT;
-
- if (sock->type != SOCK_SEQPACKET || protocol != 0)
- return -ESOCKTNOSUPPORT;
-
- sk = sk_alloc(net, PF_ROSE, GFP_ATOMIC, &rose_proto, kern);
- if (sk == NULL)
- return -ENOMEM;
-
- 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);
- rose->fraglen = 0;
-#endif
-
- sock->ops = &rose_proto_ops;
- sk->sk_protocol = protocol;
-
- timer_setup(&rose->timer, NULL, 0);
- timer_setup(&rose->idletimer, NULL, 0);
-
- rose->t1 = msecs_to_jiffies(sysctl_rose_call_request_timeout);
- rose->t2 = msecs_to_jiffies(sysctl_rose_reset_request_timeout);
- rose->t3 = msecs_to_jiffies(sysctl_rose_clear_request_timeout);
- rose->hb = msecs_to_jiffies(sysctl_rose_ack_hold_back_timeout);
- rose->idle = msecs_to_jiffies(sysctl_rose_no_activity_timeout);
-
- rose->state = ROSE_STATE_0;
-
- return 0;
-}
-
-static struct sock *rose_make_new(struct sock *osk)
-{
- struct sock *sk;
- struct rose_sock *rose, *orose;
-
- if (osk->sk_type != SOCK_SEQPACKET)
- return NULL;
-
- sk = sk_alloc(sock_net(osk), PF_ROSE, GFP_ATOMIC, &rose_proto, 0);
- if (sk == NULL)
- return NULL;
-
- rose = rose_sk(sk);
-
- sock_init_data(NULL, sk);
-
- skb_queue_head_init(&rose->ack_queue);
-#ifdef M_BIT
- skb_queue_head_init(&rose->frag_queue);
- rose->fraglen = 0;
-#endif
-
- sk->sk_type = osk->sk_type;
- sk->sk_priority = READ_ONCE(osk->sk_priority);
- sk->sk_protocol = osk->sk_protocol;
- sk->sk_rcvbuf = osk->sk_rcvbuf;
- sk->sk_sndbuf = osk->sk_sndbuf;
- sk->sk_state = TCP_ESTABLISHED;
- sock_copy_flags(sk, osk);
-
- timer_setup(&rose->timer, NULL, 0);
- timer_setup(&rose->idletimer, NULL, 0);
-
- orose = rose_sk(osk);
- rose->t1 = orose->t1;
- rose->t2 = orose->t2;
- rose->t3 = orose->t3;
- rose->hb = orose->hb;
- rose->idle = orose->idle;
- rose->defer = orose->defer;
- rose->device = orose->device;
- if (rose->device)
- netdev_hold(rose->device, &rose->dev_tracker, GFP_ATOMIC);
- rose->qbitincl = orose->qbitincl;
-
- return sk;
-}
-
-static int rose_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
- struct rose_sock *rose;
-
- if (sk == NULL) return 0;
-
- sock_hold(sk);
- sock_orphan(sk);
- lock_sock(sk);
- rose = rose_sk(sk);
-
- switch (rose->state) {
- case ROSE_STATE_0:
- release_sock(sk);
- rose_disconnect(sk, 0, -1, -1);
- lock_sock(sk);
- rose_destroy_socket(sk);
- break;
-
- case ROSE_STATE_2:
- rose_neigh_put(rose->neighbour);
- release_sock(sk);
- rose_disconnect(sk, 0, -1, -1);
- lock_sock(sk);
- 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->sk_state = TCP_CLOSE;
- sk->sk_shutdown |= SEND_SHUTDOWN;
- sk->sk_state_change(sk);
- sock_set_flag(sk, SOCK_DEAD);
- sock_set_flag(sk, SOCK_DESTROY);
- break;
-
- default:
- break;
- }
-
- spin_lock_bh(&rose_list_lock);
- netdev_put(rose->device, &rose->dev_tracker);
- rose->device = NULL;
- spin_unlock_bh(&rose_list_lock);
- sock->sk = NULL;
- release_sock(sk);
- sock_put(sk);
-
- return 0;
-}
-
-static int rose_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len)
-{
- struct sock *sk = sock->sk;
- struct rose_sock *rose = rose_sk(sk);
- struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
- struct net_device *dev;
- ax25_address *source;
- ax25_uid_assoc *user;
- int err = -EINVAL;
- int n;
-
- if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose))
- return -EINVAL;
-
- if (addr->srose_family != AF_ROSE)
- return -EINVAL;
-
- if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1)
- return -EINVAL;
-
- if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS)
- return -EINVAL;
-
- lock_sock(sk);
-
- if (!sock_flag(sk, SOCK_ZAPPED))
- goto out_release;
-
- err = -EADDRNOTAVAIL;
- dev = rose_dev_get(&addr->srose_addr);
- if (!dev)
- goto out_release;
-
- source = &addr->srose_call;
-
- user = ax25_findbyuid(current_euid());
- if (user) {
- rose->source_call = user->call;
- ax25_uid_put(user);
- } else {
- if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
- dev_put(dev);
- err = -EACCES;
- goto out_release;
- }
- rose->source_call = *source;
- }
-
- rose->source_addr = addr->srose_addr;
- rose->device = dev;
- netdev_tracker_alloc(rose->device, &rose->dev_tracker, GFP_KERNEL);
- rose->source_ndigis = addr->srose_ndigis;
-
- if (addr_len == sizeof(struct full_sockaddr_rose)) {
- struct full_sockaddr_rose *full_addr = (struct full_sockaddr_rose *)uaddr;
- for (n = 0 ; n < addr->srose_ndigis ; n++)
- rose->source_digis[n] = full_addr->srose_digis[n];
- } else {
- if (rose->source_ndigis == 1) {
- rose->source_digis[0] = addr->srose_digi;
- }
- }
-
- rose_insert_socket(sk);
-
- sock_reset_flag(sk, SOCK_ZAPPED);
- err = 0;
-out_release:
- release_sock(sk);
- return err;
-}
-
-static int rose_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len,
- int flags)
-{
- struct sock *sk = sock->sk;
- struct rose_sock *rose = rose_sk(sk);
- struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
- unsigned char cause, diagnostic;
- ax25_uid_assoc *user;
- int n, err = 0;
-
- if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose))
- return -EINVAL;
-
- if (addr->srose_family != AF_ROSE)
- return -EINVAL;
-
- if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1)
- return -EINVAL;
-
- if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS)
- return -EINVAL;
-
- /* Source + Destination digis should not exceed ROSE_MAX_DIGIS */
- if ((rose->source_ndigis + addr->srose_ndigis) > ROSE_MAX_DIGIS)
- return -EINVAL;
-
- lock_sock(sk);
-
- if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
- /* Connect completed during a ERESTARTSYS event */
- sock->state = SS_CONNECTED;
- goto out_release;
- }
-
- if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
- sock->state = SS_UNCONNECTED;
- err = -ECONNREFUSED;
- goto out_release;
- }
-
- if (sk->sk_state == TCP_ESTABLISHED) {
- /* No reconnect on a seqpacket socket */
- err = -EISCONN;
- goto out_release;
- }
-
- if (sk->sk_state == TCP_SYN_SENT) {
- err = -EALREADY;
- goto out_release;
- }
-
- sk->sk_state = TCP_CLOSE;
- sock->state = SS_UNCONNECTED;
-
- rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause,
- &diagnostic, 0);
- if (!rose->neighbour) {
- err = -ENETUNREACH;
- goto out_release;
- }
-
- rose->lci = rose_new_lci(rose->neighbour);
- if (!rose->lci) {
- err = -ENETUNREACH;
- rose_neigh_put(rose->neighbour);
- goto out_release;
- }
-
- if (sock_flag(sk, SOCK_ZAPPED)) { /* Must bind first - autobinding in this may or may not work */
- struct net_device *dev;
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- dev = rose_dev_first();
- if (!dev) {
- err = -ENETUNREACH;
- rose_neigh_put(rose->neighbour);
- goto out_release;
- }
-
- user = ax25_findbyuid(current_euid());
- if (!user) {
- err = -EINVAL;
- rose_neigh_put(rose->neighbour);
- dev_put(dev);
- goto out_release;
- }
-
- memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN);
- rose->source_call = user->call;
- rose->device = dev;
- netdev_tracker_alloc(rose->device, &rose->dev_tracker,
- GFP_KERNEL);
- ax25_uid_put(user);
-
- rose_insert_socket(sk); /* Finish the bind */
- }
- rose->dest_addr = addr->srose_addr;
- rose->dest_call = addr->srose_call;
- rose->rand = ((long)rose & 0xFFFF) + rose->lci;
- rose->dest_ndigis = addr->srose_ndigis;
-
- if (addr_len == sizeof(struct full_sockaddr_rose)) {
- struct full_sockaddr_rose *full_addr = (struct full_sockaddr_rose *)uaddr;
- for (n = 0 ; n < addr->srose_ndigis ; n++)
- rose->dest_digis[n] = full_addr->srose_digis[n];
- } else {
- if (rose->dest_ndigis == 1) {
- rose->dest_digis[0] = addr->srose_digi;
- }
- }
-
- /* Move to connecting socket, start sending Connect Requests */
- sock->state = SS_CONNECTING;
- sk->sk_state = TCP_SYN_SENT;
-
- rose->state = ROSE_STATE_1;
-
- rose_write_internal(sk, ROSE_CALL_REQUEST);
- rose_start_heartbeat(sk);
- rose_start_t1timer(sk);
-
- /* Now the loop */
- if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
- err = -EINPROGRESS;
- goto out_release;
- }
-
- /*
- * A Connect Ack with Choke or timeout or failed routing will go to
- * closed.
- */
- if (sk->sk_state == TCP_SYN_SENT) {
- DEFINE_WAIT(wait);
-
- for (;;) {
- prepare_to_wait(sk_sleep(sk), &wait,
- TASK_INTERRUPTIBLE);
- if (sk->sk_state != TCP_SYN_SENT)
- break;
- if (!signal_pending(current)) {
- release_sock(sk);
- schedule();
- lock_sock(sk);
- continue;
- }
- err = -ERESTARTSYS;
- break;
- }
- finish_wait(sk_sleep(sk), &wait);
-
- if (err)
- goto out_release;
- }
-
- if (sk->sk_state != TCP_ESTABLISHED) {
- sock->state = SS_UNCONNECTED;
- err = sock_error(sk); /* Always set at this point */
- goto out_release;
- }
-
- sock->state = SS_CONNECTED;
-
-out_release:
- release_sock(sk);
-
- return err;
-}
-
-static int rose_accept(struct socket *sock, struct socket *newsock,
- struct proto_accept_arg *arg)
-{
- struct sk_buff *skb;
- struct sock *newsk;
- DEFINE_WAIT(wait);
- struct sock *sk;
- int err = 0;
-
- if ((sk = sock->sk) == NULL)
- return -EINVAL;
-
- lock_sock(sk);
- if (sk->sk_type != SOCK_SEQPACKET) {
- err = -EOPNOTSUPP;
- goto out_release;
- }
-
- if (sk->sk_state != TCP_LISTEN) {
- err = -EINVAL;
- goto out_release;
- }
-
- /*
- * The write queue this time is holding sockets ready to use
- * hooked into the SABM we saved
- */
- for (;;) {
- prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-
- skb = skb_dequeue(&sk->sk_receive_queue);
- if (skb)
- break;
-
- if (arg->flags & O_NONBLOCK) {
- err = -EWOULDBLOCK;
- break;
- }
- if (!signal_pending(current)) {
- release_sock(sk);
- schedule();
- lock_sock(sk);
- continue;
- }
- err = -ERESTARTSYS;
- break;
- }
- finish_wait(sk_sleep(sk), &wait);
- if (err)
- goto out_release;
-
- newsk = skb->sk;
- sock_graft(newsk, newsock);
-
- /* Now attach up the new socket */
- skb->sk = NULL;
- kfree_skb(skb);
- sk_acceptq_removed(sk);
-
-out_release:
- release_sock(sk);
-
- return err;
-}
-
-static int rose_getname(struct socket *sock, struct sockaddr *uaddr,
- int peer)
-{
- struct full_sockaddr_rose *srose = (struct full_sockaddr_rose *)uaddr;
- struct sock *sk = sock->sk;
- struct rose_sock *rose = rose_sk(sk);
- int n;
-
- memset(srose, 0, sizeof(*srose));
- if (peer != 0) {
- if (sk->sk_state != TCP_ESTABLISHED)
- return -ENOTCONN;
- srose->srose_family = AF_ROSE;
- srose->srose_addr = rose->dest_addr;
- srose->srose_call = rose->dest_call;
- srose->srose_ndigis = rose->dest_ndigis;
- for (n = 0; n < rose->dest_ndigis; n++)
- srose->srose_digis[n] = rose->dest_digis[n];
- } else {
- srose->srose_family = AF_ROSE;
- srose->srose_addr = rose->source_addr;
- srose->srose_call = rose->source_call;
- srose->srose_ndigis = rose->source_ndigis;
- for (n = 0; n < rose->source_ndigis; n++)
- srose->srose_digis[n] = rose->source_digis[n];
- }
-
- return sizeof(struct full_sockaddr_rose);
-}
-
-int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct rose_neigh *neigh, unsigned int lci)
-{
- struct sock *sk;
- struct sock *make;
- struct rose_sock *make_rose;
- struct rose_facilities_struct facilities;
- int n;
-
- skb->sk = NULL; /* Initially we don't know who it's for */
-
- /*
- * skb->data points to the rose frame start
- */
- memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
-
- if (!rose_parse_facilities(skb->data + ROSE_CALL_REQ_FACILITIES_OFF,
- skb->len - ROSE_CALL_REQ_FACILITIES_OFF,
- &facilities)) {
- rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76);
- return 0;
- }
-
- sk = rose_find_listener(&facilities.source_addr, &facilities.source_call);
-
- /*
- * We can't accept the Call Request.
- */
- if (sk == NULL || sk_acceptq_is_full(sk) ||
- (make = rose_make_new(sk)) == NULL) {
- rose_transmit_clear_request(neigh, lci, ROSE_NETWORK_CONGESTION, 120);
- return 0;
- }
-
- skb->sk = make;
- make->sk_state = TCP_ESTABLISHED;
- make_rose = rose_sk(make);
-
- make_rose->lci = lci;
- make_rose->dest_addr = facilities.dest_addr;
- make_rose->dest_call = facilities.dest_call;
- make_rose->dest_ndigis = facilities.dest_ndigis;
- for (n = 0 ; n < facilities.dest_ndigis ; n++)
- make_rose->dest_digis[n] = facilities.dest_digis[n];
- make_rose->source_addr = facilities.source_addr;
- make_rose->source_call = facilities.source_call;
- make_rose->source_ndigis = facilities.source_ndigis;
- for (n = 0 ; n < facilities.source_ndigis ; n++)
- make_rose->source_digis[n] = facilities.source_digis[n];
- make_rose->neighbour = neigh;
- make_rose->device = dev;
- /* Caller got a reference for us. */
- netdev_tracker_alloc(make_rose->device, &make_rose->dev_tracker,
- GFP_ATOMIC);
- make_rose->facilities = facilities;
-
- rose_neigh_hold(make_rose->neighbour);
-
- if (rose_sk(sk)->defer) {
- make_rose->state = ROSE_STATE_5;
- } else {
- rose_write_internal(make, ROSE_CALL_ACCEPTED);
- make_rose->state = ROSE_STATE_3;
- rose_start_idletimer(make);
- }
-
- make_rose->condition = 0x00;
- make_rose->vs = 0;
- make_rose->va = 0;
- make_rose->vr = 0;
- make_rose->vl = 0;
- sk_acceptq_added(sk);
-
- rose_insert_socket(make);
-
- skb_queue_head(&sk->sk_receive_queue, skb);
-
- rose_start_heartbeat(make);
-
- if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_data_ready(sk);
-
- return 1;
-}
-
-static int rose_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
-{
- struct sock *sk = sock->sk;
- struct rose_sock *rose = rose_sk(sk);
- DECLARE_SOCKADDR(struct sockaddr_rose *, usrose, msg->msg_name);
- int err;
- struct full_sockaddr_rose srose;
- struct sk_buff *skb;
- unsigned char *asmptr;
- int n, size, qbit = 0;
-
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT))
- return -EINVAL;
-
- if (sock_flag(sk, SOCK_ZAPPED))
- return -EADDRNOTAVAIL;
-
- if (sk->sk_shutdown & SEND_SHUTDOWN) {
- send_sig(SIGPIPE, current, 0);
- return -EPIPE;
- }
-
- if (rose->neighbour == NULL || rose->device == NULL)
- return -ENETUNREACH;
-
- if (usrose != NULL) {
- if (msg->msg_namelen != sizeof(struct sockaddr_rose) && msg->msg_namelen != sizeof(struct full_sockaddr_rose))
- return -EINVAL;
- memset(&srose, 0, sizeof(struct full_sockaddr_rose));
- memcpy(&srose, usrose, msg->msg_namelen);
- if (rosecmp(&rose->dest_addr, &srose.srose_addr) != 0 ||
- ax25cmp(&rose->dest_call, &srose.srose_call) != 0)
- return -EISCONN;
- if (srose.srose_ndigis != rose->dest_ndigis)
- return -EISCONN;
- if (srose.srose_ndigis == rose->dest_ndigis) {
- for (n = 0 ; n < srose.srose_ndigis ; n++)
- if (ax25cmp(&rose->dest_digis[n],
- &srose.srose_digis[n]))
- return -EISCONN;
- }
- if (srose.srose_family != AF_ROSE)
- return -EINVAL;
- } else {
- if (sk->sk_state != TCP_ESTABLISHED)
- return -ENOTCONN;
-
- srose.srose_family = AF_ROSE;
- srose.srose_addr = rose->dest_addr;
- srose.srose_call = rose->dest_call;
- srose.srose_ndigis = rose->dest_ndigis;
- for (n = 0 ; n < rose->dest_ndigis ; n++)
- srose.srose_digis[n] = rose->dest_digis[n];
- }
-
- /* Build a packet */
- /* Sanity check the packet size */
- if (len > 65535)
- return -EMSGSIZE;
-
- size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;
-
- if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
- return err;
-
- skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN);
-
- /*
- * Put the data on the end
- */
-
- skb_reset_transport_header(skb);
- skb_put(skb, len);
-
- err = memcpy_from_msg(skb_transport_header(skb), msg, len);
- if (err) {
- kfree_skb(skb);
- return err;
- }
-
- /*
- * If the Q BIT Include socket option is in force, the first
- * byte of the user data is the logical value of the Q Bit.
- */
- if (rose->qbitincl) {
- qbit = skb->data[0];
- skb_pull(skb, 1);
- }
-
- /*
- * Push down the ROSE header
- */
- asmptr = skb_push(skb, ROSE_MIN_LEN);
-
- /* Build a ROSE Network header */
- asmptr[0] = ((rose->lci >> 8) & 0x0F) | ROSE_GFI;
- asmptr[1] = (rose->lci >> 0) & 0xFF;
- asmptr[2] = ROSE_DATA;
-
- if (qbit)
- asmptr[0] |= ROSE_Q_BIT;
-
- if (sk->sk_state != TCP_ESTABLISHED) {
- kfree_skb(skb);
- return -ENOTCONN;
- }
-
-#ifdef M_BIT
-#define ROSE_PACLEN (256-ROSE_MIN_LEN)
- if (skb->len - ROSE_MIN_LEN > ROSE_PACLEN) {
- unsigned char header[ROSE_MIN_LEN];
- struct sk_buff *skbn;
- int frontlen;
- int lg;
-
- /* Save a copy of the Header */
- skb_copy_from_linear_data(skb, header, ROSE_MIN_LEN);
- skb_pull(skb, ROSE_MIN_LEN);
-
- frontlen = skb_headroom(skb);
-
- while (skb->len > 0) {
- if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, &err)) == NULL) {
- kfree_skb(skb);
- return err;
- }
-
- skbn->sk = sk;
- skbn->free = 1;
- skbn->arp = 1;
-
- skb_reserve(skbn, frontlen);
-
- lg = (ROSE_PACLEN > skb->len) ? skb->len : ROSE_PACLEN;
-
- /* Copy the user data */
- skb_copy_from_linear_data(skb, skb_put(skbn, lg), lg);
- skb_pull(skb, lg);
-
- /* Duplicate the Header */
- skb_push(skbn, ROSE_MIN_LEN);
- skb_copy_to_linear_data(skbn, header, ROSE_MIN_LEN);
-
- if (skb->len > 0)
- skbn->data[2] |= M_BIT;
-
- skb_queue_tail(&sk->sk_write_queue, skbn); /* Throw it on the queue */
- }
-
- skb->free = 1;
- kfree_skb(skb);
- } else {
- skb_queue_tail(&sk->sk_write_queue, skb); /* Throw it on the queue */
- }
-#else
- skb_queue_tail(&sk->sk_write_queue, skb); /* Shove it onto the queue */
-#endif
-
- rose_kick(sk);
-
- return len;
-}
-
-
-static int rose_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
- int flags)
-{
- struct sock *sk = sock->sk;
- struct rose_sock *rose = rose_sk(sk);
- size_t copied;
- unsigned char *asmptr;
- struct sk_buff *skb;
- int n, er, qbit;
-
- /*
- * This works for seqpacket too. The receiver has ordered the queue for
- * us! We do one quick check first though
- */
- if (sk->sk_state != TCP_ESTABLISHED)
- return -ENOTCONN;
-
- /* Now we can treat all alike */
- skb = skb_recv_datagram(sk, flags, &er);
- if (!skb)
- return er;
-
- qbit = (skb->data[0] & ROSE_Q_BIT) == ROSE_Q_BIT;
-
- skb_pull(skb, ROSE_MIN_LEN);
-
- if (rose->qbitincl) {
- asmptr = skb_push(skb, 1);
- *asmptr = qbit;
- }
-
- skb_reset_transport_header(skb);
- copied = skb->len;
-
- if (copied > size) {
- copied = size;
- msg->msg_flags |= MSG_TRUNC;
- }
-
- skb_copy_datagram_msg(skb, 0, msg, copied);
-
- if (msg->msg_name) {
- struct sockaddr_rose *srose;
- DECLARE_SOCKADDR(struct full_sockaddr_rose *, full_srose,
- msg->msg_name);
-
- memset(msg->msg_name, 0, sizeof(struct full_sockaddr_rose));
- srose = msg->msg_name;
- srose->srose_family = AF_ROSE;
- srose->srose_addr = rose->dest_addr;
- srose->srose_call = rose->dest_call;
- srose->srose_ndigis = rose->dest_ndigis;
- for (n = 0 ; n < rose->dest_ndigis ; n++)
- full_srose->srose_digis[n] = rose->dest_digis[n];
- msg->msg_namelen = sizeof(struct full_sockaddr_rose);
- }
-
- skb_free_datagram(sk, skb);
-
- return copied;
-}
-
-
-static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk = sock->sk;
- struct rose_sock *rose = rose_sk(sk);
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
- case TIOCOUTQ: {
- long amount;
-
- amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
- if (amount < 0)
- amount = 0;
- return put_user(amount, (unsigned int __user *) argp);
- }
-
- case TIOCINQ: {
- struct sk_buff *skb;
- long amount = 0L;
-
- spin_lock_irq(&sk->sk_receive_queue.lock);
- if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
- amount = skb->len;
- spin_unlock_irq(&sk->sk_receive_queue.lock);
- return put_user(amount, (unsigned int __user *) argp);
- }
-
- 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, argp);
-
- case SIOCRSGCAUSE: {
- struct rose_cause_struct rose_cause;
- rose_cause.cause = rose->cause;
- rose_cause.diagnostic = rose->diagnostic;
- return copy_to_user(argp, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0;
- }
-
- case SIOCRSSCAUSE: {
- struct rose_cause_struct rose_cause;
- if (copy_from_user(&rose_cause, argp, 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, argp, sizeof(ax25_address)))
- return -EFAULT;
- if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
- return ax25_listen_register(&rose_callsign, NULL);
-
- return 0;
-
- case SIOCRSGL2CALL:
- return copy_to_user(argp, &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 -ENOIOCTLCMD;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_PROC_FS
-static void *rose_info_start(struct seq_file *seq, loff_t *pos)
- __acquires(rose_list_lock)
-{
- spin_lock_bh(&rose_list_lock);
- return seq_hlist_start_head(&rose_list, *pos);
-}
-
-static void *rose_info_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- return seq_hlist_next(v, &rose_list, pos);
-}
-
-static void rose_info_stop(struct seq_file *seq, void *v)
- __releases(rose_list_lock)
-{
- spin_unlock_bh(&rose_list_lock);
-}
-
-static int rose_info_show(struct seq_file *seq, void *v)
-{
- char buf[11], rsbuf[11];
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq,
- "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");
-
- else {
- struct sock *s = sk_entry(v);
- struct rose_sock *rose = rose_sk(s);
- const char *devname, *callsign;
- const struct net_device *dev = rose->device;
-
- if (!dev)
- devname = "???";
- else
- devname = dev->name;
-
- seq_printf(seq, "%-10s %-9s ",
- rose2asc(rsbuf, &rose->dest_addr),
- ax2asc(buf, &rose->dest_call));
-
- if (ax25cmp(&rose->source_call, &null_ax25_address) == 0)
- callsign = "??????-?";
- else
- callsign = ax2asc(buf, &rose->source_call);
-
- seq_printf(seq,
- "%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %llu\n",
- rose2asc(rsbuf, &rose->source_addr),
- callsign,
- devname,
- rose->lci & 0x0FFF,
- (rose->neighbour) ? rose->neighbour->number : 0,
- rose->state,
- rose->vs,
- rose->vr,
- rose->va,
- ax25_display_timer(&rose->timer) / HZ,
- rose->t1 / HZ,
- rose->t2 / HZ,
- rose->t3 / HZ,
- rose->hb / HZ,
- ax25_display_timer(&rose->idletimer) / (60 * HZ),
- rose->idle / (60 * HZ),
- sk_wmem_alloc_get(s),
- sk_rmem_alloc_get(s),
- s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : (u64)0);
- }
-
- return 0;
-}
-
-static const struct seq_operations rose_info_seqops = {
- .start = rose_info_start,
- .next = rose_info_next,
- .stop = rose_info_stop,
- .show = rose_info_show,
-};
-#endif /* CONFIG_PROC_FS */
-
-static const struct net_proto_family rose_family_ops = {
- .family = PF_ROSE,
- .create = rose_create,
- .owner = THIS_MODULE,
-};
-
-static const struct proto_ops rose_proto_ops = {
- .family = PF_ROSE,
- .owner = THIS_MODULE,
- .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,
- .gettstamp = sock_gettstamp,
- .listen = rose_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = rose_setsockopt,
- .getsockopt = rose_getsockopt,
- .sendmsg = rose_sendmsg,
- .recvmsg = rose_recvmsg,
- .mmap = sock_no_mmap,
-};
-
-static struct notifier_block rose_dev_notifier = {
- .notifier_call = rose_device_event,
-};
-
-static struct net_device **dev_rose;
-
-static struct ax25_protocol rose_pid = {
- .pid = AX25_P_ROSE,
- .func = rose_route_frame
-};
-
-static struct ax25_linkfail rose_linkfail_notifier = {
- .func = rose_link_failed
-};
-
-static int __init rose_proto_init(void)
-{
- int i;
- int rc;
-
- if (rose_ndevs > 0x7FFFFFFF/sizeof(struct net_device *)) {
- printk(KERN_ERR "ROSE: rose_proto_init - rose_ndevs parameter too large\n");
- rc = -EINVAL;
- goto out;
- }
-
- rc = proto_register(&rose_proto, 0);
- if (rc != 0)
- goto out;
-
- rose_callsign = null_ax25_address;
-
- dev_rose = kzalloc_objs(struct net_device *, rose_ndevs);
- if (dev_rose == NULL) {
- printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n");
- rc = -ENOMEM;
- goto out_proto_unregister;
- }
-
- for (i = 0; i < rose_ndevs; i++) {
- struct net_device *dev;
- char name[IFNAMSIZ];
-
- sprintf(name, "rose%d", i);
- dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, rose_setup);
- if (!dev) {
- printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate memory\n");
- rc = -ENOMEM;
- goto fail;
- }
- rc = register_netdev(dev);
- if (rc) {
- printk(KERN_ERR "ROSE: netdevice registration failed\n");
- free_netdev(dev);
- goto fail;
- }
- rose_set_lockdep_key(dev);
- dev_rose[i] = dev;
- }
-
- sock_register(&rose_family_ops);
- register_netdevice_notifier(&rose_dev_notifier);
-
- ax25_register_pid(&rose_pid);
- ax25_linkfail_register(&rose_linkfail_notifier);
-
-#ifdef CONFIG_SYSCTL
- rose_register_sysctl();
-#endif
- rose_loopback_init();
-
- rose_add_loopback_neigh();
-
- proc_create_seq("rose", 0444, init_net.proc_net, &rose_info_seqops);
- proc_create_seq("rose_neigh", 0444, init_net.proc_net,
- &rose_neigh_seqops);
- proc_create_seq("rose_nodes", 0444, init_net.proc_net,
- &rose_node_seqops);
- proc_create_seq("rose_routes", 0444, init_net.proc_net,
- &rose_route_seqops);
-out:
- return rc;
-fail:
- while (--i >= 0) {
- unregister_netdev(dev_rose[i]);
- free_netdev(dev_rose[i]);
- }
- kfree(dev_rose);
-out_proto_unregister:
- proto_unregister(&rose_proto);
- goto out;
-}
-module_init(rose_proto_init);
-
-module_param(rose_ndevs, int, 0);
-MODULE_PARM_DESC(rose_ndevs, "number of ROSE devices");
-
-MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
-MODULE_DESCRIPTION("The amateur radio ROSE network layer protocol");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NETPROTO(PF_ROSE);
-
-static void __exit rose_exit(void)
-{
- int i;
-
- remove_proc_entry("rose", init_net.proc_net);
- remove_proc_entry("rose_neigh", init_net.proc_net);
- remove_proc_entry("rose_nodes", init_net.proc_net);
- remove_proc_entry("rose_routes", init_net.proc_net);
- rose_loopback_clear();
-
- rose_rt_free();
-
- ax25_protocol_release(AX25_P_ROSE);
- ax25_linkfail_release(&rose_linkfail_notifier);
-
- if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
- ax25_listen_release(&rose_callsign, NULL);
-
-#ifdef CONFIG_SYSCTL
- rose_unregister_sysctl();
-#endif
- unregister_netdevice_notifier(&rose_dev_notifier);
-
- sock_unregister(PF_ROSE);
-
- for (i = 0; i < rose_ndevs; i++) {
- struct net_device *dev = dev_rose[i];
-
- if (dev) {
- unregister_netdev(dev);
- free_netdev(dev);
- }
- }
-
- kfree(dev_rose);
- proto_unregister(&rose_proto);
-}
-
-module_exit(rose_exit);
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
deleted file mode 100644
index f1a76a5820f1..000000000000
--- a/net/rose/rose_dev.c
+++ /dev/null
@@ -1,141 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/types.h>
-#include <linux/sysctl.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/in.h>
-#include <linux/if_ether.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-
-#include <net/ip.h>
-#include <net/arp.h>
-
-#include <net/ax25.h>
-#include <net/rose.h>
-
-static int rose_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type,
- const void *daddr, const void *saddr, unsigned int len)
-{
- unsigned char *buff = skb_push(skb, ROSE_MIN_LEN + 2);
-
- if (daddr)
- memcpy(buff + 7, daddr, dev->addr_len);
-
- *buff++ = ROSE_GFI | ROSE_Q_BIT;
- *buff++ = 0x00;
- *buff++ = ROSE_DATA;
- *buff++ = 0x7F;
- *buff++ = AX25_P_IP;
-
- if (daddr != NULL)
- return 37;
-
- return -37;
-}
-
-static int rose_set_mac_address(struct net_device *dev, void *addr)
-{
- struct sockaddr *sa = addr;
- int err;
-
- if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len))
- return 0;
-
- if (dev->flags & IFF_UP) {
- err = rose_add_loopback_node((rose_address *)sa->sa_data);
- if (err)
- return err;
-
- rose_del_loopback_node((const rose_address *)dev->dev_addr);
- }
-
- dev_addr_set(dev, sa->sa_data);
-
- return 0;
-}
-
-static int rose_open(struct net_device *dev)
-{
- int err;
-
- err = rose_add_loopback_node((const rose_address *)dev->dev_addr);
- if (err)
- return err;
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-static int rose_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
- rose_del_loopback_node((const rose_address *)dev->dev_addr);
- return 0;
-}
-
-static netdev_tx_t rose_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct net_device_stats *stats = &dev->stats;
- unsigned int len = skb->len;
-
- if (!netif_running(dev)) {
- printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n");
- return NETDEV_TX_BUSY;
- }
-
- if (!rose_route_frame(skb, NULL)) {
- dev_kfree_skb(skb);
- stats->tx_errors++;
- return NETDEV_TX_OK;
- }
-
- stats->tx_packets++;
- stats->tx_bytes += len;
- return NETDEV_TX_OK;
-}
-
-static const struct header_ops rose_header_ops = {
- .create = rose_header,
-};
-
-static const struct net_device_ops rose_netdev_ops = {
- .ndo_open = rose_open,
- .ndo_stop = rose_close,
- .ndo_start_xmit = rose_xmit,
- .ndo_set_mac_address = rose_set_mac_address,
-};
-
-void rose_setup(struct net_device *dev)
-{
- dev->mtu = ROSE_MAX_PACKET_SIZE - 2;
- dev->netdev_ops = &rose_netdev_ops;
-
- dev->header_ops = &rose_header_ops;
- dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;
- dev->addr_len = ROSE_ADDR_LEN;
- dev->type = ARPHRD_ROSE;
-
- /* New-style flags. */
- dev->flags = IFF_NOARP;
-}
diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c
deleted file mode 100644
index ca4f217ef3d3..000000000000
--- a/net/rose/rose_in.c
+++ /dev/null
@@ -1,301 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- *
- * 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/filter.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <net/rose.h>
-
-/*
- * State machine for state 1, Awaiting Call Accepted State.
- * The handling of the timer(s) is in file rose_timer.c.
- * Handling of state 0 and connection release is in af_rose.c.
- */
-static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
-{
- struct rose_sock *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->sk_state = TCP_ESTABLISHED;
- if (!sock_flag(sk, SOCK_DEAD))
- sk->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_neigh_put(rose->neighbour);
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-/*
- * State machine for state 2, Awaiting Clear Confirmation State.
- * The handling of the timer(s) is in file rose_timer.c
- * Handling of state 0 and connection release is in af_rose.c.
- */
-static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
-{
- struct rose_sock *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_neigh_put(rose->neighbour);
- break;
-
- case ROSE_CLEAR_CONFIRMATION:
- rose_disconnect(sk, 0, -1, -1);
- rose_neigh_put(rose->neighbour);
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-/*
- * State machine for state 3, Connected State.
- * The handling of the timer(s) is in file rose_timer.c
- * Handling of state 0 and connection release is in af_rose.c.
- */
-static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m)
-{
- struct rose_sock *rose = rose_sk(sk);
- 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_neigh_put(rose->neighbour);
- 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);
- } 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;
- }
- }
- break;
-
- 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 (!sk_filter_trim_cap(sk, skb, ROSE_MIN_LEN) &&
- __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->sk_rmem_alloc) >
- (sk->sk_rcvbuf >> 1))
- 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;
-}
-
-/*
- * State machine for state 4, Awaiting Reset Confirmation State.
- * The handling of the timer(s) is in file rose_timer.c
- * Handling of state 0 and connection release is in af_rose.c.
- */
-static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
-{
- struct rose_sock *rose = rose_sk(sk);
-
- switch (frametype) {
- case ROSE_RESET_REQUEST:
- rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
- fallthrough;
- 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_neigh_put(rose->neighbour);
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-/*
- * State machine for state 5, Awaiting Call Acceptance State.
- * The handling of the timer(s) is in file rose_timer.c
- * Handling of state 0 and connection release is in af_rose.c.
- */
-static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype)
-{
- if (frametype == ROSE_CLEAR_REQUEST) {
- rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
- rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
- rose_neigh_put(rose_sk(sk)->neighbour);
- }
-
- return 0;
-}
-
-/* Higher level upcall for a LAPB frame */
-int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
-{
- struct rose_sock *rose = rose_sk(sk);
- int queued = 0, frametype, ns, nr, q, d, m;
-
- if (rose->state == ROSE_STATE_0)
- return 0;
-
- frametype = rose_decode(skb, &ns, &nr, &q, &d, &m);
-
- /*
- * ROSE_CLEAR_REQUEST carries cause and diagnostic in bytes 3..4.
- * Reject a malformed frame that is too short to contain them.
- */
- if (frametype == ROSE_CLEAR_REQUEST && skb->len < 5)
- return 0;
-
- 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;
- }
-
- rose_kick(sk);
-
- return queued;
-}
diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c
deleted file mode 100644
index 7746229fdc8c..000000000000
--- a/net/rose/rose_link.c
+++ /dev/null
@@ -1,289 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <net/rose.h>
-
-static void rose_ftimer_expiry(struct timer_list *);
-static void rose_t0timer_expiry(struct timer_list *);
-
-static void rose_transmit_restart_confirmation(struct rose_neigh *neigh);
-static void rose_transmit_restart_request(struct rose_neigh *neigh);
-
-void rose_start_ftimer(struct rose_neigh *neigh)
-{
- timer_delete(&neigh->ftimer);
-
- neigh->ftimer.function = rose_ftimer_expiry;
- neigh->ftimer.expires =
- jiffies + msecs_to_jiffies(sysctl_rose_link_fail_timeout);
-
- add_timer(&neigh->ftimer);
-}
-
-static void rose_start_t0timer(struct rose_neigh *neigh)
-{
- timer_delete(&neigh->t0timer);
-
- neigh->t0timer.function = rose_t0timer_expiry;
- neigh->t0timer.expires =
- jiffies + msecs_to_jiffies(sysctl_rose_restart_request_timeout);
-
- add_timer(&neigh->t0timer);
-}
-
-void rose_stop_ftimer(struct rose_neigh *neigh)
-{
- timer_delete(&neigh->ftimer);
-}
-
-void rose_stop_t0timer(struct rose_neigh *neigh)
-{
- timer_delete(&neigh->t0timer);
-}
-
-int rose_ftimer_running(struct rose_neigh *neigh)
-{
- return timer_pending(&neigh->ftimer);
-}
-
-static int rose_t0timer_running(struct rose_neigh *neigh)
-{
- return timer_pending(&neigh->t0timer);
-}
-
-static void rose_ftimer_expiry(struct timer_list *t)
-{
-}
-
-static void rose_t0timer_expiry(struct timer_list *t)
-{
- struct rose_neigh *neigh = timer_container_of(neigh, t, t0timer);
-
- rose_transmit_restart_request(neigh);
-
- neigh->dce_mode = 0;
-
- rose_start_t0timer(neigh);
-}
-
-/*
- * Interface to ax25_send_frame. Changes my level 2 callsign depending
- * on whether we have a global ROSE callsign or use the default port
- * callsign.
- */
-static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
-{
- const ax25_address *rose_call;
- ax25_cb *ax25s;
-
- if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
- rose_call = (const ax25_address *)neigh->dev->dev_addr;
- else
- rose_call = &rose_callsign;
-
- ax25s = neigh->ax25;
- neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
- if (ax25s)
- ax25_cb_put(ax25s);
-
- return neigh->ax25 != NULL;
-}
-
-/*
- * Interface to ax25_link_up. Changes my level 2 callsign depending
- * on whether we have a global ROSE callsign or use the default port
- * callsign.
- */
-static int rose_link_up(struct rose_neigh *neigh)
-{
- const ax25_address *rose_call;
- ax25_cb *ax25s;
-
- if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
- rose_call = (const ax25_address *)neigh->dev->dev_addr;
- else
- rose_call = &rose_callsign;
-
- ax25s = neigh->ax25;
- neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
- if (ax25s)
- ax25_cb_put(ax25s);
-
- return neigh->ax25 != NULL;
-}
-
-/*
- * This handles all restart and diagnostic frames.
- */
-void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigned short frametype)
-{
- 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:
- pr_warn("ROSE: received diagnostic #%d - %3ph\n", skb->data[3],
- skb->data + 4);
- break;
-
- default:
- printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype);
- break;
- }
-
- if (neigh->restarted) {
- while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
- if (!rose_send_frame(skbn, neigh))
- kfree_skb(skbn);
- }
-}
-
-/*
- * This routine is called when a Restart Request is needed
- */
-static void rose_transmit_restart_request(struct rose_neigh *neigh)
-{
- struct sk_buff *skb;
- unsigned char *dptr;
- int len;
-
- len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
-
- if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
- return;
-
- skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
-
- dptr = skb_put(skb, ROSE_MIN_LEN + 3);
-
- *dptr++ = AX25_P_ROSE;
- *dptr++ = ROSE_GFI;
- *dptr++ = 0x00;
- *dptr++ = ROSE_RESTART_REQUEST;
- *dptr++ = ROSE_DTE_ORIGINATED;
- *dptr++ = 0;
-
- if (!rose_send_frame(skb, neigh))
- kfree_skb(skb);
-}
-
-/*
- * This routine is called when a Restart Confirmation is needed
- */
-static void rose_transmit_restart_confirmation(struct rose_neigh *neigh)
-{
- struct sk_buff *skb;
- unsigned char *dptr;
- int len;
-
- len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
-
- if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
- return;
-
- skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
-
- dptr = skb_put(skb, ROSE_MIN_LEN + 1);
-
- *dptr++ = AX25_P_ROSE;
- *dptr++ = ROSE_GFI;
- *dptr++ = 0x00;
- *dptr++ = ROSE_RESTART_CONFIRMATION;
-
- if (!rose_send_frame(skb, neigh))
- kfree_skb(skb);
-}
-
-/*
- * This routine is called when a Clear Request is needed outside of the context
- * of a connected socket.
- */
-void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause, unsigned char diagnostic)
-{
- struct sk_buff *skb;
- unsigned char *dptr;
- int len;
-
- if (!neigh->dev)
- return;
-
- len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
-
- if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
- return;
-
- skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
-
- dptr = skb_put(skb, ROSE_MIN_LEN + 3);
-
- *dptr++ = AX25_P_ROSE;
- *dptr++ = ((lci >> 8) & 0x0F) | ROSE_GFI;
- *dptr++ = ((lci >> 0) & 0xFF);
- *dptr++ = ROSE_CLEAR_REQUEST;
- *dptr++ = cause;
- *dptr++ = diagnostic;
-
- if (!rose_send_frame(skb, neigh))
- kfree_skb(skb);
-}
-
-void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
-{
- unsigned char *dptr;
-
- if (neigh->loopback) {
- rose_loopback_queue(skb, neigh);
- return;
- }
-
- if (!rose_link_up(neigh))
- neigh->restarted = 0;
-
- dptr = skb_push(skb, 1);
- *dptr++ = AX25_P_ROSE;
-
- if (neigh->restarted) {
- if (!rose_send_frame(skb, neigh))
- kfree_skb(skb);
- } else {
- skb_queue_tail(&neigh->queue, skb);
-
- if (!rose_t0timer_running(neigh)) {
- rose_transmit_restart_request(neigh);
- neigh->dce_mode = 0;
- rose_start_t0timer(neigh);
- }
- }
-}
diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c
deleted file mode 100644
index b538e39b3df5..000000000000
--- a/net/rose/rose_loopback.c
+++ /dev/null
@@ -1,133 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/socket.h>
-#include <linux/timer.h>
-#include <net/ax25.h>
-#include <linux/skbuff.h>
-#include <net/rose.h>
-#include <linux/init.h>
-
-static struct sk_buff_head loopback_queue;
-#define ROSE_LOOPBACK_LIMIT 1000
-static struct timer_list loopback_timer;
-
-static void rose_set_loopback_timer(void);
-static void rose_loopback_timer(struct timer_list *unused);
-
-void rose_loopback_init(void)
-{
- skb_queue_head_init(&loopback_queue);
-
- timer_setup(&loopback_timer, rose_loopback_timer, 0);
-}
-
-static int rose_loopback_running(void)
-{
- return timer_pending(&loopback_timer);
-}
-
-int rose_loopback_queue(struct sk_buff *skb, struct rose_neigh *neigh)
-{
- struct sk_buff *skbn = NULL;
-
- if (skb_queue_len(&loopback_queue) < ROSE_LOOPBACK_LIMIT)
- skbn = skb_clone(skb, GFP_ATOMIC);
-
- if (skbn) {
- consume_skb(skb);
- skb_queue_tail(&loopback_queue, skbn);
-
- if (!rose_loopback_running())
- rose_set_loopback_timer();
- } else {
- kfree_skb(skb);
- }
-
- return 1;
-}
-
-static void rose_set_loopback_timer(void)
-{
- mod_timer(&loopback_timer, jiffies + 10);
-}
-
-static void rose_loopback_timer(struct timer_list *unused)
-{
- struct sk_buff *skb;
- struct net_device *dev;
- rose_address *dest;
- struct sock *sk;
- unsigned short frametype;
- unsigned int lci_i, lci_o;
- int count;
-
- for (count = 0; count < ROSE_LOOPBACK_LIMIT; count++) {
- skb = skb_dequeue(&loopback_queue);
- if (!skb)
- return;
- if (skb->len < ROSE_MIN_LEN) {
- kfree_skb(skb);
- continue;
- }
- lci_i = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
- frametype = skb->data[2];
- if (frametype == ROSE_CALL_REQUEST &&
- (skb->len <= ROSE_CALL_REQ_FACILITIES_OFF ||
- skb->data[ROSE_CALL_REQ_ADDR_LEN_OFF] !=
- ROSE_CALL_REQ_ADDR_LEN_VAL)) {
- kfree_skb(skb);
- continue;
- }
- dest = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF);
- lci_o = ROSE_DEFAULT_MAXVC + 1 - lci_i;
-
- skb_reset_transport_header(skb);
-
- sk = rose_find_socket(lci_o, rose_loopback_neigh);
- if (sk) {
- if (rose_process_rx_frame(sk, skb) == 0)
- kfree_skb(skb);
- continue;
- }
-
- if (frametype == ROSE_CALL_REQUEST) {
- if (!rose_loopback_neigh->dev &&
- !rose_loopback_neigh->loopback) {
- kfree_skb(skb);
- continue;
- }
-
- dev = rose_dev_get(dest);
- if (!dev) {
- kfree_skb(skb);
- continue;
- }
-
- if (rose_rx_call_request(skb, dev, rose_loopback_neigh, lci_o) == 0) {
- dev_put(dev);
- kfree_skb(skb);
- }
- } else {
- kfree_skb(skb);
- }
- }
- if (!skb_queue_empty(&loopback_queue))
- mod_timer(&loopback_timer, jiffies + 1);
-}
-
-void __exit rose_loopback_clear(void)
-{
- struct sk_buff *skb;
-
- timer_delete(&loopback_timer);
-
- while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
- skb->sk = NULL;
- kfree_skb(skb);
- }
-}
diff --git a/net/rose/rose_out.c b/net/rose/rose_out.c
deleted file mode 100644
index 9050e33c9604..000000000000
--- a/net/rose/rose_out.c
+++ /dev/null
@@ -1,122 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/gfp.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#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.
- */
-static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
-{
- struct rose_sock *rose = rose_sk(sk);
-
- if (skb == NULL)
- return;
-
- skb->data[2] |= (rose->vr << 5) & 0xE0;
- skb->data[2] |= (rose->vs << 1) & 0x0E;
-
- rose_start_idletimer(sk);
-
- rose_transmit_link(skb, rose->neighbour);
-}
-
-void rose_kick(struct sock *sk)
-{
- struct rose_sock *rose = rose_sk(sk);
- struct sk_buff *skb, *skbn;
- unsigned short start, end;
-
- if (rose->state != ROSE_STATE_3)
- return;
-
- if (rose->condition & ROSE_COND_PEER_RX_BUSY)
- return;
-
- if (!skb_peek(&sk->sk_write_queue))
- return;
-
- start = (skb_peek(&rose->ack_queue) == NULL) ? rose->va : rose->vs;
- end = (rose->va + sysctl_rose_window_size) % ROSE_MODULUS;
-
- if (start == end)
- return;
-
- rose->vs = start;
-
- /*
- * Transmit data until either we're out of data to send or
- * the window is full.
- */
-
- skb = skb_dequeue(&sk->sk_write_queue);
-
- do {
- if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
- skb_queue_head(&sk->sk_write_queue, skb);
- break;
- }
-
- skb_set_owner_w(skbn, sk);
-
- /*
- * Transmit the frame copy.
- */
- rose_send_iframe(sk, skbn);
-
- rose->vs = (rose->vs + 1) % ROSE_MODULUS;
-
- /*
- * Requeue the original data frame.
- */
- skb_queue_tail(&rose->ack_queue, skb);
-
- } while (rose->vs != end &&
- (skb = skb_dequeue(&sk->sk_write_queue)) != NULL);
-
- rose->vl = rose->vr;
- rose->condition &= ~ROSE_COND_ACK_PENDING;
-
- rose_stop_timer(sk);
-}
-
-/*
- * The following routines are taken from page 170 of the 7th ARRL Computer
- * Networking Conference paper, as is the whole state machine.
- */
-
-void rose_enquiry_response(struct sock *sk)
-{
- struct rose_sock *rose = rose_sk(sk);
-
- if (rose->condition & ROSE_COND_OWN_RX_BUSY)
- rose_write_internal(sk, ROSE_RNR);
- else
- rose_write_internal(sk, ROSE_RR);
-
- rose->vl = rose->vr;
- rose->condition &= ~ROSE_COND_ACK_PENDING;
-
- rose_stop_timer(sk);
-}
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
deleted file mode 100644
index e31842e6b3c8..000000000000
--- a/net/rose/rose_route.c
+++ /dev/null
@@ -1,1333 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <net/arp.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/uaccess.h>
-#include <linux/fcntl.h>
-#include <linux/termios.h> /* For TIOCINQ/OUTQ */
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <linux/init.h>
-#include <net/rose.h>
-#include <linux/seq_file.h>
-#include <linux/export.h>
-
-static unsigned int rose_neigh_no = 1;
-
-static struct rose_node *rose_node_list;
-static DEFINE_SPINLOCK(rose_node_list_lock);
-static struct rose_neigh *rose_neigh_list;
-static DEFINE_SPINLOCK(rose_neigh_list_lock);
-static struct rose_route *rose_route_list;
-static DEFINE_SPINLOCK(rose_route_list_lock);
-
-struct rose_neigh *rose_loopback_neigh;
-
-/*
- * Add a new route to a node, and in the process add the node and the
- * neighbour if it is new.
- */
-static int __must_check 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;
- int i, res = 0;
-
- spin_lock_bh(&rose_node_list_lock);
- spin_lock_bh(&rose_neigh_list_lock);
-
- 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) {
- res = -EINVAL;
- goto out;
- }
-
- 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) {
- rose_neigh = kmalloc_obj(*rose_neigh, GFP_ATOMIC);
- if (rose_neigh == NULL) {
- res = -ENOMEM;
- goto out;
- }
-
- rose_neigh->callsign = rose_route->neighbour;
- rose_neigh->digipeat = NULL;
- rose_neigh->ax25 = NULL;
- rose_neigh->dev = dev;
- rose_neigh->count = 0;
- rose_neigh->dce_mode = 0;
- rose_neigh->loopback = 0;
- rose_neigh->number = rose_neigh_no++;
- rose_neigh->restarted = 0;
- refcount_set(&rose_neigh->use, 1);
-
- skb_queue_head_init(&rose_neigh->queue);
-
- timer_setup(&rose_neigh->ftimer, NULL, 0);
- timer_setup(&rose_neigh->t0timer, NULL, 0);
-
- if (rose_route->ndigis != 0) {
- rose_neigh->digipeat =
- kmalloc_obj(ax25_digi, GFP_ATOMIC);
- if (rose_neigh->digipeat == NULL) {
- kfree(rose_neigh);
- 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->repeated[i] = 0;
- }
- }
-
- rose_neigh->next = rose_neigh_list;
- rose_neigh_list = rose_neigh;
- }
-
- /*
- * This is a new node to be inserted into the list. Find where it needs
- * to be inserted into the list, and insert it. We want to be sure
- * to order the list in descending order of mask size to ensure that
- * later when we are searching this list the first match will be the
- * best match.
- */
- if (rose_node == NULL) {
- rose_tmpn = rose_node_list;
- rose_tmpp = NULL;
-
- while (rose_tmpn != NULL) {
- if (rose_tmpn->mask > rose_route->mask) {
- rose_tmpp = rose_tmpn;
- rose_tmpn = rose_tmpn->next;
- } else {
- break;
- }
- }
-
- /* create new node */
- rose_node = kmalloc_obj(*rose_node, GFP_ATOMIC);
- if (rose_node == NULL) {
- res = -ENOMEM;
- goto out;
- }
-
- rose_node->address = rose_route->address;
- rose_node->mask = rose_route->mask;
- rose_node->count = 1;
- rose_node->loopback = 0;
- rose_node->neighbour[0] = rose_neigh;
-
- if (rose_tmpn == NULL) {
- if (rose_tmpp == NULL) { /* Empty list */
- rose_node_list = rose_node;
- rose_node->next = NULL;
- } else {
- rose_tmpp->next = rose_node;
- rose_node->next = NULL;
- }
- } else {
- if (rose_tmpp == NULL) { /* 1st node */
- rose_node->next = rose_node_list;
- rose_node_list = rose_node;
- } else {
- rose_tmpp->next = rose_node;
- rose_node->next = rose_tmpn;
- }
- }
- rose_neigh->count++;
- rose_neigh_hold(rose_neigh);
-
- goto out;
- }
-
- /* We have space, slot it in */
- if (rose_node->count < 3) {
- rose_node->neighbour[rose_node->count] = rose_neigh;
- rose_node->count++;
- rose_neigh->count++;
- rose_neigh_hold(rose_neigh);
- }
-
-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;
-
- if ((s = rose_node_list) == rose_node) {
- rose_node_list = rose_node->next;
- kfree(rose_node);
- return;
- }
-
- while (s != NULL && s->next != NULL) {
- if (s->next == rose_node) {
- s->next = rose_node->next;
- kfree(rose_node);
- return;
- }
-
- s = s->next;
- }
-}
-
-/*
- * Caller is holding rose_neigh_list_lock.
- */
-static void rose_remove_neigh(struct rose_neigh *rose_neigh)
-{
- struct rose_neigh *s;
-
- timer_delete_sync(&rose_neigh->ftimer);
- timer_delete_sync(&rose_neigh->t0timer);
-
- skb_queue_purge(&rose_neigh->queue);
-
- if ((s = rose_neigh_list) == rose_neigh) {
- rose_neigh_list = rose_neigh->next;
- return;
- }
-
- while (s != NULL && s->next != NULL) {
- if (s->next == rose_neigh) {
- s->next = rose_neigh->next;
- return;
- }
-
- s = s->next;
- }
-}
-
-/*
- * Caller is holding rose_route_list_lock.
- */
-static void rose_remove_route(struct rose_route *rose_route)
-{
- struct rose_route *s;
-
- if (rose_route->neigh1 != NULL)
- rose_neigh_put(rose_route->neigh1);
-
- if (rose_route->neigh2 != NULL)
- rose_neigh_put(rose_route->neigh2);
-
- if ((s = rose_route_list) == rose_route) {
- rose_route_list = rose_route->next;
- kfree(rose_route);
- return;
- }
-
- while (s != NULL && s->next != NULL) {
- if (s->next == rose_route) {
- s->next = rose_route->next;
- kfree(rose_route);
- return;
- }
-
- s = s->next;
- }
-}
-
-/*
- * "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)
-{
- struct rose_node *rose_node;
- struct rose_neigh *rose_neigh;
- int i, err = 0;
-
- spin_lock_bh(&rose_node_list_lock);
- spin_lock_bh(&rose_neigh_list_lock);
-
- 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) {
- err = -EINVAL;
- goto out;
- }
-
- 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) {
- err = -EINVAL;
- goto out;
- }
-
- for (i = 0; i < rose_node->count; i++) {
- if (rose_node->neighbour[i] == rose_neigh) {
- rose_neigh->count--;
- rose_neigh_put(rose_neigh);
-
- if (rose_neigh->count == 0) {
- rose_remove_neigh(rose_neigh);
- rose_neigh_put(rose_neigh);
- }
-
- rose_node->count--;
-
- if (rose_node->count == 0) {
- rose_remove_node(rose_node);
- } else {
- switch (i) {
- case 0:
- rose_node->neighbour[0] =
- rose_node->neighbour[1];
- fallthrough;
- case 1:
- rose_node->neighbour[1] =
- rose_node->neighbour[2];
- break;
- case 2:
- break;
- }
- }
- goto out;
- }
- }
- err = -EINVAL;
-
-out:
- spin_unlock_bh(&rose_neigh_list_lock);
- spin_unlock_bh(&rose_node_list_lock);
-
- return err;
-}
-
-/*
- * Add the loopback neighbour.
- */
-void rose_add_loopback_neigh(void)
-{
- struct rose_neigh *sn;
-
- rose_loopback_neigh = kmalloc_obj(struct rose_neigh);
- if (!rose_loopback_neigh)
- return;
- sn = rose_loopback_neigh;
-
- sn->callsign = null_ax25_address;
- sn->digipeat = NULL;
- sn->ax25 = NULL;
- sn->dev = NULL;
- sn->count = 0;
- sn->dce_mode = 1;
- sn->loopback = 1;
- sn->number = rose_neigh_no++;
- sn->restarted = 1;
- refcount_set(&sn->use, 1);
-
- skb_queue_head_init(&sn->queue);
-
- timer_setup(&sn->ftimer, NULL, 0);
- timer_setup(&sn->t0timer, NULL, 0);
-
- spin_lock_bh(&rose_neigh_list_lock);
- sn->next = rose_neigh_list;
- rose_neigh_list = sn;
- spin_unlock_bh(&rose_neigh_list_lock);
-}
-
-/*
- * Add a loopback node.
- */
-int rose_add_loopback_node(const rose_address *address)
-{
- struct rose_node *rose_node;
- int err = 0;
-
- 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)
- goto out;
-
- if ((rose_node = kmalloc_obj(*rose_node, GFP_ATOMIC)) == NULL) {
- err = -ENOMEM;
- goto out;
- }
-
- rose_node->address = *address;
- rose_node->mask = 10;
- rose_node->count = 1;
- rose_node->loopback = 1;
- rose_node->neighbour[0] = rose_loopback_neigh;
-
- /* Insert at the head of list. Address is always mask=10 */
- rose_node->next = rose_node_list;
- rose_node_list = rose_node;
-
- rose_loopback_neigh->count++;
- rose_neigh_hold(rose_loopback_neigh);
-
-out:
- spin_unlock_bh(&rose_node_list_lock);
-
- return err;
-}
-
-/*
- * Delete a loopback node.
- */
-void rose_del_loopback_node(const rose_address *address)
-{
- struct rose_node *rose_node;
-
- 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)
- goto out;
-
- rose_remove_node(rose_node);
-
- rose_loopback_neigh->count--;
- rose_neigh_put(rose_loopback_neigh);
-
-out:
- spin_unlock_bh(&rose_node_list_lock);
-}
-
-/*
- * A device has been removed. Remove its routes and neighbours.
- */
-void rose_rt_device_down(struct net_device *dev)
-{
- 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)
- continue;
-
- rose_node = rose_node_list;
-
- while (rose_node != NULL) {
- t = rose_node;
- rose_node = rose_node->next;
-
- for (i = t->count - 1; i >= 0; i--) {
- if (t->neighbour[i] != s)
- continue;
-
- t->count--;
-
- memmove(&t->neighbour[i], &t->neighbour[i + 1],
- sizeof(t->neighbour[0]) *
- (t->count - i));
- rose_neigh_put(s);
- }
-
- if (t->count <= 0)
- rose_remove_node(t);
- }
-
- rose_remove_neigh(s);
- rose_neigh_put(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;
-
- spin_lock_bh(&rose_route_list_lock);
- rose_route = rose_route_list;
- while (rose_route != NULL) {
- s = rose_route;
- rose_route = rose_route->next;
-
- 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
- * active connections going through them.
- * Do not clear loopback neighbour and nodes.
- */
-static int rose_clear_routes(void)
-{
- 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;
- rose_node = rose_node_list;
-
- while (rose_node != NULL) {
- t = rose_node;
- rose_node = rose_node->next;
-
- if (!t->loopback) {
- for (i = 0; i < t->count; i++)
- rose_neigh_put(t->neighbour[i]);
- rose_remove_node(t);
- }
- }
-
- while (rose_neigh != NULL) {
- s = rose_neigh;
- rose_neigh = rose_neigh->next;
-
- if (!s->loopback) {
- rose_remove_neigh(s);
- rose_neigh_put(s);
- }
- }
-
- spin_unlock_bh(&rose_neigh_list_lock);
- spin_unlock_bh(&rose_node_list_lock);
-
- return 0;
-}
-
-/*
- * Check that the device given is a valid AX.25 interface that is "up".
- * called with RTNL
- */
-static struct net_device *rose_ax25_dev_find(char *devname)
-{
- struct net_device *dev;
-
- if ((dev = __dev_get_by_name(&init_net, devname)) == NULL)
- return NULL;
-
- if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
- return dev;
-
- return NULL;
-}
-
-/*
- * Find the first active ROSE device, usually "rose0".
- */
-struct net_device *rose_dev_first(void)
-{
- struct net_device *dev, *first = NULL;
-
- rcu_read_lock();
- for_each_netdev_rcu(&init_net, dev) {
- if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE)
- if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
- first = dev;
- }
- if (first)
- dev_hold(first);
- rcu_read_unlock();
-
- return first;
-}
-
-/*
- * Find the ROSE device for the given address.
- */
-struct net_device *rose_dev_get(rose_address *addr)
-{
- struct net_device *dev;
-
- rcu_read_lock();
- for_each_netdev_rcu(&init_net, dev) {
- if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE &&
- rosecmp(addr, (const rose_address *)dev->dev_addr) == 0) {
- dev_hold(dev);
- goto out;
- }
- }
- dev = NULL;
-out:
- rcu_read_unlock();
- return dev;
-}
-
-static int rose_dev_exists(rose_address *addr)
-{
- struct net_device *dev;
-
- rcu_read_lock();
- for_each_netdev_rcu(&init_net, dev) {
- if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE &&
- rosecmp(addr, (const rose_address *)dev->dev_addr) == 0)
- goto out;
- }
- dev = NULL;
-out:
- rcu_read_unlock();
- return dev != NULL;
-}
-
-
-
-
-struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neigh)
-{
- struct rose_route *rose_route;
-
- for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next)
- if ((rose_route->neigh1 == neigh && rose_route->lci1 == lci) ||
- (rose_route->neigh2 == neigh && rose_route->lci2 == lci))
- return rose_route;
-
- return NULL;
-}
-
-/*
- * Find a neighbour or a route given a ROSE address.
- */
-struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause,
- unsigned char *diagnostic, int route_frame)
-{
- struct rose_neigh *res = NULL;
- struct rose_node *node;
- int failed = 0;
- int i;
-
- if (!route_frame) 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 (node->neighbour[i]->restarted) {
- res = node->neighbour[i];
- rose_neigh_hold(node->neighbour[i]);
- goto out;
- }
- }
- }
- }
- if (!route_frame) { /* connect request */
- 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])) {
- res = node->neighbour[i];
- rose_neigh_hold(node->neighbour[i]);
- goto out;
- }
- failed = 1;
- }
- }
- }
- }
-
- if (failed) {
- *cause = ROSE_OUT_OF_ORDER;
- *diagnostic = 0;
- } else {
- *cause = ROSE_NOT_OBTAINABLE;
- *diagnostic = 0;
- }
-
-out:
- if (!route_frame) spin_unlock_bh(&rose_node_list_lock);
- return res;
-}
-
-/*
- * Handle the ioctls that control the routing functions.
- */
-int rose_rt_ioctl(unsigned int cmd, void __user *arg)
-{
- struct rose_route_struct rose_route;
- struct net_device *dev;
- 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_find(rose_route.device)) == NULL)
- return -EINVAL;
- if (rose_dev_exists(&rose_route.address)) /* Can't add routes to ourself */
- return -EINVAL;
- if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
- return -EINVAL;
- if (rose_route.ndigis > AX25_MAX_DIGIS)
- return -EINVAL;
- err = rose_add_node(&rose_route, dev);
- return err;
-
- case SIOCDELRT:
- if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
- return -EFAULT;
- if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL)
- return -EINVAL;
- err = rose_del_node(&rose_route, dev);
- return err;
-
- case SIOCRSCLRRT:
- return rose_clear_routes();
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
-{
- struct rose_route *rose_route, *s;
-
- rose_neigh->restarted = 0;
-
- rose_stop_t0timer(rose_neigh);
- rose_start_ftimer(rose_neigh);
-
- skb_queue_purge(&rose_neigh->queue);
-
- spin_lock_bh(&rose_route_list_lock);
-
- rose_route = rose_route_list;
-
- while (rose_route != NULL) {
- if ((rose_route->neigh1 == rose_neigh && rose_route->neigh2 == rose_neigh) ||
- (rose_route->neigh1 == rose_neigh && rose_route->neigh2 == NULL) ||
- (rose_route->neigh2 == rose_neigh && rose_route->neigh1 == NULL)) {
- s = rose_route->next;
- rose_remove_route(rose_route);
- rose_route = s;
- continue;
- }
-
- if (rose_route->neigh1 == rose_neigh) {
- rose_neigh_put(rose_route->neigh1);
- rose_route->neigh1 = NULL;
- rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, ROSE_OUT_OF_ORDER, 0);
- }
-
- if (rose_route->neigh2 == rose_neigh) {
- rose_neigh_put(rose_route->neigh2);
- rose_route->neigh2 = NULL;
- rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, ROSE_OUT_OF_ORDER, 0);
- }
-
- rose_route = rose_route->next;
- }
- spin_unlock_bh(&rose_route_list_lock);
-}
-
-/*
- * A level 2 link has timed out, therefore it appears to be a poor link,
- * then don't use that neighbour until it is reset. Blow away all through
- * routes and connections using this route.
- */
-void rose_link_failed(ax25_cb *ax25, int reason)
-{
- struct rose_neigh *rose_neigh;
-
- 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) {
- rose_neigh->ax25 = NULL;
- ax25_cb_put(ax25);
-
- rose_del_route_by_neigh(rose_neigh);
- rose_kill_by_neigh(rose_neigh);
- }
- spin_unlock_bh(&rose_neigh_list_lock);
-}
-
-/*
- * A device has been "downed" remove its link status. Blow away all
- * through routes and connections that use this device.
- */
-void rose_link_device_down(struct net_device *dev)
-{
- struct rose_neigh *rose_neigh;
-
- for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) {
- if (rose_neigh->dev == dev) {
- rose_del_route_by_neigh(rose_neigh);
- rose_kill_by_neigh(rose_neigh);
- }
- }
-}
-
-/*
- * Route a frame to an appropriate AX.25 connection.
- * A NULL ax25_cb indicates an internally generated frame.
- */
-int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
-{
- struct rose_neigh *rose_neigh, *new_neigh;
- struct rose_route *rose_route;
- struct rose_facilities_struct facilities;
- rose_address *src_addr, *dest_addr;
- struct sock *sk;
- unsigned short frametype;
- unsigned int lci, new_lci;
- unsigned char cause, diagnostic;
- struct net_device *dev;
- int res = 0;
- char buf[11];
-
- if (skb->len < ROSE_MIN_LEN)
- return res;
-
- if (!ax25)
- return rose_loopback_queue(skb, NULL);
-
- frametype = skb->data[2];
- lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
- if (frametype == ROSE_CALL_REQUEST &&
- (skb->len <= ROSE_CALL_REQ_FACILITIES_OFF ||
- skb->data[ROSE_CALL_REQ_ADDR_LEN_OFF] !=
- ROSE_CALL_REQ_ADDR_LEN_VAL))
- return res;
- src_addr = (rose_address *)(skb->data + ROSE_CALL_REQ_SRC_ADDR_OFF);
- dest_addr = (rose_address *)(skb->data + ROSE_CALL_REQ_DEST_ADDR_OFF);
-
- 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(buf, &ax25->dest_addr));
- goto out;
- }
-
- /*
- * Obviously the link is working, halt the ftimer.
- */
- rose_stop_ftimer(rose_neigh);
-
- /*
- * LCI of zero is always for us, and its always a restart
- * frame.
- */
- if (lci == 0) {
- rose_link_rx_restart(skb, rose_neigh, frametype);
- goto out;
- }
-
- /*
- * Find an existing socket.
- */
- if ((sk = rose_find_socket(lci, rose_neigh)) != NULL) {
- if (frametype == ROSE_CALL_REQUEST) {
- struct rose_sock *rose = rose_sk(sk);
-
- /* Remove an existing unused socket */
- rose_clear_queues(sk);
- rose->cause = ROSE_NETWORK_CONGESTION;
- rose->diagnostic = 0;
- rose_neigh_put(rose->neighbour);
- rose->neighbour = NULL;
- rose->lci = 0;
- rose->state = ROSE_STATE_0;
- sk->sk_state = TCP_CLOSE;
- sk->sk_err = 0;
- sk->sk_shutdown |= SEND_SHUTDOWN;
- if (!sock_flag(sk, SOCK_DEAD)) {
- sk->sk_state_change(sk);
- sock_set_flag(sk, SOCK_DEAD);
- }
- }
- else {
- skb_reset_transport_header(skb);
- res = rose_process_rx_frame(sk, skb);
- goto out;
- }
- }
-
- /*
- * Is is a Call Request and is it for us ?
- */
- if (frametype == ROSE_CALL_REQUEST)
- if ((dev = rose_dev_get(dest_addr)) != NULL) {
- res = rose_rx_call_request(skb, dev, rose_neigh, lci);
- dev_put(dev);
- goto out;
- }
-
- if (!sysctl_rose_routing_control) {
- rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0);
- goto out;
- }
-
- /*
- * Route it to the next in line if we have an entry for it.
- */
- 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);
- break;
- } else if (rose_route->neigh2 != NULL) {
- 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);
- if (frametype == ROSE_CLEAR_CONFIRMATION)
- rose_remove_route(rose_route);
- res = 1;
- goto out;
- } else {
- if (frametype == ROSE_CLEAR_CONFIRMATION)
- rose_remove_route(rose_route);
- goto out;
- }
- }
- 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);
- break;
- } else if (rose_route->neigh1 != NULL) {
- skb->data[0] &= 0xF0;
- skb->data[0] |= (rose_route->lci1 >> 8) & 0x0F;
- skb->data[1] = (rose_route->lci1 >> 0) & 0xFF;
- rose_transmit_link(skb, rose_route->neigh1);
- if (frametype == ROSE_CLEAR_CONFIRMATION)
- rose_remove_route(rose_route);
- res = 1;
- goto out;
- } else {
- if (frametype == ROSE_CLEAR_CONFIRMATION)
- rose_remove_route(rose_route);
- goto out;
- }
- }
- rose_route = rose_route->next;
- }
-
- /*
- * We know that:
- * 1. The frame isn't for us,
- * 2. It isn't "owned" by any existing route.
- */
- if (frametype != ROSE_CALL_REQUEST) { /* XXX */
- res = 0;
- goto out;
- }
-
- memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
-
- if (!rose_parse_facilities(skb->data + ROSE_CALL_REQ_FACILITIES_OFF,
- skb->len - ROSE_CALL_REQ_FACILITIES_OFF,
- &facilities)) {
- rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76);
- goto out;
- }
-
- /*
- * Check for routing loops.
- */
- 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);
- goto out;
- }
- rose_route = rose_route->next;
- }
-
- if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic, 1)) == NULL) {
- rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
- goto out;
- }
-
- if ((new_lci = rose_new_lci(new_neigh)) == 0) {
- rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71);
- goto put_neigh;
- }
-
- if ((rose_route = kmalloc_obj(*rose_route, GFP_ATOMIC)) == NULL) {
- rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120);
- goto put_neigh;
- }
-
- rose_route->lci1 = lci;
- rose_route->src_addr = *src_addr;
- rose_route->dest_addr = *dest_addr;
- rose_route->src_call = facilities.dest_call;
- rose_route->dest_call = facilities.source_call;
- rose_route->rand = facilities.rand;
- rose_route->neigh1 = rose_neigh;
- rose_route->lci2 = new_lci;
- rose_route->neigh2 = new_neigh;
-
- rose_neigh_hold(rose_route->neigh1);
- rose_neigh_hold(rose_route->neigh2);
-
- rose_route->next = rose_route_list;
- rose_route_list = rose_route;
-
- 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;
-
-put_neigh:
- rose_neigh_put(new_neigh);
-out:
- spin_unlock_bh(&rose_route_list_lock);
- spin_unlock_bh(&rose_neigh_list_lock);
-
- return res;
-}
-
-#ifdef CONFIG_PROC_FS
-
-static void *rose_node_start(struct seq_file *seq, loff_t *pos)
- __acquires(rose_node_list_lock)
-{
- struct rose_node *rose_node;
- int i = 1;
-
- spin_lock_bh(&rose_node_list_lock);
- if (*pos == 0)
- return SEQ_START_TOKEN;
-
- for (rose_node = rose_node_list; rose_node && i < *pos;
- rose_node = rose_node->next, ++i);
-
- return (i == *pos) ? rose_node : NULL;
-}
-
-static void *rose_node_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
-
- return (v == SEQ_START_TOKEN) ? rose_node_list
- : ((struct rose_node *)v)->next;
-}
-
-static void rose_node_stop(struct seq_file *seq, void *v)
- __releases(rose_node_list_lock)
-{
- spin_unlock_bh(&rose_node_list_lock);
-}
-
-static int rose_node_show(struct seq_file *seq, void *v)
-{
- char rsbuf[11];
- int i;
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, "address mask n neigh neigh neigh\n");
- else {
- const struct rose_node *rose_node = v;
- seq_printf(seq, "%-10s %04d %d",
- rose2asc(rsbuf, &rose_node->address),
- rose_node->mask,
- rose_node->count);
-
- for (i = 0; i < rose_node->count; i++)
- seq_printf(seq, " %05d", rose_node->neighbour[i]->number);
-
- seq_puts(seq, "\n");
- }
- return 0;
-}
-
-const struct seq_operations rose_node_seqops = {
- .start = rose_node_start,
- .next = rose_node_next,
- .stop = rose_node_stop,
- .show = rose_node_show,
-};
-
-static void *rose_neigh_start(struct seq_file *seq, loff_t *pos)
- __acquires(rose_neigh_list_lock)
-{
- struct rose_neigh *rose_neigh;
- int i = 1;
-
- spin_lock_bh(&rose_neigh_list_lock);
- if (*pos == 0)
- return SEQ_START_TOKEN;
-
- for (rose_neigh = rose_neigh_list; rose_neigh && i < *pos;
- rose_neigh = rose_neigh->next, ++i);
-
- return (i == *pos) ? rose_neigh : NULL;
-}
-
-static void *rose_neigh_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
-
- return (v == SEQ_START_TOKEN) ? rose_neigh_list
- : ((struct rose_neigh *)v)->next;
-}
-
-static void rose_neigh_stop(struct seq_file *seq, void *v)
- __releases(rose_neigh_list_lock)
-{
- spin_unlock_bh(&rose_neigh_list_lock);
-}
-
-static int rose_neigh_show(struct seq_file *seq, void *v)
-{
- char buf[11];
- int i;
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq,
- "addr callsign dev count use mode restart t0 tf digipeaters\n");
- else {
- struct rose_neigh *rose_neigh = v;
-
- /* if (!rose_neigh->loopback) { */
- seq_printf(seq, "%05d %-9s %-4s %3d %3d %3s %3s %3lu %3lu",
- rose_neigh->number,
- (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign),
- rose_neigh->dev ? rose_neigh->dev->name : "???",
- rose_neigh->count,
- refcount_read(&rose_neigh->use) - rose_neigh->count - 1,
- (rose_neigh->dce_mode) ? "DCE" : "DTE",
- (rose_neigh->restarted) ? "yes" : "no",
- ax25_display_timer(&rose_neigh->t0timer) / HZ,
- ax25_display_timer(&rose_neigh->ftimer) / HZ);
-
- if (rose_neigh->digipeat != NULL) {
- for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
- seq_printf(seq, " %s", ax2asc(buf, &rose_neigh->digipeat->calls[i]));
- }
-
- seq_puts(seq, "\n");
- }
- return 0;
-}
-
-
-const struct seq_operations rose_neigh_seqops = {
- .start = rose_neigh_start,
- .next = rose_neigh_next,
- .stop = rose_neigh_stop,
- .show = rose_neigh_show,
-};
-
-static void *rose_route_start(struct seq_file *seq, loff_t *pos)
- __acquires(rose_route_list_lock)
-{
- struct rose_route *rose_route;
- int i = 1;
-
- spin_lock_bh(&rose_route_list_lock);
- if (*pos == 0)
- return SEQ_START_TOKEN;
-
- for (rose_route = rose_route_list; rose_route && i < *pos;
- rose_route = rose_route->next, ++i);
-
- return (i == *pos) ? rose_route : NULL;
-}
-
-static void *rose_route_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
-
- return (v == SEQ_START_TOKEN) ? rose_route_list
- : ((struct rose_route *)v)->next;
-}
-
-static void rose_route_stop(struct seq_file *seq, void *v)
- __releases(rose_route_list_lock)
-{
- spin_unlock_bh(&rose_route_list_lock);
-}
-
-static int rose_route_show(struct seq_file *seq, void *v)
-{
- char buf[11], rsbuf[11];
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq,
- "lci address callsign neigh <-> lci address callsign neigh\n");
- else {
- struct rose_route *rose_route = v;
-
- if (rose_route->neigh1)
- seq_printf(seq,
- "%3.3X %-10s %-9s %05d ",
- rose_route->lci1,
- rose2asc(rsbuf, &rose_route->src_addr),
- ax2asc(buf, &rose_route->src_call),
- rose_route->neigh1->number);
- else
- seq_puts(seq,
- "000 * * 00000 ");
-
- if (rose_route->neigh2)
- seq_printf(seq,
- "%3.3X %-10s %-9s %05d\n",
- rose_route->lci2,
- rose2asc(rsbuf, &rose_route->dest_addr),
- ax2asc(buf, &rose_route->dest_call),
- rose_route->neigh2->number);
- else
- seq_puts(seq,
- "000 * * 00000\n");
- }
- return 0;
-}
-
-struct seq_operations rose_route_seqops = {
- .start = rose_route_start,
- .next = rose_route_next,
- .stop = rose_route_stop,
- .show = rose_route_show,
-};
-#endif /* CONFIG_PROC_FS */
-
-/*
- * Release all memory associated with ROSE routing structures.
- */
-void __exit rose_rt_free(void)
-{
- struct rose_neigh *s, *rose_neigh = rose_neigh_list;
- struct rose_node *t, *rose_node = rose_node_list;
- struct rose_route *u, *rose_route = rose_route_list;
- int i;
-
- while (rose_neigh != NULL) {
- s = rose_neigh;
- rose_neigh = rose_neigh->next;
-
- rose_remove_neigh(s);
- rose_neigh_put(s);
- }
-
- while (rose_node != NULL) {
- t = rose_node;
- rose_node = rose_node->next;
-
- for (i = 0; i < t->count; i++)
- rose_neigh_put(t->neighbour[i]);
- rose_remove_node(t);
- }
-
- while (rose_route != NULL) {
- u = rose_route;
- rose_route = rose_route->next;
-
- rose_remove_route(u);
- }
-}
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
deleted file mode 100644
index 4dbc437a9e22..000000000000
--- a/net/rose/rose_subr.c
+++ /dev/null
@@ -1,556 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
- */
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <net/rose.h>
-
-static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose);
-
-/*
- * This routine purges all of the queues of frames.
- */
-void rose_clear_queues(struct sock *sk)
-{
- skb_queue_purge(&sk->sk_write_queue);
- skb_queue_purge(&rose_sk(sk)->ack_queue);
-}
-
-/*
- * This routine purges the input queue of those frames that have been
- * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
- * SDL diagram.
- */
-void rose_frames_acked(struct sock *sk, unsigned short nr)
-{
- struct sk_buff *skb;
- struct rose_sock *rose = rose_sk(sk);
-
- /*
- * Remove all the ack-ed frames from the ack queue.
- */
- if (rose->va != nr) {
- while (skb_peek(&rose->ack_queue) != NULL && rose->va != nr) {
- skb = skb_dequeue(&rose->ack_queue);
- kfree_skb(skb);
- rose->va = (rose->va + 1) % ROSE_MODULUS;
- }
- }
-}
-
-void rose_requeue_frames(struct sock *sk)
-{
- struct sk_buff *skb, *skb_prev = NULL;
-
- /*
- * Requeue all the un-ack-ed frames on the output queue to be picked
- * up by rose_kick. This arrangement handles the possibility of an
- * empty output queue.
- */
- while ((skb = skb_dequeue(&rose_sk(sk)->ack_queue)) != NULL) {
- if (skb_prev == NULL)
- skb_queue_head(&sk->sk_write_queue, skb);
- else
- skb_append(skb_prev, skb, &sk->sk_write_queue);
- skb_prev = skb;
- }
-}
-
-/*
- * Validate that the value of nr is between va and vs. Return true or
- * false for testing.
- */
-int rose_validate_nr(struct sock *sk, unsigned short nr)
-{
- struct rose_sock *rose = rose_sk(sk);
- unsigned short vc = rose->va;
-
- while (vc != rose->vs) {
- if (nr == vc) return 1;
- vc = (vc + 1) % ROSE_MODULUS;
- }
-
- return nr == rose->vs;
-}
-
-/*
- * This routine is called when the packet layer internally generates a
- * control frame.
- */
-void rose_write_internal(struct sock *sk, int frametype)
-{
- struct rose_sock *rose = rose_sk(sk);
- struct sk_buff *skb;
- unsigned char *dptr;
- unsigned char lci1, lci2;
- int maxfaclen = 0;
- int len, faclen;
- int reserve;
-
- reserve = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1;
- len = ROSE_MIN_LEN;
-
- switch (frametype) {
- case ROSE_CALL_REQUEST:
- len += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
- maxfaclen = 256;
- break;
- case ROSE_CALL_ACCEPTED:
- case ROSE_CLEAR_REQUEST:
- case ROSE_RESET_REQUEST:
- len += 2;
- break;
- }
-
- skb = alloc_skb(reserve + len + maxfaclen, GFP_ATOMIC);
- if (!skb)
- return;
-
- /*
- * Space for AX.25 header and PID.
- */
- skb_reserve(skb, reserve);
-
- dptr = skb_put(skb, len);
-
- 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++ = ROSE_CALL_REQ_ADDR_LEN_VAL;
- memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN);
- dptr += ROSE_ADDR_LEN;
- memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN);
- dptr += ROSE_ADDR_LEN;
- faclen = rose_create_facilities(dptr, rose);
- skb_put(skb, 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);
-}
-
-int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
-{
- unsigned char *frame;
-
- frame = skb->data;
-
- *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;
- }
-
- if ((frame[2] & 0x1F) == ROSE_RR ||
- (frame[2] & 0x1F) == ROSE_RNR) {
- *nr = (frame[2] >> 5) & 0x07;
- return frame[2] & 0x1F;
- }
-
- if ((frame[2] & 0x01) == ROSE_DATA) {
- *q = (frame[0] & ROSE_Q_BIT) == ROSE_Q_BIT;
- *d = (frame[0] & ROSE_D_BIT) == ROSE_D_BIT;
- *m = (frame[2] & ROSE_M_BIT) == ROSE_M_BIT;
- *nr = (frame[2] >> 5) & 0x07;
- *ns = (frame[2] >> 1) & 0x07;
- return ROSE_DATA;
- }
-
- return ROSE_ILLEGAL;
-}
-
-static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *facilities, int len)
-{
- unsigned char *pt;
- unsigned char l, lg, n = 0;
- int fac_national_digis_received = 0;
-
- do {
- switch (*p & 0xC0) {
- case 0x00:
- if (len < 2)
- return -1;
- p += 2;
- n += 2;
- len -= 2;
- break;
-
- case 0x40:
- if (len < 3)
- return -1;
- if (*p == FAC_NATIONAL_RAND)
- facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
- p += 3;
- n += 3;
- len -= 3;
- break;
-
- case 0x80:
- if (len < 4)
- return -1;
- p += 4;
- n += 4;
- len -= 4;
- break;
-
- case 0xC0:
- if (len < 2)
- return -1;
- l = p[1];
- if (len < 2 + l)
- return -1;
- if (*p == FAC_NATIONAL_DEST_DIGI) {
- if (!fac_national_digis_received) {
- if (l < AX25_ADDR_LEN)
- return -1;
- 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) {
- if (l < AX25_ADDR_LEN)
- return -1;
- memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
- facilities->dest_ndigis = 1;
- }
- }
- else if (*p == FAC_NATIONAL_FAIL_CALL) {
- if (l < AX25_ADDR_LEN)
- return -1;
- memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
- }
- else if (*p == FAC_NATIONAL_FAIL_ADD) {
- if (l < 1 + ROSE_ADDR_LEN)
- return -1;
- memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
- }
- else if (*p == FAC_NATIONAL_DIGIS) {
- if (l % AX25_ADDR_LEN)
- return -1;
- 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) {
- if (facilities->dest_ndigis >= ROSE_MAX_DIGIS)
- return -1;
- memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
- } else {
- if (facilities->source_ndigis >= ROSE_MAX_DIGIS)
- return -1;
- memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
- }
- }
- }
- p += l + 2;
- n += l + 2;
- len -= l + 2;
- break;
- }
- } while (*p != 0x00 && len > 0);
-
- return n;
-}
-
-static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *facilities, int len)
-{
- unsigned char l, n = 0;
- char callsign[11];
-
- do {
- switch (*p & 0xC0) {
- case 0x00:
- if (len < 2)
- return -1;
- p += 2;
- n += 2;
- len -= 2;
- break;
-
- case 0x40:
- if (len < 3)
- return -1;
- p += 3;
- n += 3;
- len -= 3;
- break;
-
- case 0x80:
- if (len < 4)
- return -1;
- p += 4;
- n += 4;
- len -= 4;
- break;
-
- case 0xC0:
- if (len < 2)
- return -1;
- l = p[1];
-
- /* Prevent overflows*/
- if (l < 10 || l > 20)
- return -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';
- asc2ax(&facilities->source_call, 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';
- asc2ax(&facilities->dest_call, 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, unsigned packet_len,
- struct rose_facilities_struct *facilities)
-{
- int facilities_len, len;
-
- facilities_len = *p++;
-
- if (facilities_len == 0 || (unsigned int)facilities_len > packet_len)
- return 0;
-
- while (facilities_len >= 3 && *p == 0x00) {
- facilities_len--;
- p++;
-
- switch (*p) {
- case FAC_NATIONAL: /* National */
- len = rose_parse_national(p + 1, facilities, facilities_len - 1);
- break;
-
- case FAC_CCITT: /* CCITT */
- len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
- break;
-
- default:
- printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p);
- len = 1;
- break;
- }
-
- if (len < 0)
- return 0;
- if (WARN_ON(len >= facilities_len))
- return 0;
- facilities_len -= len + 1;
- p += len + 1;
- }
-
- return facilities_len == 0;
-}
-
-static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose)
-{
- unsigned char *p = buffer + 1;
- char *callsign;
- char buf[11];
- int len, nb;
-
- /* National Facilities */
- if (rose->rand != 0 || rose->source_ndigis == 1 || rose->dest_ndigis == 1) {
- *p++ = 0x00;
- *p++ = FAC_NATIONAL;
-
- if (rose->rand != 0) {
- *p++ = FAC_NATIONAL_RAND;
- *p++ = (rose->rand >> 8) & 0xFF;
- *p++ = (rose->rand >> 0) & 0xFF;
- }
-
- /* Sent before older facilities */
- if ((rose->source_ndigis > 0) || (rose->dest_ndigis > 0)) {
- int maxdigi = 0;
- *p++ = FAC_NATIONAL_DIGIS;
- *p++ = AX25_ADDR_LEN * (rose->source_ndigis + rose->dest_ndigis);
- for (nb = 0 ; nb < rose->source_ndigis ; nb++) {
- if (++maxdigi >= ROSE_MAX_DIGIS)
- break;
- memcpy(p, &rose->source_digis[nb], AX25_ADDR_LEN);
- p[6] |= AX25_HBIT;
- p += AX25_ADDR_LEN;
- }
- for (nb = 0 ; nb < rose->dest_ndigis ; nb++) {
- if (++maxdigi >= ROSE_MAX_DIGIS)
- break;
- memcpy(p, &rose->dest_digis[nb], AX25_ADDR_LEN);
- p[6] &= ~AX25_HBIT;
- p += AX25_ADDR_LEN;
- }
- }
-
- /* For compatibility */
- if (rose->source_ndigis > 0) {
- *p++ = FAC_NATIONAL_SRC_DIGI;
- *p++ = AX25_ADDR_LEN;
- memcpy(p, &rose->source_digis[0], AX25_ADDR_LEN);
- p += AX25_ADDR_LEN;
- }
-
- /* For compatibility */
- if (rose->dest_ndigis > 0) {
- *p++ = FAC_NATIONAL_DEST_DIGI;
- *p++ = AX25_ADDR_LEN;
- memcpy(p, &rose->dest_digis[0], AX25_ADDR_LEN);
- p += AX25_ADDR_LEN;
- }
- }
-
- *p++ = 0x00;
- *p++ = FAC_CCITT;
-
- *p++ = FAC_CCITT_DEST_NSAP;
-
- callsign = ax2asc(buf, &rose->dest_call);
-
- *p++ = strlen(callsign) + 10;
- *p++ = (strlen(callsign) + 9) * 2; /* ??? */
-
- *p++ = 0x47; *p++ = 0x00; *p++ = 0x11;
- *p++ = ROSE_ADDR_LEN * 2;
- memcpy(p, &rose->dest_addr, ROSE_ADDR_LEN);
- p += ROSE_ADDR_LEN;
-
- memcpy(p, callsign, strlen(callsign));
- p += strlen(callsign);
-
- *p++ = FAC_CCITT_SRC_NSAP;
-
- callsign = ax2asc(buf, &rose->source_call);
-
- *p++ = strlen(callsign) + 10;
- *p++ = (strlen(callsign) + 9) * 2; /* ??? */
-
- *p++ = 0x47; *p++ = 0x00; *p++ = 0x11;
- *p++ = ROSE_ADDR_LEN * 2;
- memcpy(p, &rose->source_addr, ROSE_ADDR_LEN);
- p += ROSE_ADDR_LEN;
-
- memcpy(p, callsign, strlen(callsign));
- p += strlen(callsign);
-
- len = p - buffer;
- buffer[0] = len - 1;
-
- return len;
-}
-
-void rose_disconnect(struct sock *sk, int reason, int cause, int diagnostic)
-{
- struct rose_sock *rose = rose_sk(sk);
-
- rose_stop_timer(sk);
- rose_stop_idletimer(sk);
-
- rose_clear_queues(sk);
-
- rose->lci = 0;
- rose->state = ROSE_STATE_0;
-
- if (cause != -1)
- rose->cause = cause;
-
- if (diagnostic != -1)
- rose->diagnostic = diagnostic;
-
- sk->sk_state = TCP_CLOSE;
- sk->sk_err = reason;
- sk->sk_shutdown |= SEND_SHUTDOWN;
-
- if (!sock_flag(sk, SOCK_DEAD)) {
- sk->sk_state_change(sk);
- sock_set_flag(sk, SOCK_DEAD);
- }
-}
diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c
deleted file mode 100644
index bb60a1654d61..000000000000
--- a/net/rose/rose_timer.c
+++ /dev/null
@@ -1,227 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * 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>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <net/ax25.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <net/rose.h>
-
-static void rose_heartbeat_expiry(struct timer_list *t);
-static void rose_timer_expiry(struct timer_list *);
-static void rose_idletimer_expiry(struct timer_list *);
-
-void rose_start_heartbeat(struct sock *sk)
-{
- sk_stop_timer(sk, &sk->sk_timer);
-
- sk->sk_timer.function = rose_heartbeat_expiry;
- sk->sk_timer.expires = jiffies + 5 * HZ;
-
- sk_reset_timer(sk, &sk->sk_timer, sk->sk_timer.expires);
-}
-
-void rose_start_t1timer(struct sock *sk)
-{
- struct rose_sock *rose = rose_sk(sk);
-
- sk_stop_timer(sk, &rose->timer);
-
- rose->timer.function = rose_timer_expiry;
- rose->timer.expires = jiffies + rose->t1;
-
- sk_reset_timer(sk, &rose->timer, rose->timer.expires);
-}
-
-void rose_start_t2timer(struct sock *sk)
-{
- struct rose_sock *rose = rose_sk(sk);
-
- sk_stop_timer(sk, &rose->timer);
-
- rose->timer.function = rose_timer_expiry;
- rose->timer.expires = jiffies + rose->t2;
-
- sk_reset_timer(sk, &rose->timer, rose->timer.expires);
-}
-
-void rose_start_t3timer(struct sock *sk)
-{
- struct rose_sock *rose = rose_sk(sk);
-
- sk_stop_timer(sk, &rose->timer);
-
- rose->timer.function = rose_timer_expiry;
- rose->timer.expires = jiffies + rose->t3;
-
- sk_reset_timer(sk, &rose->timer, rose->timer.expires);
-}
-
-void rose_start_hbtimer(struct sock *sk)
-{
- struct rose_sock *rose = rose_sk(sk);
-
- sk_stop_timer(sk, &rose->timer);
-
- rose->timer.function = rose_timer_expiry;
- rose->timer.expires = jiffies + rose->hb;
-
- sk_reset_timer(sk, &rose->timer, rose->timer.expires);
-}
-
-void rose_start_idletimer(struct sock *sk)
-{
- struct rose_sock *rose = rose_sk(sk);
-
- sk_stop_timer(sk, &rose->idletimer);
-
- if (rose->idle > 0) {
- rose->idletimer.function = rose_idletimer_expiry;
- rose->idletimer.expires = jiffies + rose->idle;
-
- sk_reset_timer(sk, &rose->idletimer, rose->idletimer.expires);
- }
-}
-
-void rose_stop_heartbeat(struct sock *sk)
-{
- sk_stop_timer(sk, &sk->sk_timer);
-}
-
-void rose_stop_timer(struct sock *sk)
-{
- sk_stop_timer(sk, &rose_sk(sk)->timer);
-}
-
-void rose_stop_idletimer(struct sock *sk)
-{
- sk_stop_timer(sk, &rose_sk(sk)->idletimer);
-}
-
-static void rose_heartbeat_expiry(struct timer_list *t)
-{
- struct sock *sk = timer_container_of(sk, t, sk_timer);
- struct rose_sock *rose = rose_sk(sk);
-
- bh_lock_sock(sk);
- if (sock_owned_by_user(sk)) {
- sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ/20);
- goto out;
- }
- 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 (sock_flag(sk, SOCK_DESTROY) ||
- (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
- bh_unlock_sock(sk);
- rose_destroy_socket(sk);
- sock_put(sk);
- return;
- }
- break;
-
- case ROSE_STATE_3:
- /*
- * Check for the state of the receive buffer.
- */
- if (atomic_read(&sk->sk_rmem_alloc) < (sk->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);
-out:
- bh_unlock_sock(sk);
- sock_put(sk);
-}
-
-static void rose_timer_expiry(struct timer_list *t)
-{
- struct rose_sock *rose = timer_container_of(rose, t, timer);
- struct sock *sk = &rose->sock;
-
- bh_lock_sock(sk);
- if (sock_owned_by_user(sk)) {
- sk_reset_timer(sk, &rose->timer, jiffies + HZ/20);
- goto out;
- }
- 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_neigh_put(rose->neighbour);
- 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;
- }
-out:
- bh_unlock_sock(sk);
- sock_put(sk);
-}
-
-static void rose_idletimer_expiry(struct timer_list *t)
-{
- struct rose_sock *rose = timer_container_of(rose, t, idletimer);
- struct sock *sk = &rose->sock;
-
- bh_lock_sock(sk);
- if (sock_owned_by_user(sk)) {
- sk_reset_timer(sk, &rose->idletimer, jiffies + HZ/20);
- goto out;
- }
- rose_clear_queues(sk);
-
- rose_write_internal(sk, ROSE_CLEAR_REQUEST);
- rose_sk(sk)->state = ROSE_STATE_2;
-
- rose_start_t3timer(sk);
-
- sk->sk_state = TCP_CLOSE;
- sk->sk_err = 0;
- sk->sk_shutdown |= SEND_SHUTDOWN;
-
- if (!sock_flag(sk, SOCK_DEAD)) {
- sk->sk_state_change(sk);
- sock_set_flag(sk, SOCK_DEAD);
- }
-out:
- bh_unlock_sock(sk);
- sock_put(sk);
-}
diff --git a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c
deleted file mode 100644
index d801315b7083..000000000000
--- a/net/rose/sysctl_net_rose.c
+++ /dev/null
@@ -1,125 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
- */
-#include <linux/mm.h>
-#include <linux/sysctl.h>
-#include <linux/init.h>
-#include <net/ax25.h>
-#include <net/rose.h>
-
-static int min_timer[] = {1 * HZ};
-static int max_timer[] = {300 * HZ};
-static int min_idle[] = {0 * HZ};
-static int max_idle[] = {65535 * HZ};
-static int min_route[1], max_route[] = {1};
-static int min_ftimer[] = {60 * HZ};
-static int max_ftimer[] = {600 * HZ};
-static int min_maxvcs[] = {1}, max_maxvcs[] = {254};
-static int min_window[] = {1}, max_window[] = {7};
-
-static struct ctl_table_header *rose_table_header;
-
-static struct ctl_table rose_table[] = {
- {
- .procname = "restart_request_timeout",
- .data = &sysctl_rose_restart_request_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_timer,
- .extra2 = &max_timer
- },
- {
- .procname = "call_request_timeout",
- .data = &sysctl_rose_call_request_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_timer,
- .extra2 = &max_timer
- },
- {
- .procname = "reset_request_timeout",
- .data = &sysctl_rose_reset_request_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_timer,
- .extra2 = &max_timer
- },
- {
- .procname = "clear_request_timeout",
- .data = &sysctl_rose_clear_request_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_timer,
- .extra2 = &max_timer
- },
- {
- .procname = "no_activity_timeout",
- .data = &sysctl_rose_no_activity_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_idle,
- .extra2 = &max_idle
- },
- {
- .procname = "acknowledge_hold_back_timeout",
- .data = &sysctl_rose_ack_hold_back_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_timer,
- .extra2 = &max_timer
- },
- {
- .procname = "routing_control",
- .data = &sysctl_rose_routing_control,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_route,
- .extra2 = &max_route
- },
- {
- .procname = "link_fail_timeout",
- .data = &sysctl_rose_link_fail_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_ftimer,
- .extra2 = &max_ftimer
- },
- {
- .procname = "maximum_virtual_circuits",
- .data = &sysctl_rose_maximum_vcs,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_maxvcs,
- .extra2 = &max_maxvcs
- },
- {
- .procname = "window_size",
- .data = &sysctl_rose_window_size,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_window,
- .extra2 = &max_window
- },
-};
-
-void __init rose_register_sysctl(void)
-{
- rose_table_header = register_net_sysctl(&init_net, "net/rose", rose_table);
-}
-
-void rose_unregister_sysctl(void)
-{
- unregister_net_sysctl_table(rose_table_header);
-}
diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig
index d10b3d4adbd1..acbab8dae53f 100644
--- a/arch/mips/configs/bcm47xx_defconfig
+++ b/arch/mips/configs/bcm47xx_defconfig
@@ -28,7 +28,6 @@ CONFIG_NETFILTER=y
CONFIG_VLAN_8021Q=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_FQ_CODEL=y
-CONFIG_HAMRADIO=y
CONFIG_CFG80211=y
CONFIG_MAC80211=y
CONFIG_MTD=y
diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig
index 3b64e151e187..aa63ada62e28 100644
--- a/arch/mips/configs/bigsur_defconfig
+++ b/arch/mips/configs/bigsur_defconfig
@@ -84,16 +84,6 @@ CONFIG_IP_VS_FTP=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
-CONFIG_HAMRADIO=y
-CONFIG_AX25=m
-CONFIG_NETROM=m
-CONFIG_ROSE=m
-CONFIG_MKISS=m
-CONFIG_6PACK=m
-CONFIG_BPQETHER=m
-CONFIG_BAYCOM_SER_FDX=m
-CONFIG_BAYCOM_SER_HDX=m
-CONFIG_YAM=m
CONFIG_FW_LOADER=m
CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_NBD=m
diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig
index 8097974489e3..ad80ad2eae6b 100644
--- a/arch/mips/configs/gpr_defconfig
+++ b/arch/mips/configs/gpr_defconfig
@@ -126,17 +126,6 @@ CONFIG_NET_EMATCH_TEXT=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_PKTGEN=m
-CONFIG_HAMRADIO=y
-CONFIG_AX25=m
-# CONFIG_AX25_DAMA_SLAVE is not set
-CONFIG_NETROM=m
-CONFIG_ROSE=m
-CONFIG_MKISS=m
-CONFIG_6PACK=m
-CONFIG_BPQETHER=m
-CONFIG_BAYCOM_SER_FDX=m
-CONFIG_BAYCOM_SER_HDX=m
-CONFIG_YAM=m
CONFIG_CFG80211=y
CONFIG_MAC80211=y
CONFIG_MTD=y
diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig
index 63787b8b733e..1295164af08e 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -172,17 +172,6 @@ CONFIG_NET_EMATCH_TEXT=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_PKTGEN=m
-CONFIG_HAMRADIO=y
-CONFIG_AX25=m
-# CONFIG_AX25_DAMA_SLAVE is not set
-CONFIG_NETROM=m
-CONFIG_ROSE=m
-CONFIG_MKISS=m
-CONFIG_6PACK=m
-CONFIG_BPQETHER=m
-CONFIG_BAYCOM_SER_FDX=m
-CONFIG_BAYCOM_SER_HDX=m
-CONFIG_YAM=m
CONFIG_BT=m
CONFIG_BT_RFCOMM=m
CONFIG_BT_RFCOMM_TTY=y
diff --git a/arch/mips/configs/rb532_defconfig b/arch/mips/configs/rb532_defconfig
index 30d18b084cda..a88322fe3935 100644
--- a/arch/mips/configs/rb532_defconfig
+++ b/arch/mips/configs/rb532_defconfig
@@ -95,7 +95,6 @@ CONFIG_NET_ACT_GACT=m
CONFIG_GACT_PROB=y
CONFIG_NET_ACT_MIRRED=m
CONFIG_NET_ACT_PEDIT=m
-CONFIG_HAMRADIO=y
CONFIG_MTD=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_BLOCK2MTD=y
diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
index b1e67ff0c4f0..ad9fbd0cbb38 100644
--- a/arch/mips/configs/rm200_defconfig
+++ b/arch/mips/configs/rm200_defconfig
@@ -147,13 +147,6 @@ CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
-CONFIG_HAMRADIO=y
-CONFIG_AX25=m
-CONFIG_NETROM=m
-CONFIG_ROSE=m
-CONFIG_MKISS=m
-CONFIG_6PACK=m
-CONFIG_BPQETHER=m
CONFIG_CONNECTOR=m
CONFIG_PARPORT=m
CONFIG_PARPORT_PC=m
diff --git a/arch/mips/configs/rt305x_defconfig b/arch/mips/configs/rt305x_defconfig
index 8f9701efef19..c920976bedd0 100644
--- a/arch/mips/configs/rt305x_defconfig
+++ b/arch/mips/configs/rt305x_defconfig
@@ -64,7 +64,6 @@ CONFIG_BRIDGE=y
# CONFIG_BRIDGE_IGMP_SNOOPING is not set
CONFIG_VLAN_8021Q=y
CONFIG_NET_SCHED=y
-CONFIG_HAMRADIO=y
CONFIG_MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_BLOCK=y
diff --git a/arch/mips/configs/xway_defconfig b/arch/mips/configs/xway_defconfig
index aae8497b6872..f1c53bbb72e9 100644
--- a/arch/mips/configs/xway_defconfig
+++ b/arch/mips/configs/xway_defconfig
@@ -66,7 +66,6 @@ CONFIG_BRIDGE=y
# CONFIG_BRIDGE_IGMP_SNOOPING is not set
CONFIG_VLAN_8021Q=y
CONFIG_NET_SCHED=y
-CONFIG_HAMRADIO=y
CONFIG_MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_BLOCK=y
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem
2026-04-21 2:18 [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem Jakub Kicinski
@ 2026-04-21 6:04 ` Greg KH
2026-04-21 13:45 ` Stephen Hemminger
2026-04-21 13:55 ` Stephen Hemminger
2 siblings, 0 replies; 7+ messages in thread
From: Greg KH @ 2026-04-21 6:04 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, corbet,
skhan, federico.vaga, carlos.bilbao, avadhut.naik, alexs,
si.yanteng, dzm91, 2023002089, tsbogend, dsahern, jani.nikula,
mchehab+huawei, jirislaby, tytso, herbert, ebiggers,
johannes.berg, geert, pablo, tglx, mashiro.chen, mingo, dqfext,
jreuter, sdf, pkshih, enelsonmoore, mkl, toke, kees, crossd,
jlayton, wangliang74, aha310510, takamitz, kuniyu, linux-doc,
linux-mips
On Mon, Apr 20, 2026 at 07:18:23PM -0700, Jakub Kicinski wrote:
> Remove the amateur radio (AX.25, NET/ROM, ROSE) protocol implementation
> and all associated hamradio device drivers from the kernel tree.
> This set of protocols has long been a huge bug/syzbot magnet,
> and since nobody stepped up to help us deal with the influx
> of the AI-generated bug reports we need to move it out of tree
> to protect our sanity.
>
> The code is moved to an out-of-tree repo:
> https://github.com/linux-netdev/mod-orphan
> if it's cleaned up and reworked there we can accept it back.
>
> Minimal stub headers are kept for include/net/ax25.h (AX25_P_IP,
> AX25_ADDR_LEN, ax25_address) and include/net/rose.h (ROSE_ADDR_LEN)
> so that the conditional integration code in arp.c and tun.c continues
> to compile and work when the out-of-tree modules are loaded.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem
2026-04-21 2:18 [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem Jakub Kicinski
2026-04-21 6:04 ` Greg KH
@ 2026-04-21 13:45 ` Stephen Hemminger
2026-04-21 13:55 ` Stephen Hemminger
2 siblings, 0 replies; 7+ messages in thread
From: Stephen Hemminger @ 2026-04-21 13:45 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, corbet,
skhan, federico.vaga, carlos.bilbao, avadhut.naik, alexs,
si.yanteng, dzm91, 2023002089, tsbogend, dsahern, jani.nikula,
mchehab+huawei, gregkh, jirislaby, tytso, herbert, ebiggers,
johannes.berg, geert, pablo, tglx, mashiro.chen, mingo, dqfext,
jreuter, sdf, pkshih, enelsonmoore, mkl, toke, kees, crossd,
jlayton, wangliang74, aha310510, takamitz, kuniyu, linux-doc,
linux-mips
On Mon, 20 Apr 2026 19:18:23 -0700
Jakub Kicinski <kuba@kernel.org> wrote:
> Remove the amateur radio (AX.25, NET/ROM, ROSE) protocol implementation
> and all associated hamradio device drivers from the kernel tree.
> This set of protocols has long been a huge bug/syzbot magnet,
> and since nobody stepped up to help us deal with the influx
> of the AI-generated bug reports we need to move it out of tree
> to protect our sanity.
>
> The code is moved to an out-of-tree repo:
> https://github.com/linux-netdev/mod-orphan
> if it's cleaned up and reworked there we can accept it back.
>
> Minimal stub headers are kept for include/net/ax25.h (AX25_P_IP,
> AX25_ADDR_LEN, ax25_address) and include/net/rose.h (ROSE_ADDR_LEN)
> so that the conditional integration code in arp.c and tun.c continues
> to compile and work when the out-of-tree modules are loaded.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
Acked-by: Stephen Hemminger <stephen@networkplumber.org>
PS: once this is merged will remove these protos from iproute2 as well
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem
2026-04-21 2:18 [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem Jakub Kicinski
2026-04-21 6:04 ` Greg KH
2026-04-21 13:45 ` Stephen Hemminger
@ 2026-04-21 13:55 ` Stephen Hemminger
2026-04-21 16:17 ` Dan Cross
2 siblings, 1 reply; 7+ messages in thread
From: Stephen Hemminger @ 2026-04-21 13:55 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, corbet,
skhan, federico.vaga, carlos.bilbao, avadhut.naik, alexs,
si.yanteng, dzm91, 2023002089, tsbogend, dsahern, jani.nikula,
mchehab+huawei, gregkh, jirislaby, tytso, herbert, ebiggers,
johannes.berg, geert, pablo, tglx, mashiro.chen, mingo, dqfext,
jreuter, sdf, pkshih, enelsonmoore, mkl, toke, kees, crossd,
jlayton, wangliang74, aha310510, takamitz, kuniyu, linux-doc,
linux-mips
On Mon, 20 Apr 2026 19:18:23 -0700
Jakub Kicinski <kuba@kernel.org> wrote:
> Remove the amateur radio (AX.25, NET/ROM, ROSE) protocol implementation
> and all associated hamradio device drivers from the kernel tree.
> This set of protocols has long been a huge bug/syzbot magnet,
> and since nobody stepped up to help us deal with the influx
> of the AI-generated bug reports we need to move it out of tree
> to protect our sanity.
>
> The code is moved to an out-of-tree repo:
> https://github.com/linux-netdev/mod-orphan
> if it's cleaned up and reworked there we can accept it back.
It would be good if these protocols could be done in userspace
or with BPF?
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem
2026-04-21 13:55 ` Stephen Hemminger
@ 2026-04-21 16:17 ` Dan Cross
2026-04-21 17:14 ` Stephen Hemminger
0 siblings, 1 reply; 7+ messages in thread
From: Dan Cross @ 2026-04-21 16:17 UTC (permalink / raw)
To: stephen
Cc: Jakub Kicinski, davem, netdev, edumazet, pabeni, andrew+netdev,
horms, corbet, skhan, federico.vaga, carlos.bilbao, avadhut.naik,
alexs, si.yanteng, dzm91, 2023002089, tsbogend, dsahern,
jani.nikula, mchehab+huawei, gregkh, jirislaby, tytso, herbert,
ebiggers, johannes.berg, geert, pablo, tglx, mashiro.chen, mingo,
dqfext, jreuter, sdf, pkshih, enelsonmoore, mkl, toke, kees,
jlayton, wangliang74, aha310510, takamitz, kuniyu, linux-doc,
linux-mips
On Tue, Apr 21, 2026 at 9:55 AM Stephen Hemminger
<stephen@networkplumber.org> wrote:
> On Mon, 20 Apr 2026 19:18:23 -0700
> Jakub Kicinski <kuba@kernel.org> wrote:
> > Remove the amateur radio (AX.25, NET/ROM, ROSE) protocol implementation
> > and all associated hamradio device drivers from the kernel tree.
> > This set of protocols has long been a huge bug/syzbot magnet,
> > and since nobody stepped up to help us deal with the influx
> > of the AI-generated bug reports we need to move it out of tree
> > to protect our sanity.
> >
> > The code is moved to an out-of-tree repo:
> > https://github.com/linux-netdev/mod-orphan
> > if it's cleaned up and reworked there we can accept it back.
>
> It would be good if these protocols could be done in userspace
> or with BPF?
Consensus for a userspace implementation is what folks on linux-hams
seem to be converging on.
The amateur radio protocols are more or less specific to low-speed
links, they are not particularly coupled to anything else that
requires running in the kernel, and the main coupling point (IP over
AX.25) can be implemented via TAP/TUN.
There are several popular packages that already implement AX.25 and
NET/ROM in user-space (for the interested, LinBPQ seems to be the
canonical example). The main missing piece is ROSE, but it is likely
easier to add that to an existing package, or potentially something
brand new, than keep it in the kernel.
There's no compelling reason to keep these protocols in the kernel,
whether in-tree or out-of-tree; at least, one has not been
articulated.
- Dan C.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem
2026-04-21 16:17 ` Dan Cross
@ 2026-04-21 17:14 ` Stephen Hemminger
2026-04-21 17:47 ` Dan Cross
0 siblings, 1 reply; 7+ messages in thread
From: Stephen Hemminger @ 2026-04-21 17:14 UTC (permalink / raw)
To: Dan Cross
Cc: Jakub Kicinski, davem, netdev, edumazet, pabeni, andrew+netdev,
horms, corbet, skhan, federico.vaga, carlos.bilbao, avadhut.naik,
alexs, si.yanteng, dzm91, 2023002089, tsbogend, dsahern,
jani.nikula, mchehab+huawei, gregkh, jirislaby, tytso, herbert,
ebiggers, johannes.berg, geert, pablo, tglx, mashiro.chen, mingo,
dqfext, jreuter, sdf, pkshih, enelsonmoore, mkl, toke, kees,
jlayton, wangliang74, aha310510, takamitz, kuniyu, linux-doc,
linux-mips
On Tue, 21 Apr 2026 12:17:23 -0400
Dan Cross <crossd@gmail.com> wrote:
> On Tue, Apr 21, 2026 at 9:55 AM Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> > On Mon, 20 Apr 2026 19:18:23 -0700
> > Jakub Kicinski <kuba@kernel.org> wrote:
> > > Remove the amateur radio (AX.25, NET/ROM, ROSE) protocol implementation
> > > and all associated hamradio device drivers from the kernel tree.
> > > This set of protocols has long been a huge bug/syzbot magnet,
> > > and since nobody stepped up to help us deal with the influx
> > > of the AI-generated bug reports we need to move it out of tree
> > > to protect our sanity.
> > >
> > > The code is moved to an out-of-tree repo:
> > > https://github.com/linux-netdev/mod-orphan
> > > if it's cleaned up and reworked there we can accept it back.
> >
> > It would be good if these protocols could be done in userspace
> > or with BPF?
>
> Consensus for a userspace implementation is what folks on linux-hams
> seem to be converging on.
>
> The amateur radio protocols are more or less specific to low-speed
> links, they are not particularly coupled to anything else that
> requires running in the kernel, and the main coupling point (IP over
> AX.25) can be implemented via TAP/TUN.
>
> There are several popular packages that already implement AX.25 and
> NET/ROM in user-space (for the interested, LinBPQ seems to be the
> canonical example). The main missing piece is ROSE, but it is likely
> easier to add that to an existing package, or potentially something
> brand new, than keep it in the kernel.
>
> There's no compelling reason to keep these protocols in the kernel,
> whether in-tree or out-of-tree; at least, one has not been
> articulated.
>
> - Dan C.
Thanks, my other concern is carrying support for these in ip commands.
If not kernel based, then iproute2 doesn't need to worry.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem
2026-04-21 17:14 ` Stephen Hemminger
@ 2026-04-21 17:47 ` Dan Cross
0 siblings, 0 replies; 7+ messages in thread
From: Dan Cross @ 2026-04-21 17:47 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Jakub Kicinski, davem, netdev, edumazet, pabeni, andrew+netdev,
horms, corbet, skhan, federico.vaga, carlos.bilbao, avadhut.naik,
alexs, si.yanteng, dzm91, 2023002089, tsbogend, dsahern,
jani.nikula, mchehab+huawei, gregkh, jirislaby, tytso, herbert,
ebiggers, johannes.berg, geert, pablo, tglx, mashiro.chen, mingo,
dqfext, jreuter, sdf, pkshih, enelsonmoore, mkl, toke, kees,
jlayton, wangliang74, aha310510, takamitz, kuniyu, linux-doc,
linux-mips
On Tue, Apr 21, 2026 at 1:14 PM Stephen Hemminger
<stephen@networkplumber.org> wrote:
> On Tue, 21 Apr 2026 12:17:23 -0400
> Dan Cross <crossd@gmail.com> wrote:
>
> > On Tue, Apr 21, 2026 at 9:55 AM Stephen Hemminger
> > <stephen@networkplumber.org> wrote:
> > > On Mon, 20 Apr 2026 19:18:23 -0700
> > > Jakub Kicinski <kuba@kernel.org> wrote:
> > > > Remove the amateur radio (AX.25, NET/ROM, ROSE) protocol implementation
> > > > and all associated hamradio device drivers from the kernel tree.
> > > > This set of protocols has long been a huge bug/syzbot magnet,
> > > > and since nobody stepped up to help us deal with the influx
> > > > of the AI-generated bug reports we need to move it out of tree
> > > > to protect our sanity.
> > > >
> > > > The code is moved to an out-of-tree repo:
> > > > https://github.com/linux-netdev/mod-orphan
> > > > if it's cleaned up and reworked there we can accept it back.
> > >
> > > It would be good if these protocols could be done in userspace
> > > or with BPF?
> >
> > Consensus for a userspace implementation is what folks on linux-hams
> > seem to be converging on.
> >
> > The amateur radio protocols are more or less specific to low-speed
> > links, they are not particularly coupled to anything else that
> > requires running in the kernel, and the main coupling point (IP over
> > AX.25) can be implemented via TAP/TUN.
> >
> > There are several popular packages that already implement AX.25 and
> > NET/ROM in user-space (for the interested, LinBPQ seems to be the
> > canonical example). The main missing piece is ROSE, but it is likely
> > easier to add that to an existing package, or potentially something
> > brand new, than keep it in the kernel.
> >
> > There's no compelling reason to keep these protocols in the kernel,
> > whether in-tree or out-of-tree; at least, one has not been
> > articulated.
>
> Thanks, my other concern is carrying support for these in ip commands.
> If not kernel based, then iproute2 doesn't need to worry.
Agreed.
If someone really wants mimic the existing output of those commands in
the context of a userspace implementation, they could write a wrapper
program that invokes the real thing, and extracts relevant information
from the ham protocol implementation, and interpolates it into the
output. It may be an imperfect simulation, but it's probably close
enough for most users.
- Dan C.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-04-21 17:48 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-21 2:18 [PATCH net-deletions] net: remove ax25 and amateur radio (hamradio) subsystem Jakub Kicinski
2026-04-21 6:04 ` Greg KH
2026-04-21 13:45 ` Stephen Hemminger
2026-04-21 13:55 ` Stephen Hemminger
2026-04-21 16:17 ` Dan Cross
2026-04-21 17:14 ` Stephen Hemminger
2026-04-21 17:47 ` Dan Cross
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox