summaryrefslogtreecommitdiffstats
path: root/drivers/isdn/i4l
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-11 19:55:49 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-11 19:55:49 +0200
commit237f83dfbe668443b5e31c3c7576125871cca674 (patch)
tree11848a8d0aa414a1d3ce2024e181071b1d9dea08 /drivers/isdn/i4l
parentMerge tag 'clone3-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/brau... (diff)
parentnet/mlx5e: Return in default case statement in tx_post_resync_params (diff)
downloadlinux-237f83dfbe668443b5e31c3c7576125871cca674.tar.xz
linux-237f83dfbe668443b5e31c3c7576125871cca674.zip
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: "Some highlights from this development cycle: 1) Big refactoring of ipv6 route and neigh handling to support nexthop objects configurable as units from userspace. From David Ahern. 2) Convert explored_states in BPF verifier into a hash table, significantly decreased state held for programs with bpf2bpf calls, from Alexei Starovoitov. 3) Implement bpf_send_signal() helper, from Yonghong Song. 4) Various classifier enhancements to mvpp2 driver, from Maxime Chevallier. 5) Add aRFS support to hns3 driver, from Jian Shen. 6) Fix use after free in inet frags by allocating fqdirs dynamically and reworking how rhashtable dismantle occurs, from Eric Dumazet. 7) Add act_ctinfo packet classifier action, from Kevin Darbyshire-Bryant. 8) Add TFO key backup infrastructure, from Jason Baron. 9) Remove several old and unused ISDN drivers, from Arnd Bergmann. 10) Add devlink notifications for flash update status to mlxsw driver, from Jiri Pirko. 11) Lots of kTLS offload infrastructure fixes, from Jakub Kicinski. 12) Add support for mv88e6250 DSA chips, from Rasmus Villemoes. 13) Various enhancements to ipv6 flow label handling, from Eric Dumazet and Willem de Bruijn. 14) Support TLS offload in nfp driver, from Jakub Kicinski, Dirk van der Merwe, and others. 15) Various improvements to axienet driver including converting it to phylink, from Robert Hancock. 16) Add PTP support to sja1105 DSA driver, from Vladimir Oltean. 17) Add mqprio qdisc offload support to dpaa2-eth, from Ioana Radulescu. 18) Add devlink health reporting to mlx5, from Moshe Shemesh. 19) Convert stmmac over to phylink, from Jose Abreu. 20) Add PTP PHC (Physical Hardware Clock) support to mlxsw, from Shalom Toledo. 21) Add nftables SYNPROXY support, from Fernando Fernandez Mancera. 22) Convert tcp_fastopen over to use SipHash, from Ard Biesheuvel. 23) Track spill/fill of constants in BPF verifier, from Alexei Starovoitov. 24) Support bounded loops in BPF, from Alexei Starovoitov. 25) Various page_pool API fixes and improvements, from Jesper Dangaard Brouer. 26) Just like ipv4, support ref-countless ipv6 route handling. From Wei Wang. 27) Support VLAN offloading in aquantia driver, from Igor Russkikh. 28) Add AF_XDP zero-copy support to mlx5, from Maxim Mikityanskiy. 29) Add flower GRE encap/decap support to nfp driver, from Pieter Jansen van Vuuren. 30) Protect against stack overflow when using act_mirred, from John Hurley. 31) Allow devmap map lookups from eBPF, from Toke Høiland-Jørgensen. 32) Use page_pool API in netsec driver, Ilias Apalodimas. 33) Add Google gve network driver, from Catherine Sullivan. 34) More indirect call avoidance, from Paolo Abeni. 35) Add kTLS TX HW offload support to mlx5, from Tariq Toukan. 36) Add XDP_REDIRECT support to bnxt_en, from Andy Gospodarek. 37) Add MPLS manipulation actions to TC, from John Hurley. 38) Add sending a packet to connection tracking from TC actions, and then allow flower classifier matching on conntrack state. From Paul Blakey. 39) Netfilter hw offload support, from Pablo Neira Ayuso" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (2080 commits) net/mlx5e: Return in default case statement in tx_post_resync_params mlx5: Return -EINVAL when WARN_ON_ONCE triggers in mlx5e_tls_resync(). net: dsa: add support for BRIDGE_MROUTER attribute pkt_sched: Include const.h net: netsec: remove static declaration for netsec_set_tx_de() net: netsec: remove superfluous if statement netfilter: nf_tables: add hardware offload support net: flow_offload: rename tc_cls_flower_offload to flow_cls_offload net: flow_offload: add flow_block_cb_is_busy() and use it net: sched: remove tcf block API drivers: net: use flow block API net: sched: use flow block API net: flow_offload: add flow_block_cb_{priv, incref, decref}() net: flow_offload: add list handling functions net: flow_offload: add flow_block_cb_alloc() and flow_block_cb_free() net: flow_offload: rename TCF_BLOCK_BINDER_TYPE_* to FLOW_BLOCK_BINDER_TYPE_* net: flow_offload: rename TC_BLOCK_{UN}BIND to FLOW_BLOCK_{UN}BIND net: flow_offload: add flow_block_cb_setup_simple() net: hisilicon: Add an tx_desc to adapt HI13X1_GMAC net: hisilicon: Add an rx_desc to adapt HI13X1_GMAC ...
Diffstat (limited to 'drivers/isdn/i4l')
-rw-r--r--drivers/isdn/i4l/Kconfig129
-rw-r--r--drivers/isdn/i4l/Makefile20
-rw-r--r--drivers/isdn/i4l/isdn_audio.c711
-rw-r--r--drivers/isdn/i4l/isdn_audio.h44
-rw-r--r--drivers/isdn/i4l/isdn_bsdcomp.c930
-rw-r--r--drivers/isdn/i4l/isdn_common.c2368
-rw-r--r--drivers/isdn/i4l/isdn_common.h47
-rw-r--r--drivers/isdn/i4l/isdn_concap.c99
-rw-r--r--drivers/isdn/i4l/isdn_concap.h11
-rw-r--r--drivers/isdn/i4l/isdn_net.c3198
-rw-r--r--drivers/isdn/i4l/isdn_net.h151
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c3046
-rw-r--r--drivers/isdn/i4l/isdn_ppp.h41
-rw-r--r--drivers/isdn/i4l/isdn_tty.c3756
-rw-r--r--drivers/isdn/i4l/isdn_tty.h120
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.c1123
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.h17
-rw-r--r--drivers/isdn/i4l/isdn_v110.c625
-rw-r--r--drivers/isdn/i4l/isdn_v110.h29
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.c332
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.h30
-rw-r--r--drivers/isdn/i4l/isdnhdlc.c617
22 files changed, 0 insertions, 17444 deletions
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
deleted file mode 100644
index caa1b52f06f7..000000000000
--- a/drivers/isdn/i4l/Kconfig
+++ /dev/null
@@ -1,129 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Old ISDN4Linux config
-#
-
-if ISDN_I4L
-
-config ISDN_PPP
- bool "Support synchronous PPP"
- depends on INET
- select SLHC
- help
- Over digital connections such as ISDN, there is no need to
- synchronize sender and recipient's clocks with start and stop bits
- as is done over analog telephone lines. Instead, one can use
- "synchronous PPP". Saying Y here will include this protocol. This
- protocol is used by Cisco and Sun for example. So you want to say Y
- here if the other end of your ISDN connection supports it. You will
- need a special version of pppd (called ipppd) for using this
- feature. See <file:Documentation/isdn/README.syncppp> and
- <file:Documentation/isdn/syncPPP.FAQ> for more information.
-
-config ISDN_PPP_VJ
- bool "Use VJ-compression with synchronous PPP"
- depends on ISDN_PPP
- help
- This enables Van Jacobson header compression for synchronous PPP.
- Say Y if the other end of the connection supports it.
-
-config ISDN_MPP
- bool "Support generic MP (RFC 1717)"
- depends on ISDN_PPP
- help
- With synchronous PPP enabled, it is possible to increase throughput
- by bundling several ISDN-connections, using this protocol. See
- <file:Documentation/isdn/README.syncppp> for more information.
-
-config IPPP_FILTER
- bool "Filtering for synchronous PPP"
- depends on ISDN_PPP
- help
- Say Y here if you want to be able to filter the packets passing over
- IPPP interfaces. This allows you to control which packets count as
- activity (i.e. which packets will reset the idle timer or bring up
- a demand-dialled link) and which packets are to be dropped entirely.
- You need to say Y here if you wish to use the pass-filter and
- active-filter options to ipppd.
-
-config ISDN_PPP_BSDCOMP
- tristate "Support BSD compression"
- depends on ISDN_PPP
- help
- Support for the BSD-Compress compression method for PPP, which uses
- the LZW compression method to compress each PPP packet before it is
- sent over the wire. The machine at the other end of the PPP link
- (usually your ISP) has to support the BSD-Compress compression
- method as well for this to be useful. Even if they don't support it,
- it is safe to say Y here.
-
-config ISDN_AUDIO
- bool "Support audio via ISDN"
- help
- If you say Y here, the modem-emulator will support a subset of the
- EIA Class 8 Voice commands. Using a getty with voice-support
- (mgetty+sendfax by <gert@greenie.muc.de> with an extension, available
- with the ISDN utility package for example), you will be able to use
- your Linux box as an ISDN-answering machine. Of course, this must be
- supported by the lowlevel driver also. Currently, the HiSax driver
- is the only voice-supporting driver. See
- <file:Documentation/isdn/README.audio> for more information.
-
-config ISDN_TTY_FAX
- bool "Support AT-Fax Class 1 and 2 commands"
- depends on ISDN_AUDIO
- help
- If you say Y here, the modem-emulator will support a subset of the
- Fax Class 1 and 2 commands. Using a getty with fax-support
- (mgetty+sendfax, hylafax), you will be able to use your Linux box as
- an ISDN-fax-machine. This must be supported by the lowlevel driver
- also. See <file:Documentation/isdn/README.fax> for more information.
-
-config ISDN_X25
- bool "X.25 PLP on top of ISDN"
- depends on X25
- help
- This feature provides the X.25 protocol over ISDN connections.
- See <file:Documentation/isdn/README.x25> for more information
- if you are thinking about using this.
-
-
-menu "ISDN feature submodules"
-
-config ISDN_DRV_LOOP
- tristate "isdnloop support"
- depends on BROKEN_ON_SMP
- help
- This driver provides a virtual ISDN card. Its primary purpose is
- testing of linklevel features or configuration without getting
- charged by your service-provider for lots of phone calls.
- You need will need the loopctrl utility from the latest isdn4k-utils
- package to set up this driver.
-
-config ISDN_DIVERSION
- tristate "Support isdn diversion services"
- help
- This option allows you to use some supplementary diversion
- services in conjunction with the HiSax driver on an EURO/DSS1
- line.
-
- Supported options are CD (call deflection), CFU (Call forward
- unconditional), CFB (Call forward when busy) and CFNR (call forward
- not reachable). Additionally the actual CFU, CFB and CFNR state may
- be interrogated.
-
- The use of CFU, CFB, CFNR and interrogation may be limited to some
- countries. The keypad protocol is still not implemented. CD should
- work in all countries if the service has been subscribed to.
-
- Please read the file <file:Documentation/isdn/README.diversion>.
-
-endmenu
-
-comment "ISDN4Linux hardware drivers"
-
-source "drivers/isdn/hisax/Kconfig"
-
-# end ISDN_I4L
-endif
-
diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile
deleted file mode 100644
index be77500c9e86..000000000000
--- a/drivers/isdn/i4l/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Makefile for the kernel ISDN subsystem and device drivers.
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_I4L) += isdn.o
-obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
-obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o
-
-# Multipart objects.
-
-isdn-y := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
-
-# Optional parts of multipart objects.
-
-isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o
-isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
-isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
-isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
-
diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c
deleted file mode 100644
index b6bcd1eca128..000000000000
--- a/drivers/isdn/i4l/isdn_audio.c
+++ /dev/null
@@ -1,711 +0,0 @@
-/* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
- *
- * Linux ISDN subsystem, audio conversion and compression (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
- * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/isdn.h>
-#include <linux/slab.h>
-#include "isdn_audio.h"
-#include "isdn_common.h"
-
-char *isdn_audio_revision = "$Revision: 1.1.2.2 $";
-
-/*
- * Misc. lookup-tables.
- */
-
-/* ulaw -> signed 16-bit */
-static short isdn_audio_ulaw_to_s16[] =
-{
- 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
- 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
- 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
- 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
- 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
- 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
- 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
- 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
- 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
- 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
- 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
- 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
- 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
- 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
- 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
- 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
- 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
- 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
- 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
- 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
- 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
- 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
- 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
- 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
- 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
- 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
- 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
- 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
- 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
- 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
- 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
- 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
-};
-
-/* alaw -> signed 16-bit */
-static short isdn_audio_alaw_to_s16[] =
-{
- 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
- 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
- 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
- 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
- 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
- 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
- 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
- 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
- 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
- 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
- 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
- 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
- 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
- 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
- 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
- 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
- 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
- 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
- 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
- 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
- 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
- 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
- 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
- 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
- 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
- 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
- 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
- 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
- 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
- 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
- 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
- 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
-};
-
-/* alaw -> ulaw */
-static char isdn_audio_alaw_to_ulaw[] =
-{
- 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
- 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
- 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
- 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
- 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
- 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
- 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
- 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
- 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
- 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
- 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
- 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
- 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
- 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
- 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
- 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
- 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
- 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
- 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
- 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
- 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
- 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
- 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
- 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
- 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
- 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
- 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
- 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
- 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
- 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
- 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
- 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
-};
-
-/* ulaw -> alaw */
-static char isdn_audio_ulaw_to_alaw[] =
-{
- 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
- 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
- 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
- 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
- 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
- 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
- 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
- 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
- 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
- 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
- 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
- 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
- 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
- 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
- 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
- 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
- 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
- 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
- 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
- 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
- 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
- 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
- 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
- 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
- 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
- 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
- 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
- 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
- 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
- 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
- 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
- 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
-};
-
-#define NCOEFF 8 /* number of frequencies to be analyzed */
-#define DTMF_TRESH 4000 /* above this is dtmf */
-#define SILENCE_TRESH 200 /* below this is silence */
-#define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */
-#define LOGRP 0
-#define HIGRP 1
-
-/* For DTMF recognition:
- * 2 * cos(2 * PI * k / N) precalculated for all k
- */
-static int cos2pik[NCOEFF] =
-{
- 55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
-};
-
-static char dtmf_matrix[4][4] =
-{
- {'1', '2', '3', 'A'},
- {'4', '5', '6', 'B'},
- {'7', '8', '9', 'C'},
- {'*', '0', '#', 'D'}
-};
-
-static inline void
-isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n)
-{
-#ifdef __i386__
- unsigned long d0, d1, d2, d3;
- __asm__ __volatile__(
- "cld\n"
- "1:\tlodsb\n\t"
- "xlatb\n\t"
- "stosb\n\t"
- "loop 1b\n\t"
- : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
- : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
- : "memory", "ax");
-#else
- while (n--)
- *buff = table[*(unsigned char *)buff], buff++;
-#endif
-}
-
-void
-isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
-{
- isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
-}
-
-void
-isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
-{
- isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
-}
-
-/*
- * linear <-> adpcm conversion stuff
- * Most parts from the mgetty-package.
- * (C) by Gert Doering and Klaus Weidner
- * Used by permission of Gert Doering
- */
-
-
-#define ZEROTRAP /* turn on the trap as per the MIL-STD */
-#undef ZEROTRAP
-#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
-#define CLIP 32635
-
-static unsigned char
-isdn_audio_linear2ulaw(int sample)
-{
- static int exp_lut[256] =
- {
- 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
- };
- int sign,
- exponent,
- mantissa;
- unsigned char ulawbyte;
-
- /* Get the sample into sign-magnitude. */
- sign = (sample >> 8) & 0x80; /* set aside the sign */
- if (sign != 0)
- sample = -sample; /* get magnitude */
- if (sample > CLIP)
- sample = CLIP; /* clip the magnitude */
-
- /* Convert from 16 bit linear to ulaw. */
- sample = sample + BIAS;
- exponent = exp_lut[(sample >> 7) & 0xFF];
- mantissa = (sample >> (exponent + 3)) & 0x0F;
- ulawbyte = ~(sign | (exponent << 4) | mantissa);
-#ifdef ZEROTRAP
- /* optional CCITT trap */
- if (ulawbyte == 0)
- ulawbyte = 0x02;
-#endif
- return (ulawbyte);
-}
-
-
-static int Mx[3][8] =
-{
- {0x3800, 0x5600, 0, 0, 0, 0, 0, 0},
- {0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0},
- {0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607},
-};
-
-static int bitmask[9] =
-{
- 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
-};
-
-static int
-isdn_audio_get_bits(adpcm_state *s, unsigned char **in, int *len)
-{
- while (s->nleft < s->nbits) {
- int d = *((*in)++);
- (*len)--;
- s->word = (s->word << 8) | d;
- s->nleft += 8;
- }
- s->nleft -= s->nbits;
- return (s->word >> s->nleft) & bitmask[s->nbits];
-}
-
-static void
-isdn_audio_put_bits(int data, int nbits, adpcm_state *s,
- unsigned char **out, int *len)
-{
- s->word = (s->word << nbits) | (data & bitmask[nbits]);
- s->nleft += nbits;
- while (s->nleft >= 8) {
- int d = (s->word >> (s->nleft - 8));
- *(out[0]++) = d & 255;
- (*len)++;
- s->nleft -= 8;
- }
-}
-
-adpcm_state *
-isdn_audio_adpcm_init(adpcm_state *s, int nbits)
-{
- if (!s)
- s = kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
- if (s) {
- s->a = 0;
- s->d = 5;
- s->word = 0;
- s->nleft = 0;
- s->nbits = nbits;
- }
- return s;
-}
-
-dtmf_state *
-isdn_audio_dtmf_init(dtmf_state *s)
-{
- if (!s)
- s = kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
- if (s) {
- s->idx = 0;
- s->last = ' ';
- }
- return s;
-}
-
-/*
- * Decompression of adpcm data to a/u-law
- *
- */
-
-int
-isdn_audio_adpcm2xlaw(adpcm_state *s, int fmt, unsigned char *in,
- unsigned char *out, int len)
-{
- int a = s->a;
- int d = s->d;
- int nbits = s->nbits;
- int olen = 0;
-
- while (len) {
- int e = isdn_audio_get_bits(s, &in, &len);
- int sign;
-
- if (nbits == 4 && e == 0)
- d = 4;
- sign = (e >> (nbits - 1)) ? -1 : 1;
- e &= bitmask[nbits - 1];
- a += sign * ((e << 1) + 1) * d >> 1;
- if (d & 1)
- a++;
- if (fmt)
- *out++ = isdn_audio_ulaw_to_alaw[
- isdn_audio_linear2ulaw(a << 2)];
- else
- *out++ = isdn_audio_linear2ulaw(a << 2);
- olen++;
- d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
- if (d < 5)
- d = 5;
- }
- s->a = a;
- s->d = d;
- return olen;
-}
-
-int
-isdn_audio_xlaw2adpcm(adpcm_state *s, int fmt, unsigned char *in,
- unsigned char *out, int len)
-{
- int a = s->a;
- int d = s->d;
- int nbits = s->nbits;
- int olen = 0;
-
- while (len--) {
- int e = 0,
- nmax = 1 << (nbits - 1);
- int sign,
- delta;
-
- if (fmt)
- delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
- else
- delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
- if (delta < 0) {
- e = nmax;
- delta = -delta;
- }
- while (--nmax && delta > d) {
- delta -= d;
- e++;
- }
- if (nbits == 4 && ((e & 0x0f) == 0))
- e = 8;
- isdn_audio_put_bits(e, nbits, s, &out, &olen);
- sign = (e >> (nbits - 1)) ? -1 : 1;
- e &= bitmask[nbits - 1];
-
- a += sign * ((e << 1) + 1) * d >> 1;
- if (d & 1)
- a++;
- d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
- if (d < 5)
- d = 5;
- }
- s->a = a;
- s->d = d;
- return olen;
-}
-
-/*
- * Goertzel algorithm.
- * See http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/
- * for more info.
- * Result is stored into an sk_buff and queued up for later
- * evaluation.
- */
-static void
-isdn_audio_goertzel(int *sample, modem_info *info)
-{
- int sk,
- sk1,
- sk2;
- int k,
- n;
- struct sk_buff *skb;
- int *result;
-
- skb = dev_alloc_skb(sizeof(int) * NCOEFF);
- if (!skb) {
- printk(KERN_WARNING
- "isdn_audio: Could not alloc DTMF result for ttyI%d\n",
- info->line);
- return;
- }
- result = skb_put(skb, sizeof(int) * NCOEFF);
- for (k = 0; k < NCOEFF; k++) {
- sk = sk1 = sk2 = 0;
- for (n = 0; n < DTMF_NPOINTS; n++) {
- sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;
- sk2 = sk1;
- sk1 = sk;
- }
- /* Avoid overflows */
- sk >>= 1;
- sk2 >>= 1;
- /* compute |X(k)|**2 */
- /* report overflows. This should not happen. */
- /* Comment this out if desired */
- if (sk < -32768 || sk > 32767)
- printk(KERN_DEBUG
- "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
- if (sk2 < -32768 || sk2 > 32767)
- printk(KERN_DEBUG
- "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
- result[k] =
- ((sk * sk) >> AMP_BITS) -
- ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
- ((sk2 * sk2) >> AMP_BITS);
- }
- skb_queue_tail(&info->dtmf_queue, skb);
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
-}
-
-void
-isdn_audio_eval_dtmf(modem_info *info)
-{
- struct sk_buff *skb;
- int *result;
- dtmf_state *s;
- int silence;
- int i;
- int di;
- int ch;
- int grp[2];
- char what;
- char *p;
- int thresh;
-
- while ((skb = skb_dequeue(&info->dtmf_queue))) {
- result = (int *) skb->data;
- s = info->dtmf_state;
- grp[LOGRP] = grp[HIGRP] = -1;
- silence = 0;
- thresh = 0;
- for (i = 0; i < NCOEFF; i++) {
- if (result[i] > DTMF_TRESH) {
- if (result[i] > thresh)
- thresh = result[i];
- }
- else if (result[i] < SILENCE_TRESH)
- silence++;
- }
- if (silence == NCOEFF)
- what = ' ';
- else {
- if (thresh > 0) {
- thresh = thresh >> 4; /* touchtones must match within 12 dB */
- for (i = 0; i < NCOEFF; i++) {
- if (result[i] < thresh)
- continue; /* ignore */
- /* good level found. This is allowed only one time per group */
- if (i < NCOEFF / 2) {
- /* lowgroup*/
- if (grp[LOGRP] >= 0) {
- // Bad. Another tone found. */
- grp[LOGRP] = -1;
- break;
- }
- else
- grp[LOGRP] = i;
- }
- else { /* higroup */
- if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
- grp[HIGRP] = -1;
- break;
- }
- else
- grp[HIGRP] = i - NCOEFF/2;
- }
- }
- if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
- what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
- if (s->last != ' ' && s->last != '.')
- s->last = what; /* min. 1 non-DTMF between DTMF */
- } else
- what = '.';
- }
- else
- what = '.';
- }
- if ((what != s->last) && (what != ' ') && (what != '.')) {
- printk(KERN_DEBUG "dtmf: tt='%c'\n", what);
- p = skb->data;
- *p++ = 0x10;
- *p = what;
- skb_trim(skb, 2);
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
- di = info->isdn_driver;
- ch = info->isdn_channel;
- __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
- dev->drv[di]->rcvcount[ch] += 2;
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
- } else
- kfree_skb(skb);
- s->last = what;
- }
-}
-
-/*
- * Decode DTMF tones, queue result in separate sk_buf for
- * later examination.
- * Parameters:
- * s = pointer to state-struct.
- * buf = input audio data
- * len = size of audio data.
- * fmt = audio data format (0 = ulaw, 1 = alaw)
- */
-void
-isdn_audio_calc_dtmf(modem_info *info, unsigned char *buf, int len, int fmt)
-{
- dtmf_state *s = info->dtmf_state;
- int i;
- int c;
-
- while (len) {
- c = DTMF_NPOINTS - s->idx;
- if (c > len)
- c = len;
- if (c <= 0)
- break;
- for (i = 0; i < c; i++) {
- if (fmt)
- s->buf[s->idx++] =
- isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
- else
- s->buf[s->idx++] =
- isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
- }
- if (s->idx == DTMF_NPOINTS) {
- isdn_audio_goertzel(s->buf, info);
- s->idx = 0;
- }
- len -= c;
- }
-}
-
-silence_state *
-isdn_audio_silence_init(silence_state *s)
-{
- if (!s)
- s = kmalloc(sizeof(silence_state), GFP_ATOMIC);
- if (s) {
- s->idx = 0;
- s->state = 0;
- }
- return s;
-}
-
-void
-isdn_audio_calc_silence(modem_info *info, unsigned char *buf, int len, int fmt)
-{
- silence_state *s = info->silence_state;
- int i;
- signed char c;
-
- if (!info->emu.vpar[1]) return;
-
- for (i = 0; i < len; i++) {
- if (fmt)
- c = isdn_audio_alaw_to_ulaw[*buf++];
- else
- c = *buf++;
-
- if (c > 0) c -= 128;
- c = abs(c);
-
- if (c > (info->emu.vpar[1] * 4)) {
- s->idx = 0;
- s->state = 1;
- } else {
- if (s->idx < 210000) s->idx++;
- }
- }
-}
-
-void
-isdn_audio_put_dle_code(modem_info *info, u_char code)
-{
- struct sk_buff *skb;
- int di;
- int ch;
- char *p;
-
- skb = dev_alloc_skb(2);
- if (!skb) {
- printk(KERN_WARNING
- "isdn_audio: Could not alloc skb for ttyI%d\n",
- info->line);
- return;
- }
- p = skb_put(skb, 2);
- p[0] = 0x10;
- p[1] = code;
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
- di = info->isdn_driver;
- ch = info->isdn_channel;
- __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
- dev->drv[di]->rcvcount[ch] += 2;
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
-}
-
-void
-isdn_audio_eval_silence(modem_info *info)
-{
- silence_state *s = info->silence_state;
- char what;
-
- what = ' ';
-
- if (s->idx > (info->emu.vpar[2] * 800)) {
- s->idx = 0;
- if (!s->state) { /* silence from beginning of rec */
- what = 's';
- } else {
- what = 'q';
- }
- }
- if ((what == 's') || (what == 'q')) {
- printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
- (what == 's') ? "silence" : "quiet");
- isdn_audio_put_dle_code(info, what);
- }
-}
diff --git a/drivers/isdn/i4l/isdn_audio.h b/drivers/isdn/i4l/isdn_audio.h
deleted file mode 100644
index 013c3582e0d1..000000000000
--- a/drivers/isdn/i4l/isdn_audio.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* $Id: isdn_audio.h,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
- *
- * Linux ISDN subsystem, audio conversion and compression (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
-typedef struct adpcm_state {
- int a;
- int d;
- int word;
- int nleft;
- int nbits;
-} adpcm_state;
-
-typedef struct dtmf_state {
- char last;
- char llast;
- int idx;
- int buf[DTMF_NPOINTS];
-} dtmf_state;
-
-typedef struct silence_state {
- int state;
- unsigned int idx;
-} silence_state;
-
-extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long);
-extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
-extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
-extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
-extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
-extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
-extern void isdn_audio_eval_dtmf(modem_info *);
-dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
-extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int);
-extern void isdn_audio_eval_silence(modem_info *);
-silence_state *isdn_audio_silence_init(silence_state *);
-extern void isdn_audio_put_dle_code(modem_info *, u_char);
diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c
deleted file mode 100644
index 7f28b967ed19..000000000000
--- a/drivers/isdn/i4l/isdn_bsdcomp.c
+++ /dev/null
@@ -1,930 +0,0 @@
-/*
- * BSD compression module
- *
- * Patched version for ISDN syncPPP written 1997/1998 by Michael Hipp
- * The whole module is now SKB based.
- *
- */
-
-/*
- * Update: The Berkeley copyright was changed, and the change
- * is retroactive to all "true" BSD software (ie everything
- * from UCB as opposed to other peoples code that just carried
- * the same license). The new copyright doesn't clash with the
- * GPL, so the module-only restriction has been removed..
- */
-
-/*
- * Original copyright notice:
- *
- * Copyright (c) 1985, 1986 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * James A. Woods, derived from original work by Spencer Thomas
- * and Joseph Orost.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h> /* used in new tty drivers */
-#include <linux/signal.h> /* used in new tty drivers */
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-#include <asm/types.h>
-
-#include <linux/if.h>
-
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/inet.h>
-#include <linux/ioctl.h>
-#include <linux/vmalloc.h>
-
-#include <linux/ppp_defs.h>
-
-#include <linux/isdn.h>
-#include <linux/isdn_ppp.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/if_arp.h>
-#include <linux/ppp-comp.h>
-
-#include "isdn_ppp.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: BSD Compression for PPP over ISDN");
-MODULE_LICENSE("Dual BSD/GPL");
-
-#define BSD_VERSION(x) ((x) >> 5)
-#define BSD_NBITS(x) ((x) & 0x1F)
-
-#define BSD_CURRENT_VERSION 1
-
-#define DEBUG 1
-
-/*
- * A dictionary for doing BSD compress.
- */
-
-struct bsd_dict {
- u32 fcode;
- u16 codem1; /* output of hash table -1 */
- u16 cptr; /* map code to hash table entry */
-};
-
-struct bsd_db {
- int totlen; /* length of this structure */
- unsigned int hsize; /* size of the hash table */
- unsigned char hshift; /* used in hash function */
- unsigned char n_bits; /* current bits/code */
- unsigned char maxbits; /* maximum bits/code */
- unsigned char debug; /* non-zero if debug desired */
- unsigned char unit; /* ppp unit number */
- u16 seqno; /* sequence # of next packet */
- unsigned int mru; /* size of receive (decompress) bufr */
- unsigned int maxmaxcode; /* largest valid code */
- unsigned int max_ent; /* largest code in use */
- unsigned int in_count; /* uncompressed bytes, aged */
- unsigned int bytes_out; /* compressed bytes, aged */
- unsigned int ratio; /* recent compression ratio */
- unsigned int checkpoint; /* when to next check the ratio */
- unsigned int clear_count; /* times dictionary cleared */
- unsigned int incomp_count; /* incompressible packets */
- unsigned int incomp_bytes; /* incompressible bytes */
- unsigned int uncomp_count; /* uncompressed packets */
- unsigned int uncomp_bytes; /* uncompressed bytes */
- unsigned int comp_count; /* compressed packets */
- unsigned int comp_bytes; /* compressed bytes */
- unsigned short *lens; /* array of lengths of codes */
- struct bsd_dict *dict; /* dictionary */
- int xmit;
-};
-
-#define BSD_OVHD 2 /* BSD compress overhead/packet */
-#define MIN_BSD_BITS 9
-#define BSD_INIT_BITS MIN_BSD_BITS
-#define MAX_BSD_BITS 15
-
-/*
- * the next two codes should not be changed lightly, as they must not
- * lie within the contiguous general code space.
- */
-#define CLEAR 256 /* table clear output code */
-#define FIRST 257 /* first free entry */
-#define LAST 255
-
-#define MAXCODE(b) ((1 << (b)) - 1)
-#define BADCODEM1 MAXCODE(MAX_BSD_BITS)
-
-#define BSD_HASH(prefix, suffix, hshift) ((((unsigned long)(suffix)) << (hshift)) \
- ^ (unsigned long)(prefix))
-#define BSD_KEY(prefix, suffix) ((((unsigned long)(suffix)) << 16) \
- + (unsigned long)(prefix))
-
-#define CHECK_GAP 10000 /* Ratio check interval */
-
-#define RATIO_SCALE_LOG 8
-#define RATIO_SCALE (1 << RATIO_SCALE_LOG)
-#define RATIO_MAX (0x7fffffff >> RATIO_SCALE_LOG)
-
-/*
- * clear the dictionary
- */
-
-static void bsd_clear(struct bsd_db *db)
-{
- db->clear_count++;
- db->max_ent = FIRST - 1;
- db->n_bits = BSD_INIT_BITS;
- db->bytes_out = 0;
- db->in_count = 0;
- db->incomp_count = 0;
- db->ratio = 0;
- db->checkpoint = CHECK_GAP;
-}
-
-/*
- * If the dictionary is full, then see if it is time to reset it.
- *
- * Compute the compression ratio using fixed-point arithmetic
- * with 8 fractional bits.
- *
- * Since we have an infinite stream instead of a single file,
- * watch only the local compression ratio.
- *
- * Since both peers must reset the dictionary at the same time even in
- * the absence of CLEAR codes (while packets are incompressible), they
- * must compute the same ratio.
- */
-static int bsd_check(struct bsd_db *db) /* 1=output CLEAR */
-{
- unsigned int new_ratio;
-
- if (db->in_count >= db->checkpoint)
- {
- /* age the ratio by limiting the size of the counts */
- if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX)
- {
- db->in_count -= (db->in_count >> 2);
- db->bytes_out -= (db->bytes_out >> 2);
- }
-
- db->checkpoint = db->in_count + CHECK_GAP;
-
- if (db->max_ent >= db->maxmaxcode)
- {
- /* Reset the dictionary only if the ratio is worse,
- * or if it looks as if it has been poisoned
- * by incompressible data.
- *
- * This does not overflow, because
- * db->in_count <= RATIO_MAX.
- */
-
- new_ratio = db->in_count << RATIO_SCALE_LOG;
- if (db->bytes_out != 0)
- {
- new_ratio /= db->bytes_out;
- }
-
- if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
- {
- bsd_clear(db);
- return 1;
- }
- db->ratio = new_ratio;
- }
- }
- return 0;
-}
-
-/*
- * Return statistics.
- */
-
-static void bsd_stats(void *state, struct compstat *stats)
-{
- struct bsd_db *db = (struct bsd_db *) state;
-
- stats->unc_bytes = db->uncomp_bytes;
- stats->unc_packets = db->uncomp_count;
- stats->comp_bytes = db->comp_bytes;
- stats->comp_packets = db->comp_count;
- stats->inc_bytes = db->incomp_bytes;
- stats->inc_packets = db->incomp_count;
- stats->in_count = db->in_count;
- stats->bytes_out = db->bytes_out;
-}
-
-/*
- * Reset state, as on a CCP ResetReq.
- */
-static void bsd_reset(void *state, unsigned char code, unsigned char id,
- unsigned char *data, unsigned len,
- struct isdn_ppp_resetparams *rsparm)
-{
- struct bsd_db *db = (struct bsd_db *) state;
-
- bsd_clear(db);
- db->seqno = 0;
- db->clear_count = 0;
-}
-
-/*
- * Release the compression structure
- */
-static void bsd_free(void *state)
-{
- struct bsd_db *db = (struct bsd_db *) state;
-
- if (db) {
- /*
- * Release the dictionary
- */
- vfree(db->dict);
- db->dict = NULL;
-
- /*
- * Release the string buffer
- */
- vfree(db->lens);
- db->lens = NULL;
-
- /*
- * Finally release the structure itself.
- */
- kfree(db);
- }
-}
-
-
-/*
- * Allocate space for a (de) compressor.
- */
-static void *bsd_alloc(struct isdn_ppp_comp_data *data)
-{
- int bits;
- unsigned int hsize, hshift, maxmaxcode;
- struct bsd_db *db;
- int decomp;
-
- static unsigned int htab[][2] = {
- { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } ,
- { 9001 , 5 } , { 18013 , 6 } , { 35023 , 7 } , { 69001 , 8 }
- };
-
- if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
- || BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
- return NULL;
-
- bits = BSD_NBITS(data->options[0]);
-
- if (bits < 9 || bits > 15)
- return NULL;
-
- hsize = htab[bits - 9][0];
- hshift = htab[bits - 9][1];
-
- /*
- * Allocate the main control structure for this instance.
- */
- maxmaxcode = MAXCODE(bits);
- db = kzalloc(sizeof(struct bsd_db), GFP_KERNEL);
- if (!db)
- return NULL;
-
- db->xmit = data->flags & IPPP_COMP_FLAG_XMIT;
- decomp = db->xmit ? 0 : 1;
-
- /*
- * Allocate space for the dictionary. This may be more than one page in
- * length.
- */
- db->dict = vmalloc(array_size(hsize, sizeof(struct bsd_dict)));
- if (!db->dict) {
- bsd_free(db);
- return NULL;
- }
-
- /*
- * If this is the compression buffer then there is no length data.
- * For decompression, the length information is needed as well.
- */
- if (!decomp)
- db->lens = NULL;
- else {
- db->lens = vmalloc(array_size(sizeof(db->lens[0]),
- maxmaxcode + 1));
- if (!db->lens) {
- bsd_free(db);
- return (NULL);
- }
- }
-
- /*
- * Initialize the data information for the compression code
- */
- db->totlen = sizeof(struct bsd_db) + (sizeof(struct bsd_dict) * hsize);
- db->hsize = hsize;
- db->hshift = hshift;
- db->maxmaxcode = maxmaxcode;
- db->maxbits = bits;
-
- return (void *)db;
-}
-
-/*
- * Initialize the database.
- */
-static int bsd_init(void *state, struct isdn_ppp_comp_data *data, int unit, int debug)
-{
- struct bsd_db *db = state;
- int indx;
- int decomp;
-
- if (!state || !data) {
- printk(KERN_ERR "isdn_bsd_init: [%d] ERR, state %lx data %lx\n", unit, (long)state, (long)data);
- return 0;
- }
-
- decomp = db->xmit ? 0 : 1;
-
- if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
- || (BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
- || (BSD_NBITS(data->options[0]) != db->maxbits)
- || (decomp && db->lens == NULL)) {
- printk(KERN_ERR "isdn_bsd: %d %d %d %d %lx\n", data->optlen, data->num, data->options[0], decomp, (unsigned long)db->lens);
- return 0;
- }
-
- if (decomp)
- for (indx = LAST; indx >= 0; indx--)
- db->lens[indx] = 1;
-
- indx = db->hsize;
- while (indx-- != 0) {
- db->dict[indx].codem1 = BADCODEM1;
- db->dict[indx].cptr = 0;
- }
-
- db->unit = unit;
- db->mru = 0;
-
- db->debug = 1;
-
- bsd_reset(db, 0, 0, NULL, 0, NULL);
-
- return 1;
-}
-
-/*
- * Obtain pointers to the various structures in the compression tables
- */
-
-#define dict_ptrx(p, idx) &(p->dict[idx])
-#define lens_ptrx(p, idx) &(p->lens[idx])
-
-#ifdef DEBUG
-static unsigned short *lens_ptr(struct bsd_db *db, int idx)
-{
- if ((unsigned int) idx > (unsigned int) db->maxmaxcode) {
- printk(KERN_DEBUG "<9>ppp: lens_ptr(%d) > max\n", idx);
- idx = 0;
- }
- return lens_ptrx(db, idx);
-}
-
-static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx)
-{
- if ((unsigned int) idx >= (unsigned int) db->hsize) {
- printk(KERN_DEBUG "<9>ppp: dict_ptr(%d) > max\n", idx);
- idx = 0;
- }
- return dict_ptrx(db, idx);
-}
-
-#else
-#define lens_ptr(db, idx) lens_ptrx(db, idx)
-#define dict_ptr(db, idx) dict_ptrx(db, idx)
-#endif
-
-/*
- * compress a packet
- */
-static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out, int proto)
-{
- struct bsd_db *db;
- int hshift;
- unsigned int max_ent;
- unsigned int n_bits;
- unsigned int bitno;
- unsigned long accm;
- int ent;
- unsigned long fcode;
- struct bsd_dict *dictp;
- unsigned char c;
- int hval, disp, ilen, mxcode;
- unsigned char *rptr = skb_in->data;
- int isize = skb_in->len;
-
-#define OUTPUT(ent) \
- { \
- bitno -= n_bits; \
- accm |= ((ent) << bitno); \
- do { \
- if (skb_out && skb_tailroom(skb_out) > 0) \
- skb_put_u8(skb_out, (u8)(accm >> 24)); \
- accm <<= 8; \
- bitno += 8; \
- } while (bitno <= 24); \
- }
-
- /*
- * If the protocol is not in the range we're interested in,
- * just return without compressing the packet. If it is,
- * the protocol becomes the first byte to compress.
- */
- printk(KERN_DEBUG "bsd_compress called with %x\n", proto);
-
- ent = proto;
- if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1))
- return 0;
-
- db = (struct bsd_db *) state;
- hshift = db->hshift;
- max_ent = db->max_ent;
- n_bits = db->n_bits;
- bitno = 32;
- accm = 0;
- mxcode = MAXCODE(n_bits);
-
- /* This is the PPP header information */
- if (skb_out && skb_tailroom(skb_out) >= 2) {
- char *v = skb_put(skb_out, 2);
- /* we only push our own data on the header,
- AC,PC and protos is pushed by caller */
- v[0] = db->seqno >> 8;
- v[1] = db->seqno;
- }
-
- ilen = ++isize; /* This is off by one, but that is what is in draft! */
-
- while (--ilen > 0) {
- c = *rptr++;
- fcode = BSD_KEY(ent, c);
- hval = BSD_HASH(ent, c, hshift);
- dictp = dict_ptr(db, hval);
-
- /* Validate and then check the entry. */
- if (dictp->codem1 >= max_ent)
- goto nomatch;
-
- if (dictp->fcode == fcode) {
- ent = dictp->codem1 + 1;
- continue; /* found (prefix,suffix) */
- }
-
- /* continue probing until a match or invalid entry */
- disp = (hval == 0) ? 1 : hval;
-
- do {
- hval += disp;
- if (hval >= db->hsize)
- hval -= db->hsize;
- dictp = dict_ptr(db, hval);
- if (dictp->codem1 >= max_ent)
- goto nomatch;
- } while (dictp->fcode != fcode);
-
- ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
- continue;
-
- nomatch:
- OUTPUT(ent); /* output the prefix */
-
- /* code -> hashtable */
- if (max_ent < db->maxmaxcode) {
- struct bsd_dict *dictp2;
- struct bsd_dict *dictp3;
- int indx;
-
- /* expand code size if needed */
- if (max_ent >= mxcode) {
- db->n_bits = ++n_bits;
- mxcode = MAXCODE(n_bits);
- }
-
- /*
- * Invalidate old hash table entry using
- * this code, and then take it over.
- */
- dictp2 = dict_ptr(db, max_ent + 1);
- indx = dictp2->cptr;
- dictp3 = dict_ptr(db, indx);
-
- if (dictp3->codem1 == max_ent)
- dictp3->codem1 = BADCODEM1;
-
- dictp2->cptr = hval;
- dictp->codem1 = max_ent;
- dictp->fcode = fcode;
- db->max_ent = ++max_ent;
-
- if (db->lens) {
- unsigned short *len1 = lens_ptr(db, max_ent);
- unsigned short *len2 = lens_ptr(db, ent);
- *len1 = *len2 + 1;
- }
- }
- ent = c;
- }
-
- OUTPUT(ent); /* output the last code */
-
- if (skb_out)
- db->bytes_out += skb_out->len; /* Do not count bytes from here */
- db->uncomp_bytes += isize;
- db->in_count += isize;
- ++db->uncomp_count;
- ++db->seqno;
-
- if (bitno < 32)
- ++db->bytes_out; /* must be set before calling bsd_check */
-
- /*
- * Generate the clear command if needed
- */
-
- if (bsd_check(db))
- OUTPUT(CLEAR);
-
- /*
- * Pad dribble bits of last code with ones.
- * Do not emit a completely useless byte of ones.
- */
- if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0)
- skb_put_u8(skb_out,
- (unsigned char)((accm | (0xff << (bitno - 8))) >> 24));
-
- /*
- * Increase code size if we would have without the packet
- * boundary because the decompressor will do so.
- */
- if (max_ent >= mxcode && max_ent < db->maxmaxcode)
- db->n_bits++;
-
- /* If output length is too large then this is an incompressible frame. */
- if (!skb_out || skb_out->len >= skb_in->len) {
- ++db->incomp_count;
- db->incomp_bytes += isize;
- return 0;
- }
-
- /* Count the number of compressed frames */
- ++db->comp_count;
- db->comp_bytes += skb_out->len;
- return skb_out->len;
-
-#undef OUTPUT
-}
-
-/*
- * Update the "BSD Compress" dictionary on the receiver for
- * incompressible data by pretending to compress the incoming data.
- */
-static void bsd_incomp(void *state, struct sk_buff *skb_in, int proto)
-{
- bsd_compress(state, skb_in, NULL, proto);
-}
-
-/*
- * Decompress "BSD Compress".
- */
-static int bsd_decompress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,
- struct isdn_ppp_resetparams *rsparm)
-{
- struct bsd_db *db;
- unsigned int max_ent;
- unsigned long accm;
- unsigned int bitno; /* 1st valid bit in accm */
- unsigned int n_bits;
- unsigned int tgtbitno; /* bitno when we have a code */
- struct bsd_dict *dictp;
- int seq;
- unsigned int incode;
- unsigned int oldcode;
- unsigned int finchar;
- unsigned char *p, *ibuf;
- int ilen;
- int codelen;
- int extra;
-
- db = (struct bsd_db *) state;
- max_ent = db->max_ent;
- accm = 0;
- bitno = 32; /* 1st valid bit in accm */
- n_bits = db->n_bits;
- tgtbitno = 32 - n_bits; /* bitno when we have a code */
-
- printk(KERN_DEBUG "bsd_decompress called\n");
-
- if (!skb_in || !skb_out) {
- printk(KERN_ERR "bsd_decompress called with NULL parameter\n");
- return DECOMP_ERROR;
- }
-
- /*
- * Get the sequence number.
- */
- if ((p = skb_pull(skb_in, 2)) == NULL) {
- return DECOMP_ERROR;
- }
- p -= 2;
- seq = (p[0] << 8) + p[1];
- ilen = skb_in->len;
- ibuf = skb_in->data;
-
- /*
- * Check the sequence number and give up if it differs from
- * the value we're expecting.
- */
- if (seq != db->seqno) {
- if (db->debug) {
- printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n",
- db->unit, seq, db->seqno - 1);
- }
- return DECOMP_ERROR;
- }
-
- ++db->seqno;
- db->bytes_out += ilen;
-
- if (skb_tailroom(skb_out) > 0)
- skb_put_u8(skb_out, 0);
- else
- return DECOMP_ERR_NOMEM;
-
- oldcode = CLEAR;
-
- /*
- * Keep the checkpoint correctly so that incompressible packets
- * clear the dictionary at the proper times.
- */
-
- for (;;) {
- if (ilen-- <= 0) {
- db->in_count += (skb_out->len - 1); /* don't count the header */
- break;
- }
-
- /*
- * Accumulate bytes until we have a complete code.
- * Then get the next code, relying on the 32-bit,
- * unsigned accm to mask the result.
- */
-
- bitno -= 8;
- accm |= *ibuf++ << bitno;
- if (tgtbitno < bitno)
- continue;
-
- incode = accm >> tgtbitno;
- accm <<= n_bits;
- bitno += n_bits;
-
- /*
- * The dictionary must only be cleared at the end of a packet.
- */
-
- if (incode == CLEAR) {
- if (ilen > 0) {
- if (db->debug)
- printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit);
- return DECOMP_FATALERROR; /* probably a bug */
- }
- bsd_clear(db);
- break;
- }
-
- if ((incode > max_ent + 2) || (incode > db->maxmaxcode)
- || (incode > max_ent && oldcode == CLEAR)) {
- if (db->debug) {
- printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
- db->unit, incode, oldcode);
- printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n",
- max_ent, skb_out->len, db->seqno);
- }
- return DECOMP_FATALERROR; /* probably a bug */
- }
-
- /* Special case for KwKwK string. */
- if (incode > max_ent) {
- finchar = oldcode;
- extra = 1;
- } else {
- finchar = incode;
- extra = 0;
- }
-
- codelen = *(lens_ptr(db, finchar));
- if (skb_tailroom(skb_out) < codelen + extra) {
- if (db->debug) {
- printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit);
-#ifdef DEBUG
- printk(KERN_DEBUG " len=%d, finchar=0x%x, codelen=%d,skblen=%d\n",
- ilen, finchar, codelen, skb_out->len);
-#endif
- }
- return DECOMP_FATALERROR;
- }
-
- /*
- * Decode this code and install it in the decompressed buffer.
- */
-
- p = skb_put(skb_out, codelen);
- p += codelen;
- while (finchar > LAST) {
- struct bsd_dict *dictp2 = dict_ptr(db, finchar);
-
- dictp = dict_ptr(db, dictp2->cptr);
-
-#ifdef DEBUG
- if (--codelen <= 0 || dictp->codem1 != finchar - 1) {
- if (codelen <= 0) {
- printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit);
- printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent);
- } else {
- if (dictp->codem1 != finchar - 1) {
- printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ", db->unit, incode, finchar);
- printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1);
- }
- }
- return DECOMP_FATALERROR;
- }
-#endif
-
- {
- u32 fcode = dictp->fcode;
- *--p = (fcode >> 16) & 0xff;
- finchar = fcode & 0xffff;
- }
- }
- *--p = finchar;
-
-#ifdef DEBUG
- if (--codelen != 0)
- printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent);
-#endif
-
- if (extra) /* the KwKwK case again */
- skb_put_u8(skb_out, finchar);
-
- /*
- * If not first code in a packet, and
- * if not out of code space, then allocate a new code.
- *
- * Keep the hash table correct so it can be used
- * with uncompressed packets.
- */
- if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
- struct bsd_dict *dictp2, *dictp3;
- u16 *lens1, *lens2;
- unsigned long fcode;
- int hval, disp, indx;
-
- fcode = BSD_KEY(oldcode, finchar);
- hval = BSD_HASH(oldcode, finchar, db->hshift);
- dictp = dict_ptr(db, hval);
-
- /* look for a free hash table entry */
- if (dictp->codem1 < max_ent) {
- disp = (hval == 0) ? 1 : hval;
- do {
- hval += disp;
- if (hval >= db->hsize)
- hval -= db->hsize;
- dictp = dict_ptr(db, hval);
- } while (dictp->codem1 < max_ent);
- }
-
- /*
- * Invalidate previous hash table entry
- * assigned this code, and then take it over
- */
-
- dictp2 = dict_ptr(db, max_ent + 1);
- indx = dictp2->cptr;
- dictp3 = dict_ptr(db, indx);
-
- if (dictp3->codem1 == max_ent)
- dictp3->codem1 = BADCODEM1;
-
- dictp2->cptr = hval;
- dictp->codem1 = max_ent;
- dictp->fcode = fcode;
- db->max_ent = ++max_ent;
-
- /* Update the length of this string. */
- lens1 = lens_ptr(db, max_ent);
- lens2 = lens_ptr(db, oldcode);
- *lens1 = *lens2 + 1;
-
- /* Expand code size if needed. */
- if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
- db->n_bits = ++n_bits;
- tgtbitno = 32-n_bits;
- }
- }
- oldcode = incode;
- }
-
- ++db->comp_count;
- ++db->uncomp_count;
- db->comp_bytes += skb_in->len - BSD_OVHD;
- db->uncomp_bytes += skb_out->len;
-
- if (bsd_check(db)) {
- if (db->debug)
- printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n",
- db->unit, db->seqno - 1);
- }
- return skb_out->len;
-}
-
-/*************************************************************
- * Table of addresses for the BSD compression module
- *************************************************************/
-
-static struct isdn_ppp_compressor ippp_bsd_compress = {
- .owner = THIS_MODULE,
- .num = CI_BSD_COMPRESS,
- .alloc = bsd_alloc,
- .free = bsd_free,
- .init = bsd_init,
- .reset = bsd_reset,
- .compress = bsd_compress,
- .decompress = bsd_decompress,
- .incomp = bsd_incomp,
- .stat = bsd_stats,
-};
-
-/*************************************************************
- * Module support routines
- *************************************************************/
-
-static int __init isdn_bsdcomp_init(void)
-{
- int answer = isdn_ppp_register_compressor(&ippp_bsd_compress);
- if (answer == 0)
- printk(KERN_INFO "PPP BSD Compression module registered\n");
- return answer;
-}
-
-static void __exit isdn_bsdcomp_exit(void)
-{
- isdn_ppp_unregister_compressor(&ippp_bsd_compress);
-}
-
-module_init(isdn_bsdcomp_init);
-module_exit(isdn_bsdcomp_exit);
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
deleted file mode 100644
index 74ee00f5b310..000000000000
--- a/drivers/isdn/i4l/isdn_common.c
+++ /dev/null
@@ -1,2368 +0,0 @@
-/* $Id: isdn_common.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
- * Linux ISDN subsystem, common used functions (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/isdn.h>
-#include <linux/mutex.h>
-#include "isdn_common.h"
-#include "isdn_tty.h"
-#include "isdn_net.h"
-#include "isdn_ppp.h"
-#ifdef CONFIG_ISDN_AUDIO
-#include "isdn_audio.h"
-#endif
-#ifdef CONFIG_ISDN_DIVERSION_MODULE
-#define CONFIG_ISDN_DIVERSION
-#endif
-#ifdef CONFIG_ISDN_DIVERSION
-#include <linux/isdn_divertif.h>
-#endif /* CONFIG_ISDN_DIVERSION */
-#include "isdn_v110.h"
-
-/* Debugflags */
-#undef ISDN_DEBUG_STATCALLB
-
-MODULE_DESCRIPTION("ISDN4Linux: link layer");
-MODULE_AUTHOR("Fritz Elfert");
-MODULE_LICENSE("GPL");
-
-isdn_dev *dev;
-
-static DEFINE_MUTEX(isdn_mutex);
-static char *isdn_revision = "$Revision: 1.1.2.3 $";
-
-extern char *isdn_net_revision;
-#ifdef CONFIG_ISDN_PPP
-extern char *isdn_ppp_revision;
-#else
-static char *isdn_ppp_revision = ": none $";
-#endif
-#ifdef CONFIG_ISDN_AUDIO
-extern char *isdn_audio_revision;
-#else
-static char *isdn_audio_revision = ": none $";
-#endif
-extern char *isdn_v110_revision;
-
-#ifdef CONFIG_ISDN_DIVERSION
-static isdn_divert_if *divert_if; /* = NULL */
-#endif /* CONFIG_ISDN_DIVERSION */
-
-
-static int isdn_writebuf_stub(int, int, const u_char __user *, int);
-static void set_global_features(void);
-static int isdn_wildmat(char *s, char *p);
-static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding);
-
-static inline void
-isdn_lock_driver(isdn_driver_t *drv)
-{
- try_module_get(drv->interface->owner);
- drv->locks++;
-}
-
-void
-isdn_lock_drivers(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (!dev->drv[i])
- continue;
- isdn_lock_driver(dev->drv[i]);
- }
-}
-
-static inline void
-isdn_unlock_driver(isdn_driver_t *drv)
-{
- if (drv->locks > 0) {
- drv->locks--;
- module_put(drv->interface->owner);
- }
-}
-
-void
-isdn_unlock_drivers(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (!dev->drv[i])
- continue;
- isdn_unlock_driver(dev->drv[i]);
- }
-}
-
-#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-void
-isdn_dumppkt(char *s, u_char *p, int len, int dumplen)
-{
- int dumpc;
-
- printk(KERN_DEBUG "%s(%d) ", s, len);
- for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++)
- printk(" %02x", *p++);
- printk("\n");
-}
-#endif
-
-/*
- * I picked the pattern-matching-functions from an old GNU-tar version (1.10)
- * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz)
- */
-static int
-isdn_star(char *s, char *p)
-{
- while (isdn_wildmat(s, p)) {
- if (*++s == '\0')
- return (2);
- }
- return (0);
-}
-
-/*
- * Shell-type Pattern-matching for incoming caller-Ids
- * This function gets a string in s and checks, if it matches the pattern
- * given in p.
- *
- * Return:
- * 0 = match.
- * 1 = no match.
- * 2 = no match. Would eventually match, if s would be longer.
- *
- * Possible Patterns:
- *
- * '?' matches one character
- * '*' matches zero or more characters
- * [xyz] matches the set of characters in brackets.
- * [^xyz] matches any single character not in the set of characters
- */
-
-static int
-isdn_wildmat(char *s, char *p)
-{
- register int last;
- register int matched;
- register int reverse;
- register int nostar = 1;
-
- if (!(*s) && !(*p))
- return (1);
- for (; *p; s++, p++)
- switch (*p) {
- case '\\':
- /* Literal match with following character. */
- p++;
- /* fall through */
- default:
- if (*s != *p)
- return (*s == '\0') ? 2 : 1;
- continue;
- case '?':
- /* Match anything. */
- if (*s == '\0')
- return (2);
- continue;
- case '*':
- nostar = 0;
- /* Trailing star matches everything. */
- return (*++p ? isdn_star(s, p) : 0);
- case '[':
- /* [^....] means inverse character class. */
- if ((reverse = (p[1] == '^')))
- p++;
- for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
- /* This next line requires a good C compiler. */
- if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
- matched = 1;
- if (matched == reverse)
- return (1);
- continue;
- }
- return (*s == '\0') ? 0 : nostar;
-}
-
-int isdn_msncmp(const char *msn1, const char *msn2)
-{
- char TmpMsn1[ISDN_MSNLEN];
- char TmpMsn2[ISDN_MSNLEN];
- char *p;
-
- for (p = TmpMsn1; *msn1 && *msn1 != ':';) // Strip off a SPID
- *p++ = *msn1++;
- *p = '\0';
-
- for (p = TmpMsn2; *msn2 && *msn2 != ':';) // Strip off a SPID
- *p++ = *msn2++;
- *p = '\0';
-
- return isdn_wildmat(TmpMsn1, TmpMsn2);
-}
-
-int
-isdn_dc2minor(int di, int ch)
-{
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->chanmap[i] == ch && dev->drvmap[i] == di)
- return i;
- return -1;
-}
-
-static int isdn_timer_cnt1 = 0;
-static int isdn_timer_cnt2 = 0;
-static int isdn_timer_cnt3 = 0;
-
-static void
-isdn_timer_funct(struct timer_list *unused)
-{
- int tf = dev->tflags;
- if (tf & ISDN_TIMER_FAST) {
- if (tf & ISDN_TIMER_MODEMREAD)
- isdn_tty_readmodem();
- if (tf & ISDN_TIMER_MODEMPLUS)
- isdn_tty_modem_escape();
- if (tf & ISDN_TIMER_MODEMXMIT)
- isdn_tty_modem_xmit();
- }
- if (tf & ISDN_TIMER_SLOW) {
- if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) {
- isdn_timer_cnt1 = 0;
- if (tf & ISDN_TIMER_NETDIAL)
- isdn_net_dial();
- }
- if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
- isdn_timer_cnt2 = 0;
- if (tf & ISDN_TIMER_NETHANGUP)
- isdn_net_autohup();
- if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) {
- isdn_timer_cnt3 = 0;
- if (tf & ISDN_TIMER_MODEMRING)
- isdn_tty_modem_ring();
- }
- if (tf & ISDN_TIMER_CARRIER)
- isdn_tty_carrier_timeout();
- }
- }
- if (tf)
- mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES);
-}
-
-void
-isdn_timer_ctrl(int tf, int onoff)
-{
- unsigned long flags;
- int old_tflags;
-
- spin_lock_irqsave(&dev->timerlock, flags);
- if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
- /* If the slow-timer wasn't activated until now */
- isdn_timer_cnt1 = 0;
- isdn_timer_cnt2 = 0;
- }
- old_tflags = dev->tflags;
- if (onoff)
- dev->tflags |= tf;
- else
- dev->tflags &= ~tf;
- if (dev->tflags && !old_tflags)
- mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES);
- spin_unlock_irqrestore(&dev->timerlock, flags);
-}
-
-/*
- * Receive a packet from B-Channel. (Called from low-level-module)
- */
-static void
-isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
-{
- int i;
-
- if ((i = isdn_dc2minor(di, channel)) == -1) {
- dev_kfree_skb(skb);
- return;
- }
- /* Update statistics */
- dev->ibytes[i] += skb->len;
-
- /* First, try to deliver data to network-device */
- if (isdn_net_rcv_skb(i, skb))
- return;
-
- /* V.110 handling
- * makes sense for async streams only, so it is
- * called after possible net-device delivery.
- */
- if (dev->v110[i]) {
- atomic_inc(&dev->v110use[i]);
- skb = isdn_v110_decode(dev->v110[i], skb);
- atomic_dec(&dev->v110use[i]);
- if (!skb)
- return;
- }
-
- /* No network-device found, deliver to tty or raw-channel */
- if (skb->len) {
- if (isdn_tty_rcv_skb(i, di, channel, skb))
- return;
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
- } else
- dev_kfree_skb(skb);
-}
-
-/*
- * Intercept command from Linklevel to Lowlevel.
- * If layer 2 protocol is V.110 and this is not supported by current
- * lowlevel-driver, use driver's transparent mode and handle V.110 in
- * linklevel instead.
- */
-int
-isdn_command(isdn_ctrl *cmd)
-{
- if (cmd->driver == -1) {
- printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
- return (1);
- }
- if (!dev->drv[cmd->driver]) {
- printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d] NULL\n",
- cmd->command, cmd->driver);
- return (1);
- }
- if (!dev->drv[cmd->driver]->interface) {
- printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d]->interface NULL\n",
- cmd->command, cmd->driver);
- return (1);
- }
- if (cmd->command == ISDN_CMD_SETL2) {
- int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
- unsigned long l2prot = (cmd->arg >> 8) & 255;
- unsigned long features = (dev->drv[cmd->driver]->interface->features
- >> ISDN_FEATURE_L2_SHIFT) &
- ISDN_FEATURE_L2_MASK;
- unsigned long l2_feature = (1 << l2prot);
-
- switch (l2prot) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- /* If V.110 requested, but not supported by
- * HL-driver, set emulator-flag and change
- * Layer-2 to transparent
- */
- if (!(features & l2_feature)) {
- dev->v110emu[idx] = l2prot;
- cmd->arg = (cmd->arg & 255) |
- (ISDN_PROTO_L2_TRANS << 8);
- } else
- dev->v110emu[idx] = 0;
- }
- }
- return dev->drv[cmd->driver]->interface->command(cmd);
-}
-
-void
-isdn_all_eaz(int di, int ch)
-{
- isdn_ctrl cmd;
-
- if (di < 0)
- return;
- cmd.driver = di;
- cmd.arg = ch;
- cmd.command = ISDN_CMD_SETEAZ;
- cmd.parm.num[0] = '\0';
- isdn_command(&cmd);
-}
-
-/*
- * Begin of a CAPI like LL<->HL interface, currently used only for
- * supplementary service (CAPI 2.0 part III)
- */
-#include <linux/isdn/capicmd.h>
-
-static int
-isdn_capi_rec_hl_msg(capi_msg *cm)
-{
- switch (cm->Command) {
- case CAPI_FACILITY:
- /* in the moment only handled in tty */
- return (isdn_tty_capi_facility(cm));
- default:
- return (-1);
- }
-}
-
-static int
-isdn_status_callback(isdn_ctrl *c)
-{
- int di;
- u_long flags;
- int i;
- int r;
- int retval = 0;
- isdn_ctrl cmd;
- isdn_net_dev *p;
-
- di = c->driver;
- i = isdn_dc2minor(di, c->arg);
- switch (c->command) {
- case ISDN_STAT_BSENT:
- if (i < 0)
- return -1;
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (isdn_net_stat_callback(i, c))
- return 0;
- if (isdn_v110_stat_callback(i, c))
- return 0;
- if (isdn_tty_stat_callback(i, c))
- return 0;
- wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
- break;
- case ISDN_STAT_STAVAIL:
- dev->drv[di]->stavail += c->arg;
- wake_up_interruptible(&dev->drv[di]->st_waitq);
- break;
- case ISDN_STAT_RUN:
- dev->drv[di]->flags |= DRV_FLAG_RUNNING;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di)
- isdn_all_eaz(di, dev->chanmap[i]);
- set_global_features();
- break;
- case ISDN_STAT_STOP:
- dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
- break;
- case ISDN_STAT_ICALL:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- return 0;
- }
- /* Try to find a network-interface which will accept incoming call */
- r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup));
- switch (r) {
- case 0:
- /* No network-device replies.
- * Try ttyI's.
- * These return 0 on no match, 1 on match and
- * 3 on eventually match, if CID is longer.
- */
- if (c->command == ISDN_STAT_ICALL)
- if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return (retval);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- if ((retval = divert_if->stat_callback(c)))
- return (retval); /* processed */
-#endif /* CONFIG_ISDN_DIVERSION */
- if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
- /* No tty responding */
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- retval = 2;
- }
- break;
- case 1:
- /* Schedule connection-setup */
- isdn_net_dial();
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTD;
- for (p = dev->netdev; p; p = p->next)
- if (p->local->isdn_channel == cmd.arg)
- {
- strcpy(cmd.parm.setup.eazmsn, p->local->msn);
- isdn_command(&cmd);
- retval = 1;
- break;
- }
- break;
-
- case 2: /* For calling back, first reject incoming call ... */
- case 3: /* Interface found, but down, reject call actively */
- retval = 2;
- printk(KERN_INFO "isdn: Rejecting Call\n");
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- if (r == 3)
- break;
- /* Fall through */
- case 4:
- /* ... then start callback. */
- isdn_net_dial();
- break;
- case 5:
- /* Number would eventually match, if longer */
- retval = 3;
- break;
- }
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "ICALL: ret=%d\n", retval);
-#endif
- return retval;
- break;
- case ISDN_STAT_CINF:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (strcmp(c->parm.num, "0"))
- isdn_net_stat_callback(i, c);
- isdn_tty_stat_callback(i, c);
- break;
- case ISDN_STAT_CAUSE:
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
-#endif
- printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
- dev->drvid[di], c->arg, c->parm.num);
- isdn_tty_stat_callback(i, c);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- case ISDN_STAT_DISPLAY:
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display);
-#endif
- isdn_tty_stat_callback(i, c);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- case ISDN_STAT_DCONN:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- /* Find any net-device, waiting for D-channel setup */
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- /* Find any ttyI, waiting for D-channel setup */
- if (isdn_tty_stat_callback(i, c)) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTB;
- isdn_command(&cmd);
- break;
- }
- break;
- case ISDN_STAT_DHUP:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->online &= ~(1 << (c->arg));
- isdn_info_update();
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- if (isdn_tty_stat_callback(i, c))
- break;
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- break;
- case ISDN_STAT_BCONN:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
-#endif
- /* Signal B-channel-connect to network-devices */
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->online |= (1 << (c->arg));
- isdn_info_update();
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_BHUP:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->online &= ~(1 << (c->arg));
- isdn_info_update();
-#ifdef CONFIG_ISDN_X25
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c))
- break;
-#endif
- isdn_v110_stat_callback(i, c);
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_NODCH:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (isdn_net_stat_callback(i, c))
- break;
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_ADDCH:
- spin_lock_irqsave(&dev->lock, flags);
- if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -1;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_info_update();
- break;
- case ISDN_STAT_DISCH:
- spin_lock_irqsave(&dev->lock, flags);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if ((dev->drvmap[i] == di) &&
- (dev->chanmap[i] == c->arg)) {
- if (c->parm.num[0])
- dev->usage[i] &= ~ISDN_USAGE_DISABLED;
- else
- if (USG_NONE(dev->usage[i])) {
- dev->usage[i] |= ISDN_USAGE_DISABLED;
- }
- else
- retval = -1;
- break;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_info_update();
- break;
- case ISDN_STAT_UNLOAD:
- while (dev->drv[di]->locks > 0) {
- isdn_unlock_driver(dev->drv[di]);
- }
- spin_lock_irqsave(&dev->lock, flags);
- isdn_tty_stat_callback(i, c);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di) {
- dev->drvmap[i] = -1;
- dev->chanmap[i] = -1;
- dev->usage[i] &= ~ISDN_USAGE_DISABLED;
- }
- dev->drivers--;
- dev->channels -= dev->drv[di]->channels;
- kfree(dev->drv[di]->rcverr);
- kfree(dev->drv[di]->rcvcount);
- for (i = 0; i < dev->drv[di]->channels; i++)
- skb_queue_purge(&dev->drv[di]->rpqueue[i]);
- kfree(dev->drv[di]->rpqueue);
- kfree(dev->drv[di]->rcv_waitq);
- kfree(dev->drv[di]);
- dev->drv[di] = NULL;
- dev->drvid[di][0] = '\0';
- isdn_info_update();
- set_global_features();
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- case ISDN_STAT_L1ERR:
- break;
- case CAPI_PUT_MESSAGE:
- return (isdn_capi_rec_hl_msg(&c->parm.cmsg));
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_STAT_FAXIND:
- isdn_tty_stat_callback(i, c);
- break;
-#endif
-#ifdef CONFIG_ISDN_AUDIO
- case ISDN_STAT_AUDIO:
- isdn_tty_stat_callback(i, c);
- break;
-#endif
-#ifdef CONFIG_ISDN_DIVERSION
- case ISDN_STAT_PROT:
- case ISDN_STAT_REDIR:
- if (divert_if)
- return (divert_if->stat_callback(c));
-#endif /* CONFIG_ISDN_DIVERSION */
- /* fall through */
- default:
- return -1;
- }
- return 0;
-}
-
-/*
- * Get integer from char-pointer, set pointer to end of number
- */
-int
-isdn_getnum(char **p)
-{
- int v = -1;
-
- while (*p[0] >= '0' && *p[0] <= '9')
- v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0');
- return v;
-}
-
-#define DLE 0x10
-
-/*
- * isdn_readbchan() tries to get data from the read-queue.
- * It MUST be called with interrupts off.
- *
- * Be aware that this is not an atomic operation when sleep != 0, even though
- * interrupts are turned off! Well, like that we are currently only called
- * on behalf of a read system call on raw device files (which are documented
- * to be dangerous and for debugging purpose only). The inode semaphore
- * takes care that this is not called for the same minor device number while
- * we are sleeping, but access is not serialized against simultaneous read()
- * from the corresponding ttyI device. Can other ugly events, like changes
- * of the mapping (di,ch)<->minor, happen during the sleep? --he
- */
-int
-isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue_head_t *sleep)
-{
- int count;
- int count_pull;
- int count_put;
- int dflag;
- struct sk_buff *skb;
- u_char *cp;
-
- if (!dev->drv[di])
- return 0;
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
- if (sleep)
- wait_event_interruptible(*sleep,
- !skb_queue_empty(&dev->drv[di]->rpqueue[channel]));
- else
- return 0;
- }
- if (len > dev->drv[di]->rcvcount[channel])
- len = dev->drv[di]->rcvcount[channel];
- cp = buf;
- count = 0;
- while (len) {
- if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
- break;
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_LOCK(skb))
- break;
- ISDN_AUDIO_SKB_LOCK(skb) = 1;
- if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
- char *p = skb->data;
- unsigned long DLEmask = (1 << channel);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (len > 0)) {
- len--;
- if (dev->drv[di]->DLEflag & DLEmask) {
- *cp++ = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } else {
- *cp++ = *p;
- if (*p == DLE) {
- dev->drv[di]->DLEflag |= DLEmask;
- (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
- }
- p++;
- count_pull++;
- }
- count_put++;
- }
- if (count_pull >= skb->len)
- dflag = 1;
- } else {
-#endif
- /* No DLE's in buff, so simply copy it */
- dflag = 1;
- if ((count_pull = skb->len) > len) {
- count_pull = len;
- dflag = 0;
- }
- count_put = count_pull;
- skb_copy_from_linear_data(skb, cp, count_put);
- cp += count_put;
- len -= count_put;
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- count += count_put;
- if (fp) {
- memset(fp, 0, count_put);
- fp += count_put;
- }
- if (dflag) {
- /* We got all the data in this buff.
- * Now we can dequeue it.
- */
- if (fp)
- *(fp - 1) = 0xff;
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- dev_kfree_skb(skb);
- } else {
- /* Not yet emptied this buff, so it
- * must stay in the queue, for further calls
- * but we pull off the data we got until now.
- */
- skb_pull(skb, count_pull);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
- dev->drv[di]->rcvcount[channel] -= count_put;
- }
- return count;
-}
-
-/*
- * isdn_readbchan_tty() tries to get data from the read-queue.
- * It MUST be called with interrupts off.
- *
- * Be aware that this is not an atomic operation when sleep != 0, even though
- * interrupts are turned off! Well, like that we are currently only called
- * on behalf of a read system call on raw device files (which are documented
- * to be dangerous and for debugging purpose only). The inode semaphore
- * takes care that this is not called for the same minor device number while
- * we are sleeping, but access is not serialized against simultaneous read()
- * from the corresponding ttyI device. Can other ugly events, like changes
- * of the mapping (di,ch)<->minor, happen during the sleep? --he
- */
-int
-isdn_readbchan_tty(int di, int channel, struct tty_port *port, int cisco_hack)
-{
- int count;
- int count_pull;
- int count_put;
- int dflag;
- struct sk_buff *skb;
- char last = 0;
- int len;
-
- if (!dev->drv[di])
- return 0;
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
- return 0;
-
- len = tty_buffer_request_room(port, dev->drv[di]->rcvcount[channel]);
- if (len == 0)
- return len;
-
- count = 0;
- while (len) {
- if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
- break;
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_LOCK(skb))
- break;
- ISDN_AUDIO_SKB_LOCK(skb) = 1;
- if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) {
- char *p = skb->data;
- unsigned long DLEmask = (1 << channel);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (len > 0)) {
- /* push every character but the last to the tty buffer directly */
- if (count_put)
- tty_insert_flip_char(port, last, TTY_NORMAL);
- len--;
- if (dev->drv[di]->DLEflag & DLEmask) {
- last = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } else {
- last = *p;
- if (last == DLE) {
- dev->drv[di]->DLEflag |= DLEmask;
- (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
- }
- p++;
- count_pull++;
- }
- count_put++;
- }
- if (count_pull >= skb->len)
- dflag = 1;
- } else {
-#endif
- /* No DLE's in buff, so simply copy it */
- dflag = 1;
- if ((count_pull = skb->len) > len) {
- count_pull = len;
- dflag = 0;
- }
- count_put = count_pull;
- if (count_put > 1)
- tty_insert_flip_string(port, skb->data, count_put - 1);
- last = skb->data[count_put - 1];
- len -= count_put;
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- count += count_put;
- if (dflag) {
- /* We got all the data in this buff.
- * Now we can dequeue it.
- */
- if (cisco_hack)
- tty_insert_flip_char(port, last, 0xFF);
- else
- tty_insert_flip_char(port, last, TTY_NORMAL);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- dev_kfree_skb(skb);
- } else {
- tty_insert_flip_char(port, last, TTY_NORMAL);
- /* Not yet emptied this buff, so it
- * must stay in the queue, for further calls
- * but we pull off the data we got until now.
- */
- skb_pull(skb, count_pull);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
- dev->drv[di]->rcvcount[channel] -= count_put;
- }
- return count;
-}
-
-
-static inline int
-isdn_minor2drv(int minor)
-{
- return (dev->drvmap[minor]);
-}
-
-static inline int
-isdn_minor2chan(int minor)
-{
- return (dev->chanmap[minor]);
-}
-
-static char *
-isdn_statstr(void)
-{
- static char istatbuf[2048];
- char *p;
- int i;
-
- sprintf(istatbuf, "idmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nchmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->chanmap[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\ndrmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->drvmap[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nusage:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->usage[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nflags:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (dev->drv[i]) {
- sprintf(p, "%ld ", dev->drv[i]->online);
- p = istatbuf + strlen(istatbuf);
- } else {
- sprintf(p, "? ");
- p = istatbuf + strlen(istatbuf);
- }
- }
- sprintf(p, "\nphone:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%s ", dev->num[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\n");
- return istatbuf;
-}
-
-/* Module interface-code */
-
-void
-isdn_info_update(void)
-{
- infostruct *p = dev->infochain;
-
- while (p) {
- *(p->private) = 1;
- p = (infostruct *) p->next;
- }
- wake_up_interruptible(&(dev->info_waitq));
-}
-
-static ssize_t
-isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off)
-{
- uint minor = iminor(file_inode(file));
- int len = 0;
- int drvidx;
- int chidx;
- int retval;
- char *p;
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- if (!file->private_data) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
- }
- wait_event_interruptible(dev->info_waitq,
- file->private_data);
- }
- p = isdn_statstr();
- file->private_data = NULL;
- if ((len = strlen(p)) <= count) {
- if (copy_to_user(buf, p, len)) {
- retval = -EFAULT;
- goto out;
- }
- *off += len;
- retval = len;
- goto out;
- }
- retval = 0;
- goto out;
- }
- if (!dev->drivers) {
- retval = -ENODEV;
- goto out;
- }
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
- retval = -ENODEV;
- goto out;
- }
- chidx = isdn_minor2chan(minor);
- if (!(p = kmalloc(count, GFP_KERNEL))) {
- retval = -ENOMEM;
- goto out;
- }
- len = isdn_readbchan(drvidx, chidx, p, NULL, count,
- &dev->drv[drvidx]->rcv_waitq[chidx]);
- *off += len;
- if (copy_to_user(buf, p, len))
- len = -EFAULT;
- kfree(p);
- retval = len;
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!dev->drv[drvidx]->stavail) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
- }
- wait_event_interruptible(dev->drv[drvidx]->st_waitq,
- dev->drv[drvidx]->stavail);
- }
- if (dev->drv[drvidx]->interface->readstat) {
- if (count > dev->drv[drvidx]->stavail)
- count = dev->drv[drvidx]->stavail;
- len = dev->drv[drvidx]->interface->readstat(buf, count,
- drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
- if (len < 0) {
- retval = len;
- goto out;
- }
- } else {
- len = 0;
- }
- if (len)
- dev->drv[drvidx]->stavail -= len;
- else
- dev->drv[drvidx]->stavail = 0;
- *off += len;
- retval = len;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
- goto out;
- }
-#endif
- retval = -ENODEV;
-out:
- mutex_unlock(&isdn_mutex);
- return retval;
-}
-
-static ssize_t
-isdn_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
-{
- uint minor = iminor(file_inode(file));
- int drvidx;
- int chidx;
- int retval;
-
- if (minor == ISDN_MINOR_STATUS)
- return -EPERM;
- if (!dev->drivers)
- return -ENODEV;
-
- mutex_lock(&isdn_mutex);
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
- retval = -ENODEV;
- goto out;
- }
- chidx = isdn_minor2chan(minor);
- wait_event_interruptible(dev->drv[drvidx]->snd_waitq[chidx],
- (retval = isdn_writebuf_stub(drvidx, chidx, buf, count)));
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- /*
- * We want to use the isdnctrl device to load the firmware
- *
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
- */
- if (dev->drv[drvidx]->interface->writecmd)
- retval = dev->drv[drvidx]->interface->
- writecmd(buf, count, drvidx,
- isdn_minor2chan(minor - ISDN_MINOR_CTRL));
- else
- retval = count;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
- goto out;
- }
-#endif
- retval = -ENODEV;
-out:
- mutex_unlock(&isdn_mutex);
- return retval;
-}
-
-static __poll_t
-isdn_poll(struct file *file, poll_table *wait)
-{
- __poll_t mask = 0;
- unsigned int minor = iminor(file_inode(file));
- int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- poll_wait(file, &(dev->info_waitq), wait);
- /* mask = EPOLLOUT | EPOLLWRNORM; */
- if (file->private_data) {
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- goto out;
- }
- if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
- if (drvidx < 0) {
- /* driver deregistered while file open */
- mask = EPOLLHUP;
- goto out;
- }
- poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
- mask = EPOLLOUT | EPOLLWRNORM;
- if (dev->drv[drvidx]->stavail) {
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- mask = isdn_ppp_poll(file, wait);
- goto out;
- }
-#endif
- mask = EPOLLERR;
-out:
- mutex_unlock(&isdn_mutex);
- return mask;
-}
-
-
-static int
-isdn_ioctl(struct file *file, uint cmd, ulong arg)
-{
- uint minor = iminor(file_inode(file));
- isdn_ctrl c;
- int drvidx;
- int ret;
- int i;
- char __user *p;
- char *s;
- union iocpar {
- char name[10];
- char bname[22];
- isdn_ioctl_struct iocts;
- isdn_net_ioctl_phone phone;
- isdn_net_ioctl_cfg cfg;
- } iocpar;
- void __user *argp = (void __user *)arg;
-
-#define name iocpar.name
-#define bname iocpar.bname
-#define iocts iocpar.iocts
-#define phone iocpar.phone
-#define cfg iocpar.cfg
-
- if (minor == ISDN_MINOR_STATUS) {
- switch (cmd) {
- case IIOCGETDVR:
- return (TTY_DV +
- (NET_DV << 8) +
- (INF_DV << 16));
- case IIOCGETCPS:
- if (arg) {
- ulong __user *p = argp;
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- put_user(dev->ibytes[i], p++);
- put_user(dev->obytes[i], p++);
- }
- return 0;
- } else
- return -EINVAL;
- break;
- case IIOCNETGPN:
- /* Get peer phone number of a connected
- * isdn network interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- return isdn_net_getpeer(&phone, argp);
- } else
- return -EINVAL;
- default:
- return -EINVAL;
- }
- }
- if (!dev->drivers)
- return -ENODEV;
- if (minor <= ISDN_MINOR_BMAX) {
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0)
- return -ENODEV;
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- return -ENODEV;
- return 0;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
-/*
- * isdn net devices manage lots of configuration variables as linked lists.
- * Those lists must only be manipulated from user space. Some of the ioctl's
- * service routines access user space and are not atomic. Therefore, ioctl's
- * manipulating the lists and ioctl's sleeping while accessing the lists
- * are serialized by means of a semaphore.
- */
- switch (cmd) {
- case IIOCNETDWRSET:
- printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
- return (-EINVAL);
- case IIOCNETLCR:
- printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
- return -ENODEV;
- case IIOCNETAIF:
- /* Add a network-interface */
- if (arg) {
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- s = name;
- } else {
- s = NULL;
- }
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- if ((s = isdn_net_new(s, NULL))) {
- if (copy_to_user(argp, s, strlen(s) + 1)) {
- ret = -EFAULT;
- } else {
- ret = 0;
- }
- } else
- ret = -ENODEV;
- mutex_unlock(&dev->mtx);
- return ret;
- case IIOCNETASL:
- /* Add a slave to a network-interface */
- if (arg) {
- if (copy_from_user(bname, argp, sizeof(bname) - 1))
- return -EFAULT;
- bname[sizeof(bname)-1] = 0;
- } else
- return -EINVAL;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- if ((s = isdn_net_newslave(bname))) {
- if (copy_to_user(argp, s, strlen(s) + 1)) {
- ret = -EFAULT;
- } else {
- ret = 0;
- }
- } else
- ret = -ENODEV;
- mutex_unlock(&dev->mtx);
- return ret;
- case IIOCNETDIF:
- /* Delete a network-interface */
- if (arg) {
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_rm(name);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETSCF:
- /* Set configurable parameters of a network-interface */
- if (arg) {
- if (copy_from_user(&cfg, argp, sizeof(cfg)))
- return -EFAULT;
- return isdn_net_setcfg(&cfg);
- } else
- return -EINVAL;
- case IIOCNETGCF:
- /* Get configurable parameters of a network-interface */
- if (arg) {
- if (copy_from_user(&cfg, argp, sizeof(cfg)))
- return -EFAULT;
- if (!(ret = isdn_net_getcfg(&cfg))) {
- if (copy_to_user(argp, &cfg, sizeof(cfg)))
- return -EFAULT;
- }
- return ret;
- } else
- return -EINVAL;
- case IIOCNETANM:
- /* Add a phone-number to a network-interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_addphone(&phone);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETGNM:
- /* Get list of phone-numbers of a network-interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_getphones(&phone, argp);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETDNM:
- /* Delete a phone-number of a network-interface */
- if (arg) {
- if (copy_from_user(&phone, argp, sizeof(phone)))
- return -EFAULT;
- ret = mutex_lock_interruptible(&dev->mtx);
- if (ret) return ret;
- ret = isdn_net_delphone(&phone);
- mutex_unlock(&dev->mtx);
- return ret;
- } else
- return -EINVAL;
- case IIOCNETDIL:
- /* Force dialing of a network-interface */
- if (arg) {
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_net_force_dial(name);
- } else
- return -EINVAL;
-#ifdef CONFIG_ISDN_PPP
- case IIOCNETALN:
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_ppp_dial_slave(name);
- case IIOCNETDLN:
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_ppp_hangup_slave(name);
-#endif
- case IIOCNETHUP:
- /* Force hangup of a network-interface */
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, argp, sizeof(name)))
- return -EFAULT;
- return isdn_net_force_hangup(name);
- break;
- case IIOCSETVER:
- dev->net_verbose = arg;
- printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
- return 0;
- case IIOCSETGST:
- if (arg)
- dev->global_flags |= ISDN_GLOBAL_STOPPED;
- else
- dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
- printk(KERN_INFO "isdn: Global Mode %s\n",
- (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
- return 0;
- case IIOCSETBRJ:
- drvidx = -1;
- if (arg) {
- int i;
- char *p;
- if (copy_from_user(&iocts, argp,
- sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- iocts.drvid[sizeof(iocts.drvid) - 1] = 0;
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- }
- }
- if (drvidx == -1)
- return -ENODEV;
- if (iocts.arg)
- dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
- else
- dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
- return 0;
- case IIOCSIGPRF:
- dev->profd = current;
- return 0;
- break;
- case IIOCGETPRF:
- /* Get all Modem-Profiles */
- if (arg) {
- char __user *p = argp;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (copy_to_user(p, dev->mdm.info[i].emu.profile,
- ISDN_MODEM_NUMREG))
- return -EFAULT;
- p += ISDN_MODEM_NUMREG;
- if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
- return -EFAULT;
- p += ISDN_MSNLEN;
- if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
- return -EFAULT;
- p += ISDN_LMSNLEN;
- }
- return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
- } else
- return -EINVAL;
- break;
- case IIOCSETPRF:
- /* Set all Modem-Profiles */
- if (arg) {
- char __user *p = argp;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (copy_from_user(dev->mdm.info[i].emu.profile, p,
- ISDN_MODEM_NUMREG))
- return -EFAULT;
- p += ISDN_MODEM_NUMREG;
- if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
- return -EFAULT;
- p += ISDN_LMSNLEN;
- if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
- return -EFAULT;
- p += ISDN_MSNLEN;
- }
- return 0;
- } else
- return -EINVAL;
- break;
- case IIOCSETMAP:
- case IIOCGETMAP:
- /* Set/Get MSN->EAZ-Mapping for a driver */
- if (arg) {
-
- if (copy_from_user(&iocts, argp,
- sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- iocts.drvid[sizeof(iocts.drvid) - 1] = 0;
- if (strlen(iocts.drvid)) {
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- if (cmd == IIOCSETMAP) {
- int loop = 1;
-
- p = (char __user *) iocts.arg;
- i = 0;
- while (loop) {
- int j = 0;
-
- while (1) {
- get_user(bname[j], p++);
- switch (bname[j]) {
- case '\0':
- loop = 0;
- /* Fall through */
- case ',':
- bname[j] = '\0';
- strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
- j = ISDN_MSNLEN;
- break;
- default:
- j++;
- }
- if (j >= ISDN_MSNLEN)
- break;
- }
- if (++i > 9)
- break;
- }
- } else {
- p = (char __user *) iocts.arg;
- for (i = 0; i < 10; i++) {
- snprintf(bname, sizeof(bname), "%s%s",
- strlen(dev->drv[drvidx]->msn2eaz[i]) ?
- dev->drv[drvidx]->msn2eaz[i] : "_",
- (i < 9) ? "," : "\0");
- if (copy_to_user(p, bname, strlen(bname) + 1))
- return -EFAULT;
- p += strlen(bname);
- }
- }
- return 0;
- } else
- return -EINVAL;
- case IIOCDBGVAR:
- return -EINVAL;
- default:
- if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
- cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
- else
- return -EINVAL;
- if (arg) {
- int i;
- char *p;
- if (copy_from_user(&iocts, argp, sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- iocts.drvid[sizeof(iocts.drvid) - 1] = 0;
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- c.driver = drvidx;
- c.command = ISDN_CMD_IOCTL;
- c.arg = cmd;
- memcpy(c.parm.num, &iocts.arg, sizeof(ulong));
- ret = isdn_command(&c);
- memcpy(&iocts.arg, c.parm.num, sizeof(ulong));
- if (copy_to_user(argp, &iocts, sizeof(isdn_ioctl_struct)))
- return -EFAULT;
- return ret;
- } else
- return -EINVAL;
- }
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
-#endif
- return -ENODEV;
-
-#undef name
-#undef bname
-#undef iocts
-#undef phone
-#undef cfg
-}
-
-static long
-isdn_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- mutex_lock(&isdn_mutex);
- ret = isdn_ioctl(file, cmd, arg);
- mutex_unlock(&isdn_mutex);
-
- return ret;
-}
-
-/*
- * Open the device code.
- */
-static int
-isdn_open(struct inode *ino, struct file *filep)
-{
- uint minor = iminor(ino);
- int drvidx;
- int chidx;
- int retval = -ENODEV;
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- infostruct *p;
-
- if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
- p->next = (char *) dev->infochain;
- p->private = (char *) &(filep->private_data);
- dev->infochain = p;
- /* At opening we allow a single update */
- filep->private_data = (char *) 1;
- retval = 0;
- goto out;
- } else {
- retval = -ENOMEM;
- goto out;
- }
- }
- if (!dev->channels)
- goto out;
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0)
- goto out;
- chidx = isdn_minor2chan(minor);
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
- goto out;
- if (!(dev->drv[drvidx]->online & (1 << chidx)))
- goto out;
- isdn_lock_drivers();
- retval = 0;
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0)
- goto out;
- isdn_lock_drivers();
- retval = 0;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
- if (retval == 0)
- isdn_lock_drivers();
- goto out;
- }
-#endif
-out:
- nonseekable_open(ino, filep);
- mutex_unlock(&isdn_mutex);
- return retval;
-}
-
-static int
-isdn_close(struct inode *ino, struct file *filep)
-{
- uint minor = iminor(ino);
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- infostruct *p = dev->infochain;
- infostruct *q = NULL;
-
- while (p) {
- if (p->private == (char *) &(filep->private_data)) {
- if (q)
- q->next = p->next;
- else
- dev->infochain = (infostruct *) (p->next);
- kfree(p);
- goto out;
- }
- q = p;
- p = (infostruct *) (p->next);
- }
- printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
- goto out;
- }
- isdn_unlock_drivers();
- if (minor <= ISDN_MINOR_BMAX)
- goto out;
- if (minor <= ISDN_MINOR_CTRLMAX) {
- if (dev->profd == current)
- dev->profd = NULL;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
-#endif
-
-out:
- mutex_unlock(&isdn_mutex);
- return 0;
-}
-
-static const struct file_operations isdn_fops =
-{
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = isdn_read,
- .write = isdn_write,
- .poll = isdn_poll,
- .unlocked_ioctl = isdn_unlocked_ioctl,
- .open = isdn_open,
- .release = isdn_close,
-};
-
-char *
-isdn_map_eaz2msn(char *msn, int di)
-{
- isdn_driver_t *this = dev->drv[di];
- int i;
-
- if (strlen(msn) == 1) {
- i = msn[0] - '0';
- if ((i >= 0) && (i <= 9))
- if (strlen(this->msn2eaz[i]))
- return (this->msn2eaz[i]);
- }
- return (msn);
-}
-
-/*
- * Find an unused ISDN-channel, whose feature-flags match the
- * given L2- and L3-protocols.
- */
-#define L2V (~(ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038))
-
-/*
- * This function must be called with holding the dev->lock.
- */
-int
-isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
- , int pre_chan, char *msn)
-{
- int i;
- ulong features;
- ulong vfeatures;
-
- features = ((1 << l2_proto) | (0x10000 << l3_proto));
- vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) &
- ~(ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038));
- /* If Layer-2 protocol is V.110, accept drivers with
- * transparent feature even if these don't support V.110
- * because we can emulate this in linklevel.
- */
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_NONE(dev->usage[i]) &&
- (dev->drvmap[i] != -1)) {
- int d = dev->drvmap[i];
- if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
- ((pre_dev != d) || (pre_chan != dev->chanmap[i])))
- continue;
- if (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
- continue;
- if (dev->usage[i] & ISDN_USAGE_DISABLED)
- continue; /* usage not allowed */
- if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
- if (((dev->drv[d]->interface->features & features) == features) ||
- (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
- (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
- if ((pre_dev < 0) || (pre_chan < 0)) {
- dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[i] |= usage;
- isdn_info_update();
- return i;
- } else {
- if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) {
- dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[i] |= usage;
- isdn_info_update();
- return i;
- }
- }
- }
- }
- }
- return -1;
-}
-
-/*
- * Set state of ISDN-channel to 'unused'
- */
-void
-isdn_free_channel(int di, int ch, int usage)
-{
- int i;
-
- if ((di < 0) || (ch < 0)) {
- printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n",
- __func__, di, ch);
- return;
- }
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) &&
- (dev->drvmap[i] == di) &&
- (dev->chanmap[i] == ch)) {
- dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
- strcpy(dev->num[i], "???");
- dev->ibytes[i] = 0;
- dev->obytes[i] = 0;
-// 20.10.99 JIM, try to reinitialize v110 !
- dev->v110emu[i] = 0;
- atomic_set(&(dev->v110use[i]), 0);
- isdn_v110_close(dev->v110[i]);
- dev->v110[i] = NULL;
-// 20.10.99 JIM, try to reinitialize v110 !
- isdn_info_update();
- if (dev->drv[di])
- skb_queue_purge(&dev->drv[di]->rpqueue[ch]);
- }
-}
-
-/*
- * Cancel Exclusive-Flag for ISDN-channel
- */
-void
-isdn_unexclusive_channel(int di, int ch)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if ((dev->drvmap[i] == di) &&
- (dev->chanmap[i] == ch)) {
- dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE;
- isdn_info_update();
- return;
- }
-}
-
-/*
- * writebuf replacement for SKB_ABLE drivers
- */
-static int
-isdn_writebuf_stub(int drvidx, int chan, const u_char __user *buf, int len)
-{
- int ret;
- int hl = dev->drv[drvidx]->interface->hl_hdrlen;
- struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
-
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, hl);
- if (copy_from_user(skb_put(skb, len), buf, len)) {
- dev_kfree_skb(skb);
- return -EFAULT;
- }
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
- if (ret <= 0)
- dev_kfree_skb(skb);
- if (ret > 0)
- dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
- return ret;
-}
-
-/*
- * Return: length of data on success, -ERRcode on failure.
- */
-int
-isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
-{
- int ret;
- struct sk_buff *nskb = NULL;
- int v110_ret = skb->len;
- int idx = isdn_dc2minor(drvidx, chan);
-
- if (dev->v110[idx]) {
- atomic_inc(&dev->v110use[idx]);
- nskb = isdn_v110_encode(dev->v110[idx], skb);
- atomic_dec(&dev->v110use[idx]);
- if (!nskb)
- return 0;
- v110_ret = *((int *)nskb->data);
- skb_pull(nskb, sizeof(int));
- if (!nskb->len) {
- dev_kfree_skb(nskb);
- return v110_ret;
- }
- /* V.110 must always be acknowledged */
- ack = 1;
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
- } else {
- int hl = dev->drv[drvidx]->interface->hl_hdrlen;
-
- if (skb_headroom(skb) < hl) {
- /*
- * This should only occur when new HL driver with
- * increased hl_hdrlen was loaded after netdevice
- * was created and connected to the new driver.
- *
- * The V.110 branch (re-allocates on its own) does
- * not need this
- */
- struct sk_buff *skb_tmp;
-
- skb_tmp = skb_realloc_headroom(skb, hl);
- printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed");
- if (!skb_tmp) return -ENOMEM; /* 0 better? */
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp);
- if (ret > 0) {
- dev_kfree_skb(skb);
- } else {
- dev_kfree_skb(skb_tmp);
- }
- } else {
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
- }
- }
- if (ret > 0) {
- dev->obytes[idx] += ret;
- if (dev->v110[idx]) {
- atomic_inc(&dev->v110use[idx]);
- dev->v110[idx]->skbuser++;
- atomic_dec(&dev->v110use[idx]);
- /* For V.110 return unencoded data length */
- ret = v110_ret;
- /* if the complete frame was send we free the skb;
- if not upper function will requeue the skb */
- if (ret == skb->len)
- dev_kfree_skb(skb);
- }
- } else
- if (dev->v110[idx])
- dev_kfree_skb(nskb);
- return ret;
-}
-
-static int
-isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
-{
- int j, k, m;
-
- init_waitqueue_head(&d->st_waitq);
- if (d->flags & DRV_FLAG_RUNNING)
- return -1;
- if (n < 1) return 0;
-
- m = (adding) ? d->channels + n : n;
-
- if (dev->channels + n > ISDN_MAX_CHANNELS) {
- printk(KERN_WARNING "register_isdn: Max. %d channels supported\n",
- ISDN_MAX_CHANNELS);
- return -1;
- }
-
- if ((adding) && (d->rcverr))
- kfree(d->rcverr);
- if (!(d->rcverr = kcalloc(m, sizeof(int), GFP_ATOMIC))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
- return -1;
- }
-
- if ((adding) && (d->rcvcount))
- kfree(d->rcvcount);
- if (!(d->rcvcount = kcalloc(m, sizeof(int), GFP_ATOMIC))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
- if (!adding)
- kfree(d->rcverr);
- return -1;
- }
-
- if ((adding) && (d->rpqueue)) {
- for (j = 0; j < d->channels; j++)
- skb_queue_purge(&d->rpqueue[j]);
- kfree(d->rpqueue);
- }
- d->rpqueue = kmalloc_array(m, sizeof(struct sk_buff_head), GFP_ATOMIC);
- if (!d->rpqueue) {
- printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
- if (!adding) {
- kfree(d->rcvcount);
- kfree(d->rcverr);
- }
- return -1;
- }
- for (j = 0; j < m; j++) {
- skb_queue_head_init(&d->rpqueue[j]);
- }
-
- if ((adding) && (d->rcv_waitq))
- kfree(d->rcv_waitq);
- d->rcv_waitq = kmalloc(array3_size(sizeof(wait_queue_head_t), 2, m),
- GFP_ATOMIC);
- if (!d->rcv_waitq) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
- if (!adding) {
- kfree(d->rpqueue);
- kfree(d->rcvcount);
- kfree(d->rcverr);
- }
- return -1;
- }
- d->snd_waitq = d->rcv_waitq + m;
- for (j = 0; j < m; j++) {
- init_waitqueue_head(&d->rcv_waitq[j]);
- init_waitqueue_head(&d->snd_waitq[j]);
- }
-
- dev->channels += n;
- for (j = d->channels; j < m; j++)
- for (k = 0; k < ISDN_MAX_CHANNELS; k++)
- if (dev->chanmap[k] < 0) {
- dev->chanmap[k] = j;
- dev->drvmap[k] = drvidx;
- break;
- }
- d->channels = m;
- return 0;
-}
-
-/*
- * Low-level-driver registration
- */
-
-static void
-set_global_features(void)
-{
- int drvidx;
-
- dev->global_features = 0;
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
- if (!dev->drv[drvidx])
- continue;
- if (dev->drv[drvidx]->interface)
- dev->global_features |= dev->drv[drvidx]->interface->features;
- }
-}
-
-#ifdef CONFIG_ISDN_DIVERSION
-
-static char *map_drvname(int di)
-{
- if ((di < 0) || (di >= ISDN_MAX_DRIVERS))
- return (NULL);
- return (dev->drvid[di]); /* driver name */
-} /* map_drvname */
-
-static int map_namedrv(char *id)
-{ int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- { if (!strcmp(dev->drvid[i], id))
- return (i);
- }
- return (-1);
-} /* map_namedrv */
-
-int DIVERT_REG_NAME(isdn_divert_if *i_div)
-{
- if (i_div->if_magic != DIVERT_IF_MAGIC)
- return (DIVERT_VER_ERR);
- switch (i_div->cmd)
- {
- case DIVERT_CMD_REL:
- if (divert_if != i_div)
- return (DIVERT_REL_ERR);
- divert_if = NULL; /* free interface */
- return (DIVERT_NO_ERR);
-
- case DIVERT_CMD_REG:
- if (divert_if)
- return (DIVERT_REG_ERR);
- i_div->ll_cmd = isdn_command; /* set command function */
- i_div->drv_to_name = map_drvname;
- i_div->name_to_drv = map_namedrv;
- divert_if = i_div; /* remember interface */
- return (DIVERT_NO_ERR);
-
- default:
- return (DIVERT_CMD_ERR);
- }
-} /* DIVERT_REG_NAME */
-
-EXPORT_SYMBOL(DIVERT_REG_NAME);
-
-#endif /* CONFIG_ISDN_DIVERSION */
-
-
-EXPORT_SYMBOL(register_isdn);
-#ifdef CONFIG_ISDN_PPP
-EXPORT_SYMBOL(isdn_ppp_register_compressor);
-EXPORT_SYMBOL(isdn_ppp_unregister_compressor);
-#endif
-
-int
-register_isdn(isdn_if *i)
-{
- isdn_driver_t *d;
- int j;
- ulong flags;
- int drvidx;
-
- if (dev->drivers >= ISDN_MAX_DRIVERS) {
- printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n",
- ISDN_MAX_DRIVERS);
- return 0;
- }
- if (!i->writebuf_skb) {
- printk(KERN_WARNING "register_isdn: No write routine given.\n");
- return 0;
- }
- if (!(d = kzalloc(sizeof(isdn_driver_t), GFP_KERNEL))) {
- printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
- return 0;
- }
-
- d->maxbufsize = i->maxbufsize;
- d->pktcount = 0;
- d->stavail = 0;
- d->flags = DRV_FLAG_LOADED;
- d->online = 0;
- d->interface = i;
- d->channels = 0;
- spin_lock_irqsave(&dev->lock, flags);
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
- if (!dev->drv[drvidx])
- break;
- if (isdn_add_channels(d, drvidx, i->channels, 0)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- kfree(d);
- return 0;
- }
- i->channels = drvidx;
- i->rcvcallb_skb = isdn_receive_skb_callback;
- i->statcallb = isdn_status_callback;
- if (!strlen(i->id))
- sprintf(i->id, "line%d", drvidx);
- for (j = 0; j < drvidx; j++)
- if (!strcmp(i->id, dev->drvid[j]))
- sprintf(i->id, "line%d", drvidx);
- dev->drv[drvidx] = d;
- strcpy(dev->drvid[drvidx], i->id);
- isdn_info_update();
- dev->drivers++;
- set_global_features();
- spin_unlock_irqrestore(&dev->lock, flags);
- return 1;
-}
-
-/*
-*****************************************************************************
-* And now the modules code.
-*****************************************************************************
-*/
-
-static char *
-isdn_getrev(const char *revision)
-{
- char *rev;
- char *p;
-
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
-}
-
-/*
- * Allocate and initialize all data, register modem-devices
- */
-static int __init isdn_init(void)
-{
- int i;
- char tmprev[50];
-
- dev = vzalloc(sizeof(isdn_dev));
- if (!dev) {
- printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
- return -EIO;
- }
- timer_setup(&dev->timer, isdn_timer_funct, 0);
- spin_lock_init(&dev->lock);
- spin_lock_init(&dev->timerlock);
-#ifdef MODULE
- dev->owner = THIS_MODULE;
-#endif
- mutex_init(&dev->mtx);
- init_waitqueue_head(&dev->info_waitq);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- dev->drvmap[i] = -1;
- dev->chanmap[i] = -1;
- dev->m_idx[i] = -1;
- strcpy(dev->num[i], "???");
- }
- if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
- printk(KERN_WARNING "isdn: Could not register control devices\n");
- vfree(dev);
- return -EIO;
- }
- if ((isdn_tty_modem_init()) < 0) {
- printk(KERN_WARNING "isdn: Could not register tty devices\n");
- vfree(dev);
- unregister_chrdev(ISDN_MAJOR, "isdn");
- return -EIO;
- }
-#ifdef CONFIG_ISDN_PPP
- if (isdn_ppp_init() < 0) {
- printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n");
- isdn_tty_exit();
- unregister_chrdev(ISDN_MAJOR, "isdn");
- vfree(dev);
- return -EIO;
- }
-#endif /* CONFIG_ISDN_PPP */
-
- strcpy(tmprev, isdn_revision);
- printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_net_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_ppp_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_audio_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_v110_revision);
- printk("%s", isdn_getrev(tmprev));
-
-#ifdef MODULE
- printk(" loaded\n");
-#else
- printk("\n");
-#endif
- isdn_info_update();
- return 0;
-}
-
-/*
- * Unload module
- */
-static void __exit isdn_exit(void)
-{
-#ifdef CONFIG_ISDN_PPP
- isdn_ppp_cleanup();
-#endif
- if (isdn_net_rmall() < 0) {
- printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n");
- return;
- }
- isdn_tty_exit();
- unregister_chrdev(ISDN_MAJOR, "isdn");
- del_timer_sync(&dev->timer);
- /* call vfree with interrupts enabled, else it will hang */
- vfree(dev);
- printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
-}
-
-module_init(isdn_init);
-module_exit(isdn_exit);
diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h
deleted file mode 100644
index 2260ef07ab9c..000000000000
--- a/drivers/isdn/i4l/isdn_common.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* $Id: isdn_common.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem
- * common used functions and debugging-switches (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#undef ISDN_DEBUG_MODEM_OPEN
-#undef ISDN_DEBUG_MODEM_IOCTL
-#undef ISDN_DEBUG_MODEM_WAITSENT
-#undef ISDN_DEBUG_MODEM_HUP
-#undef ISDN_DEBUG_MODEM_ICALL
-#undef ISDN_DEBUG_MODEM_DUMP
-#undef ISDN_DEBUG_MODEM_VOICE
-#undef ISDN_DEBUG_AT
-#undef ISDN_DEBUG_NET_DUMP
-#undef ISDN_DEBUG_NET_DIAL
-#undef ISDN_DEBUG_NET_ICALL
-
-/* Prototypes */
-extern void isdn_lock_drivers(void);
-extern void isdn_unlock_drivers(void);
-extern void isdn_free_channel(int di, int ch, int usage);
-extern void isdn_all_eaz(int di, int ch);
-extern int isdn_command(isdn_ctrl *);
-extern int isdn_dc2minor(int di, int ch);
-extern void isdn_info_update(void);
-extern char *isdn_map_eaz2msn(char *msn, int di);
-extern void isdn_timer_ctrl(int tf, int onoff);
-extern void isdn_unexclusive_channel(int di, int ch);
-extern int isdn_getnum(char **);
-extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
-extern int isdn_readbchan_tty(int, int, struct tty_port *, int);
-extern int isdn_get_free_channel(int, int, int, int, int, char *);
-extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
-extern int register_isdn(isdn_if *i);
-extern int isdn_msncmp(const char *, const char *);
-#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-extern void isdn_dumppkt(char *, u_char *, int, int);
-#endif
diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
deleted file mode 100644
index 336523ec077c..000000000000
--- a/drivers/isdn/i4l/isdn_concap.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/* $Id: isdn_concap.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, protocol encapsulation
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
- * stuff goes here. Stuff that depends only on the concap protocol goes to
- * another -- protocol specific -- source file.
- *
- */
-
-
-#include <linux/isdn.h>
-#include "isdn_x25iface.h"
-#include "isdn_net.h"
-#include <linux/concap.h>
-#include "isdn_concap.h"
-
-
-/* The following set of device service operations are for encapsulation
- protocols that require for reliable datalink semantics. That means:
-
- - before any data is to be submitted the connection must explicitly
- be set up.
- - after the successful set up of the connection is signalled the
- connection is considered to be reliably up.
-
- Auto-dialing ist not compatible with this requirements. Thus, auto-dialing
- is completely bypassed.
-
- It might be possible to implement a (non standardized) datalink protocol
- that provides a reliable data link service while using some auto dialing
- mechanism. Such a protocol would need an auxiliary channel (i.e. user-user-
- signaling on the D-channel) while the B-channel is down.
-*/
-
-
-static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
-{
- struct net_device *ndev = concap->net_dev;
- isdn_net_dev *nd = ((isdn_net_local *) netdev_priv(ndev))->netdev;
- isdn_net_local *lp = isdn_net_get_locked_lp(nd);
-
- IX25DEBUG("isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
- if (!lp) {
- IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 1);
- return 1;
- }
- lp->huptimer = 0;
- isdn_net_writebuf_skb(lp, skb);
- spin_unlock_bh(&lp->xmit_lock);
- IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 0);
- return 0;
-}
-
-
-static int isdn_concap_dl_connect_req(struct concap_proto *concap)
-{
- struct net_device *ndev = concap->net_dev;
- isdn_net_local *lp = netdev_priv(ndev);
- int ret;
- IX25DEBUG("isdn_concap_dl_connect_req: %s \n", ndev->name);
-
- /* dial ... */
- ret = isdn_net_dial_req(lp);
- if (ret) IX25DEBUG("dialing failed\n");
- return ret;
-}
-
-static int isdn_concap_dl_disconn_req(struct concap_proto *concap)
-{
- IX25DEBUG("isdn_concap_dl_disconn_req: %s \n", concap->net_dev->name);
-
- isdn_net_hangup(concap->net_dev);
- return 0;
-}
-
-struct concap_device_ops isdn_concap_reliable_dl_dops = {
- .data_req = &isdn_concap_dl_data_req,
- .connect_req = &isdn_concap_dl_connect_req,
- .disconn_req = &isdn_concap_dl_disconn_req
-};
-
-/* The following should better go into a dedicated source file such that
- this sourcefile does not need to include any protocol specific header
- files. For now:
-*/
-struct concap_proto *isdn_concap_new(int encap)
-{
- switch (encap) {
- case ISDN_NET_ENCAP_X25IFACE:
- return isdn_x25iface_proto_new();
- }
- return NULL;
-}
diff --git a/drivers/isdn/i4l/isdn_concap.h b/drivers/isdn/i4l/isdn_concap.h
deleted file mode 100644
index cd7e3ba74e25..000000000000
--- a/drivers/isdn/i4l/isdn_concap.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* $Id: isdn_concap.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, protocol encapsulation
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-extern struct concap_device_ops isdn_concap_reliable_dl_dops;
-extern struct concap_proto *isdn_concap_new(int);
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
deleted file mode 100644
index c138f66f2659..000000000000
--- a/drivers/isdn/i4l/isdn_net.c
+++ /dev/null
@@ -1,3198 +0,0 @@
-/* $Id: isdn_net.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, network interfaces and related functions (linklevel).
- *
- * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02
- * guy@traverse.com.au
- * Outgoing calls - looks for a 'V' in first char of dialed number
- * Incoming calls - checks first character of eaz as follows:
- * Numeric - accept DATA only - original functionality
- * 'V' - accept VOICE (DOV) only
- * 'B' - accept BOTH DATA and DOV types
- *
- * Jan 2001: fix CISCO HDLC Bjoern A. Zeeb <i4l@zabbadoz.net>
- * for info on the protocol, see
- * http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
- */
-
-#include <linux/isdn.h>
-#include <linux/slab.h>
-#include <net/arp.h>
-#include <net/dst.h>
-#include <net/pkt_sched.h>
-#include <linux/inetdevice.h>
-#include "isdn_common.h"
-#include "isdn_net.h"
-#ifdef CONFIG_ISDN_PPP
-#include "isdn_ppp.h"
-#endif
-#ifdef CONFIG_ISDN_X25
-#include <linux/concap.h>
-#include "isdn_concap.h"
-#endif
-
-
-/*
- * Outline of new tbusy handling:
- *
- * Old method, roughly spoken, consisted of setting tbusy when entering
- * isdn_net_start_xmit() and at several other locations and clearing
- * it from isdn_net_start_xmit() thread when sending was successful.
- *
- * With 2.3.x multithreaded network core, to prevent problems, tbusy should
- * only be set by the isdn_net_start_xmit() thread and only when a tx-busy
- * condition is detected. Other threads (in particular isdn_net_stat_callb())
- * are only allowed to clear tbusy.
- *
- * -HE
- */
-
-/*
- * About SOFTNET:
- * Most of the changes were pretty obvious and basically done by HE already.
- *
- * One problem of the isdn net device code is that it uses struct net_device
- * for masters and slaves. However, only master interface are registered to
- * the network layer, and therefore, it only makes sense to call netif_*
- * functions on them.
- *
- * --KG
- */
-
-/*
- * Find out if the netdevice has been ifup-ed yet.
- * For slaves, look at the corresponding master.
- */
-static __inline__ int isdn_net_device_started(isdn_net_dev *n)
-{
- isdn_net_local *lp = n->local;
- struct net_device *dev;
-
- if (lp->master)
- dev = lp->master;
- else
- dev = n->dev;
- return netif_running(dev);
-}
-
-/*
- * wake up the network -> net_device queue.
- * For slaves, wake the corresponding master interface.
- */
-static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
-{
- if (lp->master)
- netif_wake_queue(lp->master);
- else
- netif_wake_queue(lp->netdev->dev);
-}
-
-/*
- * stop the network -> net_device queue.
- * For slaves, stop the corresponding master interface.
- */
-static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
-{
- if (lp->master)
- netif_stop_queue(lp->master);
- else
- netif_stop_queue(lp->netdev->dev);
-}
-
-/*
- * find out if the net_device which this lp belongs to (lp can be
- * master or slave) is busy. It's busy iff all (master and slave)
- * queues are busy
- */
-static __inline__ int isdn_net_device_busy(isdn_net_local *lp)
-{
- isdn_net_local *nlp;
- isdn_net_dev *nd;
- unsigned long flags;
-
- if (!isdn_net_lp_busy(lp))
- return 0;
-
- if (lp->master)
- nd = ISDN_MASTER_PRIV(lp)->netdev;
- else
- nd = lp->netdev;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
- nlp = lp->next;
- while (nlp != lp) {
- if (!isdn_net_lp_busy(nlp)) {
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return 0;
- }
- nlp = nlp->next;
- }
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return 1;
-}
-
-static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp)
-{
- atomic_inc(&lp->frame_cnt);
- if (isdn_net_device_busy(lp))
- isdn_net_device_stop_queue(lp);
-}
-
-static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
-{
- atomic_dec(&lp->frame_cnt);
-
- if (!(isdn_net_device_busy(lp))) {
- if (!skb_queue_empty(&lp->super_tx_queue)) {
- schedule_work(&lp->tqueue);
- } else {
- isdn_net_device_wake_queue(lp);
- }
- }
-}
-
-static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
-{
- atomic_set(&lp->frame_cnt, 0);
-}
-
-/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
- * to be safe.
- * For 2.3.x we push it up to 20 secs, because call establishment
- * (in particular callback) may take such a long time, and we
- * don't want confusing messages in the log. However, there is a slight
- * possibility that this large timeout will break other things like MPPP,
- * which might rely on the tx timeout. If so, we'll find out this way...
- */
-
-#define ISDN_NET_TX_TIMEOUT (20 * HZ)
-
-/* Prototypes */
-
-static int isdn_net_force_dial_lp(isdn_net_local *);
-static netdev_tx_t isdn_net_start_xmit(struct sk_buff *,
- struct net_device *);
-
-static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
-static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
-
-char *isdn_net_revision = "$Revision: 1.1.2.2 $";
-
-/*
- * Code for raw-networking over ISDN
- */
-
-static void
-isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
-{
- if (skb) {
-
- u_short proto = ntohs(skb->protocol);
-
- printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n",
- dev->name,
- (reason != NULL) ? reason : "unknown",
- (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : "");
-
- dst_link_failure(skb);
- }
- else { /* dial not triggered by rawIP packet */
- printk(KERN_DEBUG "isdn_net: %s: %s\n",
- dev->name,
- (reason != NULL) ? reason : "reason unknown");
- }
-}
-
-static void
-isdn_net_reset(struct net_device *dev)
-{
-#ifdef CONFIG_ISDN_X25
- struct concap_device_ops *dops =
- ((isdn_net_local *)netdev_priv(dev))->dops;
- struct concap_proto *cprot =
- ((isdn_net_local *)netdev_priv(dev))->netdev->cprot;
-#endif
-#ifdef CONFIG_ISDN_X25
- if (cprot && cprot->pops && dops)
- cprot->pops->restart(cprot, dev, dops);
-#endif
-}
-
-/* Open/initialize the board. */
-static int
-isdn_net_open(struct net_device *dev)
-{
- int i;
- struct net_device *p;
- struct in_device *in_dev;
-
- /* moved here from isdn_net_reset, because only the master has an
- interface associated which is supposed to be started. BTW:
- we need to call netif_start_queue, not netif_wake_queue here */
- netif_start_queue(dev);
-
- isdn_net_reset(dev);
- /* Fill in the MAC-level header (not needed, but for compatibility... */
- for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
- dev->dev_addr[i] = 0xfc;
- if ((in_dev = dev->ip_ptr) != NULL) {
- /*
- * Any address will do - we take the first
- */
- struct in_ifaddr *ifa = in_dev->ifa_list;
- if (ifa != NULL)
- memcpy(dev->dev_addr + 2, &ifa->ifa_local, 4);
- }
-
- /* If this interface has slaves, start them also */
- p = MASTER_TO_SLAVE(dev);
- if (p) {
- while (p) {
- isdn_net_reset(p);
- p = MASTER_TO_SLAVE(p);
- }
- }
- isdn_lock_drivers();
- return 0;
-}
-
-/*
- * Assign an ISDN-channel to a net-interface
- */
-static void
-isdn_net_bind_channel(isdn_net_local *lp, int idx)
-{
- lp->flags |= ISDN_NET_CONNECTED;
- lp->isdn_device = dev->drvmap[idx];
- lp->isdn_channel = dev->chanmap[idx];
- dev->rx_netdev[idx] = lp->netdev;
- dev->st_netdev[idx] = lp->netdev;
-}
-
-/*
- * unbind a net-interface (resets interface after an error)
- */
-static void
-isdn_net_unbind_channel(isdn_net_local *lp)
-{
- skb_queue_purge(&lp->super_tx_queue);
-
- if (!lp->master) { /* reset only master device */
- /* Moral equivalent of dev_purge_queues():
- BEWARE! This chunk of code cannot be called from hardware
- interrupt handler. I hope it is true. --ANK
- */
- qdisc_reset_all_tx(lp->netdev->dev);
- }
- lp->dialstate = 0;
- dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
- dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
- if (lp->isdn_device != -1 && lp->isdn_channel != -1)
- isdn_free_channel(lp->isdn_device, lp->isdn_channel,
- ISDN_USAGE_NET);
- lp->flags &= ~ISDN_NET_CONNECTED;
- lp->isdn_device = -1;
- lp->isdn_channel = -1;
-}
-
-/*
- * Perform auto-hangup and cps-calculation for net-interfaces.
- *
- * auto-hangup:
- * Increment idle-counter (this counter is reset on any incoming or
- * outgoing packet), if counter exceeds configured limit either do a
- * hangup immediately or - if configured - wait until just before the next
- * charge-info.
- *
- * cps-calculation (needed for dynamic channel-bundling):
- * Since this function is called every second, simply reset the
- * byte-counter of the interface after copying it to the cps-variable.
- */
-static unsigned long last_jiffies = -HZ;
-
-void
-isdn_net_autohup(void)
-{
- isdn_net_dev *p = dev->netdev;
- int anymore;
-
- anymore = 0;
- while (p) {
- isdn_net_local *l = p->local;
- if (jiffies == last_jiffies)
- l->cps = l->transcount;
- else
- l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
- l->transcount = 0;
- if (dev->net_verbose > 3)
- printk(KERN_DEBUG "%s: %d bogocps\n", p->dev->name, l->cps);
- if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
- anymore = 1;
- l->huptimer++;
- /*
- * if there is some dialmode where timeout-hangup
- * should _not_ be done, check for that here
- */
- if ((l->onhtime) &&
- (l->huptimer > l->onhtime))
- {
- if (l->hupflags & ISDN_MANCHARGE &&
- l->hupflags & ISDN_CHARGEHUP) {
- while (time_after(jiffies, l->chargetime + l->chargeint))
- l->chargetime += l->chargeint;
- if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
- if (l->outgoing || l->hupflags & ISDN_INHUP)
- isdn_net_hangup(p->dev);
- } else if (l->outgoing) {
- if (l->hupflags & ISDN_CHARGEHUP) {
- if (l->hupflags & ISDN_WAITCHARGE) {
- printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
- p->dev->name, l->hupflags);
- isdn_net_hangup(p->dev);
- } else if (time_after(jiffies, l->chargetime + l->chargeint)) {
- printk(KERN_DEBUG
- "isdn_net: %s: chtime = %lu, chint = %d\n",
- p->dev->name, l->chargetime, l->chargeint);
- isdn_net_hangup(p->dev);
- }
- } else
- isdn_net_hangup(p->dev);
- } else if (l->hupflags & ISDN_INHUP)
- isdn_net_hangup(p->dev);
- }
-
- if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
- isdn_net_hangup(p->dev);
- break;
- }
- }
- p = (isdn_net_dev *) p->next;
- }
- last_jiffies = jiffies;
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
-}
-
-static void isdn_net_lp_disconnected(isdn_net_local *lp)
-{
- isdn_net_rm_from_bundle(lp);
-}
-
-/*
- * Handle status-messages from ISDN-interfacecard.
- * This function is called from within the main-status-dispatcher
- * isdn_status_callback, which itself is called from the low-level driver.
- * Return: 1 = Event handled, 0 = not for us or unknown Event.
- */
-int
-isdn_net_stat_callback(int idx, isdn_ctrl *c)
-{
- isdn_net_dev *p = dev->st_netdev[idx];
- int cmd = c->command;
-
- if (p) {
- isdn_net_local *lp = p->local;
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
- struct concap_proto_ops *pops = cprot ? cprot->pops : NULL;
-#endif
- switch (cmd) {
- case ISDN_STAT_BSENT:
- /* A packet has successfully been sent out */
- if ((lp->flags & ISDN_NET_CONNECTED) &&
- (!lp->dialstate)) {
- isdn_net_dec_frame_cnt(lp);
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += c->parm.length;
- }
- return 1;
- case ISDN_STAT_DCONN:
- /* D-Channel is up */
- switch (lp->dialstate) {
- case 4:
- case 7:
- case 8:
- lp->dialstate++;
- return 1;
- case 12:
- lp->dialstate = 5;
- return 1;
- }
- break;
- case ISDN_STAT_DHUP:
- /* Either D-Channel-hangup or error during dialout */
-#ifdef CONFIG_ISDN_X25
- /* If we are not connencted then dialing had
- failed. If there are generic encap protocol
- receiver routines signal the closure of
- the link*/
-
- if (!(lp->flags & ISDN_NET_CONNECTED)
- && pops && pops->disconn_ind)
- pops->disconn_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
- if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
- if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
- isdn_net_ciscohdlck_disconnected(lp);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_free(lp);
-#endif
- isdn_net_lp_disconnected(lp);
- isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- printk(KERN_INFO "%s: remote hangup\n", p->dev->name);
- printk(KERN_INFO "%s: Chargesum is %d\n", p->dev->name,
- lp->charge);
- isdn_net_unbind_channel(lp);
- return 1;
- }
- break;
-#ifdef CONFIG_ISDN_X25
- case ISDN_STAT_BHUP:
- /* B-Channel-hangup */
- /* try if there are generic encap protocol
- receiver routines and signal the closure of
- the link */
- if (pops && pops->disconn_ind) {
- pops->disconn_ind(cprot);
- return 1;
- }
- break;
-#endif /* CONFIG_ISDN_X25 */
- case ISDN_STAT_BCONN:
- /* B-Channel is up */
- isdn_net_zero_frame_cnt(lp);
- switch (lp->dialstate) {
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- case 12:
- if (lp->dialstate <= 6) {
- dev->usage[idx] |= ISDN_USAGE_OUTGOING;
- isdn_info_update();
- } else
- dev->rx_netdev[idx] = p;
- lp->dialstate = 0;
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
- if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
- isdn_net_ciscohdlck_connected(lp);
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
- if (lp->master) { /* is lp a slave? */
- isdn_net_dev *nd = ISDN_MASTER_PRIV(lp)->netdev;
- isdn_net_add_to_bundle(nd, lp);
- }
- }
- printk(KERN_INFO "isdn_net: %s connected\n", p->dev->name);
- /* If first Chargeinfo comes before B-Channel connect,
- * we correct the timestamp here.
- */
- lp->chargetime = jiffies;
-
- /* reset dial-timeout */
- lp->dialstarted = 0;
- lp->dialwait_timer = 0;
-
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_wakeup_daemon(lp);
-#endif
-#ifdef CONFIG_ISDN_X25
- /* try if there are generic concap receiver routines */
- if (pops)
- if (pops->connect_ind)
- pops->connect_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
- /* ppp needs to do negotiations first */
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
- isdn_net_device_wake_queue(lp);
- return 1;
- }
- break;
- case ISDN_STAT_NODCH:
- /* No D-Channel avail. */
- if (lp->dialstate == 4) {
- lp->dialstate--;
- return 1;
- }
- break;
- case ISDN_STAT_CINF:
- /* Charge-info from TelCo. Calculate interval between
- * charge-infos and set timestamp for last info for
- * usage by isdn_net_autohup()
- */
- lp->charge++;
- if (lp->hupflags & ISDN_HAVECHARGE) {
- lp->hupflags &= ~ISDN_WAITCHARGE;
- lp->chargeint = jiffies - lp->chargetime - (2 * HZ);
- }
- if (lp->hupflags & ISDN_WAITCHARGE)
- lp->hupflags |= ISDN_HAVECHARGE;
- lp->chargetime = jiffies;
- printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
- p->dev->name, lp->chargetime);
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * Perform dialout for net-interfaces and timeout-handling for
- * D-Channel-up and B-Channel-up Messages.
- * This function is initially called from within isdn_net_start_xmit() or
- * or isdn_net_find_icall() after initializing the dialstate for an
- * interface. If further calls are needed, the function schedules itself
- * for a timer-callback via isdn_timer_function().
- * The dialstate is also affected by incoming status-messages from
- * the ISDN-Channel which are handled in isdn_net_stat_callback() above.
- */
-void
-isdn_net_dial(void)
-{
- isdn_net_dev *p = dev->netdev;
- int anymore = 0;
- int i;
- isdn_ctrl cmd;
- u_char *phone_number;
-
- while (p) {
- isdn_net_local *lp = p->local;
-
-#ifdef ISDN_DEBUG_NET_DIAL
- if (lp->dialstate)
- printk(KERN_DEBUG "%s: dialstate=%d\n", p->dev->name, lp->dialstate);
-#endif
- switch (lp->dialstate) {
- case 0:
- /* Nothing to do for this interface */
- break;
- case 1:
- /* Initiate dialout. Set phone-number-pointer to first number
- * of interface.
- */
- lp->dial = lp->phone[1];
- if (!lp->dial) {
- printk(KERN_WARNING "%s: phone number deleted?\n",
- p->dev->name);
- isdn_net_hangup(p->dev);
- break;
- }
- anymore = 1;
-
- if (lp->dialtimeout > 0)
- if (lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) {
- lp->dialstarted = jiffies;
- lp->dialwait_timer = 0;
- }
-
- lp->dialstate++;
- /* Fall through */
- case 2:
- /* Prepare dialing. Clear EAZ, then set EAZ. */
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver));
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- lp->dialretry = 0;
- anymore = 1;
- lp->dialstate++;
- /* Fall through */
- case 3:
- /* Setup interface, dial current phone-number, switch to next number.
- * If list of phone-numbers is exhausted, increment
- * retry-counter.
- */
- if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) {
- char *s;
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- s = "dial suppressed: isdn system stopped";
- else
- s = "dial suppressed: dialmode `off'";
- isdn_net_unreachable(p->dev, NULL, s);
- isdn_net_hangup(p->dev);
- break;
- }
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
- isdn_command(&cmd);
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
- isdn_command(&cmd);
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- if (!lp->dial) {
- printk(KERN_WARNING "%s: phone number deleted?\n",
- p->dev->name);
- isdn_net_hangup(p->dev);
- break;
- }
- if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
- lp->dialstate = 4;
- printk(KERN_INFO "%s: Open leased line ...\n", p->dev->name);
- } else {
- if (lp->dialtimeout > 0)
- if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
- lp->dialwait_timer = jiffies + lp->dialwait;
- lp->dialstarted = 0;
- isdn_net_unreachable(p->dev, NULL, "dial: timed out");
- isdn_net_hangup(p->dev);
- break;
- }
-
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_DIAL;
- cmd.parm.setup.si2 = 0;
-
- /* check for DOV */
- phone_number = lp->dial->num;
- if ((*phone_number == 'v') ||
- (*phone_number == 'V')) { /* DOV call */
- cmd.parm.setup.si1 = 1;
- } else { /* DATA call */
- cmd.parm.setup.si1 = 7;
- }
-
- strcpy(cmd.parm.setup.phone, phone_number);
- /*
- * Switch to next number or back to start if at end of list.
- */
- if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) {
- lp->dial = lp->phone[1];
- lp->dialretry++;
-
- if (lp->dialretry > lp->dialmax) {
- if (lp->dialtimeout == 0) {
- lp->dialwait_timer = jiffies + lp->dialwait;
- lp->dialstarted = 0;
- isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times");
- }
- isdn_net_hangup(p->dev);
- break;
- }
- }
- sprintf(cmd.parm.setup.eazmsn, "%s",
- isdn_map_eaz2msn(lp->msn, cmd.driver));
- i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
- if (i >= 0) {
- strcpy(dev->num[i], cmd.parm.setup.phone);
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- isdn_info_update();
- }
- printk(KERN_INFO "%s: dialing %d %s... %s\n", p->dev->name,
- lp->dialretry, cmd.parm.setup.phone,
- (cmd.parm.setup.si1 == 1) ? "DOV" : "");
- lp->dtimer = 0;
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
- lp->isdn_channel);
-#endif
- isdn_command(&cmd);
- }
- lp->huptimer = 0;
- lp->outgoing = 1;
- if (lp->chargeint) {
- lp->hupflags |= ISDN_HAVECHARGE;
- lp->hupflags &= ~ISDN_WAITCHARGE;
- } else {
- lp->hupflags |= ISDN_WAITCHARGE;
- lp->hupflags &= ~ISDN_HAVECHARGE;
- }
- anymore = 1;
- lp->dialstate =
- (lp->cbdelay &&
- (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4;
- break;
- case 4:
- /* Wait for D-Channel-connect.
- * If timeout, switch back to state 3.
- * Dialmax-handling moved to state 3.
- */
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- lp->dialstate = 3;
- anymore = 1;
- break;
- case 5:
- /* Got D-Channel-Connect, send B-Channel-request */
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTB;
- anymore = 1;
- lp->dtimer = 0;
- lp->dialstate++;
- isdn_command(&cmd);
- break;
- case 6:
- /* Wait for B- or D-Channel-connect. If timeout,
- * switch back to state 3.
- */
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer);
-#endif
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- lp->dialstate = 3;
- anymore = 1;
- break;
- case 7:
- /* Got incoming Call, setup L2 and L3 protocols,
- * then wait for D-Channel-connect
- */
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
-#endif
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
- isdn_command(&cmd);
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
- isdn_command(&cmd);
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
- isdn_net_hangup(p->dev);
- else {
- anymore = 1;
- lp->dialstate++;
- }
- break;
- case 9:
- /* Got incoming D-Channel-Connect, send B-Channel-request */
- cmd.driver = lp->isdn_device;
- cmd.arg = lp->isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTB;
- isdn_command(&cmd);
- anymore = 1;
- lp->dtimer = 0;
- lp->dialstate++;
- break;
- case 8:
- case 10:
- /* Wait for B- or D-channel-connect */
-#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
-#endif
- if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- isdn_net_hangup(p->dev);
- else
- anymore = 1;
- break;
- case 11:
- /* Callback Delay */
- if (lp->dtimer++ > lp->cbdelay)
- lp->dialstate = 1;
- anymore = 1;
- break;
- case 12:
- /* Remote does callback. Hangup after cbdelay, then wait for incoming
- * call (in state 4).
- */
- if (lp->dtimer++ > lp->cbdelay)
- {
- printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->dev->name);
- lp->dtimer = 0;
- lp->dialstate = 4;
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = lp->isdn_channel;
- isdn_command(&cmd);
- isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- }
- anymore = 1;
- break;
- default:
- printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
- lp->dialstate, p->dev->name);
- }
- p = (isdn_net_dev *) p->next;
- }
- isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore);
-}
-
-/*
- * Perform hangup for a net-interface.
- */
-void
-isdn_net_hangup(struct net_device *d)
-{
- isdn_net_local *lp = netdev_priv(d);
- isdn_ctrl cmd;
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
- struct concap_proto_ops *pops = cprot ? cprot->pops : NULL;
-#endif
-
- if (lp->flags & ISDN_NET_CONNECTED) {
- if (lp->slave != NULL) {
- isdn_net_local *slp = ISDN_SLAVE_PRIV(lp);
- if (slp->flags & ISDN_NET_CONNECTED) {
- printk(KERN_INFO
- "isdn_net: hang up slave %s before %s\n",
- lp->slave->name, d->name);
- isdn_net_hangup(lp->slave);
- }
- }
- printk(KERN_INFO "isdn_net: local hangup %s\n", d->name);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_free(lp);
-#endif
- isdn_net_lp_disconnected(lp);
-#ifdef CONFIG_ISDN_X25
- /* try if there are generic encap protocol
- receiver routines and signal the closure of
- the link */
- if (pops && pops->disconn_ind)
- pops->disconn_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
-
- cmd.driver = lp->isdn_device;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = lp->isdn_channel;
- isdn_command(&cmd);
- printk(KERN_INFO "%s: Chargesum is %d\n", d->name, lp->charge);
- isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- }
- isdn_net_unbind_channel(lp);
-}
-
-typedef struct {
- __be16 source;
- __be16 dest;
-} ip_ports;
-
-static void
-isdn_net_log_skb(struct sk_buff *skb, isdn_net_local *lp)
-{
- /* hopefully, this was set correctly */
- const u_char *p = skb_network_header(skb);
- unsigned short proto = ntohs(skb->protocol);
- int data_ofs;
- ip_ports *ipp;
- char addinfo[100];
-
- addinfo[0] = '\0';
- /* This check stolen from 2.1.72 dev_queue_xmit_nit() */
- if (p < skb->data || skb_network_header(skb) >= skb_tail_pointer(skb)) {
- /* fall back to old isdn_net_log_packet method() */
- char *buf = skb->data;
-
- printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->netdev->dev->name);
- p = buf;
- proto = ETH_P_IP;
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_IPTYP:
- proto = ntohs(*(__be16 *)&buf[0]);
- p = &buf[2];
- break;
- case ISDN_NET_ENCAP_ETHER:
- proto = ntohs(*(__be16 *)&buf[12]);
- p = &buf[14];
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- proto = ntohs(*(__be16 *)&buf[2]);
- p = &buf[4];
- break;
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- proto = ntohs(skb->protocol);
- p = &buf[IPPP_MAX_HEADER];
- break;
-#endif
- }
- }
- data_ofs = ((p[0] & 15) * 4);
- switch (proto) {
- case ETH_P_IP:
- switch (p[9]) {
- case 1:
- strcpy(addinfo, " ICMP");
- break;
- case 2:
- strcpy(addinfo, " IGMP");
- break;
- case 4:
- strcpy(addinfo, " IPIP");
- break;
- case 6:
- ipp = (ip_ports *) (&p[data_ofs]);
- sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source),
- ntohs(ipp->dest));
- break;
- case 8:
- strcpy(addinfo, " EGP");
- break;
- case 12:
- strcpy(addinfo, " PUP");
- break;
- case 17:
- ipp = (ip_ports *) (&p[data_ofs]);
- sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source),
- ntohs(ipp->dest));
- break;
- case 22:
- strcpy(addinfo, " IDP");
- break;
- }
- printk(KERN_INFO "OPEN: %pI4 -> %pI4%s\n",
- p + 12, p + 16, addinfo);
- break;
- case ETH_P_ARP:
- printk(KERN_INFO "OPEN: ARP %pI4 -> *.*.*.* ?%pI4\n",
- p + 14, p + 24);
- break;
- }
-}
-
-/*
- * this function is used to send supervisory data, i.e. data which was
- * not received from the network layer, but e.g. frames from ipppd, CCP
- * reset frames etc.
- */
-void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
-{
- if (in_irq()) {
- // we can't grab the lock from irq context,
- // so we just queue the packet
- skb_queue_tail(&lp->super_tx_queue, skb);
- schedule_work(&lp->tqueue);
- return;
- }
-
- spin_lock_bh(&lp->xmit_lock);
- if (!isdn_net_lp_busy(lp)) {
- isdn_net_writebuf_skb(lp, skb);
- } else {
- skb_queue_tail(&lp->super_tx_queue, skb);
- }
- spin_unlock_bh(&lp->xmit_lock);
-}
-
-/*
- * called from tq_immediate
- */
-static void isdn_net_softint(struct work_struct *work)
-{
- isdn_net_local *lp = container_of(work, isdn_net_local, tqueue);
- struct sk_buff *skb;
-
- spin_lock_bh(&lp->xmit_lock);
- while (!isdn_net_lp_busy(lp)) {
- skb = skb_dequeue(&lp->super_tx_queue);
- if (!skb)
- break;
- isdn_net_writebuf_skb(lp, skb);
- }
- spin_unlock_bh(&lp->xmit_lock);
-}
-
-/*
- * all frames sent from the (net) LL to a HL driver should go via this function
- * it's serialized by the caller holding the lp->xmit_lock spinlock
- */
-void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
-{
- int ret;
- int len = skb->len; /* save len */
-
- /* before obtaining the lock the caller should have checked that
- the lp isn't busy */
- if (isdn_net_lp_busy(lp)) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- goto error;
- }
-
- if (!(lp->flags & ISDN_NET_CONNECTED)) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- goto error;
- }
- ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
- if (ret != len) {
- /* we should never get here */
- printk(KERN_WARNING "%s: HL driver queue full\n", lp->netdev->dev->name);
- goto error;
- }
-
- lp->transcount += len;
- isdn_net_inc_frame_cnt(lp);
- return;
-
-error:
- dev_kfree_skb(skb);
- lp->stats.tx_errors++;
-
-}
-
-
-/*
- * Helper function for isdn_net_start_xmit.
- * When called, the connection is already established.
- * Based on cps-calculation, check if device is overloaded.
- * If so, and if a slave exists, trigger dialing for it.
- * If any slave is online, deliver packets using a simple round robin
- * scheme.
- *
- * Return: 0 on success, !0 on failure.
- */
-
-static int
-isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
-{
- isdn_net_dev *nd;
- isdn_net_local *slp;
- isdn_net_local *lp = netdev_priv(ndev);
- int retv = NETDEV_TX_OK;
-
- if (((isdn_net_local *) netdev_priv(ndev))->master) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- /* For the other encaps the header has already been built */
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
- return isdn_ppp_xmit(skb, ndev);
- }
-#endif
- nd = ((isdn_net_local *) netdev_priv(ndev))->netdev;
- lp = isdn_net_get_locked_lp(nd);
- if (!lp) {
- printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
- return NETDEV_TX_BUSY;
- }
- /* we have our lp locked from now on */
-
- /* Reset hangup-timeout */
- lp->huptimer = 0; // FIXME?
- isdn_net_writebuf_skb(lp, skb);
- spin_unlock_bh(&lp->xmit_lock);
-
- /* the following stuff is here for backwards compatibility.
- * in future, start-up and hangup of slaves (based on current load)
- * should move to userspace and get based on an overall cps
- * calculation
- */
- if (lp->cps > lp->triggercps) {
- if (lp->slave) {
- if (!lp->sqfull) {
- /* First time overload: set timestamp only */
- lp->sqfull = 1;
- lp->sqfull_stamp = jiffies;
- } else {
- /* subsequent overload: if slavedelay exceeded, start dialing */
- if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) {
- slp = ISDN_SLAVE_PRIV(lp);
- if (!(slp->flags & ISDN_NET_CONNECTED)) {
- isdn_net_force_dial_lp(ISDN_SLAVE_PRIV(lp));
- }
- }
- }
- }
- } else {
- if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) {
- lp->sqfull = 0;
- }
- /* this is a hack to allow auto-hangup for slaves on moderate loads */
- nd->queue = nd->local;
- }
-
- return retv;
-
-}
-
-static void
-isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
-{
- isdn_net_local *lp = netdev_priv(dev);
- if (!skb)
- return;
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
- const int pullsize = skb_network_offset(skb) - ETH_HLEN;
- if (pullsize > 0) {
- printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize);
- skb_pull(skb, pullsize);
- }
- }
-}
-
-
-static void isdn_net_tx_timeout(struct net_device *ndev)
-{
- isdn_net_local *lp = netdev_priv(ndev);
-
- printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
- if (!lp->dialstate) {
- lp->stats.tx_errors++;
- /*
- * There is a certain probability that this currently
- * works at all because if we always wake up the interface,
- * then upper layer will try to send the next packet
- * immediately. And then, the old clean_up logic in the
- * driver will hopefully continue to work as it used to do.
- *
- * This is rather primitive right know, we better should
- * clean internal queues here, in particular for multilink and
- * ppp, and reset HL driver's channel, too. --HE
- *
- * actually, this may not matter at all, because ISDN hardware
- * should not see transmitter hangs at all IMO
- * changed KERN_DEBUG to KERN_WARNING to find out if this is
- * ever called --KG
- */
- }
- netif_trans_update(ndev);
- netif_wake_queue(ndev);
-}
-
-/*
- * Try sending a packet.
- * If this interface isn't connected to a ISDN-Channel, find a free channel,
- * and start dialing.
- */
-static netdev_tx_t
-isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
- isdn_net_local *lp = netdev_priv(ndev);
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
-/* At this point hard_start_xmit() passes control to the encapsulation
- protocol (if present).
- For X.25 auto-dialing is completly bypassed because:
- - It does not conform with the semantics of a reliable datalink
- service as needed by X.25 PLP.
- - I don't want that the interface starts dialing when the network layer
- sends a message which requests to disconnect the lapb link (or if it
- sends any other message not resulting in data transmission).
- Instead, dialing will be initiated by the encapsulation protocol entity
- when a dl_establish request is received from the upper layer.
-*/
- if (cprot && cprot->pops) {
- int ret = cprot->pops->encap_and_xmit(cprot, skb);
-
- if (ret)
- netif_stop_queue(ndev);
- return ret;
- } else
-#endif
- /* auto-dialing xmit function */
- {
-#ifdef ISDN_DEBUG_NET_DUMP
- u_char *buf;
-#endif
- isdn_net_adjust_hdr(skb, ndev);
-#ifdef ISDN_DEBUG_NET_DUMP
- buf = skb->data;
- isdn_dumppkt("S:", buf, skb->len, 40);
-#endif
-
- if (!(lp->flags & ISDN_NET_CONNECTED)) {
- int chi;
- /* only do autodial if allowed by config */
- if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
- isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- if (lp->phone[1]) {
- ulong flags;
-
- if (lp->dialwait_timer <= 0)
- if (lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait))
- lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait;
-
- if (lp->dialwait_timer > 0) {
- if (time_before(jiffies, lp->dialwait_timer)) {
- isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- } else
- lp->dialwait_timer = 0;
- }
- /* Grab a free ISDN-Channel */
- spin_lock_irqsave(&dev->lock, flags);
- if (((chi =
- isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel,
- lp->msn)
- ) < 0) &&
- ((chi =
- isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel^1,
- lp->msn)
- ) < 0)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_unreachable(ndev, skb,
- "No channel");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- /* Log packet, which triggered dialing */
- if (dev->net_verbose)
- isdn_net_log_skb(skb, lp);
- lp->dialstate = 1;
- /* Connect interface with channel */
- isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
- /* no 'first_skb' handling for syncPPP */
- if (isdn_ppp_bind(lp) < 0) {
- dev_kfree_skb(skb);
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */
- }
-#ifdef CONFIG_IPPP_FILTER
- if (isdn_ppp_autodial_filter(skb, lp)) {
- isdn_ppp_free(lp);
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-#endif
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_dial(); /* Initiate dialing */
- netif_stop_queue(ndev);
- return NETDEV_TX_BUSY; /* let upper layer requeue skb packet */
- }
-#endif
- /* Initiate dialing */
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_dial();
- isdn_net_device_stop_queue(lp);
- return NETDEV_TX_BUSY;
- } else {
- isdn_net_unreachable(ndev, skb,
- "No phone number");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- } else {
- /* Device is connected to an ISDN channel */
- netif_trans_update(ndev);
- if (!lp->dialstate) {
- /* ISDN connection is established, try sending */
- int ret;
- ret = (isdn_net_xmit(ndev, skb));
- if (ret) netif_stop_queue(ndev);
- return ret;
- } else
- netif_stop_queue(ndev);
- }
- }
- return NETDEV_TX_BUSY;
-}
-
-/*
- * Shutdown a net-interface.
- */
-static int
-isdn_net_close(struct net_device *dev)
-{
- struct net_device *p;
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot =
- ((isdn_net_local *)netdev_priv(dev))->netdev->cprot;
- /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name); */
-#endif
-
-#ifdef CONFIG_ISDN_X25
- if (cprot && cprot->pops) cprot->pops->close(cprot);
-#endif
- netif_stop_queue(dev);
- p = MASTER_TO_SLAVE(dev);
- if (p) {
- /* If this interface has slaves, stop them also */
- while (p) {
-#ifdef CONFIG_ISDN_X25
- cprot = ((isdn_net_local *)netdev_priv(p))
- ->netdev->cprot;
- if (cprot && cprot->pops)
- cprot->pops->close(cprot);
-#endif
- isdn_net_hangup(p);
- p = MASTER_TO_SLAVE(p);
- }
- }
- isdn_net_hangup(dev);
- isdn_unlock_drivers();
- return 0;
-}
-
-/*
- * Get statistics
- */
-static struct net_device_stats *
-isdn_net_get_stats(struct net_device *dev)
-{
- isdn_net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
-/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
- * instead of dev->hard_header_len off. This is done because the
- * lowlevel-driver has already pulled off its stuff when we get
- * here and this routine only gets called with p_encap == ETHER.
- * Determine the packet's protocol ID. The rule here is that we
- * assume 802.3 if the type field is short enough to be a length.
- * This is normal practice and works for any 'now in use' protocol.
- */
-
-static __be16
-isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
- struct ethhdr *eth;
- unsigned char *rawp;
-
- skb_reset_mac_header(skb);
- skb_pull(skb, ETH_HLEN);
- eth = eth_hdr(skb);
-
- if (*eth->h_dest & 1) {
- if (ether_addr_equal(eth->h_dest, dev->broadcast))
- skb->pkt_type = PACKET_BROADCAST;
- else
- skb->pkt_type = PACKET_MULTICAST;
- }
- /*
- * This ALLMULTI check should be redundant by 1.4
- * so don't forget to remove it.
- */
-
- else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
- if (!ether_addr_equal(eth->h_dest, dev->dev_addr))
- skb->pkt_type = PACKET_OTHERHOST;
- }
- if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
- return eth->h_proto;
-
- rawp = skb->data;
-
- /*
- * This is a magic hack to spot IPX packets. Older Novell breaks
- * the protocol design and runs IPX over 802.3 without an 802.2 LLC
- * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
- * won't work for fault tolerant netware but does for the rest.
- */
- if (*(unsigned short *) rawp == 0xFFFF)
- return htons(ETH_P_802_3);
- /*
- * Real 802.2 LLC
- */
- return htons(ETH_P_802_2);
-}
-
-
-/*
- * CISCO HDLC keepalive specific stuff
- */
-static struct sk_buff*
-isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
-{
- unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
- struct sk_buff *skb;
-
- skb = alloc_skb(hl + len, GFP_ATOMIC);
- if (skb)
- skb_reserve(skb, hl);
- else
- printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
- return skb;
-}
-
-/* cisco hdlck device private ioctls */
-static int
-isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- isdn_net_local *lp = netdev_priv(dev);
- unsigned long len = 0;
- unsigned long expires = 0;
- int tmp = 0;
- int period = lp->cisco_keepalive_period;
- s8 debserint = lp->cisco_debserint;
- int rc = 0;
-
- if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
- return -EINVAL;
-
- switch (cmd) {
- /* get/set keepalive period */
- case SIOCGKEEPPERIOD:
- len = (unsigned long)sizeof(lp->cisco_keepalive_period);
- if (copy_to_user(ifr->ifr_data,
- &lp->cisco_keepalive_period, len))
- rc = -EFAULT;
- break;
- case SIOCSKEEPPERIOD:
- tmp = lp->cisco_keepalive_period;
- len = (unsigned long)sizeof(lp->cisco_keepalive_period);
- if (copy_from_user(&period, ifr->ifr_data, len))
- rc = -EFAULT;
- if ((period > 0) && (period <= 32767))
- lp->cisco_keepalive_period = period;
- else
- rc = -EINVAL;
- if (!rc && (tmp != lp->cisco_keepalive_period)) {
- expires = (unsigned long)(jiffies +
- lp->cisco_keepalive_period * HZ);
- mod_timer(&lp->cisco_timer, expires);
- printk(KERN_INFO "%s: Keepalive period set "
- "to %d seconds.\n",
- dev->name, lp->cisco_keepalive_period);
- }
- break;
-
- /* get/set debugging */
- case SIOCGDEBSERINT:
- len = (unsigned long)sizeof(lp->cisco_debserint);
- if (copy_to_user(ifr->ifr_data,
- &lp->cisco_debserint, len))
- rc = -EFAULT;
- break;
- case SIOCSDEBSERINT:
- len = (unsigned long)sizeof(lp->cisco_debserint);
- if (copy_from_user(&debserint,
- ifr->ifr_data, len))
- rc = -EFAULT;
- if ((debserint >= 0) && (debserint <= 64))
- lp->cisco_debserint = debserint;
- else
- rc = -EINVAL;
- break;
-
- default:
- rc = -EINVAL;
- break;
- }
- return (rc);
-}
-
-
-static int isdn_net_ioctl(struct net_device *dev,
- struct ifreq *ifr, int cmd)
-{
- isdn_net_local *lp = netdev_priv(dev);
-
- switch (lp->p_encap) {
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- return isdn_ppp_dev_ioctl(dev, ifr, cmd);
-#endif
- case ISDN_NET_ENCAP_CISCOHDLCK:
- return isdn_ciscohdlck_dev_ioctl(dev, ifr, cmd);
- default:
- return -EINVAL;
- }
-}
-
-/* called via cisco_timer.function */
-static void
-isdn_net_ciscohdlck_slarp_send_keepalive(struct timer_list *t)
-{
- isdn_net_local *lp = from_timer(lp, t, cisco_timer);
- struct sk_buff *skb;
- unsigned char *p;
- unsigned long last_cisco_myseq = lp->cisco_myseq;
- int myseq_diff = 0;
-
- if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) {
- printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
- return;
- }
- lp->cisco_myseq++;
-
- myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
- if ((lp->cisco_line_state) && ((myseq_diff >= 3) || (myseq_diff <= -3))) {
- /* line up -> down */
- lp->cisco_line_state = 0;
- printk(KERN_WARNING
- "UPDOWN: Line protocol on Interface %s,"
- " changed state to down\n", lp->netdev->dev->name);
- /* should stop routing higher-level data across */
- } else if ((!lp->cisco_line_state) &&
- (myseq_diff >= 0) && (myseq_diff <= 2)) {
- /* line down -> up */
- lp->cisco_line_state = 1;
- printk(KERN_WARNING
- "UPDOWN: Line protocol on Interface %s,"
- " changed state to up\n", lp->netdev->dev->name);
- /* restart routing higher-level data across */
- }
-
- if (lp->cisco_debserint)
- printk(KERN_DEBUG "%s: HDLC "
- "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
- lp->netdev->dev->name, last_cisco_myseq, lp->cisco_mineseen,
- ((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
- lp->cisco_yourseq,
- ((lp->cisco_line_state) ? "line up" : "line down"));
-
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
- if (!skb)
- return;
-
- p = skb_put(skb, 4 + 14);
-
- /* cisco header */
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
-
- /* slarp keepalive */
- *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_KEEPALIVE);
- *(__be32 *)(p + 8) = cpu_to_be32(lp->cisco_myseq);
- *(__be32 *)(p + 12) = cpu_to_be32(lp->cisco_yourseq);
- *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliability, always 0xffff
- p += 18;
-
- isdn_net_write_super(lp, skb);
-
- lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
-
- add_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
-{
- struct sk_buff *skb;
- unsigned char *p;
-
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
- if (!skb)
- return;
-
- p = skb_put(skb, 4 + 14);
-
- /* cisco header */
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
-
- /* slarp request */
- *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REQUEST);
- *(__be32 *)(p + 8) = cpu_to_be32(0); // address
- *(__be32 *)(p + 12) = cpu_to_be32(0); // netmask
- *(__be16 *)(p + 16) = cpu_to_be16(0); // unused
- p += 18;
-
- isdn_net_write_super(lp, skb);
-}
-
-static void
-isdn_net_ciscohdlck_connected(isdn_net_local *lp)
-{
- lp->cisco_myseq = 0;
- lp->cisco_mineseen = 0;
- lp->cisco_yourseq = 0;
- lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
- lp->cisco_last_slarp_in = 0;
- lp->cisco_line_state = 0;
- lp->cisco_debserint = 0;
-
- /* send slarp request because interface/seq.no.s reset */
- isdn_net_ciscohdlck_slarp_send_request(lp);
-
- timer_setup(&lp->cisco_timer,
- isdn_net_ciscohdlck_slarp_send_keepalive, 0);
- lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
- add_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_disconnected(isdn_net_local *lp)
-{
- del_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
-{
- struct sk_buff *skb;
- unsigned char *p;
- struct in_device *in_dev = NULL;
- __be32 addr = 0; /* local ipv4 address */
- __be32 mask = 0; /* local netmask */
-
- if ((in_dev = lp->netdev->dev->ip_ptr) != NULL) {
- /* take primary(first) address of interface */
- struct in_ifaddr *ifa = in_dev->ifa_list;
- if (ifa != NULL) {
- addr = ifa->ifa_local;
- mask = ifa->ifa_mask;
- }
- }
-
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
- if (!skb)
- return;
-
- p = skb_put(skb, 4 + 14);
-
- /* cisco header */
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP);
-
- /* slarp reply, send own ip/netmask; if values are nonsense remote
- * should think we are unable to provide it with an address via SLARP */
- *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REPLY);
- *(__be32 *)(p + 8) = addr; // address
- *(__be32 *)(p + 12) = mask; // netmask
- *(__be16 *)(p + 16) = cpu_to_be16(0); // unused
- p += 18;
-
- isdn_net_write_super(lp, skb);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
-{
- unsigned char *p;
- int period;
- u32 code;
- u32 my_seq;
- u32 your_seq;
- __be32 local;
- __be32 *addr, *mask;
-
- if (skb->len < 14)
- return;
-
- p = skb->data;
- code = be32_to_cpup((__be32 *)p);
- p += 4;
-
- switch (code) {
- case CISCO_SLARP_REQUEST:
- lp->cisco_yourseq = 0;
- isdn_net_ciscohdlck_slarp_send_reply(lp);
- break;
- case CISCO_SLARP_REPLY:
- addr = (__be32 *)p;
- mask = (__be32 *)(p + 4);
- if (*mask != cpu_to_be32(0xfffffffc))
- goto slarp_reply_out;
- if ((*addr & cpu_to_be32(3)) == cpu_to_be32(0) ||
- (*addr & cpu_to_be32(3)) == cpu_to_be32(3))
- goto slarp_reply_out;
- local = *addr ^ cpu_to_be32(3);
- printk(KERN_INFO "%s: got slarp reply: remote ip: %pI4, local ip: %pI4 mask: %pI4\n",
- lp->netdev->dev->name, addr, &local, mask);
- break;
- slarp_reply_out:
- printk(KERN_INFO "%s: got invalid slarp reply (%pI4/%pI4) - ignored\n",
- lp->netdev->dev->name, addr, mask);
- break;
- case CISCO_SLARP_KEEPALIVE:
- period = (int)((jiffies - lp->cisco_last_slarp_in
- + HZ / 2 - 1) / HZ);
- if (lp->cisco_debserint &&
- (period != lp->cisco_keepalive_period) &&
- lp->cisco_last_slarp_in) {
- printk(KERN_DEBUG "%s: Keepalive period mismatch - "
- "is %d but should be %d.\n",
- lp->netdev->dev->name, period,
- lp->cisco_keepalive_period);
- }
- lp->cisco_last_slarp_in = jiffies;
- my_seq = be32_to_cpup((__be32 *)(p + 0));
- your_seq = be32_to_cpup((__be32 *)(p + 4));
- p += 10;
- lp->cisco_yourseq = my_seq;
- lp->cisco_mineseen = your_seq;
- break;
- }
-}
-
-static void
-isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
-{
- unsigned char *p;
- u8 addr;
- u8 ctrl;
- u16 type;
-
- if (skb->len < 4)
- goto out_free;
-
- p = skb->data;
- addr = *(u8 *)(p + 0);
- ctrl = *(u8 *)(p + 1);
- type = be16_to_cpup((__be16 *)(p + 2));
- p += 4;
- skb_pull(skb, 4);
-
- if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
- printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
- lp->netdev->dev->name, addr);
- goto out_free;
- }
- if (ctrl != CISCO_CTRL) {
- printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
- lp->netdev->dev->name, ctrl);
- goto out_free;
- }
-
- switch (type) {
- case CISCO_TYPE_SLARP:
- isdn_net_ciscohdlck_slarp_in(lp, skb);
- goto out_free;
- case CISCO_TYPE_CDP:
- if (lp->cisco_debserint)
- printk(KERN_DEBUG "%s: Received CDP packet. use "
- "\"no cdp enable\" on cisco.\n",
- lp->netdev->dev->name);
- goto out_free;
- default:
- /* no special cisco protocol */
- skb->protocol = htons(type);
- netif_rx(skb);
- return;
- }
-
-out_free:
- kfree_skb(skb);
-}
-
-/*
- * Got a packet from ISDN-Channel.
- */
-static void
-isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
-{
- isdn_net_local *lp = netdev_priv(ndev);
- isdn_net_local *olp = lp; /* original 'lp' */
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = lp->netdev->cprot;
-#endif
- lp->transcount += skb->len;
-
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
- if (lp->master) {
- /* Bundling: If device is a slave-device, deliver to master, also
- * handle master's statistics and hangup-timeout
- */
- ndev = lp->master;
- lp = netdev_priv(ndev);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
- }
- skb->dev = ndev;
- skb->pkt_type = PACKET_HOST;
- skb_reset_mac_header(skb);
-#ifdef ISDN_DEBUG_NET_DUMP
- isdn_dumppkt("R:", skb->data, skb->len, 40);
-#endif
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_ETHER:
- /* Ethernet over ISDN */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb->protocol = isdn_net_type_trans(skb, ndev);
- break;
- case ISDN_NET_ENCAP_UIHDLC:
- /* HDLC with UI-frame (for ispa with -h1 option) */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb_pull(skb, 2);
- /* Fall through */
- case ISDN_NET_ENCAP_RAWIP:
- /* RAW-IP without MAC-Header */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb->protocol = htons(ETH_P_IP);
- break;
- case ISDN_NET_ENCAP_CISCOHDLCK:
- isdn_net_ciscohdlck_receive(lp, skb);
- return;
- case ISDN_NET_ENCAP_CISCOHDLC:
- /* CISCO-HDLC IP with type field and fake I-frame-header */
- skb_pull(skb, 2);
- /* Fall through */
- case ISDN_NET_ENCAP_IPTYP:
- /* IP with type field */
- olp->huptimer = 0;
- lp->huptimer = 0;
- skb->protocol = *(__be16 *)&(skb->data[0]);
- skb_pull(skb, 2);
- if (*(unsigned short *) skb->data == 0xFFFF)
- skb->protocol = htons(ETH_P_802_3);
- break;
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- /* huptimer is done in isdn_ppp_push_higher */
- isdn_ppp_receive(lp->netdev, olp, skb);
- return;
-#endif
-
- default:
-#ifdef CONFIG_ISDN_X25
- /* try if there are generic sync_device receiver routines */
- if (cprot) if (cprot->pops)
- if (cprot->pops->data_ind) {
- cprot->pops->data_ind(cprot, skb);
- return;
- };
-#endif /* CONFIG_ISDN_X25 */
- printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
- lp->netdev->dev->name);
- kfree_skb(skb);
- return;
- }
-
- netif_rx(skb);
- return;
-}
-
-/*
- * A packet arrived via ISDN. Search interface-chain for a corresponding
- * interface. If found, deliver packet to receiver-function and return 1,
- * else return 0.
- */
-int
-isdn_net_rcv_skb(int idx, struct sk_buff *skb)
-{
- isdn_net_dev *p = dev->rx_netdev[idx];
-
- if (p) {
- isdn_net_local *lp = p->local;
- if ((lp->flags & ISDN_NET_CONNECTED) &&
- (!lp->dialstate)) {
- isdn_net_receive(p->dev, skb);
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * build an header
- * depends on encaps that is being used.
- */
-
-static int isdn_net_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type,
- const void *daddr, const void *saddr, unsigned plen)
-{
- isdn_net_local *lp = netdev_priv(dev);
- unsigned char *p;
- int len = 0;
-
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_ETHER:
- len = eth_header(skb, dev, type, daddr, saddr, plen);
- break;
-#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- /* stick on a fake header to keep fragmentation code happy. */
- len = IPPP_MAX_HEADER;
- skb_push(skb, len);
- break;
-#endif
- case ISDN_NET_ENCAP_RAWIP:
- printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
- len = 0;
- break;
- case ISDN_NET_ENCAP_IPTYP:
- /* ethernet type field */
- *((__be16 *)skb_push(skb, 2)) = htons(type);
- len = 2;
- break;
- case ISDN_NET_ENCAP_UIHDLC:
- /* HDLC with UI-Frames (for ispa with -h1 option) */
- *((__be16 *)skb_push(skb, 2)) = htons(0x0103);
- len = 2;
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- case ISDN_NET_ENCAP_CISCOHDLCK:
- p = skb_push(skb, 4);
- *(u8 *)(p + 0) = CISCO_ADDR_UNICAST;
- *(u8 *)(p + 1) = CISCO_CTRL;
- *(__be16 *)(p + 2) = cpu_to_be16(type);
- p += 4;
- len = 4;
- break;
-#ifdef CONFIG_ISDN_X25
- default:
- /* try if there are generic concap protocol routines */
- if (lp->netdev->cprot) {
- printk(KERN_WARNING "isdn_net_header called with concap_proto!\n");
- len = 0;
- break;
- }
- break;
-#endif /* CONFIG_ISDN_X25 */
- }
- return len;
-}
-
-static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
- __be16 type)
-{
- const struct net_device *dev = neigh->dev;
- isdn_net_local *lp = netdev_priv(dev);
-
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
- return eth_header_cache(neigh, hh, type);
- return -1;
-}
-
-static void isdn_header_cache_update(struct hh_cache *hh,
- const struct net_device *dev,
- const unsigned char *haddr)
-{
- isdn_net_local *lp = netdev_priv(dev);
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
- eth_header_cache_update(hh, dev, haddr);
-}
-
-static const struct header_ops isdn_header_ops = {
- .create = isdn_net_header,
- .cache = isdn_header_cache,
- .cache_update = isdn_header_cache_update,
-};
-
-/*
- * Interface-setup. (just after registering a new interface)
- */
-static int
-isdn_net_init(struct net_device *ndev)
-{
- ushort max_hlhdr_len = 0;
- int drvidx;
-
- /*
- * up till binding we ask the protocol layer to reserve as much
- * as we might need for HL layer
- */
-
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
- if (dev->drv[drvidx])
- if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen)
- max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen;
-
- ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
- return 0;
-}
-
-static void
-isdn_net_swapbind(int drvidx)
-{
- isdn_net_dev *p;
-
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: swapping ch of %d\n", drvidx);
-#endif
- p = dev->netdev;
- while (p) {
- if (p->local->pre_device == drvidx)
- switch (p->local->pre_channel) {
- case 0:
- p->local->pre_channel = 1;
- break;
- case 1:
- p->local->pre_channel = 0;
- break;
- }
- p = (isdn_net_dev *) p->next;
- }
-}
-
-static void
-isdn_net_swap_usage(int i1, int i2)
-{
- int u1 = dev->usage[i1] & ISDN_USAGE_EXCLUSIVE;
- int u2 = dev->usage[i2] & ISDN_USAGE_EXCLUSIVE;
-
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: usage of %d and %d\n", i1, i2);
-#endif
- dev->usage[i1] &= ~ISDN_USAGE_EXCLUSIVE;
- dev->usage[i1] |= u2;
- dev->usage[i2] &= ~ISDN_USAGE_EXCLUSIVE;
- dev->usage[i2] |= u1;
- isdn_info_update();
-}
-
-/*
- * An incoming call-request has arrived.
- * Search the interface-chain for an appropriate interface.
- * If found, connect the interface to the ISDN-channel and initiate
- * D- and B-Channel-setup. If secure-flag is set, accept only
- * configured phone-numbers. If callback-flag is set, initiate
- * callback-dialing.
- *
- * Return-Value: 0 = No appropriate interface for this call.
- * 1 = Call accepted
- * 2 = Reject call, wait cbdelay, then call back
- * 3 = Reject call
- * 4 = Wait cbdelay, then call back
- * 5 = No appropriate interface for this call,
- * would eventually match if CID was longer.
- */
-
-int
-isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
-{
- char *eaz;
- int si1;
- int si2;
- int ematch;
- int wret;
- int swapped;
- int sidx = 0;
- u_long flags;
- isdn_net_dev *p;
- isdn_net_phone *n;
- char nr[ISDN_MSNLEN];
- char *my_eaz;
-
- /* Search name in netdev-chain */
- if (!setup->phone[0]) {
- nr[0] = '0';
- nr[1] = '\0';
- printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n");
- } else
- strlcpy(nr, setup->phone, ISDN_MSNLEN);
- si1 = (int) setup->si1;
- si2 = (int) setup->si2;
- if (!setup->eazmsn[0]) {
- printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n");
- eaz = "0";
- } else
- eaz = setup->eazmsn;
- if (dev->net_verbose > 1)
- printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
- /* Accept DATA and VOICE calls at this stage
- * local eaz is checked later for allowed call types
- */
- if ((si1 != 7) && (si1 != 1)) {
- if (dev->net_verbose > 1)
- printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n");
- return 0;
- }
- n = (isdn_net_phone *) 0;
- p = dev->netdev;
- ematch = wret = swapped = 0;
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
- dev->usage[idx]);
-#endif
- while (p) {
- int matchret;
- isdn_net_local *lp = p->local;
-
- /* If last check has triggered as binding-swap, revert it */
- switch (swapped) {
- case 2:
- isdn_net_swap_usage(idx, sidx);
- /* fall through */
- case 1:
- isdn_net_swapbind(di);
- break;
- }
- swapped = 0;
- /* check acceptable call types for DOV */
- my_eaz = isdn_map_eaz2msn(lp->msn, di);
- if (si1 == 1) { /* it's a DOV call, check if we allow it */
- if (*my_eaz == 'v' || *my_eaz == 'V' ||
- *my_eaz == 'b' || *my_eaz == 'B')
- my_eaz++; /* skip to allow a match */
- else
- my_eaz = NULL; /* force non match */
- } else { /* it's a DATA call, check if we allow it */
- if (*my_eaz == 'b' || *my_eaz == 'B')
- my_eaz++; /* skip to allow a match */
- }
- if (my_eaz)
- matchret = isdn_msncmp(eaz, my_eaz);
- else
- matchret = 1;
- if (!matchret)
- ematch = 1;
-
- /* Remember if more numbers eventually can match */
- if (matchret > wret)
- wret = matchret;
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
- p->dev->name, lp->msn, lp->flags, lp->dialstate);
-#endif
- if ((!matchret) && /* EAZ is matching */
- (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */
- (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
- ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */
- (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */
- )))
- {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
- lp->pre_device, lp->pre_channel);
-#endif
- if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) {
- if ((lp->pre_channel != ch) ||
- (lp->pre_device != di)) {
- /* Here we got a problem:
- * If using an ICN-Card, an incoming call is always signaled on
- * on the first channel of the card, if both channels are
- * down. However this channel may be bound exclusive. If the
- * second channel is free, this call should be accepted.
- * The solution is horribly but it runs, so what:
- * We exchange the exclusive bindings of the two channels, the
- * corresponding variables in the interface-structs.
- */
- if (ch == 0) {
- sidx = isdn_dc2minor(di, 1);
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: ch is 0\n");
-#endif
- if (USG_NONE(dev->usage[sidx])) {
- /* Second Channel is free, now see if it is bound
- * exclusive too. */
- if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n");
-#endif
- /* Yes, swap bindings only, if the original
- * binding is bound to channel 1 of this driver */
- if ((lp->pre_device == di) &&
- (lp->pre_channel == 1)) {
- isdn_net_swapbind(di);
- swapped = 1;
- } else {
- /* ... else iterate next device */
- p = (isdn_net_dev *) p->next;
- continue;
- }
- } else {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: 2nd channel is down and unbound\n");
-#endif
- /* No, swap always and swap excl-usage also */
- isdn_net_swap_usage(idx, sidx);
- isdn_net_swapbind(di);
- swapped = 2;
- }
- /* Now check for exclusive binding again */
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: final check\n");
-#endif
- if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) &&
- ((lp->pre_channel != ch) ||
- (lp->pre_device != di))) {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: final check failed\n");
-#endif
- p = (isdn_net_dev *) p->next;
- continue;
- }
- }
- } else {
- /* We are already on the second channel, so nothing to do */
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: already on 2nd channel\n");
-#endif
- }
- }
- }
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: match2\n");
-#endif
- n = lp->phone[0];
- if (lp->flags & ISDN_NET_SECURE) {
- while (n) {
- if (!isdn_msncmp(nr, n->num))
- break;
- n = (isdn_net_phone *) n->next;
- }
- }
- if (n || (!(lp->flags & ISDN_NET_SECURE))) {
-#ifdef ISDN_DEBUG_NET_ICALL
- printk(KERN_DEBUG "n_fi: match3\n");
-#endif
- /* matching interface found */
-
- /*
- * Is the state STOPPED?
- * If so, no dialin is allowed,
- * so reject actively.
- * */
- if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
- printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
- p->dev->name);
- return 3;
- }
- /*
- * Is the interface up?
- * If not, reject the call actively.
- */
- if (!isdn_net_device_started(p)) {
- printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
- p->dev->name);
- return 3;
- }
- /* Interface is up, now see if it's a slave. If so, see if
- * it's master and parent slave is online. If not, reject the call.
- */
- if (lp->master) {
- isdn_net_local *mlp = ISDN_MASTER_PRIV(lp);
- printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name);
- printk(KERN_DEBUG "master=%s\n", lp->master->name);
- if (mlp->flags & ISDN_NET_CONNECTED) {
- printk(KERN_DEBUG "master online\n");
- /* Master is online, find parent-slave (master if first slave) */
- while (mlp->slave) {
- if (ISDN_SLAVE_PRIV(mlp) == lp)
- break;
- mlp = ISDN_SLAVE_PRIV(mlp);
- }
- } else
- printk(KERN_DEBUG "master offline\n");
- /* Found parent, if it's offline iterate next device */
- printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED);
- if (!(mlp->flags & ISDN_NET_CONNECTED)) {
- p = (isdn_net_dev *) p->next;
- continue;
- }
- }
- if (lp->flags & ISDN_NET_CALLBACK) {
- int chi;
- /*
- * Is the state MANUAL?
- * If so, no callback can be made,
- * so reject actively.
- * */
- if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
- printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
- p->dev->name);
- return 3;
- }
- printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n",
- p->dev->name, nr, eaz);
- if (lp->phone[1]) {
- /* Grab a free ISDN-Channel */
- spin_lock_irqsave(&dev->lock, flags);
- if ((chi =
- isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel,
- lp->msn)
- ) < 0) {
-
- printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n",
- p->dev->name);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- /* Setup dialstate. */
- lp->dtimer = 0;
- lp->dialstate = 11;
- /* Connect interface with channel */
- isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- if (isdn_ppp_bind(lp) < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_unbind_channel(lp);
- return 0;
- }
-#endif
- spin_unlock_irqrestore(&dev->lock, flags);
- /* Initiate dialing by returning 2 or 4 */
- return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
- } else
- printk(KERN_WARNING "isdn_net: %s: No phone number\n",
- p->dev->name);
- return 0;
- } else {
- printk(KERN_DEBUG "%s: call from %s -> %s accepted\n",
- p->dev->name, nr, eaz);
- /* if this interface is dialing, it does it probably on a different
- device, so free this device */
- if ((lp->dialstate == 4) || (lp->dialstate == 12)) {
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_free(lp);
-#endif
- isdn_net_lp_disconnected(lp);
- isdn_free_channel(lp->isdn_device, lp->isdn_channel,
- ISDN_USAGE_NET);
- }
- spin_lock_irqsave(&dev->lock, flags);
- dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[idx] |= ISDN_USAGE_NET;
- strcpy(dev->num[idx], nr);
- isdn_info_update();
- dev->st_netdev[idx] = lp->netdev;
- lp->isdn_device = di;
- lp->isdn_channel = ch;
- lp->ppp_slot = -1;
- lp->flags |= ISDN_NET_CONNECTED;
- lp->dialstate = 7;
- lp->dtimer = 0;
- lp->outgoing = 0;
- lp->huptimer = 0;
- lp->hupflags |= ISDN_WAITCHARGE;
- lp->hupflags &= ~ISDN_HAVECHARGE;
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
- if (isdn_ppp_bind(lp) < 0) {
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- }
-#endif
- spin_unlock_irqrestore(&dev->lock, flags);
- return 1;
- }
- }
- }
- p = (isdn_net_dev *) p->next;
- }
- /* If none of configured EAZ/MSN matched and not verbose, be silent */
- if (!ematch || dev->net_verbose)
- printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz);
- return (wret == 2) ? 5 : 0;
-}
-
-/*
- * Search list of net-interfaces for an interface with given name.
- */
-isdn_net_dev *
-isdn_net_findif(char *name)
-{
- isdn_net_dev *p = dev->netdev;
-
- while (p) {
- if (!strcmp(p->dev->name, name))
- return p;
- p = (isdn_net_dev *) p->next;
- }
- return (isdn_net_dev *) NULL;
-}
-
-/*
- * Force a net-interface to dial out.
- * This is called from the userlevel-routine below or
- * from isdn_net_start_xmit().
- */
-static int
-isdn_net_force_dial_lp(isdn_net_local *lp)
-{
- if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) {
- int chi;
- if (lp->phone[1]) {
- ulong flags;
-
- /* Grab a free ISDN-Channel */
- spin_lock_irqsave(&dev->lock, flags);
- if ((chi = isdn_get_free_channel(
- ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel,
- lp->msn)) < 0) {
- printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n",
- lp->netdev->dev->name);
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EAGAIN;
- }
- lp->dialstate = 1;
- /* Connect interface with channel */
- isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- if (isdn_ppp_bind(lp) < 0) {
- isdn_net_unbind_channel(lp);
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EAGAIN;
- }
-#endif
- /* Initiate dialing */
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_dial();
- return 0;
- } else
- return -EINVAL;
- } else
- return -EBUSY;
-}
-
-/*
- * This is called from certain upper protocol layers (multilink ppp
- * and x25iface encapsulation module) that want to initiate dialing
- * themselves.
- */
-int
-isdn_net_dial_req(isdn_net_local *lp)
-{
- /* is there a better error code? */
- if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY;
-
- return isdn_net_force_dial_lp(lp);
-}
-
-/*
- * Force a net-interface to dial out.
- * This is always called from within userspace (ISDN_IOCTL_NET_DIAL).
- */
-int
-isdn_net_force_dial(char *name)
-{
- isdn_net_dev *p = isdn_net_findif(name);
-
- if (!p)
- return -ENODEV;
- return (isdn_net_force_dial_lp(p->local));
-}
-
-/* The ISDN-specific entries in the device structure. */
-static const struct net_device_ops isdn_netdev_ops = {
- .ndo_init = isdn_net_init,
- .ndo_open = isdn_net_open,
- .ndo_stop = isdn_net_close,
- .ndo_do_ioctl = isdn_net_ioctl,
-
- .ndo_start_xmit = isdn_net_start_xmit,
- .ndo_get_stats = isdn_net_get_stats,
- .ndo_tx_timeout = isdn_net_tx_timeout,
-};
-
-/*
- * Helper for alloc_netdev()
- */
-static void _isdn_setup(struct net_device *dev)
-{
- isdn_net_local *lp = netdev_priv(dev);
-
- ether_setup(dev);
-
- /* Setup the generic properties */
- dev->flags = IFF_NOARP | IFF_POINTOPOINT;
-
- /* isdn prepends a header in the tx path, can't share skbs */
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->header_ops = NULL;
- dev->netdev_ops = &isdn_netdev_ops;
-
- /* for clients with MPPP maybe higher values better */
- dev->tx_queue_len = 30;
-
- lp->p_encap = ISDN_NET_ENCAP_RAWIP;
- lp->magic = ISDN_NET_MAGIC;
- lp->last = lp;
- lp->next = lp;
- lp->isdn_device = -1;
- lp->isdn_channel = -1;
- lp->pre_device = -1;
- lp->pre_channel = -1;
- lp->exclusive = -1;
- lp->ppp_slot = -1;
- lp->pppbind = -1;
- skb_queue_head_init(&lp->super_tx_queue);
- lp->l2_proto = ISDN_PROTO_L2_X75I;
- lp->l3_proto = ISDN_PROTO_L3_TRANS;
- lp->triggercps = 6000;
- lp->slavedelay = 10 * HZ;
- lp->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
- lp->onhtime = 10; /* Default hangup-time for saving costs */
- lp->dialmax = 1;
- /* Hangup before Callback, manual dial */
- lp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;
- lp->cbdelay = 25; /* Wait 5 secs before Callback */
- lp->dialtimeout = -1; /* Infinite Dial-Timeout */
- lp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
- lp->dialstarted = 0; /* Jiffies of last dial-start */
- lp->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
-}
-
-/*
- * Allocate a new network-interface and initialize its data structures.
- */
-char *
-isdn_net_new(char *name, struct net_device *master)
-{
- isdn_net_dev *netdev;
-
- /* Avoid creating an existing interface */
- if (isdn_net_findif(name)) {
- printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
- return NULL;
- }
- if (name == NULL)
- return NULL;
- if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
- return NULL;
- }
- netdev->dev = alloc_netdev(sizeof(isdn_net_local), name,
- NET_NAME_UNKNOWN, _isdn_setup);
- if (!netdev->dev) {
- printk(KERN_WARNING "isdn_net: Could not allocate network device\n");
- kfree(netdev);
- return NULL;
- }
- netdev->local = netdev_priv(netdev->dev);
-
- if (master) {
- /* Device shall be a slave */
- struct net_device *p = MASTER_TO_SLAVE(master);
- struct net_device *q = master;
-
- netdev->local->master = master;
- /* Put device at end of slave-chain */
- while (p) {
- q = p;
- p = MASTER_TO_SLAVE(p);
- }
- MASTER_TO_SLAVE(q) = netdev->dev;
- } else {
- /* Device shall be a master */
- /*
- * Watchdog timer (currently) for master only.
- */
- netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT;
- if (register_netdev(netdev->dev) != 0) {
- printk(KERN_WARNING "isdn_net: Could not register net-device\n");
- free_netdev(netdev->dev);
- kfree(netdev);
- return NULL;
- }
- }
- netdev->queue = netdev->local;
- spin_lock_init(&netdev->queue_lock);
-
- netdev->local->netdev = netdev;
-
- INIT_WORK(&netdev->local->tqueue, isdn_net_softint);
- spin_lock_init(&netdev->local->xmit_lock);
-
- /* Put into to netdev-chain */
- netdev->next = (void *) dev->netdev;
- dev->netdev = netdev;
- return netdev->dev->name;
-}
-
-char *
-isdn_net_newslave(char *parm)
-{
- char *p = strchr(parm, ',');
- isdn_net_dev *n;
- char newname[10];
-
- if (p) {
- /* Slave-Name MUST not be empty or overflow 'newname' */
- if (strscpy(newname, p + 1, sizeof(newname)) <= 0)
- return NULL;
- *p = 0;
- /* Master must already exist */
- if (!(n = isdn_net_findif(parm)))
- return NULL;
- /* Master must be a real interface, not a slave */
- if (n->local->master)
- return NULL;
- /* Master must not be started yet */
- if (isdn_net_device_started(n))
- return NULL;
- return (isdn_net_new(newname, n->dev));
- }
- return NULL;
-}
-
-/*
- * Set interface-parameters.
- * Always set all parameters, so the user-level application is responsible
- * for not overwriting existing setups. It has to get the current
- * setup first, if only selected parameters are to be changed.
- */
-int
-isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
-{
- isdn_net_dev *p = isdn_net_findif(cfg->name);
- ulong features;
- int i;
- int drvidx;
- int chidx;
- char drvid[25];
-
- if (p) {
- isdn_net_local *lp = p->local;
-
- /* See if any registered driver supports the features we want */
- features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
- ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (dev->drv[i])
- if ((dev->drv[i]->interface->features & features) == features)
- break;
- if (i == ISDN_MAX_DRIVERS) {
- printk(KERN_WARNING "isdn_net: No driver with selected features\n");
- return -ENODEV;
- }
- if (lp->p_encap != cfg->p_encap) {
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot = p->cprot;
-#endif
- if (isdn_net_device_started(p)) {
- printk(KERN_WARNING "%s: cannot change encap when if is up\n",
- p->dev->name);
- return -EBUSY;
- }
-#ifdef CONFIG_ISDN_X25
- if (cprot && cprot->pops)
- cprot->pops->proto_del(cprot);
- p->cprot = NULL;
- lp->dops = NULL;
- /* ... , prepare for configuration of new one ... */
- switch (cfg->p_encap) {
- case ISDN_NET_ENCAP_X25IFACE:
- lp->dops = &isdn_concap_reliable_dl_dops;
- }
- /* ... and allocate new one ... */
- p->cprot = isdn_concap_new(cfg->p_encap);
- /* p -> cprot == NULL now if p_encap is not supported
- by means of the concap_proto mechanism */
- /* the protocol is not configured yet; this will
- happen later when isdn_net_reset() is called */
-#endif
- }
- switch (cfg->p_encap) {
- case ISDN_NET_ENCAP_SYNCPPP:
-#ifndef CONFIG_ISDN_PPP
- printk(KERN_WARNING "%s: SyncPPP support not configured\n",
- p->dev->name);
- return -EINVAL;
-#else
- p->dev->type = ARPHRD_PPP; /* change ARP type */
- p->dev->addr_len = 0;
-#endif
- break;
- case ISDN_NET_ENCAP_X25IFACE:
-#ifndef CONFIG_ISDN_X25
- printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
- p->dev->name);
- return -EINVAL;
-#else
- p->dev->type = ARPHRD_X25; /* change ARP type */
- p->dev->addr_len = 0;
-#endif
- break;
- case ISDN_NET_ENCAP_CISCOHDLCK:
- break;
- default:
- if (cfg->p_encap >= 0 &&
- cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP)
- break;
- printk(KERN_WARNING
- "%s: encapsulation protocol %d not supported\n",
- p->dev->name, cfg->p_encap);
- return -EINVAL;
- }
- if (strlen(cfg->drvid)) {
- /* A bind has been requested ... */
- char *c,
- *e;
-
- if (strnlen(cfg->drvid, sizeof(cfg->drvid)) ==
- sizeof(cfg->drvid))
- return -EINVAL;
- drvidx = -1;
- chidx = -1;
- strcpy(drvid, cfg->drvid);
- if ((c = strchr(drvid, ','))) {
- /* The channel-number is appended to the driver-Id with a comma */
- chidx = (int) simple_strtoul(c + 1, &e, 10);
- if (e == c)
- chidx = -1;
- *c = '\0';
- }
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- /* Lookup driver-Id in array */
- if (!(strcmp(dev->drvid[i], drvid))) {
- drvidx = i;
- break;
- }
- if ((drvidx == -1) || (chidx == -1))
- /* Either driver-Id or channel-number invalid */
- return -ENODEV;
- } else {
- /* Parameters are valid, so get them */
- drvidx = lp->pre_device;
- chidx = lp->pre_channel;
- }
- if (cfg->exclusive > 0) {
- unsigned long flags;
-
- /* If binding is exclusive, try to grab the channel */
- spin_lock_irqsave(&dev->lock, flags);
- if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
- lp->l2_proto, lp->l3_proto, drvidx,
- chidx, lp->msn)) < 0) {
- /* Grab failed, because desired channel is in use */
- lp->exclusive = -1;
- spin_unlock_irqrestore(&dev->lock, flags);
- return -EBUSY;
- }
- /* All went ok, so update isdninfo */
- dev->usage[i] = ISDN_USAGE_EXCLUSIVE;
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- lp->exclusive = i;
- } else {
- /* Non-exclusive binding or unbind. */
- lp->exclusive = -1;
- if ((lp->pre_device != -1) && (cfg->exclusive == -1)) {
- isdn_unexclusive_channel(lp->pre_device, lp->pre_channel);
- isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET);
- drvidx = -1;
- chidx = -1;
- }
- }
- strlcpy(lp->msn, cfg->eaz, sizeof(lp->msn));
- lp->pre_device = drvidx;
- lp->pre_channel = chidx;
- lp->onhtime = cfg->onhtime;
- lp->charge = cfg->charge;
- lp->l2_proto = cfg->l2_proto;
- lp->l3_proto = cfg->l3_proto;
- lp->cbdelay = cfg->cbdelay;
- lp->dialmax = cfg->dialmax;
- lp->triggercps = cfg->triggercps;
- lp->slavedelay = cfg->slavedelay * HZ;
- lp->pppbind = cfg->pppbind;
- lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
- lp->dialwait = cfg->dialwait * HZ;
- if (cfg->secure)
- lp->flags |= ISDN_NET_SECURE;
- else
- lp->flags &= ~ISDN_NET_SECURE;
- if (cfg->cbhup)
- lp->flags |= ISDN_NET_CBHUP;
- else
- lp->flags &= ~ISDN_NET_CBHUP;
- switch (cfg->callback) {
- case 0:
- lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
- break;
- case 1:
- lp->flags |= ISDN_NET_CALLBACK;
- lp->flags &= ~ISDN_NET_CBOUT;
- break;
- case 2:
- lp->flags |= ISDN_NET_CBOUT;
- lp->flags &= ~ISDN_NET_CALLBACK;
- break;
- }
- lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */
- if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
- /* old isdnctrl version, where only 0 or 1 is given */
- printk(KERN_WARNING
- "Old isdnctrl version detected! Please update.\n");
- lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */
- }
- else {
- lp->flags |= cfg->dialmode; /* turn on selected bits */
- }
- if (cfg->chargehup)
- lp->hupflags |= ISDN_CHARGEHUP;
- else
- lp->hupflags &= ~ISDN_CHARGEHUP;
- if (cfg->ihup)
- lp->hupflags |= ISDN_INHUP;
- else
- lp->hupflags &= ~ISDN_INHUP;
- if (cfg->chargeint > 10) {
- lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
- lp->chargeint = cfg->chargeint * HZ;
- }
- if (cfg->p_encap != lp->p_encap) {
- if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
- p->dev->header_ops = NULL;
- p->dev->flags = IFF_NOARP | IFF_POINTOPOINT;
- } else {
- p->dev->header_ops = &isdn_header_ops;
- if (cfg->p_encap == ISDN_NET_ENCAP_ETHER)
- p->dev->flags = IFF_BROADCAST | IFF_MULTICAST;
- else
- p->dev->flags = IFF_NOARP | IFF_POINTOPOINT;
- }
- }
- lp->p_encap = cfg->p_encap;
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Perform get-interface-parameters.ioctl
- */
-int
-isdn_net_getcfg(isdn_net_ioctl_cfg *cfg)
-{
- isdn_net_dev *p = isdn_net_findif(cfg->name);
-
- if (p) {
- isdn_net_local *lp = p->local;
-
- strcpy(cfg->eaz, lp->msn);
- cfg->exclusive = lp->exclusive;
- if (lp->pre_device >= 0) {
- sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device],
- lp->pre_channel);
- } else
- cfg->drvid[0] = '\0';
- cfg->onhtime = lp->onhtime;
- cfg->charge = lp->charge;
- cfg->l2_proto = lp->l2_proto;
- cfg->l3_proto = lp->l3_proto;
- cfg->p_encap = lp->p_encap;
- cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
- cfg->callback = 0;
- if (lp->flags & ISDN_NET_CALLBACK)
- cfg->callback = 1;
- if (lp->flags & ISDN_NET_CBOUT)
- cfg->callback = 2;
- cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
- cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
- cfg->chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
- cfg->ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0;
- cfg->cbdelay = lp->cbdelay;
- cfg->dialmax = lp->dialmax;
- cfg->triggercps = lp->triggercps;
- cfg->slavedelay = lp->slavedelay / HZ;
- cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
- (lp->chargeint / HZ) : 0;
- cfg->pppbind = lp->pppbind;
- cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
- cfg->dialwait = lp->dialwait / HZ;
- if (lp->slave) {
- if (strlen(lp->slave->name) >= 10)
- strcpy(cfg->slave, "too-long");
- else
- strcpy(cfg->slave, lp->slave->name);
- } else
- cfg->slave[0] = '\0';
- if (lp->master) {
- if (strlen(lp->master->name) >= 10)
- strcpy(cfg->master, "too-long");
- else
- strcpy(cfg->master, lp->master->name);
- } else
- cfg->master[0] = '\0';
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Add a phone-number to an interface.
- */
-int
-isdn_net_addphone(isdn_net_ioctl_phone *phone)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- isdn_net_phone *n;
-
- if (p) {
- if (!(n = kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
- return -ENOMEM;
- strlcpy(n->num, phone->phone, sizeof(n->num));
- n->next = p->local->phone[phone->outgoing & 1];
- p->local->phone[phone->outgoing & 1] = n;
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Copy a string of all phone-numbers of an interface to user space.
- * This might sleep and must be called with the isdn semaphore down.
- */
-int
-isdn_net_getphones(isdn_net_ioctl_phone *phone, char __user *phones)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int inout = phone->outgoing & 1;
- int more = 0;
- int count = 0;
- isdn_net_phone *n;
-
- if (!p)
- return -ENODEV;
- inout &= 1;
- for (n = p->local->phone[inout]; n; n = n->next) {
- if (more) {
- put_user(' ', phones++);
- count++;
- }
- if (copy_to_user(phones, n->num, strlen(n->num) + 1)) {
- return -EFAULT;
- }
- phones += strlen(n->num);
- count += strlen(n->num);
- more = 1;
- }
- put_user(0, phones);
- count++;
- return count;
-}
-
-/*
- * Copy a string containing the peer's phone number of a connected interface
- * to user space.
- */
-int
-isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int ch, dv, idx;
-
- if (!p)
- return -ENODEV;
- /*
- * Theoretical race: while this executes, the remote number might
- * become invalid (hang up) or change (new connection), resulting
- * in (partially) wrong number copied to user. This race
- * currently ignored.
- */
- ch = p->local->isdn_channel;
- dv = p->local->isdn_device;
- if (ch < 0 && dv < 0)
- return -ENOTCONN;
- idx = isdn_dc2minor(dv, ch);
- if (idx < 0)
- return -ENODEV;
- /* for pre-bound channels, we need this extra check */
- if (strncmp(dev->num[idx], "???", 3) == 0)
- return -ENOTCONN;
- strncpy(phone->phone, dev->num[idx], ISDN_MSNLEN);
- phone->outgoing = USG_OUTGOING(dev->usage[idx]);
- if (copy_to_user(peer, phone, sizeof(*peer)))
- return -EFAULT;
- return 0;
-}
-/*
- * Delete a phone-number from an interface.
- */
-int
-isdn_net_delphone(isdn_net_ioctl_phone *phone)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int inout = phone->outgoing & 1;
- isdn_net_phone *n;
- isdn_net_phone *m;
-
- if (p) {
- n = p->local->phone[inout];
- m = NULL;
- while (n) {
- if (!strcmp(n->num, phone->phone)) {
- if (p->local->dial == n)
- p->local->dial = n->next;
- if (m)
- m->next = n->next;
- else
- p->local->phone[inout] = n->next;
- kfree(n);
- return 0;
- }
- m = n;
- n = (isdn_net_phone *) n->next;
- }
- return -EINVAL;
- }
- return -ENODEV;
-}
-
-/*
- * Delete all phone-numbers of an interface.
- */
-static int
-isdn_net_rmallphone(isdn_net_dev *p)
-{
- isdn_net_phone *n;
- isdn_net_phone *m;
- int i;
-
- for (i = 0; i < 2; i++) {
- n = p->local->phone[i];
- while (n) {
- m = n->next;
- kfree(n);
- n = m;
- }
- p->local->phone[i] = NULL;
- }
- p->local->dial = NULL;
- return 0;
-}
-
-/*
- * Force a hangup of a network-interface.
- */
-int
-isdn_net_force_hangup(char *name)
-{
- isdn_net_dev *p = isdn_net_findif(name);
- struct net_device *q;
-
- if (p) {
- if (p->local->isdn_device < 0)
- return 1;
- q = p->local->slave;
- /* If this interface has slaves, do a hangup for them also. */
- while (q) {
- isdn_net_hangup(q);
- q = MASTER_TO_SLAVE(q);
- }
- isdn_net_hangup(p->dev);
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Helper-function for isdn_net_rm: Do the real work.
- */
-static int
-isdn_net_realrm(isdn_net_dev *p, isdn_net_dev *q)
-{
- u_long flags;
-
- if (isdn_net_device_started(p)) {
- return -EBUSY;
- }
-#ifdef CONFIG_ISDN_X25
- if (p->cprot && p->cprot->pops)
- p->cprot->pops->proto_del(p->cprot);
-#endif
- /* Free all phone-entries */
- isdn_net_rmallphone(p);
- /* If interface is bound exclusive, free channel-usage */
- if (p->local->exclusive != -1)
- isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
- if (p->local->master) {
- /* It's a slave-device, so update master's slave-pointer if necessary */
- if (((isdn_net_local *) ISDN_MASTER_PRIV(p->local))->slave ==
- p->dev)
- ((isdn_net_local *)ISDN_MASTER_PRIV(p->local))->slave =
- p->local->slave;
- } else {
- /* Unregister only if it's a master-device */
- unregister_netdev(p->dev);
- }
- /* Unlink device from chain */
- spin_lock_irqsave(&dev->lock, flags);
- if (q)
- q->next = p->next;
- else
- dev->netdev = p->next;
- if (p->local->slave) {
- /* If this interface has a slave, remove it also */
- char *slavename = p->local->slave->name;
- isdn_net_dev *n = dev->netdev;
- q = NULL;
- while (n) {
- if (!strcmp(n->dev->name, slavename)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_net_realrm(n, q);
- spin_lock_irqsave(&dev->lock, flags);
- break;
- }
- q = n;
- n = (isdn_net_dev *)n->next;
- }
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- /* If no more net-devices remain, disable auto-hangup timer */
- if (dev->netdev == NULL)
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
- free_netdev(p->dev);
- kfree(p);
-
- return 0;
-}
-
-/*
- * Remove a single network-interface.
- */
-int
-isdn_net_rm(char *name)
-{
- u_long flags;
- isdn_net_dev *p;
- isdn_net_dev *q;
-
- /* Search name in netdev-chain */
- spin_lock_irqsave(&dev->lock, flags);
- p = dev->netdev;
- q = NULL;
- while (p) {
- if (!strcmp(p->dev->name, name)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return (isdn_net_realrm(p, q));
- }
- q = p;
- p = (isdn_net_dev *) p->next;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- /* If no more net-devices remain, disable auto-hangup timer */
- if (dev->netdev == NULL)
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
- return -ENODEV;
-}
-
-/*
- * Remove all network-interfaces
- */
-int
-isdn_net_rmall(void)
-{
- u_long flags;
- int ret;
-
- /* Walk through netdev-chain */
- spin_lock_irqsave(&dev->lock, flags);
- while (dev->netdev) {
- if (!dev->netdev->local->master) {
- /* Remove master-devices only, slaves get removed with their master */
- spin_unlock_irqrestore(&dev->lock, flags);
- if ((ret = isdn_net_realrm(dev->netdev, NULL))) {
- return ret;
- }
- spin_lock_irqsave(&dev->lock, flags);
- }
- }
- dev->netdev = NULL;
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
-}
diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
deleted file mode 100644
index cca6d68da171..000000000000
--- a/drivers/isdn/i4l/isdn_net.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/* $Id: isdn_net.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, network related functions (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-/* Definitions for hupflags: */
-#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */
-#define ISDN_HAVECHARGE 2 /* We know a charge info */
-#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */
-#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */
-#define ISDN_MANCHARGE 16 /* Charge Interval manually set */
-
-/*
- * Definitions for Cisco-HDLC header.
- */
-
-#define CISCO_ADDR_UNICAST 0x0f
-#define CISCO_ADDR_BROADCAST 0x8f
-#define CISCO_CTRL 0x00
-#define CISCO_TYPE_CDP 0x2000
-#define CISCO_TYPE_SLARP 0x8035
-#define CISCO_SLARP_REQUEST 0
-#define CISCO_SLARP_REPLY 1
-#define CISCO_SLARP_KEEPALIVE 2
-
-extern char *isdn_net_new(char *, struct net_device *);
-extern char *isdn_net_newslave(char *);
-extern int isdn_net_rm(char *);
-extern int isdn_net_rmall(void);
-extern int isdn_net_stat_callback(int, isdn_ctrl *);
-extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
-extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
-extern int isdn_net_addphone(isdn_net_ioctl_phone *);
-extern int isdn_net_getphones(isdn_net_ioctl_phone *, char __user *);
-extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone __user *);
-extern int isdn_net_delphone(isdn_net_ioctl_phone *);
-extern int isdn_net_find_icall(int, int, int, setup_parm *);
-extern void isdn_net_hangup(struct net_device *);
-extern void isdn_net_dial(void);
-extern void isdn_net_autohup(void);
-extern int isdn_net_force_hangup(char *);
-extern int isdn_net_force_dial(char *);
-extern isdn_net_dev *isdn_net_findif(char *);
-extern int isdn_net_rcv_skb(int, struct sk_buff *);
-extern int isdn_net_dial_req(isdn_net_local *);
-extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
-extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
-
-#define ISDN_NET_MAX_QUEUE_LENGTH 2
-
-#define ISDN_MASTER_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->master))
-#define ISDN_SLAVE_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->slave))
-#define MASTER_TO_SLAVE(master) \
- (((isdn_net_local *) netdev_priv(master))->slave)
-
-/*
- * is this particular channel busy?
- */
-static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
-{
- if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
- return 0;
- else
- return 1;
-}
-
-/*
- * For the given net device, this will get a non-busy channel out of the
- * corresponding bundle. The returned channel is locked.
- */
-static __inline__ isdn_net_local *isdn_net_get_locked_lp(isdn_net_dev *nd)
-{
- unsigned long flags;
- isdn_net_local *lp;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
- lp = nd->queue; /* get lp on top of queue */
- while (isdn_net_lp_busy(nd->queue)) {
- nd->queue = nd->queue->next;
- if (nd->queue == lp) { /* not found -- should never happen */
- lp = NULL;
- goto errout;
- }
- }
- lp = nd->queue;
- nd->queue = nd->queue->next;
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- spin_lock(&lp->xmit_lock);
- local_bh_disable();
- return lp;
-errout:
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return lp;
-}
-
-/*
- * add a channel to a bundle
- */
-static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
-{
- isdn_net_local *lp;
- unsigned long flags;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
-
- lp = nd->queue;
-// printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n",
-// __func__, lp->name, lp, nlp->name, nlp, lp->last);
- nlp->last = lp->last;
- lp->last->next = nlp;
- lp->last = nlp;
- nlp->next = lp;
- nd->queue = nlp;
-
- spin_unlock_irqrestore(&nd->queue_lock, flags);
-}
-/*
- * remove a channel from the bundle it belongs to
- */
-static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
-{
- isdn_net_local *master_lp = lp;
- unsigned long flags;
-
- if (lp->master)
- master_lp = ISDN_MASTER_PRIV(lp);
-
-// printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
-// __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue);
- spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
- lp->last->next = lp->next;
- lp->next->last = lp->last;
- if (master_lp->netdev->queue == lp) {
- master_lp->netdev->queue = lp->next;
- if (lp->next == lp) { /* last in queue */
- master_lp->netdev->queue = master_lp->netdev->local;
- }
- }
- lp->next = lp->last = lp; /* (re)set own pointers */
-// printk(KERN_DEBUG "%s: mndq(%p)\n",
-// __func__, master_lp->netdev->queue);
- spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
-}
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
deleted file mode 100644
index 7e0f419c14f8..000000000000
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ /dev/null
@@ -1,3046 +0,0 @@
-/* $Id: isdn_ppp.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
- * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
- *
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/isdn.h>
-#include <linux/poll.h>
-#include <linux/ppp-comp.h>
-#include <linux/slab.h>
-#ifdef CONFIG_IPPP_FILTER
-#include <linux/filter.h>
-#endif
-
-#include "isdn_common.h"
-#include "isdn_ppp.h"
-#include "isdn_net.h"
-
-#ifndef PPP_IPX
-#define PPP_IPX 0x002b
-#endif
-
-/* Prototypes */
-static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
-static int isdn_ppp_closewait(int slot);
-static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb, int proto);
-static int isdn_ppp_if_get_unit(char *namebuf);
-static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *);
-static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
- struct ippp_struct *, struct ippp_struct *, int *proto);
-static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb, int proto);
-static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
- struct ippp_struct *is, struct ippp_struct *master, int type);
-static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb);
-
-/* New CCP stuff */
-static void isdn_ppp_ccp_kickup(struct ippp_struct *is);
-static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
- unsigned char code, unsigned char id,
- unsigned char *data, int len);
-static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is);
-static void isdn_ppp_ccp_reset_free(struct ippp_struct *is);
-static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
- unsigned char id);
-static void isdn_ppp_ccp_timer_callback(struct timer_list *t);
-static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
- unsigned char id);
-static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
- struct isdn_ppp_resetparams *rp);
-static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
- unsigned char id);
-
-
-
-#ifdef CONFIG_ISDN_MPP
-static ippp_bundle *isdn_ppp_bundle_arr = NULL;
-
-static int isdn_ppp_mp_bundle_array_init(void);
-static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to);
-static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb);
-static void isdn_ppp_mp_cleanup(isdn_net_local *lp);
-
-static int isdn_ppp_bundle(struct ippp_struct *, int unit);
-#endif /* CONFIG_ISDN_MPP */
-
-char *isdn_ppp_revision = "$Revision: 1.1.2.3 $";
-
-static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
-
-static struct isdn_ppp_compressor *ipc_head = NULL;
-
-/*
- * frame log (debug)
- */
-static void
-isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, int unit, int slot)
-{
- int cnt,
- j,
- i;
- char buf[80];
-
- if (len < maxlen)
- maxlen = len;
-
- for (i = 0, cnt = 0; cnt < maxlen; i++) {
- for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
- sprintf(buf + j * 3, "%02x ", (unsigned char)data[cnt]);
- printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n", unit, slot, info, i, buf);
- }
-}
-
-/*
- * unbind isdn_net_local <=> ippp-device
- * note: it can happen, that we hangup/free the master before the slaves
- * in this case we bind another lp to the master device
- */
-int
-isdn_ppp_free(isdn_net_local *lp)
-{
- struct ippp_struct *is;
-
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return 0;
- }
-
-#ifdef CONFIG_ISDN_MPP
- spin_lock(&lp->netdev->pb->lock);
-#endif
- isdn_net_rm_from_bundle(lp);
-#ifdef CONFIG_ISDN_MPP
- if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
- isdn_ppp_mp_cleanup(lp);
-
- lp->netdev->pb->ref_ct--;
- spin_unlock(&lp->netdev->pb->lock);
-#endif /* CONFIG_ISDN_MPP */
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
- __func__, lp->ppp_slot);
- return 0;
- }
- is = ippp_table[lp->ppp_slot];
- if ((is->state & IPPP_CONNECT))
- isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
- else if (is->state & IPPP_ASSIGNED)
- is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */
-
- if (is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
-
- is->lp = NULL; /* link is down .. set lp to NULL */
- lp->ppp_slot = -1; /* is this OK ?? */
-
- return 0;
-}
-
-/*
- * bind isdn_net_local <=> ippp-device
- *
- * This function is allways called with holding dev->lock so
- * no additional lock is needed
- */
-int
-isdn_ppp_bind(isdn_net_local *lp)
-{
- int i;
- int unit = 0;
- struct ippp_struct *is;
- int retval;
-
- if (lp->pppbind < 0) { /* device bounded to ippp device ? */
- isdn_net_dev *net_dev = dev->netdev;
- char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
- memset(exclusive, 0, ISDN_MAX_CHANNELS);
- while (net_dev) { /* step through net devices to find exclusive minors */
- isdn_net_local *lp = net_dev->local;
- if (lp->pppbind >= 0)
- exclusive[lp->pppbind] = 1;
- net_dev = net_dev->next;
- }
- /*
- * search a free device / slot
- */
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */
- break;
- }
- }
- } else {
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (ippp_table[i]->minor == lp->pppbind &&
- (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)
- break;
- }
- }
-
- if (i >= ISDN_MAX_CHANNELS) {
- printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n");
- retval = -1;
- goto out;
- }
- /* get unit number from interface name .. ugly! */
- unit = isdn_ppp_if_get_unit(lp->netdev->dev->name);
- if (unit < 0) {
- printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",
- lp->netdev->dev->name);
- retval = -1;
- goto out;
- }
-
- lp->ppp_slot = i;
- is = ippp_table[i];
- is->lp = lp;
- is->unit = unit;
- is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */
-#ifdef CONFIG_ISDN_MPP
- retval = isdn_ppp_mp_init(lp, NULL);
- if (retval < 0)
- goto out;
-#endif /* CONFIG_ISDN_MPP */
-
- retval = lp->ppp_slot;
-
-out:
- return retval;
-}
-
-/*
- * kick the ipppd on the device
- * (wakes up daemon after B-channel connect)
- */
-
-void
-isdn_ppp_wakeup_daemon(isdn_net_local *lp)
-{
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return;
- }
- ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
- wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
-}
-
-/*
- * there was a hangup on the netdevice
- * force wakeup of the ippp device
- * go into 'device waits for release' state
- */
-static int
-isdn_ppp_closewait(int slot)
-{
- struct ippp_struct *is;
-
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __func__, slot);
- return 0;
- }
- is = ippp_table[slot];
- if (is->state)
- wake_up_interruptible(&is->wq);
- is->state = IPPP_CLOSEWAIT;
- return 1;
-}
-
-/*
- * isdn_ppp_find_slot / isdn_ppp_free_slot
- */
-
-static int
-isdn_ppp_get_slot(void)
-{
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (!ippp_table[i]->state)
- return i;
- }
- return -1;
-}
-
-/*
- * isdn_ppp_open
- */
-
-int
-isdn_ppp_open(int min, struct file *file)
-{
- int slot;
- struct ippp_struct *is;
-
- if (min < 0 || min >= ISDN_MAX_CHANNELS)
- return -ENODEV;
-
- slot = isdn_ppp_get_slot();
- if (slot < 0) {
- return -EBUSY;
- }
- is = file->private_data = ippp_table[slot];
-
- printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",
- slot, min, is->state);
-
- /* compression stuff */
- is->link_compressor = is->compressor = NULL;
- is->link_decompressor = is->decompressor = NULL;
- is->link_comp_stat = is->comp_stat = NULL;
- is->link_decomp_stat = is->decomp_stat = NULL;
- is->compflags = 0;
-
- is->reset = isdn_ppp_ccp_reset_alloc(is);
- if (!is->reset)
- return -ENOMEM;
-
- is->lp = NULL;
- is->mp_seqno = 0; /* MP sequence number */
- is->pppcfg = 0; /* ppp configuration */
- is->mpppcfg = 0; /* mppp configuration */
- is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
- is->unit = -1; /* set, when we have our interface */
- is->mru = 1524; /* MRU, default 1524 */
- is->maxcid = 16; /* VJ: maxcid */
- is->tk = current;
- init_waitqueue_head(&is->wq);
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
- is->last = is->rq;
- is->minor = min;
-#ifdef CONFIG_ISDN_PPP_VJ
- /*
- * VJ header compression init
- */
- is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
- if (IS_ERR(is->slcomp)) {
- isdn_ppp_ccp_reset_free(is);
- return PTR_ERR(is->slcomp);
- }
-#endif
-#ifdef CONFIG_IPPP_FILTER
- is->pass_filter = NULL;
- is->active_filter = NULL;
-#endif
- is->state = IPPP_OPEN;
-
- return 0;
-}
-
-/*
- * release ippp device
- */
-void
-isdn_ppp_release(int min, struct file *file)
-{
- int i;
- struct ippp_struct *is;
-
- if (min < 0 || min >= ISDN_MAX_CHANNELS)
- return;
- is = file->private_data;
-
- if (!is) {
- printk(KERN_ERR "%s: no file->private_data\n", __func__);
- return;
- }
- if (is->debug & 0x1)
- printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
-
- if (is->lp) { /* a lp address says: this link is still up */
- isdn_net_dev *p = is->lp->netdev;
-
- if (!p) {
- printk(KERN_ERR "%s: no lp->netdev\n", __func__);
- return;
- }
- is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
- /*
- * isdn_net_hangup() calls isdn_ppp_free()
- * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
- * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
- */
- isdn_net_hangup(p->dev);
- }
- for (i = 0; i < NUM_RCV_BUFFS; i++) {
- kfree(is->rq[i].buf);
- is->rq[i].buf = NULL;
- }
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
- is->last = is->rq;
-
-#ifdef CONFIG_ISDN_PPP_VJ
-/* TODO: if this was the previous master: link the slcomp to the new master */
- slhc_free(is->slcomp);
- is->slcomp = NULL;
-#endif
-#ifdef CONFIG_IPPP_FILTER
- if (is->pass_filter) {
- bpf_prog_destroy(is->pass_filter);
- is->pass_filter = NULL;
- }
-
- if (is->active_filter) {
- bpf_prog_destroy(is->active_filter);
- is->active_filter = NULL;
- }
-#endif
-
-/* TODO: if this was the previous master: link the stuff to the new master */
- if (is->comp_stat)
- is->compressor->free(is->comp_stat);
- if (is->link_comp_stat)
- is->link_compressor->free(is->link_comp_stat);
- if (is->link_decomp_stat)
- is->link_decompressor->free(is->link_decomp_stat);
- if (is->decomp_stat)
- is->decompressor->free(is->decomp_stat);
- is->compressor = is->link_compressor = NULL;
- is->decompressor = is->link_decompressor = NULL;
- is->comp_stat = is->link_comp_stat = NULL;
- is->decomp_stat = is->link_decomp_stat = NULL;
-
- /* Clean up if necessary */
- if (is->reset)
- isdn_ppp_ccp_reset_free(is);
-
- /* this slot is ready for new connections */
- is->state = 0;
-}
-
-/*
- * get_arg .. ioctl helper
- */
-static int
-get_arg(void __user *b, void *val, int len)
-{
- if (len <= 0)
- len = sizeof(void *);
- if (copy_from_user(val, b, len))
- return -EFAULT;
- return 0;
-}
-
-/*
- * set arg .. ioctl helper
- */
-static int
-set_arg(void __user *b, void *val, int len)
-{
- if (len <= 0)
- len = sizeof(void *);
- if (copy_to_user(b, val, len))
- return -EFAULT;
- return 0;
-}
-
-#ifdef CONFIG_IPPP_FILTER
-static int get_filter(void __user *arg, struct sock_filter **p)
-{
- struct sock_fprog uprog;
- struct sock_filter *code = NULL;
- int len;
-
- if (copy_from_user(&uprog, arg, sizeof(uprog)))
- return -EFAULT;
-
- if (!uprog.len) {
- *p = NULL;
- return 0;
- }
-
- /* uprog.len is unsigned short, so no overflow here */
- len = uprog.len * sizeof(struct sock_filter);
- code = memdup_user(uprog.filter, len);
- if (IS_ERR(code))
- return PTR_ERR(code);
-
- *p = code;
- return uprog.len;
-}
-#endif /* CONFIG_IPPP_FILTER */
-
-/*
- * ippp device ioctl
- */
-int
-isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
-{
- unsigned long val;
- int r, i, j;
- struct ippp_struct *is;
- isdn_net_local *lp;
- struct isdn_ppp_comp_data data;
- void __user *argp = (void __user *)arg;
-
- is = file->private_data;
- lp = is->lp;
-
- if (is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
-
- if (!(is->state & IPPP_OPEN))
- return -EINVAL;
-
- switch (cmd) {
- case PPPIOCBUNDLE:
-#ifdef CONFIG_ISDN_MPP
- if (!(is->state & IPPP_CONNECT))
- return -EINVAL;
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
- (int) min, (int) is->unit, (int) val);
- return isdn_ppp_bundle(is, val);
-#else
- return -1;
-#endif
- break;
- case PPPIOCGUNIT: /* get ppp/isdn unit number */
- if ((r = set_arg(argp, &is->unit, sizeof(is->unit))))
- return r;
- break;
- case PPPIOCGIFNAME:
- if (!lp)
- return -EINVAL;
- if ((r = set_arg(argp, lp->netdev->dev->name,
- strlen(lp->netdev->dev->name))))
- return r;
- break;
- case PPPIOCGMPFLAGS: /* get configuration flags */
- if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg))))
- return r;
- break;
- case PPPIOCSMPFLAGS: /* set configuration flags */
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- is->mpppcfg = val;
- break;
- case PPPIOCGFLAGS: /* get configuration flags */
- if ((r = set_arg(argp, &is->pppcfg, sizeof(is->pppcfg))))
- return r;
- break;
- case PPPIOCSFLAGS: /* set configuration flags */
- if ((r = get_arg(argp, &val, sizeof(val)))) {
- return r;
- }
- if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
- if (lp) {
- /* OK .. we are ready to send buffers */
- is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
- netif_wake_queue(lp->netdev->dev);
- break;
- }
- }
- is->pppcfg = val;
- break;
- case PPPIOCGIDLE: /* get idle time information */
- if (lp) {
- struct ppp_idle pidle;
- pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
- if ((r = set_arg(argp, &pidle, sizeof(struct ppp_idle))))
- return r;
- }
- break;
- case PPPIOCSMRU: /* set receive unit size for PPP */
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- is->mru = val;
- break;
- case PPPIOCSMPMRU:
- break;
- case PPPIOCSMPMTU:
- break;
- case PPPIOCSMAXCID: /* set the maximum compression slot id */
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- val++;
- if (is->maxcid != val) {
-#ifdef CONFIG_ISDN_PPP_VJ
- struct slcompress *sltmp;
-#endif
- if (is->debug & 0x1)
- printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
- is->maxcid = val;
-#ifdef CONFIG_ISDN_PPP_VJ
- sltmp = slhc_init(16, val);
- if (IS_ERR(sltmp))
- return PTR_ERR(sltmp);
- if (is->slcomp)
- slhc_free(is->slcomp);
- is->slcomp = sltmp;
-#endif
- }
- break;
- case PPPIOCGDEBUG:
- if ((r = set_arg(argp, &is->debug, sizeof(is->debug))))
- return r;
- break;
- case PPPIOCSDEBUG:
- if ((r = get_arg(argp, &val, sizeof(val))))
- return r;
- is->debug = val;
- break;
- case PPPIOCGCOMPRESSORS:
- {
- unsigned long protos[8] = {0,};
- struct isdn_ppp_compressor *ipc = ipc_head;
- while (ipc) {
- j = ipc->num / (sizeof(long) * 8);
- i = ipc->num % (sizeof(long) * 8);
- if (j < 8)
- protos[j] |= (1UL << i);
- ipc = ipc->next;
- }
- if ((r = set_arg(argp, protos, 8 * sizeof(long))))
- return r;
- }
- break;
- case PPPIOCSCOMPRESSOR:
- if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data))))
- return r;
- return isdn_ppp_set_compressor(is, &data);
- case PPPIOCGCALLINFO:
- {
- struct pppcallinfo pci;
- memset((char *)&pci, 0, sizeof(struct pppcallinfo));
- if (lp)
- {
- strncpy(pci.local_num, lp->msn, 63);
- if (lp->dial) {
- strncpy(pci.remote_num, lp->dial->num, 63);
- }
- pci.charge_units = lp->charge;
- if (lp->outgoing)
- pci.calltype = CALLTYPE_OUTGOING;
- else
- pci.calltype = CALLTYPE_INCOMING;
- if (lp->flags & ISDN_NET_CALLBACK)
- pci.calltype |= CALLTYPE_CALLBACK;
- }
- return set_arg(argp, &pci, sizeof(struct pppcallinfo));
- }
-#ifdef CONFIG_IPPP_FILTER
- case PPPIOCSPASS:
- {
- struct sock_fprog_kern fprog;
- struct sock_filter *code;
- int err, len = get_filter(argp, &code);
-
- if (len < 0)
- return len;
-
- fprog.len = len;
- fprog.filter = code;
-
- if (is->pass_filter) {
- bpf_prog_destroy(is->pass_filter);
- is->pass_filter = NULL;
- }
- if (fprog.filter != NULL)
- err = bpf_prog_create(&is->pass_filter, &fprog);
- else
- err = 0;
- kfree(code);
-
- return err;
- }
- case PPPIOCSACTIVE:
- {
- struct sock_fprog_kern fprog;
- struct sock_filter *code;
- int err, len = get_filter(argp, &code);
-
- if (len < 0)
- return len;
-
- fprog.len = len;
- fprog.filter = code;
-
- if (is->active_filter) {
- bpf_prog_destroy(is->active_filter);
- is->active_filter = NULL;
- }
- if (fprog.filter != NULL)
- err = bpf_prog_create(&is->active_filter, &fprog);
- else
- err = 0;
- kfree(code);
-
- return err;
- }
-#endif /* CONFIG_IPPP_FILTER */
- default:
- break;
- }
- return 0;
-}
-
-__poll_t
-isdn_ppp_poll(struct file *file, poll_table *wait)
-{
- __poll_t mask;
- struct ippp_buf_queue *bf, *bl;
- u_long flags;
- struct ippp_struct *is;
-
- is = file->private_data;
-
- if (is->debug & 0x2)
- printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
- iminor(file_inode(file)));
-
- /* just registers wait_queue hook. This doesn't really wait. */
- poll_wait(file, &is->wq, wait);
-
- if (!(is->state & IPPP_OPEN)) {
- if (is->state == IPPP_CLOSEWAIT)
- return EPOLLHUP;
- printk(KERN_DEBUG "isdn_ppp: device not open\n");
- return EPOLLERR;
- }
- /* we're always ready to send .. */
- mask = EPOLLOUT | EPOLLWRNORM;
-
- spin_lock_irqsave(&is->buflock, flags);
- bl = is->last;
- bf = is->first;
- /*
- * if IPPP_NOBLOCK is set we return even if we have nothing to read
- */
- if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
- is->state &= ~IPPP_NOBLOCK;
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- spin_unlock_irqrestore(&is->buflock, flags);
- return mask;
-}
-
-/*
- * fill up isdn_ppp_read() queue ..
- */
-
-static int
-isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
-{
- struct ippp_buf_queue *bf, *bl;
- u_long flags;
- u_char *nbuf;
- struct ippp_struct *is;
-
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
- return 0;
- }
- is = ippp_table[slot];
-
- if (!(is->state & IPPP_CONNECT)) {
- printk(KERN_DEBUG "ippp: device not activated.\n");
- return 0;
- }
- nbuf = kmalloc(len + 4, GFP_ATOMIC);
- if (!nbuf) {
- printk(KERN_WARNING "ippp: Can't alloc buf\n");
- return 0;
- }
- nbuf[0] = PPP_ALLSTATIONS;
- nbuf[1] = PPP_UI;
- nbuf[2] = proto >> 8;
- nbuf[3] = proto & 0xff;
- memcpy(nbuf + 4, buf, len);
-
- spin_lock_irqsave(&is->buflock, flags);
- bf = is->first;
- bl = is->last;
-
- if (bf == bl) {
- printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
- bf = bf->next;
- kfree(bf->buf);
- is->first = bf;
- }
- bl->buf = (char *) nbuf;
- bl->len = len + 4;
-
- is->last = bl->next;
- spin_unlock_irqrestore(&is->buflock, flags);
- wake_up_interruptible(&is->wq);
- return len;
-}
-
-/*
- * read() .. non-blocking: ipppd calls it only after select()
- * reports, that there is data
- */
-
-int
-isdn_ppp_read(int min, struct file *file, char __user *buf, int count)
-{
- struct ippp_struct *is;
- struct ippp_buf_queue *b;
- u_long flags;
- u_char *save_buf;
-
- is = file->private_data;
-
- if (!(is->state & IPPP_OPEN))
- return 0;
-
- spin_lock_irqsave(&is->buflock, flags);
- b = is->first->next;
- save_buf = b->buf;
- if (!save_buf) {
- spin_unlock_irqrestore(&is->buflock, flags);
- return -EAGAIN;
- }
- if (b->len < count)
- count = b->len;
- b->buf = NULL;
- is->first = b;
-
- spin_unlock_irqrestore(&is->buflock, flags);
- if (copy_to_user(buf, save_buf, count))
- count = -EFAULT;
- kfree(save_buf);
-
- return count;
-}
-
-/*
- * ipppd wanna write a packet to the card .. non-blocking
- */
-
-int
-isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
-{
- isdn_net_local *lp;
- struct ippp_struct *is;
- int proto;
-
- is = file->private_data;
-
- if (!(is->state & IPPP_CONNECT))
- return 0;
-
- lp = is->lp;
-
- /* -> push it directly to the lowlevel interface */
-
- if (!lp)
- printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
- else {
- if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
- unsigned char protobuf[4];
- /*
- * Don't reset huptimer for
- * LCP packets. (Echo requests).
- */
- if (copy_from_user(protobuf, buf, 4))
- return -EFAULT;
-
- proto = PPP_PROTOCOL(protobuf);
- if (proto != PPP_LCP)
- lp->huptimer = 0;
-
- return 0;
- }
-
- if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
- lp->dialstate == 0 &&
- (lp->flags & ISDN_NET_CONNECTED)) {
- unsigned short hl;
- struct sk_buff *skb;
- unsigned char *cpy_buf;
- /*
- * we need to reserve enough space in front of
- * sk_buff. old call to dev_alloc_skb only reserved
- * 16 bytes, now we are looking what the driver want
- */
- hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
- skb = alloc_skb(hl + count, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
- return count;
- }
- skb_reserve(skb, hl);
- cpy_buf = skb_put(skb, count);
- if (copy_from_user(cpy_buf, buf, count))
- {
- kfree_skb(skb);
- return -EFAULT;
- }
-
- /*
- * Don't reset huptimer for
- * LCP packets. (Echo requests).
- */
- proto = PPP_PROTOCOL(cpy_buf);
- if (proto != PPP_LCP)
- lp->huptimer = 0;
-
- if (is->debug & 0x40) {
- printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
- isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
- }
-
- isdn_ppp_send_ccp(lp->netdev, lp, skb); /* keeps CCP/compression states in sync */
-
- isdn_net_write_super(lp, skb);
- }
- }
- return count;
-}
-
-/*
- * init memory, structures etc.
- */
-
-int
-isdn_ppp_init(void)
-{
- int i,
- j;
-
-#ifdef CONFIG_ISDN_MPP
- if (isdn_ppp_mp_bundle_array_init() < 0)
- return -ENOMEM;
-#endif /* CONFIG_ISDN_MPP */
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
- for (j = 0; j < i; j++)
- kfree(ippp_table[j]);
- return -1;
- }
- spin_lock_init(&ippp_table[i]->buflock);
- ippp_table[i]->state = 0;
- ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
- ippp_table[i]->last = ippp_table[i]->rq;
-
- for (j = 0; j < NUM_RCV_BUFFS; j++) {
- ippp_table[i]->rq[j].buf = NULL;
- ippp_table[i]->rq[j].last = ippp_table[i]->rq +
- (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
- ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
- }
- }
- return 0;
-}
-
-void
-isdn_ppp_cleanup(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- kfree(ippp_table[i]);
-
-#ifdef CONFIG_ISDN_MPP
- kfree(isdn_ppp_bundle_arr);
-#endif /* CONFIG_ISDN_MPP */
-
-}
-
-/*
- * check for address/control field and skip if allowed
- * retval != 0 -> discard packet silently
- */
-static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb)
-{
- if (skb->len < 1)
- return -1;
-
- if (skb->data[0] == 0xff) {
- if (skb->len < 2)
- return -1;
-
- if (skb->data[1] != 0x03)
- return -1;
-
- // skip address/control (AC) field
- skb_pull(skb, 2);
- } else {
- if (is->pppcfg & SC_REJ_COMP_AC)
- // if AC compression was not negotiated, but used, discard packet
- return -1;
- }
- return 0;
-}
-
-/*
- * get the PPP protocol header and pull skb
- * retval < 0 -> discard packet silently
- */
-static int isdn_ppp_strip_proto(struct sk_buff *skb)
-{
- int proto;
-
- if (skb->len < 1)
- return -1;
-
- if (skb->data[0] & 0x1) {
- // protocol field is compressed
- proto = skb->data[0];
- skb_pull(skb, 1);
- } else {
- if (skb->len < 2)
- return -1;
- proto = ((int) skb->data[0] << 8) + skb->data[1];
- skb_pull(skb, 2);
- }
- return proto;
-}
-
-
-/*
- * handler for incoming packets on a syncPPP interface
- */
-void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
-{
- struct ippp_struct *is;
- int slot;
- int proto;
-
- BUG_ON(net_dev->local->master); // we're called with the master device always
-
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
- lp->ppp_slot);
- kfree_skb(skb);
- return;
- }
- is = ippp_table[slot];
-
- if (is->debug & 0x4) {
- printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
- (long)is, (long)lp, lp->ppp_slot, is->unit, (int)skb->len);
- isdn_ppp_frame_log("receive", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
- }
-
- if (isdn_ppp_skip_ac(is, skb) < 0) {
- kfree_skb(skb);
- return;
- }
- proto = isdn_ppp_strip_proto(skb);
- if (proto < 0) {
- kfree_skb(skb);
- return;
- }
-
-#ifdef CONFIG_ISDN_MPP
- if (is->compflags & SC_LINK_DECOMP_ON) {
- skb = isdn_ppp_decompress(skb, is, NULL, &proto);
- if (!skb) // decompression error
- return;
- }
-
- if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
- if (proto == PPP_MP) {
- isdn_ppp_mp_receive(net_dev, lp, skb);
- return;
- }
- }
-#endif
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
-}
-
-/*
- * we receive a reassembled frame, MPPP has been taken care of before.
- * address/control and protocol have been stripped from the skb
- * note: net_dev has to be master net_dev
- */
-static void
-isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb, int proto)
-{
- struct net_device *dev = net_dev->dev;
- struct ippp_struct *is, *mis;
- isdn_net_local *mlp = NULL;
- int slot;
-
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
- lp->ppp_slot);
- goto drop_packet;
- }
- is = ippp_table[slot];
-
- if (lp->master) { // FIXME?
- mlp = ISDN_MASTER_PRIV(lp);
- slot = mlp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
- lp->ppp_slot);
- goto drop_packet;
- }
- }
- mis = ippp_table[slot];
-
- if (is->debug & 0x10) {
- printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
- isdn_ppp_frame_log("rpush", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
- }
- if (mis->compflags & SC_DECOMP_ON) {
- skb = isdn_ppp_decompress(skb, is, mis, &proto);
- if (!skb) // decompression error
- return;
- }
- switch (proto) {
- case PPP_IPX: /* untested */
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IPX\n");
- skb->protocol = htons(ETH_P_IPX);
- break;
- case PPP_IP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IP\n");
- skb->protocol = htons(ETH_P_IP);
- break;
- case PPP_COMP:
- case PPP_COMPFRAG:
- printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
- goto drop_packet;
-#ifdef CONFIG_ISDN_PPP_VJ
- case PPP_VJC_UNCOMP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
- if (net_dev->local->ppp_slot < 0) {
- printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
- __func__, net_dev->local->ppp_slot);
- goto drop_packet;
- }
- if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
- printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
- goto drop_packet;
- }
- skb->protocol = htons(ETH_P_IP);
- break;
- case PPP_VJC_COMP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
- {
- struct sk_buff *skb_old = skb;
- int pkt_len;
- skb = dev_alloc_skb(skb_old->len + 128);
-
- if (!skb) {
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- skb = skb_old;
- goto drop_packet;
- }
- skb_put(skb, skb_old->len + 128);
- skb_copy_from_linear_data(skb_old, skb->data,
- skb_old->len);
- if (net_dev->local->ppp_slot < 0) {
- printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
- __func__, net_dev->local->ppp_slot);
- goto drop_packet;
- }
- pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
- skb->data, skb_old->len);
- kfree_skb(skb_old);
- if (pkt_len < 0)
- goto drop_packet;
-
- skb_trim(skb, pkt_len);
- skb->protocol = htons(ETH_P_IP);
- }
- break;
-#endif
- case PPP_CCP:
- case PPP_CCPFRAG:
- isdn_ppp_receive_ccp(net_dev, lp, skb, proto);
- /* Dont pop up ResetReq/Ack stuff to the daemon any
- longer - the job is done already */
- if (skb->data[0] == CCP_RESETREQ ||
- skb->data[0] == CCP_RESETACK)
- break;
- /* fall through */
- default:
- isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
- kfree_skb(skb);
- return;
- }
-
-#ifdef CONFIG_IPPP_FILTER
- /* check if the packet passes the pass and active filters
- * the filter instructions are constructed assuming
- * a four-byte PPP header on each packet (which is still present) */
- skb_push(skb, 4);
-
- {
- u_int16_t *p = (u_int16_t *) skb->data;
-
- *p = 0; /* indicate inbound */
- }
-
- if (is->pass_filter
- && BPF_PROG_RUN(is->pass_filter, skb) == 0) {
- if (is->debug & 0x2)
- printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
- kfree_skb(skb);
- return;
- }
- if (!(is->active_filter
- && BPF_PROG_RUN(is->active_filter, skb) == 0)) {
- if (is->debug & 0x2)
- printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
- lp->huptimer = 0;
- if (mlp)
- mlp->huptimer = 0;
- }
- skb_pull(skb, 4);
-#else /* CONFIG_IPPP_FILTER */
- lp->huptimer = 0;
- if (mlp)
- mlp->huptimer = 0;
-#endif /* CONFIG_IPPP_FILTER */
- skb->dev = dev;
- skb_reset_mac_header(skb);
- netif_rx(skb);
- /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
- return;
-
-drop_packet:
- net_dev->local->stats.rx_dropped++;
- kfree_skb(skb);
-}
-
-/*
- * isdn_ppp_skb_push ..
- * checks whether we have enough space at the beginning of the skb
- * and allocs a new SKB if necessary
- */
-static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p, int len)
-{
- struct sk_buff *skb = *skb_p;
-
- if (skb_headroom(skb) < len) {
- struct sk_buff *nskb = skb_realloc_headroom(skb, len);
-
- if (!nskb) {
- printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n", skb_headroom(skb), len);
- dev_kfree_skb(skb);
- *skb_p = nskb;
- return skb_push(nskb, len);
- }
- return skb_push(skb, len);
-}
-
-/*
- * send ppp frame .. we expect a PIDCOMPressable proto --
- * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
- *
- * VJ compression may change skb pointer!!! .. requeue with old
- * skb isn't allowed!!
- */
-
-int
-isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
-{
- isdn_net_local *lp, *mlp;
- isdn_net_dev *nd;
- unsigned int proto = PPP_IP; /* 0x21 */
- struct ippp_struct *ipt, *ipts;
- int slot, retval = NETDEV_TX_OK;
-
- mlp = netdev_priv(netdev);
- nd = mlp->netdev; /* get master lp */
-
- slot = mlp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
- mlp->ppp_slot);
- kfree_skb(skb);
- goto out;
- }
- ipts = ippp_table[slot];
-
- if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
- if (ipts->debug & 0x1)
- printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
- retval = NETDEV_TX_BUSY;
- goto out;
- }
-
- switch (ntohs(skb->protocol)) {
- case ETH_P_IP:
- proto = PPP_IP;
- break;
- case ETH_P_IPX:
- proto = PPP_IPX; /* untested */
- break;
- default:
- printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
- skb->protocol);
- dev_kfree_skb(skb);
- goto out;
- }
-
- lp = isdn_net_get_locked_lp(nd);
- if (!lp) {
- printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
- retval = NETDEV_TX_BUSY;
- goto out;
- }
- /* we have our lp locked from now on */
-
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
- lp->ppp_slot);
- kfree_skb(skb);
- goto unlock;
- }
- ipt = ippp_table[slot];
-
- /*
- * after this line .. requeueing in the device queue is no longer allowed!!!
- */
-
- /* Pull off the fake header we stuck on earlier to keep
- * the fragmentation code happy.
- */
- skb_pull(skb, IPPP_MAX_HEADER);
-
-#ifdef CONFIG_IPPP_FILTER
- /* check if we should pass this packet
- * the filter instructions are constructed assuming
- * a four-byte PPP header on each packet */
- *(u8 *)skb_push(skb, 4) = 1; /* indicate outbound */
-
- {
- __be16 *p = (__be16 *)skb->data;
-
- p++;
- *p = htons(proto);
- }
-
- if (ipt->pass_filter
- && BPF_PROG_RUN(ipt->pass_filter, skb) == 0) {
- if (ipt->debug & 0x4)
- printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
- kfree_skb(skb);
- goto unlock;
- }
- if (!(ipt->active_filter
- && BPF_PROG_RUN(ipt->active_filter, skb) == 0)) {
- if (ipt->debug & 0x4)
- printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
- lp->huptimer = 0;
- }
- skb_pull(skb, 4);
-#else /* CONFIG_IPPP_FILTER */
- lp->huptimer = 0;
-#endif /* CONFIG_IPPP_FILTER */
-
- if (ipt->debug & 0x4)
- printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
- if (ipts->debug & 0x40)
- isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipts->unit, lp->ppp_slot);
-
-#ifdef CONFIG_ISDN_PPP_VJ
- if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
- struct sk_buff *new_skb;
- unsigned short hl;
- /*
- * we need to reserve enough space in front of
- * sk_buff. old call to dev_alloc_skb only reserved
- * 16 bytes, now we are looking what the driver want.
- */
- hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
- /*
- * Note: hl might still be insufficient because the method
- * above does not account for a possibible MPPP slave channel
- * which had larger HL header space requirements than the
- * master.
- */
- new_skb = alloc_skb(hl + skb->len, GFP_ATOMIC);
- if (new_skb) {
- u_char *buf;
- int pktlen;
-
- skb_reserve(new_skb, hl);
- new_skb->dev = skb->dev;
- skb_put(new_skb, skb->len);
- buf = skb->data;
-
- pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
- &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
-
- if (buf != skb->data) {
- if (new_skb->data != buf)
- printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
- dev_kfree_skb(skb);
- skb = new_skb;
- } else {
- dev_kfree_skb(new_skb);
- }
-
- skb_trim(skb, pktlen);
- if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
- proto = PPP_VJC_COMP;
- skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
- } else {
- if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
- proto = PPP_VJC_UNCOMP;
- skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
- }
- }
- }
-#endif
-
- /*
- * normal (single link) or bundle compression
- */
- if (ipts->compflags & SC_COMP_ON) {
- /* We send compressed only if both down- und upstream
- compression is negotiated, that means, CCP is up */
- if (ipts->compflags & SC_DECOMP_ON) {
- skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 0);
- } else {
- printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n");
- }
- }
-
- if (ipt->debug & 0x24)
- printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
-
-#ifdef CONFIG_ISDN_MPP
- if (ipt->mpppcfg & SC_MP_PROT) {
- /* we get mp_seqno from static isdn_net_local */
- long mp_seqno = ipts->mp_seqno;
- ipts->mp_seqno++;
- if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
- unsigned char *data = isdn_ppp_skb_push(&skb, 3);
- if (!data)
- goto unlock;
- mp_seqno &= 0xfff;
- data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
- data[1] = mp_seqno & 0xff;
- data[2] = proto; /* PID compression */
- } else {
- unsigned char *data = isdn_ppp_skb_push(&skb, 5);
- if (!data)
- goto unlock;
- data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
- data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
- data[2] = (mp_seqno >> 8) & 0xff;
- data[3] = (mp_seqno >> 0) & 0xff;
- data[4] = proto; /* PID compression */
- }
- proto = PPP_MP; /* MP Protocol, 0x003d */
- }
-#endif
-
- /*
- * 'link in bundle' compression ...
- */
- if (ipt->compflags & SC_LINK_COMP_ON)
- skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 1);
-
- if ((ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) {
- unsigned char *data = isdn_ppp_skb_push(&skb, 1);
- if (!data)
- goto unlock;
- data[0] = proto & 0xff;
- }
- else {
- unsigned char *data = isdn_ppp_skb_push(&skb, 2);
- if (!data)
- goto unlock;
- data[0] = (proto >> 8) & 0xff;
- data[1] = proto & 0xff;
- }
- if (!(ipt->pppcfg & SC_COMP_AC)) {
- unsigned char *data = isdn_ppp_skb_push(&skb, 2);
- if (!data)
- goto unlock;
- data[0] = 0xff; /* All Stations */
- data[1] = 0x03; /* Unnumbered information */
- }
-
- /* tx-stats are now updated via BSENT-callback */
-
- if (ipts->debug & 0x40) {
- printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
- isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipt->unit, lp->ppp_slot);
- }
-
- isdn_net_writebuf_skb(lp, skb);
-
-unlock:
- spin_unlock_bh(&lp->xmit_lock);
-out:
- return retval;
-}
-
-#ifdef CONFIG_IPPP_FILTER
-/*
- * check if this packet may trigger auto-dial.
- */
-
-int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
-{
- struct ippp_struct *is = ippp_table[lp->ppp_slot];
- u_int16_t proto;
- int drop = 0;
-
- switch (ntohs(skb->protocol)) {
- case ETH_P_IP:
- proto = PPP_IP;
- break;
- case ETH_P_IPX:
- proto = PPP_IPX;
- break;
- default:
- printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
- skb->protocol);
- return 1;
- }
-
- /* the filter instructions are constructed assuming
- * a four-byte PPP header on each packet. we have to
- * temporarily remove part of the fake header stuck on
- * earlier.
- */
- *(u8 *)skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */
-
- {
- __be16 *p = (__be16 *)skb->data;
-
- p++;
- *p = htons(proto);
- }
-
- drop |= is->pass_filter
- && BPF_PROG_RUN(is->pass_filter, skb) == 0;
- drop |= is->active_filter
- && BPF_PROG_RUN(is->active_filter, skb) == 0;
-
- skb_push(skb, IPPP_MAX_HEADER - 4);
- return drop;
-}
-#endif
-#ifdef CONFIG_ISDN_MPP
-
-/* this is _not_ rfc1990 header, but something we convert both short and long
- * headers to for convinience's sake:
- * byte 0 is flags as in rfc1990
- * bytes 1...4 is 24-bit seqence number converted to host byte order
- */
-#define MP_HEADER_LEN 5
-
-#define MP_LONGSEQ_MASK 0x00ffffff
-#define MP_SHORTSEQ_MASK 0x00000fff
-#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
-#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
-#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK + 1) >> 1)
-#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK + 1) >> 1)
-
-/* sequence-wrap safe comparisons (for long sequence)*/
-#define MP_LT(a, b) ((a - b) & MP_LONGSEQ_MAXBIT)
-#define MP_LE(a, b) !((b - a) & MP_LONGSEQ_MAXBIT)
-#define MP_GT(a, b) ((b - a) & MP_LONGSEQ_MAXBIT)
-#define MP_GE(a, b) !((a - b) & MP_LONGSEQ_MAXBIT)
-
-#define MP_SEQ(f) ((*(u32 *)(f->data + 1)))
-#define MP_FLAGS(f) (f->data[0])
-
-static int isdn_ppp_mp_bundle_array_init(void)
-{
- int i;
- int sz = ISDN_MAX_CHANNELS * sizeof(ippp_bundle);
- if ((isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL)
- return -ENOMEM;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
- return 0;
-}
-
-static ippp_bundle *isdn_ppp_mp_bundle_alloc(void)
-{
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
- return (isdn_ppp_bundle_arr + i);
- return NULL;
-}
-
-static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to)
-{
- struct ippp_struct *is;
-
- if (lp->ppp_slot < 0) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return (-EINVAL);
- }
-
- is = ippp_table[lp->ppp_slot];
- if (add_to) {
- if (lp->netdev->pb)
- lp->netdev->pb->ref_ct--;
- lp->netdev->pb = add_to;
- } else { /* first link in a bundle */
- is->mp_seqno = 0;
- if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
- return -ENOMEM;
- lp->next = lp->last = lp; /* nobody else in a queue */
- lp->netdev->pb->frags = NULL;
- lp->netdev->pb->frames = 0;
- lp->netdev->pb->seq = UINT_MAX;
- }
- lp->netdev->pb->ref_ct++;
-
- is->last_link_seqno = 0;
- return 0;
-}
-
-static u32 isdn_ppp_mp_get_seq(int short_seq,
- struct sk_buff *skb, u32 last_seq);
-static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
- struct sk_buff *from, struct sk_buff *to);
-static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *from, struct sk_buff *to);
-static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);
-static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb);
-
-static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb)
-{
- struct ippp_struct *is;
- isdn_net_local *lpq;
- ippp_bundle *mp;
- isdn_mppp_stats *stats;
- struct sk_buff *newfrag, *frag, *start, *nextf;
- u32 newseq, minseq, thisseq;
- unsigned long flags;
- int slot;
-
- spin_lock_irqsave(&net_dev->pb->lock, flags);
- mp = net_dev->pb;
- stats = &mp->stats;
- slot = lp->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
- __func__, lp->ppp_slot);
- stats->frame_drops++;
- dev_kfree_skb(skb);
- spin_unlock_irqrestore(&mp->lock, flags);
- return;
- }
- is = ippp_table[slot];
- if (++mp->frames > stats->max_queue_len)
- stats->max_queue_len = mp->frames;
-
- if (is->debug & 0x8)
- isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
-
- newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
- skb, is->last_link_seqno);
-
-
- /* if this packet seq # is less than last already processed one,
- * toss it right away, but check for sequence start case first
- */
- if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
- mp->seq = newseq; /* the first packet: required for
- * rfc1990 non-compliant clients --
- * prevents constant packet toss */
- } else if (MP_LT(newseq, mp->seq)) {
- stats->frame_drops++;
- isdn_ppp_mp_free_skb(mp, skb);
- spin_unlock_irqrestore(&mp->lock, flags);
- return;
- }
-
- /* find the minimum received sequence number over all links */
- is->last_link_seqno = minseq = newseq;
- for (lpq = net_dev->queue;;) {
- slot = lpq->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
- __func__, lpq->ppp_slot);
- } else {
- u32 lls = ippp_table[slot]->last_link_seqno;
- if (MP_LT(lls, minseq))
- minseq = lls;
- }
- if ((lpq = lpq->next) == net_dev->queue)
- break;
- }
- if (MP_LT(minseq, mp->seq))
- minseq = mp->seq; /* can't go beyond already processed
- * packets */
- newfrag = skb;
-
- /* if this new fragment is before the first one, then enqueue it now. */
- if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
- newfrag->next = frag;
- mp->frags = frag = newfrag;
- newfrag = NULL;
- }
-
- start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
- MP_SEQ(frag) == mp->seq ? frag : NULL;
-
- /*
- * main fragment traversing loop
- *
- * try to accomplish several tasks:
- * - insert new fragment into the proper sequence slot (once that's done
- * newfrag will be set to NULL)
- * - reassemble any complete fragment sequence (non-null 'start'
- * indicates there is a contiguous sequence present)
- * - discard any incomplete sequences that are below minseq -- due
- * to the fact that sender always increment sequence number, if there
- * is an incomplete sequence below minseq, no new fragments would
- * come to complete such sequence and it should be discarded
- *
- * loop completes when we accomplished the following tasks:
- * - new fragment is inserted in the proper sequence ('newfrag' is
- * set to NULL)
- * - we hit a gap in the sequence, so no reassembly/processing is
- * possible ('start' would be set to NULL)
- *
- * algorithm for this code is derived from code in the book
- * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
- */
- while (start != NULL || newfrag != NULL) {
-
- thisseq = MP_SEQ(frag);
- nextf = frag->next;
-
- /* drop any duplicate fragments */
- if (newfrag != NULL && thisseq == newseq) {
- isdn_ppp_mp_free_skb(mp, newfrag);
- newfrag = NULL;
- }
-
- /* insert new fragment before next element if possible. */
- if (newfrag != NULL && (nextf == NULL ||
- MP_LT(newseq, MP_SEQ(nextf)))) {
- newfrag->next = nextf;
- frag->next = nextf = newfrag;
- newfrag = NULL;
- }
-
- if (start != NULL) {
- /* check for misplaced start */
- if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
- printk(KERN_WARNING"isdn_mppp(seq %d): new "
- "BEGIN flag with no prior END", thisseq);
- stats->seqerrs++;
- stats->frame_drops++;
- start = isdn_ppp_mp_discard(mp, start, frag);
- nextf = frag->next;
- }
- } else if (MP_LE(thisseq, minseq)) {
- if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
- start = frag;
- else {
- if (MP_FLAGS(frag) & MP_END_FRAG)
- stats->frame_drops++;
- if (mp->frags == frag)
- mp->frags = nextf;
- isdn_ppp_mp_free_skb(mp, frag);
- frag = nextf;
- continue;
- }
- }
-
- /* if start is non-null and we have end fragment, then
- * we have full reassembly sequence -- reassemble
- * and process packet now
- */
- if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
- minseq = mp->seq = (thisseq + 1) & MP_LONGSEQ_MASK;
- /* Reassemble the packet then dispatch it */
- isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
-
- start = NULL;
- frag = NULL;
-
- mp->frags = nextf;
- }
-
- /* check if need to update start pointer: if we just
- * reassembled the packet and sequence is contiguous
- * then next fragment should be the start of new reassembly
- * if sequence is contiguous, but we haven't reassembled yet,
- * keep going.
- * if sequence is not contiguous, either clear everything
- * below low watermark and set start to the next frag or
- * clear start ptr.
- */
- if (nextf != NULL &&
- ((thisseq + 1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
- /* if we just reassembled and the next one is here,
- * then start another reassembly. */
-
- if (frag == NULL) {
- if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
- start = nextf;
- else
- {
- printk(KERN_WARNING"isdn_mppp(seq %d):"
- " END flag with no following "
- "BEGIN", thisseq);
- stats->seqerrs++;
- }
- }
-
- } else {
- if (nextf != NULL && frag != NULL &&
- MP_LT(thisseq, minseq)) {
- /* we've got a break in the sequence
- * and we not at the end yet
- * and we did not just reassembled
- *(if we did, there wouldn't be anything before)
- * and we below the low watermark
- * discard all the frames below low watermark
- * and start over */
- stats->frame_drops++;
- mp->frags = isdn_ppp_mp_discard(mp, start, nextf);
- }
- /* break in the sequence, no reassembly */
- start = NULL;
- }
-
- frag = nextf;
- } /* while -- main loop */
-
- if (mp->frags == NULL)
- mp->frags = frag;
-
- /* rather straighforward way to deal with (not very) possible
- * queue overflow */
- if (mp->frames > MP_MAX_QUEUE_LEN) {
- stats->overflows++;
- while (mp->frames > MP_MAX_QUEUE_LEN) {
- frag = mp->frags->next;
- isdn_ppp_mp_free_skb(mp, mp->frags);
- mp->frags = frag;
- }
- }
- spin_unlock_irqrestore(&mp->lock, flags);
-}
-
-static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
-{
- struct sk_buff *frag = lp->netdev->pb->frags;
- struct sk_buff *nextfrag;
- while (frag) {
- nextfrag = frag->next;
- isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
- frag = nextfrag;
- }
- lp->netdev->pb->frags = NULL;
-}
-
-static u32 isdn_ppp_mp_get_seq(int short_seq,
- struct sk_buff *skb, u32 last_seq)
-{
- u32 seq;
- int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
-
- if (!short_seq)
- {
- seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK;
- skb_push(skb, 1);
- }
- else
- {
- /* convert 12-bit short seq number to 24-bit long one
- */
- seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK;
-
- /* check for seqence wrap */
- if (!(seq & MP_SHORTSEQ_MAXBIT) &&
- (last_seq & MP_SHORTSEQ_MAXBIT) &&
- (unsigned long)last_seq <= MP_LONGSEQ_MAX)
- seq |= (last_seq + MP_SHORTSEQ_MAX + 1) &
- (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
- else
- seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
-
- skb_push(skb, 3); /* put converted seqence back in skb */
- }
- *(u32 *)(skb->data + 1) = seq; /* put seqence back in _host_ byte
- * order */
- skb->data[0] = flags; /* restore flags */
- return seq;
-}
-
-static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
- struct sk_buff *from,
- struct sk_buff *to)
-{
- if (from)
- while (from != to) {
- struct sk_buff *next = from->next;
- isdn_ppp_mp_free_skb(mp, from);
- from = next;
- }
- return from;
-}
-
-static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *from, struct sk_buff *to)
-{
- ippp_bundle *mp = net_dev->pb;
- int proto;
- struct sk_buff *skb;
- unsigned int tot_len;
-
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return;
- }
- if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
- if (ippp_table[lp->ppp_slot]->debug & 0x40)
- printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
- "len %d\n", MP_SEQ(from), from->len);
- skb = from;
- skb_pull(skb, MP_HEADER_LEN);
- mp->frames--;
- } else {
- struct sk_buff *frag;
- int n;
-
- for (tot_len = n = 0, frag = from; frag != to; frag = frag->next, n++)
- tot_len += frag->len - MP_HEADER_LEN;
-
- if (ippp_table[lp->ppp_slot]->debug & 0x40)
- printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
- "to %d, len %d\n", MP_SEQ(from),
- (MP_SEQ(from) + n - 1) & MP_LONGSEQ_MASK, tot_len);
- if ((skb = dev_alloc_skb(tot_len)) == NULL) {
- printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
- "of size %d\n", tot_len);
- isdn_ppp_mp_discard(mp, from, to);
- return;
- }
-
- while (from != to) {
- unsigned int len = from->len - MP_HEADER_LEN;
-
- skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
- skb_put(skb, len),
- len);
- frag = from->next;
- isdn_ppp_mp_free_skb(mp, from);
- from = frag;
- }
- }
- proto = isdn_ppp_strip_proto(skb);
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
-}
-
-static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
-{
- dev_kfree_skb(skb);
- mp->frames--;
-}
-
-static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb)
-{
- printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
- slot, (int) skb->len,
- (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
- (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
-}
-
-static int
-isdn_ppp_bundle(struct ippp_struct *is, int unit)
-{
- char ifn[IFNAMSIZ + 1];
- isdn_net_dev *p;
- isdn_net_local *lp, *nlp;
- int rc;
- unsigned long flags;
-
- sprintf(ifn, "ippp%d", unit);
- p = isdn_net_findif(ifn);
- if (!p) {
- printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&p->pb->lock, flags);
-
- nlp = is->lp;
- lp = p->queue;
- if (nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
- lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
- nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
- nlp->ppp_slot : lp->ppp_slot);
- rc = -EINVAL;
- goto out;
- }
-
- isdn_net_add_to_bundle(p, nlp);
-
- ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
-
- /* maybe also SC_CCP stuff */
- ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
- (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
- ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
- (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
- rc = isdn_ppp_mp_init(nlp, p->pb);
-out:
- spin_unlock_irqrestore(&p->pb->lock, flags);
- return rc;
-}
-
-#endif /* CONFIG_ISDN_MPP */
-
-/*
- * network device ioctl handlers
- */
-
-static int
-isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
-{
- struct ppp_stats __user *res = ifr->ifr_data;
- struct ppp_stats t;
- isdn_net_local *lp = netdev_priv(dev);
-
- /* build a temporary stat struct and copy it to user space */
-
- memset(&t, 0, sizeof(struct ppp_stats));
- if (dev->flags & IFF_UP) {
- t.p.ppp_ipackets = lp->stats.rx_packets;
- t.p.ppp_ibytes = lp->stats.rx_bytes;
- t.p.ppp_ierrors = lp->stats.rx_errors;
- t.p.ppp_opackets = lp->stats.tx_packets;
- t.p.ppp_obytes = lp->stats.tx_bytes;
- t.p.ppp_oerrors = lp->stats.tx_errors;
-#ifdef CONFIG_ISDN_PPP_VJ
- if (slot >= 0 && ippp_table[slot]->slcomp) {
- struct slcompress *slcomp = ippp_table[slot]->slcomp;
- t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
- t.vj.vjs_compressed = slcomp->sls_o_compressed;
- t.vj.vjs_searches = slcomp->sls_o_searches;
- t.vj.vjs_misses = slcomp->sls_o_misses;
- t.vj.vjs_errorin = slcomp->sls_i_error;
- t.vj.vjs_tossed = slcomp->sls_i_tossed;
- t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
- t.vj.vjs_compressedin = slcomp->sls_i_compressed;
- }
-#endif
- }
- if (copy_to_user(res, &t, sizeof(struct ppp_stats)))
- return -EFAULT;
- return 0;
-}
-
-int
-isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- int error = 0;
- int len;
- isdn_net_local *lp = netdev_priv(dev);
-
-
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
- return -EINVAL;
-
- switch (cmd) {
-#define PPP_VERSION "2.3.7"
- case SIOCGPPPVER:
- len = strlen(PPP_VERSION) + 1;
- if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))
- error = -EFAULT;
- break;
-
- case SIOCGPPPSTATS:
- error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
- break;
- default:
- error = -EINVAL;
- break;
- }
- return error;
-}
-
-static int
-isdn_ppp_if_get_unit(char *name)
-{
- int len,
- i,
- unit = 0,
- deci;
-
- len = strlen(name);
-
- if (strncmp("ippp", name, 4) || len > 8)
- return -1;
-
- for (i = 0, deci = 1; i < len; i++, deci *= 10) {
- char a = name[len - i - 1];
- if (a >= '0' && a <= '9')
- unit += (a - '0') * deci;
- else
- break;
- }
- if (!i || len - i != 4)
- unit = -1;
-
- return unit;
-}
-
-
-int
-isdn_ppp_dial_slave(char *name)
-{
-#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *ndev;
- isdn_net_local *lp;
- struct net_device *sdev;
-
- if (!(ndev = isdn_net_findif(name)))
- return 1;
- lp = ndev->local;
- if (!(lp->flags & ISDN_NET_CONNECTED))
- return 5;
-
- sdev = lp->slave;
- while (sdev) {
- isdn_net_local *mlp = netdev_priv(sdev);
- if (!(mlp->flags & ISDN_NET_CONNECTED))
- break;
- sdev = mlp->slave;
- }
- if (!sdev)
- return 2;
-
- isdn_net_dial_req(netdev_priv(sdev));
- return 0;
-#else
- return -1;
-#endif
-}
-
-int
-isdn_ppp_hangup_slave(char *name)
-{
-#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *ndev;
- isdn_net_local *lp;
- struct net_device *sdev;
-
- if (!(ndev = isdn_net_findif(name)))
- return 1;
- lp = ndev->local;
- if (!(lp->flags & ISDN_NET_CONNECTED))
- return 5;
-
- sdev = lp->slave;
- while (sdev) {
- isdn_net_local *mlp = netdev_priv(sdev);
-
- if (mlp->slave) { /* find last connected link in chain */
- isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp);
-
- if (!(nlp->flags & ISDN_NET_CONNECTED))
- break;
- } else if (mlp->flags & ISDN_NET_CONNECTED)
- break;
-
- sdev = mlp->slave;
- }
- if (!sdev)
- return 2;
-
- isdn_net_hangup(sdev);
- return 0;
-#else
- return -1;
-#endif
-}
-
-/*
- * PPP compression stuff
- */
-
-
-/* Push an empty CCP Data Frame up to the daemon to wake it up and let it
- generate a CCP Reset-Request or tear down CCP altogether */
-
-static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
-{
- isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
-}
-
-/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
- but absolutely nontrivial. The most abstruse problem we are facing is
- that the generation, reception and all the handling of timeouts and
- resends including proper request id management should be entirely left
- to the (de)compressor, but indeed is not covered by the current API to
- the (de)compressor. The API is a prototype version from PPP where only
- some (de)compressors have yet been implemented and all of them are
- rather simple in their reset handling. Especially, their is only one
- outstanding ResetAck at a time with all of them and ResetReq/-Acks do
- not have parameters. For this very special case it was sufficient to
- just return an error code from the decompressor and have a single
- reset() entry to communicate all the necessary information between
- the framework and the (de)compressor. Bad enough, LZS is different
- (and any other compressor may be different, too). It has multiple
- histories (eventually) and needs to Reset each of them independently
- and thus uses multiple outstanding Acks and history numbers as an
- additional parameter to Reqs/Acks.
- All that makes it harder to port the reset state engine into the
- kernel because it is not just the same simple one as in (i)pppd but
- it must be able to pass additional parameters and have multiple out-
- standing Acks. We are trying to achieve the impossible by handling
- reset transactions independent by their id. The id MUST change when
- the data portion changes, thus any (de)compressor who uses more than
- one resettable state must provide and recognize individual ids for
- each individual reset transaction. The framework itself does _only_
- differentiate them by id, because it has no other semantics like the
- (de)compressor might.
- This looks like a major redesign of the interface would be nice,
- but I don't have an idea how to do it better. */
-
-/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is
- getting that lengthy because there is no simple "send-this-frame-out"
- function above but every wrapper does a bit different. Hope I guess
- correct in this hack... */
-
-static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
- unsigned char code, unsigned char id,
- unsigned char *data, int len)
-{
- struct sk_buff *skb;
- unsigned char *p;
- int hl;
- int cnt = 0;
- isdn_net_local *lp = is->lp;
-
- /* Alloc large enough skb */
- hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
- skb = alloc_skb(len + hl + 16, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_WARNING
- "ippp: CCP cannot send reset - out of memory\n");
- return;
- }
- skb_reserve(skb, hl);
-
- /* We may need to stuff an address and control field first */
- if (!(is->pppcfg & SC_COMP_AC)) {
- p = skb_put(skb, 2);
- *p++ = 0xff;
- *p++ = 0x03;
- }
-
- /* Stuff proto, code, id and length */
- p = skb_put(skb, 6);
- *p++ = (proto >> 8);
- *p++ = (proto & 0xff);
- *p++ = code;
- *p++ = id;
- cnt = 4 + len;
- *p++ = (cnt >> 8);
- *p++ = (cnt & 0xff);
-
- /* Now stuff remaining bytes */
- if (len) {
- skb_put_data(skb, data, len);
- }
-
- /* skb is now ready for xmit */
- printk(KERN_DEBUG "Sending CCP Frame:\n");
- isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
-
- isdn_net_write_super(lp, skb);
-}
-
-/* Allocate the reset state vector */
-static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
-{
- struct ippp_ccp_reset *r;
- r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
- if (!r) {
- printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
- " structure - no mem\n");
- return NULL;
- }
- printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
- is->reset = r;
- return r;
-}
-
-/* Destroy the reset state vector. Kill all pending timers first. */
-static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
-{
- unsigned int id;
-
- printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
- is->reset);
- for (id = 0; id < 256; id++) {
- if (is->reset->rs[id]) {
- isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
- }
- }
- kfree(is->reset);
- is->reset = NULL;
-}
-
-/* Free a given state and clear everything up for later reallocation */
-static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
- unsigned char id)
-{
- struct ippp_ccp_reset_state *rs;
-
- if (is->reset->rs[id]) {
- printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
- rs = is->reset->rs[id];
- /* Make sure the kernel will not call back later */
- if (rs->ta)
- del_timer(&rs->timer);
- is->reset->rs[id] = NULL;
- kfree(rs);
- } else {
- printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
- }
-}
-
-/* The timer callback function which is called when a ResetReq has timed out,
- aka has never been answered by a ResetAck */
-static void isdn_ppp_ccp_timer_callback(struct timer_list *t)
-{
- struct ippp_ccp_reset_state *rs =
- from_timer(rs, t, timer);
-
- if (!rs) {
- printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
- return;
- }
- if (rs->ta && rs->state == CCPResetSentReq) {
- /* We are correct here */
- if (!rs->expra) {
- /* Hmm, there is no Ack really expected. We can clean
- up the state now, it will be reallocated if the
- decompressor insists on another reset */
- rs->ta = 0;
- isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
- return;
- }
- printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
- rs->id);
- /* Push it again */
- isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
- rs->data, rs->dlen);
- /* Restart timer */
- rs->timer.expires = jiffies + HZ * 5;
- add_timer(&rs->timer);
- } else {
- printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
- rs->state);
- }
-}
-
-/* Allocate a new reset transaction state */
-static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
- unsigned char id)
-{
- struct ippp_ccp_reset_state *rs;
- if (is->reset->rs[id]) {
- printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
- id);
- return NULL;
- } else {
- rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_ATOMIC);
- if (!rs)
- return NULL;
- rs->state = CCPResetIdle;
- rs->is = is;
- rs->id = id;
- timer_setup(&rs->timer, isdn_ppp_ccp_timer_callback, 0);
- is->reset->rs[id] = rs;
- }
- return rs;
-}
-
-
-/* A decompressor wants a reset with a set of parameters - do what is
- necessary to fulfill it */
-static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
- struct isdn_ppp_resetparams *rp)
-{
- struct ippp_ccp_reset_state *rs;
-
- if (rp->valid) {
- /* The decompressor defines parameters by itself */
- if (rp->rsend) {
- /* And he wants us to send a request */
- if (!(rp->idval)) {
- printk(KERN_ERR "ippp_ccp: decompressor must"
- " specify reset id\n");
- return;
- }
- if (is->reset->rs[rp->id]) {
- /* There is already a transaction in existence
- for this id. May be still waiting for a
- Ack or may be wrong. */
- rs = is->reset->rs[rp->id];
- if (rs->state == CCPResetSentReq && rs->ta) {
- printk(KERN_DEBUG "ippp_ccp: reset"
- " trans still in progress"
- " for id %d\n", rp->id);
- } else {
- printk(KERN_WARNING "ippp_ccp: reset"
- " trans in wrong state %d for"
- " id %d\n", rs->state, rp->id);
- }
- } else {
- /* Ok, this is a new transaction */
- printk(KERN_DEBUG "ippp_ccp: new trans for id"
- " %d to be started\n", rp->id);
- rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
- if (!rs) {
- printk(KERN_ERR "ippp_ccp: out of mem"
- " allocing ccp trans\n");
- return;
- }
- rs->state = CCPResetSentReq;
- rs->expra = rp->expra;
- if (rp->dtval) {
- rs->dlen = rp->dlen;
- memcpy(rs->data, rp->data, rp->dlen);
- }
- /* HACK TODO - add link comp here */
- isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
- CCP_RESETREQ, rs->id,
- rs->data, rs->dlen);
- /* Start the timer */
- rs->timer.expires = jiffies + 5 * HZ;
- add_timer(&rs->timer);
- rs->ta = 1;
- }
- } else {
- printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
- }
- } else {
- /* The reset params are invalid. The decompressor does not
- care about them, so we just send the minimal requests
- and increase ids only when an Ack is received for a
- given id */
- if (is->reset->rs[is->reset->lastid]) {
- /* There is already a transaction in existence
- for this id. May be still waiting for a
- Ack or may be wrong. */
- rs = is->reset->rs[is->reset->lastid];
- if (rs->state == CCPResetSentReq && rs->ta) {
- printk(KERN_DEBUG "ippp_ccp: reset"
- " trans still in progress"
- " for id %d\n", rp->id);
- } else {
- printk(KERN_WARNING "ippp_ccp: reset"
- " trans in wrong state %d for"
- " id %d\n", rs->state, rp->id);
- }
- } else {
- printk(KERN_DEBUG "ippp_ccp: new trans for id"
- " %d to be started\n", is->reset->lastid);
- rs = isdn_ppp_ccp_reset_alloc_state(is,
- is->reset->lastid);
- if (!rs) {
- printk(KERN_ERR "ippp_ccp: out of mem"
- " allocing ccp trans\n");
- return;
- }
- rs->state = CCPResetSentReq;
- /* We always expect an Ack if the decompressor doesn't
- know better */
- rs->expra = 1;
- rs->dlen = 0;
- /* HACK TODO - add link comp here */
- isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
- rs->id, NULL, 0);
- /* Start the timer */
- rs->timer.expires = jiffies + 5 * HZ;
- add_timer(&rs->timer);
- rs->ta = 1;
- }
- }
-}
-
-/* An Ack was received for this id. This means we stop the timer and clean
- up the state prior to calling the decompressors reset routine. */
-static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
- unsigned char id)
-{
- struct ippp_ccp_reset_state *rs = is->reset->rs[id];
-
- if (rs) {
- if (rs->ta && rs->state == CCPResetSentReq) {
- /* Great, we are correct */
- if (!rs->expra)
- printk(KERN_DEBUG "ippp_ccp: ResetAck received"
- " for id %d but not expected\n", id);
- } else {
- printk(KERN_INFO "ippp_ccp: ResetAck received out of"
- "sync for id %d\n", id);
- }
- if (rs->ta) {
- rs->ta = 0;
- del_timer(&rs->timer);
- }
- isdn_ppp_ccp_reset_free_state(is, id);
- } else {
- printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
- " %d\n", id);
- }
- /* Make sure the simple reset stuff uses a new id next time */
- is->reset->lastid++;
-}
-
-/*
- * decompress packet
- *
- * if master = 0, we're trying to uncompress an per-link compressed packet,
- * as opposed to an compressed reconstructed-from-MPPP packet.
- * proto is updated to protocol field of uncompressed packet.
- *
- * retval: decompressed packet,
- * same packet if uncompressed,
- * NULL if decompression error
- */
-
-static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb, struct ippp_struct *is, struct ippp_struct *master,
- int *proto)
-{
- void *stat = NULL;
- struct isdn_ppp_compressor *ipc = NULL;
- struct sk_buff *skb_out;
- int len;
- struct ippp_struct *ri;
- struct isdn_ppp_resetparams rsparm;
- unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
-
- if (!master) {
- // per-link decompression
- stat = is->link_decomp_stat;
- ipc = is->link_decompressor;
- ri = is;
- } else {
- stat = master->decomp_stat;
- ipc = master->decompressor;
- ri = master;
- }
-
- if (!ipc) {
- // no decompressor -> we can't decompress.
- printk(KERN_DEBUG "ippp: no decompressor defined!\n");
- return skb;
- }
- BUG_ON(!stat); // if we have a compressor, stat has been set as well
-
- if ((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG)) {
- // compressed packets are compressed by their protocol type
-
- // Set up reset params for the decompressor
- memset(&rsparm, 0, sizeof(rsparm));
- rsparm.data = rsdata;
- rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
-
- skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
- if (!skb_out) {
- kfree_skb(skb);
- printk(KERN_ERR "ippp: decomp memory allocation failure\n");
- return NULL;
- }
- len = ipc->decompress(stat, skb, skb_out, &rsparm);
- kfree_skb(skb);
- if (len <= 0) {
- switch (len) {
- case DECOMP_ERROR:
- printk(KERN_INFO "ippp: decomp wants reset %s params\n",
- rsparm.valid ? "with" : "without");
-
- isdn_ppp_ccp_reset_trans(ri, &rsparm);
- break;
- case DECOMP_FATALERROR:
- ri->pppcfg |= SC_DC_FERROR;
- /* Kick ipppd to recognize the error */
- isdn_ppp_ccp_kickup(ri);
- break;
- }
- kfree_skb(skb_out);
- return NULL;
- }
- *proto = isdn_ppp_strip_proto(skb_out);
- if (*proto < 0) {
- kfree_skb(skb_out);
- return NULL;
- }
- return skb_out;
- } else {
- // uncompressed packets are fed through the decompressor to
- // update the decompressor state
- ipc->incomp(stat, skb, *proto);
- return skb;
- }
-}
-
-/*
- * compress a frame
- * type=0: normal/bundle compression
- * =1: link compression
- * returns original skb if we haven't compressed the frame
- * and a new skb pointer if we've done it
- */
-static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
- struct ippp_struct *is, struct ippp_struct *master, int type)
-{
- int ret;
- int new_proto;
- struct isdn_ppp_compressor *compressor;
- void *stat;
- struct sk_buff *skb_out;
-
- /* we do not compress control protocols */
- if (*proto < 0 || *proto > 0x3fff) {
- return skb_in;
- }
-
- if (type) { /* type=1 => Link compression */
- return skb_in;
- }
- else {
- if (!master) {
- compressor = is->compressor;
- stat = is->comp_stat;
- }
- else {
- compressor = master->compressor;
- stat = master->comp_stat;
- }
- new_proto = PPP_COMP;
- }
-
- if (!compressor) {
- printk(KERN_ERR "isdn_ppp: No compressor set!\n");
- return skb_in;
- }
- if (!stat) {
- printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
- return skb_in;
- }
-
- /* Allow for at least 150 % expansion (for now) */
- skb_out = alloc_skb(skb_in->len + skb_in->len / 2 + 32 +
- skb_headroom(skb_in), GFP_ATOMIC);
- if (!skb_out)
- return skb_in;
- skb_reserve(skb_out, skb_headroom(skb_in));
-
- ret = (compressor->compress)(stat, skb_in, skb_out, *proto);
- if (!ret) {
- dev_kfree_skb(skb_out);
- return skb_in;
- }
-
- dev_kfree_skb(skb_in);
- *proto = new_proto;
- return skb_out;
-}
-
-/*
- * we received a CCP frame ..
- * not a clean solution, but we MUST handle a few cases in the kernel
- */
-static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
- struct sk_buff *skb, int proto)
-{
- struct ippp_struct *is;
- struct ippp_struct *mis;
- int len;
- struct isdn_ppp_resetparams rsparm;
- unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
-
- printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
- lp->ppp_slot);
- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, lp->ppp_slot);
- return;
- }
- is = ippp_table[lp->ppp_slot];
- isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
-
- if (lp->master) {
- int slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __func__, slot);
- return;
- }
- mis = ippp_table[slot];
- } else
- mis = is;
-
- switch (skb->data[0]) {
- case CCP_CONFREQ:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable compression here!\n");
- if (proto == PPP_CCP)
- mis->compflags &= ~SC_COMP_ON;
- else
- is->compflags &= ~SC_LINK_COMP_ON;
- break;
- case CCP_TERMREQ:
- case CCP_TERMACK:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable (de)compression here!\n");
- if (proto == PPP_CCP)
- mis->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
- else
- is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
- break;
- case CCP_CONFACK:
- /* if we RECEIVE an ackowledge we enable the decompressor */
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Enable decompression here!\n");
- if (proto == PPP_CCP) {
- if (!mis->decompressor)
- break;
- mis->compflags |= SC_DECOMP_ON;
- } else {
- if (!is->decompressor)
- break;
- is->compflags |= SC_LINK_DECOMP_ON;
- }
- break;
-
- case CCP_RESETACK:
- printk(KERN_DEBUG "Received ResetAck from peer\n");
- len = (skb->data[2] << 8) | skb->data[3];
- len -= 4;
-
- if (proto == PPP_CCP) {
- /* If a reset Ack was outstanding for this id, then
- clean up the state engine */
- isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
- if (mis->decompressor && mis->decomp_stat)
- mis->decompressor->
- reset(mis->decomp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, NULL);
- /* TODO: This is not easy to decide here */
- mis->compflags &= ~SC_DECOMP_DISCARD;
- }
- else {
- isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
- if (is->link_decompressor && is->link_decomp_stat)
- is->link_decompressor->
- reset(is->link_decomp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, NULL);
- /* TODO: neither here */
- is->compflags &= ~SC_LINK_DECOMP_DISCARD;
- }
- break;
-
- case CCP_RESETREQ:
- printk(KERN_DEBUG "Received ResetReq from peer\n");
- /* Receiving a ResetReq means we must reset our compressor */
- /* Set up reset params for the reset entry */
- memset(&rsparm, 0, sizeof(rsparm));
- rsparm.data = rsdata;
- rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
- /* Isolate data length */
- len = (skb->data[2] << 8) | skb->data[3];
- len -= 4;
- if (proto == PPP_CCP) {
- if (mis->compressor && mis->comp_stat)
- mis->compressor->
- reset(mis->comp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, &rsparm);
- }
- else {
- if (is->link_compressor && is->link_comp_stat)
- is->link_compressor->
- reset(is->link_comp_stat,
- skb->data[0],
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len, &rsparm);
- }
- /* Ack the Req as specified by rsparm */
- if (rsparm.valid) {
- /* Compressor reset handler decided how to answer */
- if (rsparm.rsend) {
- /* We should send a Frame */
- isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
- rsparm.idval ? rsparm.id
- : skb->data[1],
- rsparm.dtval ?
- rsparm.data : NULL,
- rsparm.dtval ?
- rsparm.dlen : 0);
- } else {
- printk(KERN_DEBUG "ResetAck suppressed\n");
- }
- } else {
- /* We answer with a straight reflected Ack */
- isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
- skb->data[1],
- len ? &skb->data[4] : NULL,
- len);
- }
- break;
- }
-}
-
-
-/*
- * Daemon sends a CCP frame ...
- */
-
-/* TODO: Clean this up with new Reset semantics */
-
-/* I believe the CCP handling as-is is done wrong. Compressed frames
- * should only be sent/received after CCP reaches UP state, which means
- * both sides have sent CONF_ACK. Currently, we handle both directions
- * independently, which means we may accept compressed frames too early
- * (supposedly not a problem), but may also mean we send compressed frames
- * too early, which may turn out to be a problem.
- * This part of state machine should actually be handled by (i)pppd, but
- * that's too big of a change now. --kai
- */
-
-/* Actually, we might turn this into an advantage: deal with the RFC in
- * the old tradition of beeing generous on what we accept, but beeing
- * strict on what we send. Thus we should just
- * - accept compressed frames as soon as decompression is negotiated
- * - send compressed frames only when decomp *and* comp are negotiated
- * - drop rx compressed frames if we cannot decomp (instead of pushing them
- * up to ipppd)
- * and I tried to modify this file according to that. --abp
- */
-
-static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
-{
- struct ippp_struct *mis, *is;
- int proto, slot = lp->ppp_slot;
- unsigned char *data;
-
- if (!skb || skb->len < 3)
- return;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
- __func__, slot);
- return;
- }
- is = ippp_table[slot];
- /* Daemon may send with or without address and control field comp */
- data = skb->data;
- if (!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
- data += 2;
- if (skb->len < 5)
- return;
- }
-
- proto = ((int)data[0]<<8) + data[1];
- if (proto != PPP_CCP && proto != PPP_CCPFRAG)
- return;
-
- printk(KERN_DEBUG "Received CCP frame from daemon:\n");
- isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
-
- if (lp->master) {
- slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __func__, slot);
- return;
- }
- mis = ippp_table[slot];
- } else
- mis = is;
- if (mis != is)
- printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
-
- switch (data[2]) {
- case CCP_CONFREQ:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable decompression here!\n");
- if (proto == PPP_CCP)
- is->compflags &= ~SC_DECOMP_ON;
- else
- is->compflags &= ~SC_LINK_DECOMP_ON;
- break;
- case CCP_TERMREQ:
- case CCP_TERMACK:
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Disable (de)compression here!\n");
- if (proto == PPP_CCP)
- is->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
- else
- is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
- break;
- case CCP_CONFACK:
- /* if we SEND an ackowledge we can/must enable the compressor */
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Enable compression here!\n");
- if (proto == PPP_CCP) {
- if (!is->compressor)
- break;
- is->compflags |= SC_COMP_ON;
- } else {
- if (!is->compressor)
- break;
- is->compflags |= SC_LINK_COMP_ON;
- }
- break;
- case CCP_RESETACK:
- /* If we send a ACK we should reset our compressor */
- if (is->debug & 0x10)
- printk(KERN_DEBUG "Reset decompression state here!\n");
- printk(KERN_DEBUG "ResetAck from daemon passed by\n");
- if (proto == PPP_CCP) {
- /* link to master? */
- if (is->compressor && is->comp_stat)
- is->compressor->reset(is->comp_stat, 0, 0,
- NULL, 0, NULL);
- is->compflags &= ~SC_COMP_DISCARD;
- }
- else {
- if (is->link_compressor && is->link_comp_stat)
- is->link_compressor->reset(is->link_comp_stat,
- 0, 0, NULL, 0, NULL);
- is->compflags &= ~SC_LINK_COMP_DISCARD;
- }
- break;
- case CCP_RESETREQ:
- /* Just let it pass by */
- printk(KERN_DEBUG "ResetReq from daemon passed by\n");
- break;
- }
-}
-
-int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
-{
- ipc->next = ipc_head;
- ipc->prev = NULL;
- if (ipc_head) {
- ipc_head->prev = ipc;
- }
- ipc_head = ipc;
- return 0;
-}
-
-int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
-{
- if (ipc->prev)
- ipc->prev->next = ipc->next;
- else
- ipc_head = ipc->next;
- if (ipc->next)
- ipc->next->prev = ipc->prev;
- ipc->prev = ipc->next = NULL;
- return 0;
-}
-
-static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
-{
- struct isdn_ppp_compressor *ipc = ipc_head;
- int ret;
- void *stat;
- int num = data->num;
-
- if (is->debug & 0x10)
- printk(KERN_DEBUG "[%d] Set %s type %d\n", is->unit,
- (data->flags & IPPP_COMP_FLAG_XMIT) ? "compressor" : "decompressor", num);
-
- /* If is has no valid reset state vector, we cannot allocate a
- decompressor. The decompressor would cause reset transactions
- sooner or later, and they need that vector. */
-
- if (!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
- printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
- " allow decompression.\n");
- return -ENOMEM;
- }
-
- while (ipc) {
- if (ipc->num == num) {
- stat = ipc->alloc(data);
- if (stat) {
- ret = ipc->init(stat, data, is->unit, 0);
- if (!ret) {
- printk(KERN_ERR "Can't init (de)compression!\n");
- ipc->free(stat);
- stat = NULL;
- break;
- }
- }
- else {
- printk(KERN_ERR "Can't alloc (de)compression!\n");
- break;
- }
-
- if (data->flags & IPPP_COMP_FLAG_XMIT) {
- if (data->flags & IPPP_COMP_FLAG_LINK) {
- if (is->link_comp_stat)
- is->link_compressor->free(is->link_comp_stat);
- is->link_comp_stat = stat;
- is->link_compressor = ipc;
- }
- else {
- if (is->comp_stat)
- is->compressor->free(is->comp_stat);
- is->comp_stat = stat;
- is->compressor = ipc;
- }
- }
- else {
- if (data->flags & IPPP_COMP_FLAG_LINK) {
- if (is->link_decomp_stat)
- is->link_decompressor->free(is->link_decomp_stat);
- is->link_decomp_stat = stat;
- is->link_decompressor = ipc;
- }
- else {
- if (is->decomp_stat)
- is->decompressor->free(is->decomp_stat);
- is->decomp_stat = stat;
- is->decompressor = ipc;
- }
- }
- return 0;
- }
- ipc = ipc->next;
- }
- return -EINVAL;
-}
diff --git a/drivers/isdn/i4l/isdn_ppp.h b/drivers/isdn/i4l/isdn_ppp.h
deleted file mode 100644
index 34b8a2ce84f3..000000000000
--- a/drivers/isdn/i4l/isdn_ppp.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* $Id: isdn_ppp.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
- *
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
-#include <linux/isdn_ppp.h> /* for isdn_ppp info */
-
-extern int isdn_ppp_read(int, struct file *, char __user *, int);
-extern int isdn_ppp_write(int, struct file *, const char __user *, int);
-extern int isdn_ppp_open(int, struct file *);
-extern int isdn_ppp_init(void);
-extern void isdn_ppp_cleanup(void);
-extern int isdn_ppp_free(isdn_net_local *);
-extern int isdn_ppp_bind(isdn_net_local *);
-extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *);
-extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
-extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
-extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
-extern __poll_t isdn_ppp_poll(struct file *, struct poll_table_struct *);
-extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
-extern void isdn_ppp_release(int, struct file *);
-extern int isdn_ppp_dial_slave(char *);
-extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
-
-extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc);
-extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc);
-
-#define IPPP_OPEN 0x01
-#define IPPP_CONNECT 0x02
-#define IPPP_CLOSEWAIT 0x04
-#define IPPP_NOBLOCK 0x08
-#define IPPP_ASSIGNED 0x10
-
-#define IPPP_MAX_HEADER 10
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
deleted file mode 100644
index 43700fc19a31..000000000000
--- a/drivers/isdn/i4l/isdn_tty.c
+++ /dev/null
@@ -1,3756 +0,0 @@
-/*
- * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-#undef ISDN_TTY_STAT_DEBUG
-
-#include <linux/isdn.h>
-#include <linux/serial.h> /* ASYNC_* flags */
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/sched/signal.h>
-#include "isdn_common.h"
-#include "isdn_tty.h"
-#ifdef CONFIG_ISDN_AUDIO
-#include "isdn_audio.h"
-#define VBUF 0x3e0
-#define VBUFX (VBUF/16)
-#endif
-
-#define FIX_FILE_TRANSFER
-#define DUMMY_HAYES_AT
-
-/* Prototypes */
-
-static DEFINE_MUTEX(modem_info_mutex);
-static int isdn_tty_edit_at(const char *, int, modem_info *);
-static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *);
-static void isdn_tty_modem_reset_regs(modem_info *, int);
-static void isdn_tty_cmd_ATA(modem_info *);
-static void isdn_tty_flush_buffer(struct tty_struct *);
-static void isdn_tty_modem_result(int, modem_info *);
-#ifdef CONFIG_ISDN_AUDIO
-static int isdn_tty_countDLE(unsigned char *, int);
-#endif
-
-/* Leave this unchanged unless you know what you do! */
-#define MODEM_PARANOIA_CHECK
-#define MODEM_DO_RESTART
-
-static int bit2si[8] =
-{1, 5, 7, 7, 7, 7, 7, 7};
-static int si2bit[8] =
-{4, 1, 4, 4, 4, 4, 4, 4};
-
-/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
- * to stuff incoming data directly into a tty's flip-buffer. This
- * is done to speed up tty-receiving if the receive-queue is empty.
- * This routine MUST be called with interrupts off.
- * Return:
- * 1 = Success
- * 0 = Failure, data has to be buffered and later processed by
- * isdn_tty_readmodem().
- */
-static int
-isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
-{
- struct tty_port *port = &info->port;
- int c;
- int len;
- char last;
-
- if (!info->online)
- return 0;
-
- if (!(info->mcr & UART_MCR_RTS))
- return 0;
-
- len = skb->len
-#ifdef CONFIG_ISDN_AUDIO
- + ISDN_AUDIO_SKB_DLECOUNT(skb)
-#endif
- ;
-
- c = tty_buffer_request_room(port, len);
- if (c < len)
- return 0;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
- int l = skb->len;
- unsigned char *dp = skb->data;
- while (--l) {
- if (*dp == DLE)
- tty_insert_flip_char(port, DLE, 0);
- tty_insert_flip_char(port, *dp++, 0);
- }
- if (*dp == DLE)
- tty_insert_flip_char(port, DLE, 0);
- last = *dp;
- } else {
-#endif
- if (len > 1)
- tty_insert_flip_string(port, skb->data, len - 1);
- last = skb->data[len - 1];
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
- tty_insert_flip_char(port, last, 0xFF);
- else
- tty_insert_flip_char(port, last, TTY_NORMAL);
- tty_flip_buffer_push(port);
- kfree_skb(skb);
-
- return 1;
-}
-
-/* isdn_tty_readmodem() is called periodically from within timer-interrupt.
- * It tries getting received data from the receive queue an stuff it into
- * the tty's flip-buffer.
- */
-void
-isdn_tty_readmodem(void)
-{
- int resched = 0;
- int midx;
- int i;
- int r;
- modem_info *info;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- midx = dev->m_idx[i];
- if (midx < 0)
- continue;
-
- info = &dev->mdm.info[midx];
- if (!info->online)
- continue;
-
- r = 0;
-#ifdef CONFIG_ISDN_AUDIO
- isdn_audio_eval_dtmf(info);
- if ((info->vonline & 1) && (info->emu.vpar[1]))
- isdn_audio_eval_silence(info);
-#endif
- if (info->mcr & UART_MCR_RTS) {
- /* CISCO AsyncPPP Hack */
- if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
- r = isdn_readbchan_tty(info->isdn_driver,
- info->isdn_channel,
- &info->port, 0);
- else
- r = isdn_readbchan_tty(info->isdn_driver,
- info->isdn_channel,
- &info->port, 1);
- if (r)
- tty_flip_buffer_push(&info->port);
- } else
- r = 1;
-
- if (r) {
- info->rcvsched = 0;
- resched = 1;
- } else
- info->rcvsched = 1;
- }
- if (!resched)
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
-}
-
-int
-isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
-{
- ulong flags;
- int midx;
-#ifdef CONFIG_ISDN_AUDIO
- int ifmt;
-#endif
- modem_info *info;
-
- if ((midx = dev->m_idx[i]) < 0) {
- /* if midx is invalid, packet is not for tty */
- return 0;
- }
- info = &dev->mdm.info[midx];
-#ifdef CONFIG_ISDN_AUDIO
- ifmt = 1;
-
- if ((info->vonline) && (!info->emu.vpar[4]))
- isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
- if ((info->vonline & 1) && (info->emu.vpar[1]))
- isdn_audio_calc_silence(info, skb->data, skb->len, ifmt);
-#endif
- if ((info->online < 2)
-#ifdef CONFIG_ISDN_AUDIO
- && (!(info->vonline & 1))
-#endif
- ) {
- /* If Modem not listening, drop data */
- kfree_skb(skb);
- return 1;
- }
- if (info->emu.mdmreg[REG_T70] & BIT_T70) {
- if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) {
- /* T.70 decoding: throw away the T.70 header (2 or 4 bytes) */
- if (skb->data[0] == 3) /* pure data packet -> 4 byte headers */
- skb_pull(skb, 4);
- else
- if (skb->data[0] == 1) /* keepalive packet -> 2 byte hdr */
- skb_pull(skb, 2);
- } else
- /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
- if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
- skb_pull(skb, 4);
- }
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
- if (info->vonline & 1) {
- /* voice conversion/compression */
- switch (info->emu.vpar[3]) {
- case 2:
- case 3:
- case 4:
- /* adpcm
- * Since compressed data takes less
- * space, we can overwrite the buffer.
- */
- skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr,
- ifmt,
- skb->data,
- skb->data,
- skb->len));
- break;
- case 5:
- /* a-law */
- if (!ifmt)
- isdn_audio_ulaw2alaw(skb->data, skb->len);
- break;
- case 6:
- /* u-law */
- if (ifmt)
- isdn_audio_alaw2ulaw(skb->data, skb->len);
- break;
- }
- ISDN_AUDIO_SKB_DLECOUNT(skb) =
- isdn_tty_countDLE(skb->data, skb->len);
- }
-#ifdef CONFIG_ISDN_TTY_FAX
- else {
- if (info->faxonline & 2) {
- isdn_tty_fax_bitorder(info, skb);
- ISDN_AUDIO_SKB_DLECOUNT(skb) =
- isdn_tty_countDLE(skb->data, skb->len);
- }
- }
-#endif
-#endif
- /* Try to deliver directly via tty-buf if queue is empty */
- spin_lock_irqsave(&info->readlock, flags);
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
- if (isdn_tty_try_read(info, skb)) {
- spin_unlock_irqrestore(&info->readlock, flags);
- return 1;
- }
- /* Direct deliver failed or queue wasn't empty.
- * Queue up for later dequeueing via timer-irq.
- */
- __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
- dev->drv[di]->rcvcount[channel] +=
- (skb->len
-#ifdef CONFIG_ISDN_AUDIO
- + ISDN_AUDIO_SKB_DLECOUNT(skb)
-#endif
- );
- spin_unlock_irqrestore(&info->readlock, flags);
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- return 1;
-}
-
-static void
-isdn_tty_cleanup_xmit(modem_info *info)
-{
- skb_queue_purge(&info->xmit_queue);
-#ifdef CONFIG_ISDN_AUDIO
- skb_queue_purge(&info->dtmf_queue);
-#endif
-}
-
-static void
-isdn_tty_tint(modem_info *info)
-{
- struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
- int len, slen;
-
- if (!skb)
- return;
- len = skb->len;
- if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
- info->isdn_channel, 1, skb)) == len) {
- struct tty_struct *tty = info->port.tty;
- info->send_outstanding++;
- info->msr &= ~UART_MSR_CTS;
- info->lsr &= ~UART_LSR_TEMT;
- tty_wakeup(tty);
- return;
- }
- if (slen < 0) {
- /* Error: no channel, already shutdown, or wrong parameter */
- dev_kfree_skb(skb);
- return;
- }
- skb_queue_head(&info->xmit_queue, skb);
-}
-
-#ifdef CONFIG_ISDN_AUDIO
-static int
-isdn_tty_countDLE(unsigned char *buf, int len)
-{
- int count = 0;
-
- while (len--)
- if (*buf++ == DLE)
- count++;
- return count;
-}
-
-/* This routine is called from within isdn_tty_write() to perform
- * DLE-decoding when sending audio-data.
- */
-static int
-isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
-{
- unsigned char *p = &info->port.xmit_buf[info->xmit_count];
- int count = 0;
-
- while (len > 0) {
- if (m->lastDLE) {
- m->lastDLE = 0;
- switch (*p) {
- case DLE:
- /* Escape code */
- if (len > 1)
- memmove(p, p + 1, len - 1);
- p--;
- count++;
- break;
- case ETX:
- /* End of data */
- info->vonline |= 4;
- return count;
- case DC4:
- /* Abort RX */
- info->vonline &= ~1;
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\020\003", info);
- if (!info->vonline) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "DLEdown: send VCON on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\r\nVCON\r\n", info);
- }
- /* Fall through */
- case 'q':
- case 's':
- /* Silence */
- if (len > 1)
- memmove(p, p + 1, len - 1);
- p--;
- break;
- }
- } else {
- if (*p == DLE)
- m->lastDLE = 1;
- else
- count++;
- }
- p++;
- len--;
- }
- if (len < 0) {
- printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
- return 0;
- }
- return count;
-}
-
-/* This routine is called from within isdn_tty_write() when receiving
- * audio-data. It interrupts receiving, if an character other than
- * ^S or ^Q is sent.
- */
-static int
-isdn_tty_end_vrx(const char *buf, int c)
-{
- char ch;
-
- while (c--) {
- ch = *buf;
- if ((ch != 0x11) && (ch != 0x13))
- return 1;
- buf++;
- }
- return 0;
-}
-
-static int voice_cf[7] =
-{0, 0, 4, 3, 2, 0, 0};
-
-#endif /* CONFIG_ISDN_AUDIO */
-
-/* isdn_tty_senddown() is called either directly from within isdn_tty_write()
- * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
- * outgoing data from the tty's xmit-buffer, handles voice-decompression or
- * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint.
- */
-static void
-isdn_tty_senddown(modem_info *info)
-{
- int buflen;
- int skb_res;
-#ifdef CONFIG_ISDN_AUDIO
- int audio_len;
-#endif
- struct sk_buff *skb;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 4) {
- info->vonline &= ~6;
- if (!info->vonline) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "senddown: send VCON on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\r\nVCON\r\n", info);
- }
- }
-#endif
- if (!(buflen = info->xmit_count))
- return;
- if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
- info->msr &= ~UART_MSR_CTS;
- info->lsr &= ~UART_LSR_TEMT;
- /* info->xmit_count is modified here and in isdn_tty_write().
- * So we return here if isdn_tty_write() is in the
- * critical section.
- */
- atomic_inc(&info->xmit_lock);
- if (!(atomic_dec_and_test(&info->xmit_lock)))
- return;
- if (info->isdn_driver < 0) {
- info->xmit_count = 0;
- return;
- }
- skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 2)
- audio_len = buflen * voice_cf[info->emu.vpar[3]];
- else
- audio_len = 0;
- skb = dev_alloc_skb(skb_res + buflen + audio_len);
-#else
- skb = dev_alloc_skb(skb_res + buflen);
-#endif
- if (!skb) {
- printk(KERN_WARNING
- "isdn_tty: Out of memory in ttyI%d senddown\n",
- info->line);
- return;
- }
- skb_reserve(skb, skb_res);
- skb_put_data(skb, info->port.xmit_buf, buflen);
- info->xmit_count = 0;
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 2) {
- /* For now, ifmt is fixed to 1 (alaw), since this
- * is used with ISDN everywhere in the world, except
- * US, Canada and Japan.
- * Later, when US-ISDN protocols are implemented,
- * this setting will depend on the D-channel protocol.
- */
- int ifmt = 1;
-
- /* voice conversion/decompression */
- switch (info->emu.vpar[3]) {
- case 2:
- case 3:
- case 4:
- /* adpcm, compatible to ZyXel 1496 modem
- * with ROM revision 6.01
- */
- audio_len = isdn_audio_adpcm2xlaw(info->adpcms,
- ifmt,
- skb->data,
- skb_put(skb, audio_len),
- buflen);
- skb_pull(skb, buflen);
- skb_trim(skb, audio_len);
- break;
- case 5:
- /* a-law */
- if (!ifmt)
- isdn_audio_alaw2ulaw(skb->data,
- buflen);
- break;
- case 6:
- /* u-law */
- if (ifmt)
- isdn_audio_ulaw2alaw(skb->data,
- buflen);
- break;
- }
- }
-#endif /* CONFIG_ISDN_AUDIO */
- if (info->emu.mdmreg[REG_T70] & BIT_T70) {
- /* Add T.70 simplified header */
- if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT)
- memcpy(skb_push(skb, 2), "\1\0", 2);
- else
- memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
- }
- skb_queue_tail(&info->xmit_queue, skb);
-}
-
-/************************************************************
- *
- * Modem-functions
- *
- * mostly "stolen" from original Linux-serial.c and friends.
- *
- ************************************************************/
-
-/* The next routine is called once from within timer-interrupt
- * triggered within isdn_tty_modem_ncarrier(). It calls
- * isdn_tty_modem_result() to stuff a "NO CARRIER" Message
- * into the tty's buffer.
- */
-static void
-isdn_tty_modem_do_ncarrier(struct timer_list *t)
-{
- modem_info *info = from_timer(info, t, nc_timer);
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
-}
-
-/* Next routine is called, whenever the DTR-signal is raised.
- * It checks the ncarrier-flag, and triggers the above routine
- * when necessary. The ncarrier-flag is set, whenever DTR goes
- * low.
- */
-static void
-isdn_tty_modem_ncarrier(modem_info *info)
-{
- if (info->ncarrier) {
- info->nc_timer.expires = jiffies + HZ;
- add_timer(&info->nc_timer);
- }
-}
-
-/*
- * return the usage calculated by si and layer 2 protocol
- */
-static int
-isdn_calc_usage(int si, int l2)
-{
- int usg = ISDN_USAGE_MODEM;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (si == 1) {
- switch (l2) {
- case ISDN_PROTO_L2_MODEM:
- usg = ISDN_USAGE_MODEM;
- break;
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_PROTO_L2_FAX:
- usg = ISDN_USAGE_FAX;
- break;
-#endif
- case ISDN_PROTO_L2_TRANS:
- default:
- usg = ISDN_USAGE_VOICE;
- break;
- }
- }
-#endif
- return (usg);
-}
-
-/* isdn_tty_dial() performs dialing of a tty an the necessary
- * setup of the lower levels before that.
- */
-static void
-isdn_tty_dial(char *n, modem_info *info, atemu *m)
-{
- int usg = ISDN_USAGE_MODEM;
- int si = 7;
- int l2 = m->mdmreg[REG_L2PROT];
- u_long flags;
- isdn_ctrl cmd;
- int i;
- int j;
-
- for (j = 7; j >= 0; j--)
- if (m->mdmreg[REG_SI1] & (1 << j)) {
- si = bit2si[j];
- break;
- }
- usg = isdn_calc_usage(si, l2);
-#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) &&
- (l2 != ISDN_PROTO_L2_MODEM)
-#ifdef CONFIG_ISDN_TTY_FAX
- && (l2 != ISDN_PROTO_L2_FAX)
-#endif
- ) {
- l2 = ISDN_PROTO_L2_TRANS;
- usg = ISDN_USAGE_VOICE;
- }
-#endif
- m->mdmreg[REG_SI1I] = si2bit[si];
- spin_lock_irqsave(&dev->lock, flags);
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- } else {
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- info->last_dir = 1;
- strcpy(info->last_num, n);
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- info->last_l2 = l2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
-#ifdef CONFIG_ISDN_TTY_FAX
- if (l2 == ISDN_PROTO_L2_FAX) {
- cmd.parm.fax = info->fax;
- info->fax->direction = ISDN_TTY_FAX_CONN_OUT;
- }
-#endif
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- sprintf(cmd.parm.setup.phone, "%s", n);
- sprintf(cmd.parm.setup.eazmsn, "%s",
- isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.parm.setup.si1 = si;
- cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
- cmd.command = ISDN_CMD_DIAL;
- info->dialing = 1;
- info->emu.carrierwait = 0;
- strcpy(dev->num[i], n);
- isdn_info_update();
- isdn_command(&cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
- }
-}
-
-/* isdn_tty_hangup() disassociates a tty from the real
- * ISDN-line (hangup). The usage-status is cleared
- * and some cleanup is done also.
- */
-void
-isdn_tty_modem_hup(modem_info *info, int local)
-{
- isdn_ctrl cmd;
- int di, ch;
-
- if (!info)
- return;
-
- di = info->isdn_driver;
- ch = info->isdn_channel;
- if (di < 0 || ch < 0)
- return;
-
- info->isdn_driver = -1;
- info->isdn_channel = -1;
-
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
-#endif
- info->rcvsched = 0;
- isdn_tty_flush_buffer(info->port.tty);
- if (info->online) {
- info->last_lhup = local;
- info->online = 0;
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- }
-#ifdef CONFIG_ISDN_AUDIO
- info->vonline = 0;
-#ifdef CONFIG_ISDN_TTY_FAX
- info->faxonline = 0;
- info->fax->phase = ISDN_FAX_PHASE_IDLE;
-#endif
- info->emu.vpar[4] = 0;
- info->emu.vpar[5] = 8;
- kfree(info->dtmf_state);
- info->dtmf_state = NULL;
- kfree(info->silence_state);
- info->silence_state = NULL;
- kfree(info->adpcms);
- info->adpcms = NULL;
- kfree(info->adpcmr);
- info->adpcmr = NULL;
-#endif
- if ((info->msr & UART_MSR_RI) &&
- (info->emu.mdmreg[REG_RUNG] & BIT_RUNG))
- isdn_tty_modem_result(RESULT_RUNG, info);
- info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
- info->lsr |= UART_LSR_TEMT;
-
- if (local) {
- cmd.driver = di;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = ch;
- isdn_command(&cmd);
- }
-
- isdn_all_eaz(di, ch);
- info->emu.mdmreg[REG_RINGCNT] = 0;
- isdn_free_channel(di, ch, 0);
-
- if (info->drv_index >= 0) {
- dev->m_idx[info->drv_index] = -1;
- info->drv_index = -1;
- }
-}
-
-/*
- * Begin of a CAPI like interface, currently used only for
- * supplementary service (CAPI 2.0 part III)
- */
-#include <linux/isdn/capicmd.h>
-#include <linux/module.h>
-
-int
-isdn_tty_capi_facility(capi_msg *cm) {
- return (-1); /* dummy */
-}
-
-/* isdn_tty_suspend() tries to suspend the current tty connection
- */
-static void
-isdn_tty_suspend(char *id, modem_info *info, atemu *m)
-{
- isdn_ctrl cmd;
-
- int l;
-
- if (!info)
- return;
-
-#ifdef ISDN_DEBUG_MODEM_SERVICES
- printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
-#endif
- l = strlen(id);
- if ((info->isdn_driver >= 0)) {
- cmd.parm.cmsg.Length = l + 18;
- cmd.parm.cmsg.Command = CAPI_FACILITY;
- cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
- cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
- cmd.parm.cmsg.para[1] = 0;
- cmd.parm.cmsg.para[2] = l + 3;
- cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
- cmd.parm.cmsg.para[4] = 0;
- cmd.parm.cmsg.para[5] = l;
- memcpy(&cmd.parm.cmsg.para[6], id, l);
- cmd.command = CAPI_PUT_MESSAGE;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- isdn_command(&cmd);
- }
-}
-
-/* isdn_tty_resume() tries to resume a suspended call
- * setup of the lower levels before that. unfortunately here is no
- * checking for compatibility of used protocols implemented by Q931
- * It does the same things like isdn_tty_dial, the last command
- * is different, may be we can merge it.
- */
-
-static void
-isdn_tty_resume(char *id, modem_info *info, atemu *m)
-{
- int usg = ISDN_USAGE_MODEM;
- int si = 7;
- int l2 = m->mdmreg[REG_L2PROT];
- isdn_ctrl cmd;
- ulong flags;
- int i;
- int j;
- int l;
-
- l = strlen(id);
- for (j = 7; j >= 0; j--)
- if (m->mdmreg[REG_SI1] & (1 << j)) {
- si = bit2si[j];
- break;
- }
- usg = isdn_calc_usage(si, l2);
-#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) &&
- (l2 != ISDN_PROTO_L2_MODEM)
-#ifdef CONFIG_ISDN_TTY_FAX
- && (l2 != ISDN_PROTO_L2_FAX)
-#endif
- ) {
- l2 = ISDN_PROTO_L2_TRANS;
- usg = ISDN_USAGE_VOICE;
- }
-#endif
- m->mdmreg[REG_SI1I] = si2bit[si];
- spin_lock_irqsave(&dev->lock, flags);
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- } else {
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- info->last_dir = 1;
-// strcpy(info->last_num, n);
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- info->last_l2 = l2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.parm.cmsg.Length = l + 18;
- cmd.parm.cmsg.Command = CAPI_FACILITY;
- cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
- cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
- cmd.parm.cmsg.para[1] = 0;
- cmd.parm.cmsg.para[2] = l + 3;
- cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */
- cmd.parm.cmsg.para[4] = 0;
- cmd.parm.cmsg.para[5] = l;
- memcpy(&cmd.parm.cmsg.para[6], id, l);
- cmd.command = CAPI_PUT_MESSAGE;
- info->dialing = 1;
-// strcpy(dev->num[i], n);
- isdn_info_update();
- isdn_command(&cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
- }
-}
-
-/* isdn_tty_send_msg() sends a message to a HL driver
- * This is used for hybrid modem cards to send AT commands to it
- */
-
-static void
-isdn_tty_send_msg(modem_info *info, atemu *m, char *msg)
-{
- int usg = ISDN_USAGE_MODEM;
- int si = 7;
- int l2 = m->mdmreg[REG_L2PROT];
- isdn_ctrl cmd;
- ulong flags;
- int i;
- int j;
- int l;
-
- l = min(strlen(msg), sizeof(cmd.parm) - sizeof(cmd.parm.cmsg)
- + sizeof(cmd.parm.cmsg.para) - 2);
-
- if (!l) {
- isdn_tty_modem_result(RESULT_ERROR, info);
- return;
- }
- for (j = 7; j >= 0; j--)
- if (m->mdmreg[REG_SI1] & (1 << j)) {
- si = bit2si[j];
- break;
- }
- usg = isdn_calc_usage(si, l2);
-#ifdef CONFIG_ISDN_AUDIO
- if ((si == 1) &&
- (l2 != ISDN_PROTO_L2_MODEM)
-#ifdef CONFIG_ISDN_TTY_FAX
- && (l2 != ISDN_PROTO_L2_FAX)
-#endif
- ) {
- l2 = ISDN_PROTO_L2_TRANS;
- usg = ISDN_USAGE_VOICE;
- }
-#endif
- m->mdmreg[REG_SI1I] = si2bit[si];
- spin_lock_irqsave(&dev->lock, flags);
- i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- } else {
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- info->last_dir = 1;
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- isdn_command(&cmd);
- strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETEAZ;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- info->last_l2 = l2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.parm.cmsg.Length = l + 14;
- cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
- cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
- cmd.parm.cmsg.para[0] = l + 1;
- strncpy(&cmd.parm.cmsg.para[1], msg, l);
- cmd.parm.cmsg.para[l + 1] = 0xd;
- cmd.command = CAPI_PUT_MESSAGE;
-/* info->dialing = 1;
- strcpy(dev->num[i], n);
- isdn_info_update();
-*/
- isdn_command(&cmd);
- }
-}
-
-static inline int
-isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)
-{
-#ifdef MODEM_PARANOIA_CHECK
- if (!info) {
- printk(KERN_WARNING "isdn_tty: null info_struct for %s in %s\n",
- name, routine);
- return 1;
- }
- if (info->magic != ISDN_ASYNC_MAGIC) {
- printk(KERN_WARNING "isdn_tty: bad magic for modem struct %s in %s\n",
- name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void
-isdn_tty_change_speed(modem_info *info)
-{
- struct tty_port *port = &info->port;
- uint cflag,
- cval,
- quot;
- int i;
-
- if (!port->tty)
- return;
- cflag = port->tty->termios.c_cflag;
-
- quot = i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 2)
- port->tty->termios.c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- if (quot) {
- info->mcr |= UART_MCR_DTR;
- isdn_tty_modem_ncarrier(info);
- } else {
- info->mcr &= ~UART_MCR_DTR;
- if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in changespeed\n");
-#endif
- if (info->online)
- info->ncarrier = 1;
- isdn_tty_modem_reset_regs(info, 0);
- isdn_tty_modem_hup(info, 1);
- }
- return;
- }
- /* byte size and parity */
- cval = cflag & (CSIZE | CSTOPB);
- cval >>= 4;
- if (cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(cflag & PARODD))
- cval |= UART_LCR_EPAR;
-
- tty_port_set_check_carrier(port, ~cflag & CLOCAL);
-}
-
-static int
-isdn_tty_startup(modem_info *info)
-{
- if (tty_port_initialized(&info->port))
- return 0;
- isdn_lock_drivers();
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
-#endif
- /*
- * Now, initialize the UART
- */
- info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
- /*
- * and set the speed of the serial port
- */
- isdn_tty_change_speed(info);
-
- tty_port_set_initialized(&info->port, 1);
- info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
- info->send_outstanding = 0;
- return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void
-isdn_tty_shutdown(modem_info *info)
-{
- if (!tty_port_initialized(&info->port))
- return;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
-#endif
- isdn_unlock_drivers();
- info->msr &= ~UART_MSR_RI;
- if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
- info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
- if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
- isdn_tty_modem_reset_regs(info, 0);
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
-#endif
- isdn_tty_modem_hup(info, 1);
- }
- }
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
- tty_port_set_initialized(&info->port, 0);
-}
-
-/* isdn_tty_write() is the main send-routine. It is called from the upper
- * levels within the kernel to perform sending data. Depending on the
- * online-flag it either directs output to the at-command-interpreter or
- * to the lower level. Additional tasks done here:
- * - If online, check for escape-sequence (+++)
- * - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes.
- * - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed.
- * - If dialing, abort dial.
- */
-static int
-isdn_tty_write(struct tty_struct *tty, const u_char *buf, int count)
-{
- int c;
- int total = 0;
- modem_info *info = (modem_info *) tty->driver_data;
- atemu *m = &info->emu;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write"))
- return 0;
- /* See isdn_tty_senddown() */
- atomic_inc(&info->xmit_lock);
- while (1) {
- c = count;
- if (c > info->xmit_size - info->xmit_count)
- c = info->xmit_size - info->xmit_count;
- if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize)
- c = dev->drv[info->isdn_driver]->maxbufsize;
- if (c <= 0)
- break;
- if ((info->online > 1)
-#ifdef CONFIG_ISDN_AUDIO
- || (info->vonline & 3)
-#endif
- ) {
-#ifdef CONFIG_ISDN_AUDIO
- if (!info->vonline)
-#endif
- isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
- &(m->pluscount),
- &(m->lastplus));
- memcpy(&info->port.xmit_buf[info->xmit_count], buf, c);
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline) {
- int cc = isdn_tty_handleDLEdown(info, m, c);
- if (info->vonline & 2) {
- if (!cc) {
- /* If DLE decoding results in zero-transmit, but
- * c originally was non-zero, do a wakeup.
- */
- tty_wakeup(tty);
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
- }
- info->xmit_count += cc;
- }
- if ((info->vonline & 3) == 1) {
- /* Do NOT handle Ctrl-Q or Ctrl-S
- * when in full-duplex audio mode.
- */
- if (isdn_tty_end_vrx(buf, c)) {
- info->vonline &= ~1;
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG
- "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n",
- info->line);
-#endif
- isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
- }
- }
- } else
- if (TTY_IS_FCLASS1(info)) {
- int cc = isdn_tty_handleDLEdown(info, m, c);
-
- if (info->vonline & 4) { /* ETX seen */
- isdn_ctrl c;
-
- c.command = ISDN_CMD_FAXCMD;
- c.driver = info->isdn_driver;
- c.arg = info->isdn_channel;
- c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL;
- c.parm.aux.subcmd = ETX;
- isdn_command(&c);
- }
- info->vonline = 0;
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c);
-#endif
- info->xmit_count += cc;
- } else
-#endif
- info->xmit_count += c;
- } else {
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
- if (info->dialing) {
- info->dialing = 0;
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
-#endif
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- isdn_tty_modem_hup(info, 1);
- } else
- c = isdn_tty_edit_at(buf, c, info);
- }
- buf += c;
- count -= c;
- total += c;
- }
- atomic_dec(&info->xmit_lock);
- if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) {
- if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
- }
- return total;
-}
-
-static int
-isdn_tty_write_room(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- int ret;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write_room"))
- return 0;
- if (!info->online)
- return info->xmit_size;
- ret = info->xmit_size - info->xmit_count;
- return (ret < 0) ? 0 : ret;
-}
-
-static int
-isdn_tty_chars_in_buffer(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_chars_in_buffer"))
- return 0;
- if (!info->online)
- return 0;
- return (info->xmit_count);
-}
-
-static void
-isdn_tty_flush_buffer(struct tty_struct *tty)
-{
- modem_info *info;
-
- if (!tty) {
- return;
- }
- info = (modem_info *) tty->driver_data;
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_buffer")) {
- return;
- }
- isdn_tty_cleanup_xmit(info);
- info->xmit_count = 0;
- tty_wakeup(tty);
-}
-
-static void
-isdn_tty_flush_chars(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars"))
- return;
- if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue))
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
-}
-
-/*
- * ------------------------------------------------------------
- * isdn_tty_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void
-isdn_tty_throttle(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_throttle"))
- return;
- if (I_IXOFF(tty))
- info->x_char = STOP_CHAR(tty);
- info->mcr &= ~UART_MCR_RTS;
-}
-
-static void
-isdn_tty_unthrottle(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_unthrottle"))
- return;
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- info->x_char = START_CHAR(tty);
- }
- info->mcr |= UART_MCR_RTS;
-}
-
-/*
- * ------------------------------------------------------------
- * isdn_tty_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-/*
- * isdn_tty_get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows RS485 driver to be written in user space.
- */
-static int
-isdn_tty_get_lsr_info(modem_info *info, uint __user *value)
-{
- u_char status;
- uint result;
-
- status = info->lsr;
- result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result, value);
-}
-
-
-static int
-isdn_tty_tiocmget(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- u_char control, status;
-
- if (isdn_tty_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
-
- mutex_lock(&modem_info_mutex);
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
-#endif
-
- control = info->mcr;
- status = info->msr;
- mutex_unlock(&modem_info_mutex);
- return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
- | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
- | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
- | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
- | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
- | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-}
-
-static int
-isdn_tty_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
-
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);
-#endif
-
- mutex_lock(&modem_info_mutex);
- if (set & TIOCM_RTS)
- info->mcr |= UART_MCR_RTS;
- if (set & TIOCM_DTR) {
- info->mcr |= UART_MCR_DTR;
- isdn_tty_modem_ncarrier(info);
- }
-
- if (clear & TIOCM_RTS)
- info->mcr &= ~UART_MCR_RTS;
- if (clear & TIOCM_DTR) {
- info->mcr &= ~UART_MCR_DTR;
- if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
- isdn_tty_modem_reset_regs(info, 0);
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in TIOCMSET\n");
-#endif
- if (info->online)
- info->ncarrier = 1;
- isdn_tty_modem_hup(info, 1);
- }
- }
- mutex_unlock(&modem_info_mutex);
- return 0;
-}
-
-static int
-isdn_tty_ioctl(struct tty_struct *tty, uint cmd, ulong arg)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl"))
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
- switch (cmd) {
- case TIOCSERGETLSR: /* Get line status register */
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
-#endif
- return isdn_tty_get_lsr_info(info, (uint __user *) arg);
- default:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
-#endif
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void
-isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- modem_info *info = (modem_info *) tty->driver_data;
-
- mutex_lock(&modem_info_mutex);
- if (!old_termios)
- isdn_tty_change_speed(info);
- else {
- if (tty->termios.c_cflag == old_termios->c_cflag &&
- tty->termios.c_ispeed == old_termios->c_ispeed &&
- tty->termios.c_ospeed == old_termios->c_ospeed) {
- mutex_unlock(&modem_info_mutex);
- return;
- }
- isdn_tty_change_speed(info);
- }
- mutex_unlock(&modem_info_mutex);
-}
-
-/*
- * ------------------------------------------------------------
- * isdn_tty_open() and friends
- * ------------------------------------------------------------
- */
-
-static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty)
-{
- modem_info *info = &dev->mdm.info[tty->index];
-
- if (isdn_tty_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
-
- tty->driver_data = info;
-
- return tty_port_install(&info->port, driver, tty);
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int
-isdn_tty_open(struct tty_struct *tty, struct file *filp)
-{
- modem_info *info = tty->driver_data;
- struct tty_port *port = &info->port;
- int retval;
-
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
- port->count);
-#endif
- port->count++;
- port->tty = tty;
- /*
- * Start up serial port
- */
- retval = isdn_tty_startup(info);
- if (retval) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open return after startup\n");
-#endif
- return retval;
- }
- retval = tty_port_block_til_ready(port, tty, filp);
- if (retval) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
-#endif
- return retval;
- }
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line);
-#endif
- dev->modempoll++;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_open normal exit\n");
-#endif
- return 0;
-}
-
-static void
-isdn_tty_close(struct tty_struct *tty, struct file *filp)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- struct tty_port *port = &info->port;
- ulong timeout;
-
- if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
- return;
- if (tty_hung_up_p(filp)) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n");
-#endif
- return;
- }
- if ((tty->count == 1) && (port->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
- "info->count is %d\n", port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
- info->line, port->count);
- port->count = 0;
- }
- if (port->count) {
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
-#endif
- return;
- }
- info->closing = 1;
-
- tty->closing = 1;
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
- if (tty_port_initialized(port)) {
- tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
- /*
- * Before we drop DTR, make sure the UART transmitter
- * has completely drained; this is especially
- * important if there is a transmit FIFO!
- */
- timeout = jiffies + HZ;
- while (!(info->lsr & UART_LSR_TEMT)) {
- schedule_timeout_interruptible(20);
- if (time_after(jiffies, timeout))
- break;
- }
- }
- dev->modempoll--;
- isdn_tty_shutdown(info);
- isdn_tty_flush_buffer(tty);
- tty_ldisc_flush(tty);
- port->tty = NULL;
- info->ncarrier = 0;
-
- tty_port_close_end(port, tty);
- info->closing = 0;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_close normal exit\n");
-#endif
-}
-
-/*
- * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void
-isdn_tty_hangup(struct tty_struct *tty)
-{
- modem_info *info = (modem_info *) tty->driver_data;
- struct tty_port *port = &info->port;
-
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
- return;
- isdn_tty_shutdown(info);
- port->count = 0;
- tty_port_set_active(port, 0);
- port->tty = NULL;
- wake_up_interruptible(&port->open_wait);
-}
-
-/* This routine initializes all emulator-data.
- */
-static void
-isdn_tty_reset_profile(atemu *m)
-{
- m->profile[0] = 0;
- m->profile[1] = 0;
- m->profile[2] = 43;
- m->profile[3] = 13;
- m->profile[4] = 10;
- m->profile[5] = 8;
- m->profile[6] = 3;
- m->profile[7] = 60;
- m->profile[8] = 2;
- m->profile[9] = 6;
- m->profile[10] = 7;
- m->profile[11] = 70;
- m->profile[12] = 0x45;
- m->profile[13] = 4;
- m->profile[14] = ISDN_PROTO_L2_X75I;
- m->profile[15] = ISDN_PROTO_L3_TRANS;
- m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16;
- m->profile[17] = ISDN_MODEM_WINSIZE;
- m->profile[18] = 4;
- m->profile[19] = 0;
- m->profile[20] = 0;
- m->profile[23] = 0;
- m->pmsn[0] = '\0';
- m->plmsn[0] = '\0';
-}
-
-#ifdef CONFIG_ISDN_AUDIO
-static void
-isdn_tty_modem_reset_vpar(atemu *m)
-{
- m->vpar[0] = 2; /* Voice-device (2 = phone line) */
- m->vpar[1] = 0; /* Silence detection level (0 = none ) */
- m->vpar[2] = 70; /* Silence interval (7 sec. ) */
- m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */
- m->vpar[4] = 0; /* DTMF detection level (0 = softcode ) */
- m->vpar[5] = 8; /* DTMF interval (8 * 5 ms. ) */
-}
-#endif
-
-#ifdef CONFIG_ISDN_TTY_FAX
-static void
-isdn_tty_modem_reset_faxpar(modem_info *info)
-{
- T30_s *f = info->fax;
-
- f->code = 0;
- f->phase = ISDN_FAX_PHASE_IDLE;
- f->direction = 0;
- f->resolution = 1; /* fine */
- f->rate = 5; /* 14400 bit/s */
- f->width = 0;
- f->length = 0;
- f->compression = 0;
- f->ecm = 0;
- f->binary = 0;
- f->scantime = 0;
- memset(&f->id[0], 32, FAXIDLEN - 1);
- f->id[FAXIDLEN - 1] = 0;
- f->badlin = 0;
- f->badmul = 0;
- f->bor = 0;
- f->nbc = 0;
- f->cq = 0;
- f->cr = 0;
- f->ctcrty = 0;
- f->minsp = 0;
- f->phcto = 30;
- f->rel = 0;
- memset(&f->pollid[0], 32, FAXIDLEN - 1);
- f->pollid[FAXIDLEN - 1] = 0;
-}
-#endif
-
-static void
-isdn_tty_modem_reset_regs(modem_info *info, int force)
-{
- atemu *m = &info->emu;
- if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) {
- memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG);
- memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
- memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN);
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- }
-#ifdef CONFIG_ISDN_AUDIO
- isdn_tty_modem_reset_vpar(m);
-#endif
-#ifdef CONFIG_ISDN_TTY_FAX
- isdn_tty_modem_reset_faxpar(info);
-#endif
- m->mdmcmdl = 0;
-}
-
-static void
-modem_write_profile(atemu *m)
-{
- memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG);
- memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
- memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
- if (dev->profd)
- send_sig(SIGIO, dev->profd, 1);
-}
-
-static const struct tty_operations modem_ops = {
- .install = isdn_tty_install,
- .open = isdn_tty_open,
- .close = isdn_tty_close,
- .write = isdn_tty_write,
- .flush_chars = isdn_tty_flush_chars,
- .write_room = isdn_tty_write_room,
- .chars_in_buffer = isdn_tty_chars_in_buffer,
- .flush_buffer = isdn_tty_flush_buffer,
- .ioctl = isdn_tty_ioctl,
- .throttle = isdn_tty_throttle,
- .unthrottle = isdn_tty_unthrottle,
- .set_termios = isdn_tty_set_termios,
- .hangup = isdn_tty_hangup,
- .tiocmget = isdn_tty_tiocmget,
- .tiocmset = isdn_tty_tiocmset,
-};
-
-static int isdn_tty_carrier_raised(struct tty_port *port)
-{
- modem_info *info = container_of(port, modem_info, port);
- return info->msr & UART_MSR_DCD;
-}
-
-static const struct tty_port_operations isdn_tty_port_ops = {
- .carrier_raised = isdn_tty_carrier_raised,
-};
-
-int
-isdn_tty_modem_init(void)
-{
- isdn_modem_t *m;
- int i, retval;
- modem_info *info;
-
- m = &dev->mdm;
- m->tty_modem = alloc_tty_driver(ISDN_MAX_CHANNELS);
- if (!m->tty_modem)
- return -ENOMEM;
- m->tty_modem->name = "ttyI";
- m->tty_modem->major = ISDN_TTY_MAJOR;
- m->tty_modem->minor_start = 0;
- m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL;
- m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
- m->tty_modem->init_termios = tty_std_termios;
- m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- m->tty_modem->flags = TTY_DRIVER_REAL_RAW;
- m->tty_modem->driver_name = "isdn_tty";
- tty_set_operations(m->tty_modem, &modem_ops);
- retval = tty_register_driver(m->tty_modem);
- if (retval) {
- printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n");
- goto err;
- }
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &m->info[i];
-#ifdef CONFIG_ISDN_TTY_FAX
- if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) {
- printk(KERN_ERR "Could not allocate fax t30-buffer\n");
- retval = -ENOMEM;
- goto err_unregister;
- }
-#endif
- tty_port_init(&info->port);
- info->port.ops = &isdn_tty_port_ops;
- spin_lock_init(&info->readlock);
- sprintf(info->last_cause, "0000");
- sprintf(info->last_num, "none");
- info->last_dir = 0;
- info->last_lhup = 1;
- info->last_l2 = -1;
- info->last_si = 0;
- isdn_tty_reset_profile(&info->emu);
- isdn_tty_modem_reset_regs(info, 1);
- info->magic = ISDN_ASYNC_MAGIC;
- info->line = i;
- info->x_char = 0;
- info->isdn_driver = -1;
- info->isdn_channel = -1;
- info->drv_index = -1;
- info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
- timer_setup(&info->nc_timer, isdn_tty_modem_do_ncarrier, 0);
- skb_queue_head_init(&info->xmit_queue);
-#ifdef CONFIG_ISDN_AUDIO
- skb_queue_head_init(&info->dtmf_queue);
-#endif
- info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5,
- GFP_KERNEL);
- if (!info->port.xmit_buf) {
- printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
- retval = -ENOMEM;
- goto err_unregister;
- }
- /* Make room for T.70 header */
- info->port.xmit_buf += 4;
- }
- return 0;
-err_unregister:
- for (i--; i >= 0; i--) {
- info = &m->info[i];
-#ifdef CONFIG_ISDN_TTY_FAX
- kfree(info->fax);
-#endif
- kfree(info->port.xmit_buf - 4);
- info->port.xmit_buf = NULL;
- tty_port_destroy(&info->port);
- }
- tty_unregister_driver(m->tty_modem);
-err:
- put_tty_driver(m->tty_modem);
- m->tty_modem = NULL;
- return retval;
-}
-
-void
-isdn_tty_exit(void)
-{
- modem_info *info;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &dev->mdm.info[i];
- isdn_tty_cleanup_xmit(info);
-#ifdef CONFIG_ISDN_TTY_FAX
- kfree(info->fax);
-#endif
- kfree(info->port.xmit_buf - 4);
- info->port.xmit_buf = NULL;
- tty_port_destroy(&info->port);
- }
- tty_unregister_driver(dev->mdm.tty_modem);
- put_tty_driver(dev->mdm.tty_modem);
- dev->mdm.tty_modem = NULL;
-}
-
-
-/*
- * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx)
- * match the MSN against the MSNs (glob patterns) defined for tty_emulator,
- * and return 0 for match, 1 for no match, 2 if MSN could match if longer.
- */
-
-static int
-isdn_tty_match_icall(char *cid, atemu *emu, int di)
-{
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n",
- emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di),
- emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]);
-#endif
- if (strlen(emu->lmsn)) {
- char *p = emu->lmsn;
- char *q;
- int tmp;
- int ret = 0;
-
- while (1) {
- if ((q = strchr(p, ';')))
- *q = '\0';
- if ((tmp = isdn_msncmp(cid, isdn_map_eaz2msn(p, di))) > ret)
- ret = tmp;
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n",
- p, isdn_map_eaz2msn(emu->msn, di), tmp);
-#endif
- if (q) {
- *q = ';';
- p = q;
- p++;
- }
- if (!tmp)
- return 0;
- if (!q)
- break;
- }
- return ret;
- } else {
- int tmp;
- tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di));
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n",
- isdn_map_eaz2msn(emu->msn, di), tmp);
-#endif
- return tmp;
- }
-}
-
-/*
- * An incoming call-request has arrived.
- * Search the tty-devices for an appropriate device and bind
- * it to the ISDN-Channel.
- * Return:
- *
- * 0 = No matching device found.
- * 1 = A matching device found.
- * 3 = No match found, but eventually would match, if
- * CID is longer.
- */
-int
-isdn_tty_find_icall(int di, int ch, setup_parm *setup)
-{
- char *eaz;
- int i;
- int wret;
- int idx;
- int si1;
- int si2;
- char *nr;
- ulong flags;
-
- if (!setup->phone[0]) {
- nr = "0";
- printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n");
- } else
- nr = setup->phone;
- si1 = (int) setup->si1;
- si2 = (int) setup->si2;
- if (!setup->eazmsn[0]) {
- printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n");
- eaz = "0";
- } else
- eaz = setup->eazmsn;
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
-#endif
- wret = 0;
- spin_lock_irqsave(&dev->lock, flags);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
-
- if (info->port.count == 0)
- continue;
- if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
- (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
- idx = isdn_dc2minor(di, ch);
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
- printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
- info->port.flags, info->isdn_driver,
- info->isdn_channel, dev->usage[idx]);
-#endif
- if (
-#ifndef FIX_FILE_TRANSFER
- tty_port_active(&info->port) &&
-#endif
- (info->isdn_driver == -1) &&
- (info->isdn_channel == -1) &&
- (USG_NONE(dev->usage[idx]))) {
- int matchret;
-
- if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
- wret = matchret;
- if (!matchret) { /* EAZ is matching */
- info->isdn_driver = di;
- info->isdn_channel = ch;
- info->drv_index = idx;
- dev->m_idx[idx] = info->line;
- dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]);
- strcpy(dev->num[idx], nr);
- strcpy(info->emu.cpn, eaz);
- info->emu.mdmreg[REG_SI1I] = si2bit[si1];
- info->emu.mdmreg[REG_PLAN] = setup->plan;
- info->emu.mdmreg[REG_SCREEN] = setup->screen;
- isdn_info_update();
- spin_unlock_irqrestore(&dev->lock, flags);
- printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
- info->line);
- info->msr |= UART_MSR_RI;
- isdn_tty_modem_result(RESULT_RING, info);
- isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
- return 1;
- }
- }
- }
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
- ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2)) ? "rejected" : "ignored");
- return (wret == 2) ? 3 : 0;
-}
-
-int
-isdn_tty_stat_callback(int i, isdn_ctrl *c)
-{
- int mi;
- modem_info *info;
- char *e;
-
- if (i < 0)
- return 0;
- if ((mi = dev->m_idx[i]) >= 0) {
- info = &dev->mdm.info[mi];
- switch (c->command) {
- case ISDN_STAT_CINF:
- printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
- info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10);
- if (e == (char *)c->parm.num)
- info->emu.charge = 0;
-
- break;
- case ISDN_STAT_BSENT:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
-#endif
- if ((info->isdn_driver == c->driver) &&
- (info->isdn_channel == c->arg)) {
- info->msr |= UART_MSR_CTS;
- if (info->send_outstanding)
- if (!(--info->send_outstanding))
- info->lsr |= UART_LSR_TEMT;
- isdn_tty_tint(info);
- return 1;
- }
- break;
- case ISDN_STAT_CAUSE:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
-#endif
- /* Signal cause to tty-device */
- strncpy(info->last_cause, c->parm.num, 5);
- return 1;
- case ISDN_STAT_DISPLAY:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_DISPLAY ttyI%d\n", info->line);
-#endif
- /* Signal display to tty-device */
- if ((info->emu.mdmreg[REG_DISPLAY] & BIT_DISPLAY) &&
- !(info->emu.mdmreg[REG_RESPNUM] & BIT_RESPNUM)) {
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout("DISPLAY: ", info);
- isdn_tty_at_cout(c->parm.display, info);
- isdn_tty_at_cout("\r\n", info);
- }
- return 1;
- case ISDN_STAT_DCONN:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
- if (info->dialing == 1) {
- info->dialing = 2;
- return 1;
- }
- }
- break;
- case ISDN_STAT_DHUP:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
- if (info->dialing == 1)
- isdn_tty_modem_result(RESULT_BUSY, info);
- if (info->dialing > 1)
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- info->dialing = 0;
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
-#endif
- isdn_tty_modem_hup(info, 0);
- return 1;
- }
- break;
- case ISDN_STAT_BCONN:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
-#endif
- /* Wake up any processes waiting
- * for incoming call of this device when
- * DCD follow the state of incoming carrier
- */
- if (info->port.blocked_open &&
- (info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
- wake_up_interruptible(&info->port.open_wait);
- }
-
- /* Schedule CONNECT-Message to any tty
- * waiting for it and
- * set DCD-bit of its modem-status.
- */
- if (tty_port_active(&info->port) ||
- (info->port.blocked_open &&
- (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
- info->msr |= UART_MSR_DCD;
- info->emu.charge = 0;
- if (info->dialing & 0xf)
- info->last_dir = 1;
- else
- info->last_dir = 0;
- info->dialing = 0;
- info->rcvsched = 1;
- if (USG_MODEM(dev->usage[i])) {
- if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
- strcpy(info->emu.connmsg, c->parm.num);
- isdn_tty_modem_result(RESULT_CONNECT, info);
- } else
- isdn_tty_modem_result(RESULT_CONNECT64000, info);
- }
- if (USG_VOICE(dev->usage[i]))
- isdn_tty_modem_result(RESULT_VCON, info);
- return 1;
- }
- break;
- case ISDN_STAT_BHUP:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
-#endif
- isdn_tty_modem_hup(info, 0);
- return 1;
- }
- break;
- case ISDN_STAT_NODCH:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
-#endif
- if (tty_port_active(&info->port)) {
- if (info->dialing) {
- info->dialing = 0;
- info->last_l2 = -1;
- info->last_si = 0;
- sprintf(info->last_cause, "0000");
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- }
- isdn_tty_modem_hup(info, 0);
- return 1;
- }
- break;
- case ISDN_STAT_UNLOAD:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
-#endif
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &dev->mdm.info[i];
- if (info->isdn_driver == c->driver) {
- if (info->online)
- isdn_tty_modem_hup(info, 1);
- }
- }
- return 1;
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_STAT_FAXIND:
- if (tty_port_active(&info->port)) {
- isdn_tty_fax_command(info, c);
- }
- break;
-#endif
-#ifdef CONFIG_ISDN_AUDIO
- case ISDN_STAT_AUDIO:
- if (tty_port_active(&info->port)) {
- switch (c->parm.num[0]) {
- case ISDN_AUDIO_DTMF:
- if (info->vonline) {
- isdn_audio_put_dle_code(info,
- c->parm.num[1]);
- }
- break;
- }
- }
- break;
-#endif
- }
- }
- return 0;
-}
-
-/*********************************************************************
- Modem-Emulator-Routines
-*********************************************************************/
-
-#define cmdchar(c) ((c >= ' ') && (c <= 0x7f))
-
-/*
- * Put a message from the AT-emulator into receive-buffer of tty,
- * convert CR, LF, and BS to values in modem-registers 3, 4 and 5.
- */
-void
-isdn_tty_at_cout(char *msg, modem_info *info)
-{
- struct tty_port *port = &info->port;
- atemu *m = &info->emu;
- char *p;
- char c;
- u_long flags;
- struct sk_buff *skb = NULL;
- char *sp = NULL;
- int l;
-
- if (!msg) {
- printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
- return;
- }
-
- l = strlen(msg);
-
- spin_lock_irqsave(&info->readlock, flags);
- if (info->closing) {
- spin_unlock_irqrestore(&info->readlock, flags);
- return;
- }
-
- /* use queue instead of direct, if online and */
- /* data is in queue or buffer is full */
- if (info->online && ((tty_buffer_request_room(port, l) < l) ||
- !skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) {
- skb = alloc_skb(l, GFP_ATOMIC);
- if (!skb) {
- spin_unlock_irqrestore(&info->readlock, flags);
- return;
- }
- sp = skb_put(skb, l);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
-
- for (p = msg; *p; p++) {
- switch (*p) {
- case '\r':
- c = m->mdmreg[REG_CR];
- break;
- case '\n':
- c = m->mdmreg[REG_LF];
- break;
- case '\b':
- c = m->mdmreg[REG_BS];
- break;
- default:
- c = *p;
- }
- if (skb) {
- *sp++ = c;
- } else {
- if (tty_insert_flip_char(port, c, TTY_NORMAL) == 0)
- break;
- }
- }
- if (skb) {
- __skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb);
- dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len;
- spin_unlock_irqrestore(&info->readlock, flags);
- /* Schedule dequeuing */
- if (dev->modempoll && info->rcvsched)
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
-
- } else {
- spin_unlock_irqrestore(&info->readlock, flags);
- tty_flip_buffer_push(port);
- }
-}
-
-/*
- * Perform ATH Hangup
- */
-static void
-isdn_tty_on_hook(modem_info *info)
-{
- if (info->isdn_channel >= 0) {
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
-#endif
- isdn_tty_modem_hup(info, 1);
- }
-}
-
-static void
-isdn_tty_off_hook(void)
-{
- printk(KERN_DEBUG "isdn_tty_off_hook\n");
-}
-
-#define PLUSWAIT1 (HZ / 2) /* 0.5 sec. */
-#define PLUSWAIT2 (HZ * 3 / 2) /* 1.5 sec */
-
-/*
- * Check Buffer for Modem-escape-sequence, activate timer-callback to
- * isdn_tty_modem_escape() if sequence found.
- *
- * Parameters:
- * p pointer to databuffer
- * plus escape-character
- * count length of buffer
- * pluscount count of valid escape-characters so far
- * lastplus timestamp of last character
- */
-static void
-isdn_tty_check_esc(const u_char *p, u_char plus, int count, int *pluscount,
- u_long *lastplus)
-{
- if (plus > 127)
- return;
- if (count > 3) {
- p += count - 3;
- count = 3;
- *pluscount = 0;
- }
- while (count > 0) {
- if (*(p++) == plus) {
- if ((*pluscount)++) {
- /* Time since last '+' > 0.5 sec. ? */
- if (time_after(jiffies, *lastplus + PLUSWAIT1))
- *pluscount = 1;
- } else {
- /* Time since last non-'+' < 1.5 sec. ? */
- if (time_before(jiffies, *lastplus + PLUSWAIT2))
- *pluscount = 0;
- }
- if ((*pluscount == 3) && (count == 1))
- isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1);
- if (*pluscount > 3)
- *pluscount = 1;
- } else
- *pluscount = 0;
- *lastplus = jiffies;
- count--;
- }
-}
-
-/*
- * Return result of AT-emulator to tty-receive-buffer, depending on
- * modem-register 12, bit 0 and 1.
- * For CONNECT-messages also switch to online-mode.
- * For RING-message handle auto-ATA if register 0 != 0
- */
-
-static void
-isdn_tty_modem_result(int code, modem_info *info)
-{
- atemu *m = &info->emu;
- static char *msg[] =
- {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
- "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
- "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
- char s[ISDN_MSNLEN + 10];
-
- switch (code) {
- case RESULT_RING:
- m->mdmreg[REG_RINGCNT]++;
- if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA])
- /* Automatically accept incoming call */
- isdn_tty_cmd_ATA(info);
- break;
- case RESULT_NO_CARRIER:
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
- info->closing, !info->port.tty);
-#endif
- m->mdmreg[REG_RINGCNT] = 0;
- del_timer(&info->nc_timer);
- info->ncarrier = 0;
- if (info->closing || !info->port.tty)
- return;
-
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 1) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n",
- info->line);
-#endif
- /* voice-recording, add DLE-ETX */
- isdn_tty_at_cout("\020\003", info);
- }
- if (info->vonline & 2) {
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n",
- info->line);
-#endif
- /* voice-playing, add DLE-DC4 */
- isdn_tty_at_cout("\020\024", info);
- }
-#endif
- break;
- case RESULT_CONNECT:
- case RESULT_CONNECT64000:
- sprintf(info->last_cause, "0000");
- if (!info->online)
- info->online = 2;
- break;
- case RESULT_VCON:
-#ifdef ISDN_DEBUG_MODEM_VOICE
- printk(KERN_DEBUG "res3: send VCON on ttyI%d\n",
- info->line);
-#endif
- sprintf(info->last_cause, "0000");
- if (!info->online)
- info->online = 1;
- break;
- } /* switch (code) */
-
- if (m->mdmreg[REG_RESP] & BIT_RESP) {
- /* Show results */
- if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) {
- /* Show numeric results only */
- sprintf(s, "\r\n%d\r\n", code);
- isdn_tty_at_cout(s, info);
- } else {
- if (code == RESULT_RING) {
- /* return if "show RUNG" and ringcounter>1 */
- if ((m->mdmreg[REG_RUNG] & BIT_RUNG) &&
- (m->mdmreg[REG_RINGCNT] > 1))
- return;
- /* print CID, _before_ _every_ ring */
- if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) {
- isdn_tty_at_cout("\r\nCALLER NUMBER: ", info);
- isdn_tty_at_cout(dev->num[info->drv_index], info);
- if (m->mdmreg[REG_CDN] & BIT_CDN) {
- isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
- isdn_tty_at_cout(info->emu.cpn, info);
- }
- }
- }
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(msg[code], info);
- switch (code) {
- case RESULT_CONNECT:
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_MODEM:
- isdn_tty_at_cout(" ", info);
- isdn_tty_at_cout(m->connmsg, info);
- break;
- }
- break;
- case RESULT_RING:
- /* Append CPN, if enabled */
- if ((m->mdmreg[REG_CPN] & BIT_CPN)) {
- sprintf(s, "/%s", m->cpn);
- isdn_tty_at_cout(s, info);
- }
- /* Print CID only once, _after_ 1st RING */
- if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
- (m->mdmreg[REG_RINGCNT] == 1)) {
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout("CALLER NUMBER: ", info);
- isdn_tty_at_cout(dev->num[info->drv_index], info);
- if (m->mdmreg[REG_CDN] & BIT_CDN) {
- isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
- isdn_tty_at_cout(info->emu.cpn, info);
- }
- }
- break;
- case RESULT_NO_CARRIER:
- case RESULT_NO_DIALTONE:
- case RESULT_BUSY:
- case RESULT_NO_ANSWER:
- m->mdmreg[REG_RINGCNT] = 0;
- /* Append Cause-Message if enabled */
- if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) {
- sprintf(s, "/%s", info->last_cause);
- isdn_tty_at_cout(s, info);
- }
- break;
- case RESULT_CONNECT64000:
- /* Append Protocol to CONNECT message */
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- isdn_tty_at_cout("/X.75", info);
- break;
- case ISDN_PROTO_L2_HDLC:
- isdn_tty_at_cout("/HDLC", info);
- break;
- case ISDN_PROTO_L2_V11096:
- isdn_tty_at_cout("/V110/9600", info);
- break;
- case ISDN_PROTO_L2_V11019:
- isdn_tty_at_cout("/V110/19200", info);
- break;
- case ISDN_PROTO_L2_V11038:
- isdn_tty_at_cout("/V110/38400", info);
- break;
- }
- if (m->mdmreg[REG_T70] & BIT_T70) {
- isdn_tty_at_cout("/T.70", info);
- if (m->mdmreg[REG_T70] & BIT_T70_EXT)
- isdn_tty_at_cout("+", info);
- }
- break;
- }
- isdn_tty_at_cout("\r\n", info);
- }
- }
- if (code == RESULT_NO_CARRIER) {
- if (info->closing || (!info->port.tty))
- return;
-
- if (tty_port_check_carrier(&info->port))
- tty_hangup(info->port.tty);
- }
-}
-
-
-/*
- * Display a modem-register-value.
- */
-static void
-isdn_tty_show_profile(int ridx, modem_info *info)
-{
- char v[6];
-
- sprintf(v, "\r\n%d", info->emu.mdmreg[ridx]);
- isdn_tty_at_cout(v, info);
-}
-
-/*
- * Get MSN-string from char-pointer, set pointer to end of number
- */
-static void
-isdn_tty_get_msnstr(char *n, char **p)
-{
- int limit = ISDN_MSNLEN - 1;
-
- while (((*p[0] >= '0' && *p[0] <= '9') ||
- /* Why a comma ??? */
- (*p[0] == ',') || (*p[0] == ':')) &&
- (limit--))
- *n++ = *p[0]++;
- *n = '\0';
-}
-
-/*
- * Get phone-number from modem-commandbuffer
- */
-static void
-isdn_tty_getdial(char *p, char *q, int cnt)
-{
- int first = 1;
- int limit = ISDN_MSNLEN - 1; /* MUST match the size of interface var to avoid
- buffer overflow */
-
- while (strchr(" 0123456789,#.*WPTSR-", *p) && *p && --cnt > 0) {
- if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) ||
- ((*p == 'R') && first) ||
- (*p == '*') || (*p == '#')) {
- *q++ = *p;
- limit--;
- }
- if (!limit)
- break;
- p++;
- first = 0;
- }
- *q = 0;
-}
-
-#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; }
-#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; }
-
-static void
-isdn_tty_report(modem_info *info)
-{
- atemu *m = &info->emu;
- char s[80];
-
- isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info);
- sprintf(s, " Remote Number: %s\r\n", info->last_num);
- isdn_tty_at_cout(s, info);
- sprintf(s, " Direction: %s\r\n", info->last_dir ? "outgoing" : "incoming");
- isdn_tty_at_cout(s, info);
- isdn_tty_at_cout(" Layer-2 Protocol: ", info);
- switch (info->last_l2) {
- case ISDN_PROTO_L2_X75I:
- isdn_tty_at_cout("X.75i", info);
- break;
- case ISDN_PROTO_L2_X75UI:
- isdn_tty_at_cout("X.75ui", info);
- break;
- case ISDN_PROTO_L2_X75BUI:
- isdn_tty_at_cout("X.75bui", info);
- break;
- case ISDN_PROTO_L2_HDLC:
- isdn_tty_at_cout("HDLC", info);
- break;
- case ISDN_PROTO_L2_V11096:
- isdn_tty_at_cout("V.110 9600 Baud", info);
- break;
- case ISDN_PROTO_L2_V11019:
- isdn_tty_at_cout("V.110 19200 Baud", info);
- break;
- case ISDN_PROTO_L2_V11038:
- isdn_tty_at_cout("V.110 38400 Baud", info);
- break;
- case ISDN_PROTO_L2_TRANS:
- isdn_tty_at_cout("transparent", info);
- break;
- case ISDN_PROTO_L2_MODEM:
- isdn_tty_at_cout("modem", info);
- break;
- case ISDN_PROTO_L2_FAX:
- isdn_tty_at_cout("fax", info);
- break;
- default:
- isdn_tty_at_cout("unknown", info);
- break;
- }
- if (m->mdmreg[REG_T70] & BIT_T70) {
- isdn_tty_at_cout("/T.70", info);
- if (m->mdmreg[REG_T70] & BIT_T70_EXT)
- isdn_tty_at_cout("+", info);
- }
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(" Service: ", info);
- switch (info->last_si) {
- case 1:
- isdn_tty_at_cout("audio\r\n", info);
- break;
- case 5:
- isdn_tty_at_cout("btx\r\n", info);
- break;
- case 7:
- isdn_tty_at_cout("data\r\n", info);
- break;
- default:
- sprintf(s, "%d\r\n", info->last_si);
- isdn_tty_at_cout(s, info);
- break;
- }
- sprintf(s, " Hangup location: %s\r\n", info->last_lhup ? "local" : "remote");
- isdn_tty_at_cout(s, info);
- sprintf(s, " Last cause: %s\r\n", info->last_cause);
- isdn_tty_at_cout(s, info);
-}
-
-/*
- * Parse AT&.. commands.
- */
-static int
-isdn_tty_cmd_ATand(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- int i;
- char rb[100];
-
-#define MAXRB (sizeof(rb) - 1)
-
- switch (*p[0]) {
- case 'B':
- /* &B - Set Buffersize */
- p[0]++;
- i = isdn_getnum(p);
- if ((i < 0) || (i > ISDN_SERIAL_XMIT_MAX))
- PARSE_ERROR1;
-#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[REG_SI1] & 1) && (i > VBUF))
- PARSE_ERROR1;
-#endif
- m->mdmreg[REG_PSIZE] = i / 16;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- info->xmit_size /= 10;
- }
- break;
- case 'C':
- /* &C - DCD Status */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[REG_DCD] &= ~BIT_DCD;
- break;
- case 1:
- m->mdmreg[REG_DCD] |= BIT_DCD;
- break;
- default:
- PARSE_ERROR1
- }
- break;
- case 'D':
- /* &D - Set DTR-Low-behavior */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[REG_DTRHUP] &= ~BIT_DTRHUP;
- m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
- break;
- case 2:
- m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
- m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
- break;
- case 3:
- m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
- m->mdmreg[REG_DTRR] |= BIT_DTRR;
- break;
- default:
- PARSE_ERROR1
- }
- break;
- case 'E':
- /* &E -Set EAZ/MSN */
- p[0]++;
- isdn_tty_get_msnstr(m->msn, p);
- break;
- case 'F':
- /* &F -Set Factory-Defaults */
- p[0]++;
- if (info->msr & UART_MSR_DCD)
- PARSE_ERROR1;
- isdn_tty_reset_profile(m);
- isdn_tty_modem_reset_regs(info, 1);
- break;
-#ifdef DUMMY_HAYES_AT
- case 'K':
- /* only for be compilant with common scripts */
- /* &K Flowcontrol - no function */
- p[0]++;
- isdn_getnum(p);
- break;
-#endif
- case 'L':
- /* &L -Set Numbers to listen on */
- p[0]++;
- i = 0;
- while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) &&
- (i < ISDN_LMSNLEN - 1))
- m->lmsn[i++] = *p[0]++;
- m->lmsn[i] = '\0';
- break;
- case 'R':
- /* &R - Set V.110 bitrate adaption */
- p[0]++;
- i = isdn_getnum(p);
- switch (i) {
- case 0:
- /* Switch off V.110, back to X.75 */
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- m->mdmreg[REG_SI2] = 0;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- break;
- case 9600:
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11096;
- m->mdmreg[REG_SI2] = 197;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
- break;
- case 19200:
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11019;
- m->mdmreg[REG_SI2] = 199;
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
- break;
- case 38400:
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038;
- m->mdmreg[REG_SI2] = 198; /* no existing standard for this */
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
- break;
- default:
- PARSE_ERROR1;
- }
- /* Switch off T.70 */
- m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
- /* Set Service 7 */
- m->mdmreg[REG_SI1] |= 4;
- break;
- case 'S':
- /* &S - Set Windowsize */
- p[0]++;
- i = isdn_getnum(p);
- if ((i > 0) && (i < 9))
- m->mdmreg[REG_WSIZE] = i;
- else
- PARSE_ERROR1;
- break;
- case 'V':
- /* &V - Show registers */
- p[0]++;
- isdn_tty_at_cout("\r\n", info);
- for (i = 0; i < ISDN_MODEM_NUMREG; i++) {
- sprintf(rb, "S%02d=%03d%s", i,
- m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
- isdn_tty_at_cout(rb, info);
- }
- sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n",
- strlen(m->msn) ? m->msn : "None");
- isdn_tty_at_cout(rb, info);
- if (strlen(m->lmsn)) {
- isdn_tty_at_cout("\r\nListen: ", info);
- isdn_tty_at_cout(m->lmsn, info);
- isdn_tty_at_cout("\r\n", info);
- }
- break;
- case 'W':
- /* &W - Write Profile */
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- modem_write_profile(m);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 'X':
- /* &X - Switch to BTX-Mode and T.70 */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
- info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
- break;
- case 1:
- m->mdmreg[REG_T70] |= BIT_T70;
- m->mdmreg[REG_T70] &= ~BIT_T70_EXT;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- info->xmit_size = 112;
- m->mdmreg[REG_SI1] = 4;
- m->mdmreg[REG_SI2] = 0;
- break;
- case 2:
- m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT);
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- info->xmit_size = 112;
- m->mdmreg[REG_SI1] = 4;
- m->mdmreg[REG_SI2] = 0;
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
-}
-
-static int
-isdn_tty_check_ats(int mreg, int mval, modem_info *info, atemu *m)
-{
- /* Some plausibility checks */
- switch (mreg) {
- case REG_L2PROT:
- if (mval > ISDN_PROTO_L2_MAX)
- return 1;
- break;
- case REG_PSIZE:
- if ((mval * 16) > ISDN_SERIAL_XMIT_MAX)
- return 1;
-#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[REG_SI1] & 1) && (mval > VBUFX))
- return 1;
-#endif
- info->xmit_size = mval * 16;
- switch (m->mdmreg[REG_L2PROT]) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- info->xmit_size /= 10;
- }
- break;
- case REG_SI1I:
- case REG_PLAN:
- case REG_SCREEN:
- /* readonly registers */
- return 1;
- }
- return 0;
-}
-
-/*
- * Perform ATS command
- */
-static int
-isdn_tty_cmd_ATS(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- int bitpos;
- int mreg;
- int mval;
- int bval;
-
- mreg = isdn_getnum(p);
- if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG)
- PARSE_ERROR1;
- switch (*p[0]) {
- case '=':
- p[0]++;
- mval = isdn_getnum(p);
- if (mval < 0 || mval > 255)
- PARSE_ERROR1;
- if (isdn_tty_check_ats(mreg, mval, info, m))
- PARSE_ERROR1;
- m->mdmreg[mreg] = mval;
- break;
- case '.':
- /* Set/Clear a single bit */
- p[0]++;
- bitpos = isdn_getnum(p);
- if ((bitpos < 0) || (bitpos > 7))
- PARSE_ERROR1;
- switch (*p[0]) {
- case '=':
- p[0]++;
- bval = isdn_getnum(p);
- if (bval < 0 || bval > 1)
- PARSE_ERROR1;
- if (bval)
- mval = m->mdmreg[mreg] | (1 << bitpos);
- else
- mval = m->mdmreg[mreg] & ~(1 << bitpos);
- if (isdn_tty_check_ats(mreg, mval, info, m))
- PARSE_ERROR1;
- m->mdmreg[mreg] = mval;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0",
- info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case '?':
- p[0]++;
- isdn_tty_show_profile(mreg, info);
- break;
- default:
- PARSE_ERROR1;
- break;
- }
- return 0;
-}
-
-/*
- * Perform ATA command
- */
-static void
-isdn_tty_cmd_ATA(modem_info *info)
-{
- atemu *m = &info->emu;
- isdn_ctrl cmd;
- int l2;
-
- if (info->msr & UART_MSR_RI) {
- /* Accept incoming call */
- info->last_dir = 0;
- strcpy(info->last_num, dev->num[info->drv_index]);
- m->mdmreg[REG_RINGCNT] = 0;
- info->msr &= ~UART_MSR_RI;
- l2 = m->mdmreg[REG_L2PROT];
-#ifdef CONFIG_ISDN_AUDIO
- /* If more than one bit set in reg18, autoselect Layer2 */
- if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
- if (m->mdmreg[REG_SI1I] == 1) {
- if ((l2 != ISDN_PROTO_L2_MODEM) && (l2 != ISDN_PROTO_L2_FAX))
- l2 = ISDN_PROTO_L2_TRANS;
- } else
- l2 = ISDN_PROTO_L2_X75I;
- }
-#endif
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- info->last_l2 = l2;
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
-#ifdef CONFIG_ISDN_TTY_FAX
- if (l2 == ISDN_PROTO_L2_FAX) {
- cmd.parm.fax = info->fax;
- info->fax->direction = ISDN_TTY_FAX_CONN_IN;
- }
-#endif
- isdn_command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTD;
- info->dialing = 16;
- info->emu.carrierwait = 0;
- isdn_command(&cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
- } else
- isdn_tty_modem_result(RESULT_NO_ANSWER, info);
-}
-
-#ifdef CONFIG_ISDN_AUDIO
-/*
- * Parse AT+F.. commands
- */
-static int
-isdn_tty_cmd_PLUSF(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- char rs[20];
-
- if (!strncmp(p[0], "CLASS", 5)) {
- p[0] += 5;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d",
- (m->mdmreg[REG_SI1] & 1) ? 8 : 0);
-#ifdef CONFIG_ISDN_TTY_FAX
- if (TTY_IS_FCLASS2(info))
- sprintf(rs, "\r\n2");
- else if (TTY_IS_FCLASS1(info))
- sprintf(rs, "\r\n1");
-#endif
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
- m->mdmreg[REG_SI1] = 4;
- info->xmit_size =
- m->mdmreg[REG_PSIZE] * 16;
- break;
-#ifdef CONFIG_ISDN_TTY_FAX
- case '1':
- p[0]++;
- if (!(dev->global_features &
- ISDN_FEATURE_L3_FCLASS1))
- PARSE_ERROR1;
- m->mdmreg[REG_SI1] = 1;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1;
- info->xmit_size =
- m->mdmreg[REG_PSIZE] * 16;
- break;
- case '2':
- p[0]++;
- if (!(dev->global_features &
- ISDN_FEATURE_L3_FCLASS2))
- PARSE_ERROR1;
- m->mdmreg[REG_SI1] = 1;
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2;
- info->xmit_size =
- m->mdmreg[REG_PSIZE] * 16;
- break;
-#endif
- case '8':
- p[0]++;
- /* L2 will change on dialout with si=1 */
- m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
- m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
- m->mdmreg[REG_SI1] = 5;
- info->xmit_size = VBUF;
- break;
- case '?':
- p[0]++;
- strcpy(rs, "\r\n0,");
-#ifdef CONFIG_ISDN_TTY_FAX
- if (dev->global_features &
- ISDN_FEATURE_L3_FCLASS1)
- strcat(rs, "1,");
- if (dev->global_features &
- ISDN_FEATURE_L3_FCLASS2)
- strcat(rs, "2,");
-#endif
- strcat(rs, "8");
- isdn_tty_at_cout(rs, info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-#ifdef CONFIG_ISDN_TTY_FAX
- return (isdn_tty_cmd_PLUSF_FAX(p, info));
-#else
- PARSE_ERROR1;
-#endif
-}
-
-/*
- * Parse AT+V.. commands
- */
-static int
-isdn_tty_cmd_PLUSV(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- isdn_ctrl cmd;
- static char *vcmd[] =
- {"NH", "IP", "LS", "RX", "SD", "SM", "TX", "DD", NULL};
- int i;
- int par1;
- int par2;
- char rs[20];
-
- i = 0;
- while (vcmd[i]) {
- if (!strncmp(vcmd[i], p[0], 2)) {
- p[0] += 2;
- break;
- }
- i++;
- }
- switch (i) {
- case 0:
- /* AT+VNH - Auto hangup feature */
- switch (*p[0]) {
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n1", info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '1':
- p[0]++;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n1", info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 1:
- /* AT+VIP - Reset all voice parameters */
- isdn_tty_modem_reset_vpar(m);
- break;
- case 2:
- /* AT+VLS - Select device, accept incoming call */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", m->vpar[0]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- m->vpar[0] = 0;
- break;
- case '2':
- p[0]++;
- m->vpar[0] = 2;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n0,2", info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 3:
- /* AT+VRX - Start recording */
- if (!m->vpar[0])
- PARSE_ERROR1;
- if (info->online != 1) {
- isdn_tty_modem_result(RESULT_NO_ANSWER, info);
- return 1;
- }
- info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
- if (!info->dtmf_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
- PARSE_ERROR1;
- }
- info->silence_state = isdn_audio_silence_init(info->silence_state);
- if (!info->silence_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n");
- PARSE_ERROR1;
- }
- if (m->vpar[3] < 5) {
- info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
- if (!info->adpcmr) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
- PARSE_ERROR1;
- }
- }
-#ifdef ISDN_DEBUG_AT
- printk(KERN_DEBUG "AT: +VRX\n");
-#endif
- info->vonline |= 1;
- isdn_tty_modem_result(RESULT_CONNECT, info);
- return 0;
- break;
- case 4:
- /* AT+VSD - Silence detection */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n<%d>,<%d>",
- m->vpar[1],
- m->vpar[2]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if ((*p[0] >= '0') && (*p[0] <= '9')) {
- par1 = isdn_getnum(p);
- if ((par1 < 0) || (par1 > 31))
- PARSE_ERROR1;
- if (*p[0] != ',')
- PARSE_ERROR1;
- p[0]++;
- par2 = isdn_getnum(p);
- if ((par2 < 0) || (par2 > 255))
- PARSE_ERROR1;
- m->vpar[1] = par1;
- m->vpar[2] = par2;
- break;
- } else
- if (*p[0] == '?') {
- p[0]++;
- isdn_tty_at_cout("\r\n<0-31>,<0-255>",
- info);
- break;
- } else
- PARSE_ERROR1;
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 5:
- /* AT+VSM - Select compression */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n<%d>,<%d><8000>",
- m->vpar[3],
- m->vpar[1]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- par1 = isdn_getnum(p);
- if ((par1 < 2) || (par1 > 6))
- PARSE_ERROR1;
- m->vpar[3] = par1;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("5;ALAW;8;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("6;ULAW;8;0;(8000)\r\n",
- info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 6:
- /* AT+VTX - Start sending */
- if (!m->vpar[0])
- PARSE_ERROR1;
- if (info->online != 1) {
- isdn_tty_modem_result(RESULT_NO_ANSWER, info);
- return 1;
- }
- info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
- if (!info->dtmf_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
- PARSE_ERROR1;
- }
- if (m->vpar[3] < 5) {
- info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]);
- if (!info->adpcms) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
- PARSE_ERROR1;
- }
- }
-#ifdef ISDN_DEBUG_AT
- printk(KERN_DEBUG "AT: +VTX\n");
-#endif
- m->lastDLE = 0;
- info->vonline |= 2;
- isdn_tty_modem_result(RESULT_CONNECT, info);
- return 0;
- break;
- case 7:
- /* AT+VDD - DTMF detection */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n<%d>,<%d>",
- m->vpar[4],
- m->vpar[5]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if ((*p[0] >= '0') && (*p[0] <= '9')) {
- if (info->online != 1)
- PARSE_ERROR1;
- par1 = isdn_getnum(p);
- if ((par1 < 0) || (par1 > 15))
- PARSE_ERROR1;
- if (*p[0] != ',')
- PARSE_ERROR1;
- p[0]++;
- par2 = isdn_getnum(p);
- if ((par2 < 0) || (par2 > 255))
- PARSE_ERROR1;
- m->vpar[4] = par1;
- m->vpar[5] = par2;
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_AUDIO;
- cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8);
- cmd.parm.num[0] = par1;
- cmd.parm.num[1] = par2;
- isdn_command(&cmd);
- break;
- } else
- if (*p[0] == '?') {
- p[0]++;
- isdn_tty_at_cout("\r\n<0-15>,<0-255>",
- info);
- break;
- } else
- PARSE_ERROR1;
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
-}
-#endif /* CONFIG_ISDN_AUDIO */
-
-/*
- * Parse and perform an AT-command-line.
- */
-static void
-isdn_tty_parse_at(modem_info *info)
-{
- atemu *m = &info->emu;
- char *p;
- char ds[ISDN_MSNLEN];
-
-#ifdef ISDN_DEBUG_AT
- printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
-#endif
- for (p = &m->mdmcmd[2]; *p;) {
- switch (*p) {
- case ' ':
- p++;
- break;
- case 'A':
- /* A - Accept incoming call */
- p++;
- isdn_tty_cmd_ATA(info);
- return;
- case 'D':
- /* D - Dial */
- if (info->msr & UART_MSR_DCD)
- PARSE_ERROR;
- if (info->msr & UART_MSR_RI) {
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- return;
- }
- isdn_tty_getdial(++p, ds, sizeof ds);
- p += strlen(p);
- if (!strlen(m->msn))
- isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info);
- else if (strlen(ds))
- isdn_tty_dial(ds, info, m);
- else
- PARSE_ERROR;
- return;
- case 'E':
- /* E - Turn Echo on/off */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[REG_ECHO] &= ~BIT_ECHO;
- break;
- case 1:
- m->mdmreg[REG_ECHO] |= BIT_ECHO;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'H':
- /* H - On/Off-hook */
- p++;
- switch (*p) {
- case '0':
- p++;
- isdn_tty_on_hook(info);
- break;
- case '1':
- p++;
- isdn_tty_off_hook();
- break;
- default:
- isdn_tty_on_hook(info);
- break;
- }
- break;
- case 'I':
- /* I - Information */
- p++;
- isdn_tty_at_cout("\r\nLinux ISDN", info);
- switch (*p) {
- case '0':
- case '1':
- p++;
- break;
- case '2':
- p++;
- isdn_tty_report(info);
- break;
- case '3':
- p++;
- snprintf(ds, sizeof(ds), "\r\n%d", info->emu.charge);
- isdn_tty_at_cout(ds, info);
- break;
- default:;
- }
- break;
-#ifdef DUMMY_HAYES_AT
- case 'L':
- case 'M':
- /* only for be compilant with common scripts */
- /* no function */
- p++;
- isdn_getnum(&p);
- break;
-#endif
- case 'O':
- /* O - Go online */
- p++;
- if (info->msr & UART_MSR_DCD)
- /* if B-Channel is up */
- isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT : RESULT_CONNECT64000, info);
- else
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- return;
- case 'Q':
- /* Q - Turn Emulator messages on/off */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[REG_RESP] |= BIT_RESP;
- break;
- case 1:
- m->mdmreg[REG_RESP] &= ~BIT_RESP;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'S':
- /* S - Set/Get Register */
- p++;
- if (isdn_tty_cmd_ATS(&p, info))
- return;
- break;
- case 'V':
- /* V - Numeric or ASCII Emulator-messages */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[REG_RESP] |= BIT_RESPNUM;
- break;
- case 1:
- m->mdmreg[REG_RESP] &= ~BIT_RESPNUM;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'Z':
- /* Z - Load Registers from Profile */
- p++;
- if (info->msr & UART_MSR_DCD) {
- info->online = 0;
- isdn_tty_on_hook(info);
- }
- isdn_tty_modem_reset_regs(info, 1);
- break;
- case '+':
- p++;
- switch (*p) {
-#ifdef CONFIG_ISDN_AUDIO
- case 'F':
- p++;
- if (isdn_tty_cmd_PLUSF(&p, info))
- return;
- break;
- case 'V':
- if ((!(m->mdmreg[REG_SI1] & 1)) ||
- (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM))
- PARSE_ERROR;
- p++;
- if (isdn_tty_cmd_PLUSV(&p, info))
- return;
- break;
-#endif /* CONFIG_ISDN_AUDIO */
- case 'S': /* SUSPEND */
- p++;
- isdn_tty_get_msnstr(ds, &p);
- isdn_tty_suspend(ds, info, m);
- break;
- case 'R': /* RESUME */
- p++;
- isdn_tty_get_msnstr(ds, &p);
- isdn_tty_resume(ds, info, m);
- break;
- case 'M': /* MESSAGE */
- p++;
- isdn_tty_send_msg(info, m, p);
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case '&':
- p++;
- if (isdn_tty_cmd_ATand(&p, info))
- return;
- break;
- default:
- PARSE_ERROR;
- }
- }
-#ifdef CONFIG_ISDN_AUDIO
- if (!info->vonline)
-#endif
- isdn_tty_modem_result(RESULT_OK, info);
-}
-
-/* Need own toupper() because standard-toupper is not available
- * within modules.
- */
-#define my_toupper(c) (((c >= 'a') && (c <= 'z')) ? (c & 0xdf) : c)
-
-/*
- * Perform line-editing of AT-commands
- *
- * Parameters:
- * p inputbuffer
- * count length of buffer
- * channel index to line (minor-device)
- */
-static int
-isdn_tty_edit_at(const char *p, int count, modem_info *info)
-{
- atemu *m = &info->emu;
- int total = 0;
- u_char c;
- char eb[2];
- int cnt;
-
- for (cnt = count; cnt > 0; p++, cnt--) {
- c = *p;
- total++;
- if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
- /* Separator (CR or LF) */
- m->mdmcmd[m->mdmcmdl] = 0;
- if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
- eb[0] = c;
- eb[1] = 0;
- isdn_tty_at_cout(eb, info);
- }
- if ((m->mdmcmdl >= 2) && (!(strncmp(m->mdmcmd, "AT", 2))))
- isdn_tty_parse_at(info);
- m->mdmcmdl = 0;
- continue;
- }
- if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) {
- /* Backspace-Function */
- if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
- if (m->mdmcmdl)
- m->mdmcmdl--;
- if (m->mdmreg[REG_ECHO] & BIT_ECHO)
- isdn_tty_at_cout("\b", info);
- }
- continue;
- }
- if (cmdchar(c)) {
- if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
- eb[0] = c;
- eb[1] = 0;
- isdn_tty_at_cout(eb, info);
- }
- if (m->mdmcmdl < 255) {
- c = my_toupper(c);
- switch (m->mdmcmdl) {
- case 1:
- if (c == 'T') {
- m->mdmcmd[m->mdmcmdl] = c;
- m->mdmcmd[++m->mdmcmdl] = 0;
- break;
- } else
- m->mdmcmdl = 0;
- /* Fall through - check for 'A' */
- case 0:
- if (c == 'A') {
- m->mdmcmd[m->mdmcmdl] = c;
- m->mdmcmd[++m->mdmcmdl] = 0;
- }
- break;
- default:
- m->mdmcmd[m->mdmcmdl] = c;
- m->mdmcmd[++m->mdmcmdl] = 0;
- }
- }
- }
- }
- return total;
-}
-
-/*
- * Switch all modem-channels who are online and got a valid
- * escape-sequence 1.5 seconds ago, to command-mode.
- * This function is called every second via timer-interrupt from within
- * timer-dispatcher isdn_timer_function()
- */
-void
-isdn_tty_modem_escape(void)
-{
- int ton = 0;
- int i;
- int midx;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) {
- modem_info *info = &dev->mdm.info[midx];
- if (info->online) {
- ton = 1;
- if ((info->emu.pluscount == 3) &&
- time_after(jiffies,
- info->emu.lastplus + PLUSWAIT2)) {
- info->emu.pluscount = 0;
- info->online = 0;
- isdn_tty_modem_result(RESULT_OK, info);
- }
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
-}
-
-/*
- * Put a RING-message to all modem-channels who have the RI-bit set.
- * This function is called every second via timer-interrupt from within
- * timer-dispatcher isdn_timer_function()
- */
-void
-isdn_tty_modem_ring(void)
-{
- int ton = 0;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->msr & UART_MSR_RI) {
- ton = 1;
- isdn_tty_modem_result(RESULT_RING, info);
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
-}
-
-/*
- * For all online tty's, try sending data to
- * the lower levels.
- */
-void
-isdn_tty_modem_xmit(void)
-{
- int ton = 1;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->online) {
- ton = 1;
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
-}
-
-/*
- * Check all channels if we have a 'no carrier' timeout.
- * Timeout value is set by Register S7.
- */
-void
-isdn_tty_carrier_timeout(void)
-{
- int ton = 0;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (!info->dialing)
- continue;
- if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
- info->dialing = 0;
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- isdn_tty_modem_hup(info, 1);
- } else
- ton = 1;
- }
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
-}
diff --git a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h
deleted file mode 100644
index a6f801d2263b..000000000000
--- a/drivers/isdn/i4l/isdn_tty.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* $Id: isdn_tty.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, tty related functions (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#define DLE 0x10
-#define ETX 0x03
-#define DC4 0x14
-
-
-/*
- * Definition of some special Registers of AT-Emulator
- */
-#define REG_RINGATA 0
-#define REG_RINGCNT 1 /* ring counter register */
-#define REG_ESC 2
-#define REG_CR 3
-#define REG_LF 4
-#define REG_BS 5
-
-#define REG_WAITC 7
-
-#define REG_RESP 12 /* show response messages register */
-#define BIT_RESP 1 /* show response messages bit */
-#define REG_RESPNUM 12 /* show numeric responses register */
-#define BIT_RESPNUM 2 /* show numeric responses bit */
-#define REG_ECHO 12
-#define BIT_ECHO 4
-#define REG_DCD 12
-#define BIT_DCD 8
-#define REG_CTS 12
-#define BIT_CTS 16
-#define REG_DTRR 12
-#define BIT_DTRR 32
-#define REG_DSR 12
-#define BIT_DSR 64
-#define REG_CPPP 12
-#define BIT_CPPP 128
-
-#define REG_DXMT 13
-#define BIT_DXMT 1
-#define REG_T70 13
-#define BIT_T70 2
-#define BIT_T70_EXT 32
-#define REG_DTRHUP 13
-#define BIT_DTRHUP 4
-#define REG_RESPXT 13
-#define BIT_RESPXT 8
-#define REG_CIDONCE 13
-#define BIT_CIDONCE 16
-#define REG_RUNG 13 /* show RUNG message register */
-#define BIT_RUNG 64 /* show RUNG message bit */
-#define REG_DISPLAY 13
-#define BIT_DISPLAY 128
-
-#define REG_L2PROT 14
-#define REG_L3PROT 15
-#define REG_PSIZE 16
-#define REG_WSIZE 17
-#define REG_SI1 18
-#define REG_SI2 19
-#define REG_SI1I 20
-#define REG_PLAN 21
-#define REG_SCREEN 22
-
-#define REG_CPN 23
-#define BIT_CPN 1
-#define REG_CPNFCON 23
-#define BIT_CPNFCON 2
-#define REG_CDN 23
-#define BIT_CDN 4
-
-/* defines for result codes */
-#define RESULT_OK 0
-#define RESULT_CONNECT 1
-#define RESULT_RING 2
-#define RESULT_NO_CARRIER 3
-#define RESULT_ERROR 4
-#define RESULT_CONNECT64000 5
-#define RESULT_NO_DIALTONE 6
-#define RESULT_BUSY 7
-#define RESULT_NO_ANSWER 8
-#define RESULT_RINGING 9
-#define RESULT_NO_MSN_EAZ 10
-#define RESULT_VCON 11
-#define RESULT_RUNG 12
-
-#define TTY_IS_FCLASS1(info) \
- ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
- (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
-#define TTY_IS_FCLASS2(info) \
- ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
- (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
-
-extern void isdn_tty_modem_escape(void);
-extern void isdn_tty_modem_ring(void);
-extern void isdn_tty_carrier_timeout(void);
-extern void isdn_tty_modem_xmit(void);
-extern int isdn_tty_modem_init(void);
-extern void isdn_tty_exit(void);
-extern void isdn_tty_readmodem(void);
-extern int isdn_tty_find_icall(int, int, setup_parm *);
-extern int isdn_tty_stat_callback(int, isdn_ctrl *);
-extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
-extern int isdn_tty_capi_facility(capi_msg *cm);
-extern void isdn_tty_at_cout(char *, modem_info *);
-extern void isdn_tty_modem_hup(modem_info *, int);
-#ifdef CONFIG_ISDN_TTY_FAX
-extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
-extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
-extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
-#endif
diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c
deleted file mode 100644
index 47aae4916730..000000000000
--- a/drivers/isdn/i4l/isdn_ttyfax.c
+++ /dev/null
@@ -1,1123 +0,0 @@
-/* $Id: isdn_ttyfax.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
- *
- * Copyright 1999 by Armin Schindler (mac@melware.de)
- * Copyright 1999 by Ralf Spachmann (mel@melware.de)
- * Copyright 1999 by Cytronics & Melware
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#undef ISDN_TTY_FAX_STAT_DEBUG
-#undef ISDN_TTY_FAX_CMD_DEBUG
-
-#include <linux/isdn.h>
-#include "isdn_common.h"
-#include "isdn_tty.h"
-#include "isdn_ttyfax.h"
-
-
-static char *isdn_tty_fax_revision = "$Revision: 1.1.2.2 $";
-
-#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
-
-static char *
-isdn_getrev(const char *revision)
-{
- char *rev;
- char *p;
-
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
-}
-
-/*
- * Fax Class 2 Modem results
- *
- */
-
-static void
-isdn_tty_fax_modem_result(int code, modem_info *info)
-{
- atemu *m = &info->emu;
- T30_s *f = info->fax;
- char rs[50];
- char rss[50];
- char *rp;
- int i;
- static char *msg[] =
- {"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:",
- "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:",
- "+FCFR", "+FPTS:", "+FET:"};
-
-
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(msg[code], info);
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax send %s on ttyI%d\n",
- msg[code], info->line);
-#endif
- switch (code) {
- case 0: /* OK */
- break;
- case 1: /* ERROR */
- break;
- case 2: /* +FCON */
- /* Append CPN, if enabled */
- if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) &&
- (!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) {
- sprintf(rs, "/%s", m->cpn);
- isdn_tty_at_cout(rs, info);
- }
- info->online = 1;
- f->fet = 0;
- if (f->phase == ISDN_FAX_PHASE_A)
- f->phase = ISDN_FAX_PHASE_B;
- break;
- case 3: /* +FCSI */
- case 8: /* +FTSI */
- sprintf(rs, "\"%s\"", f->r_id);
- isdn_tty_at_cout(rs, info);
- break;
- case 4: /* +FDIS */
- rs[0] = 0;
- rp = &f->r_resolution;
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n",
- rs, info->line);
-#endif
- break;
- case 5: /* +FHNG */
- sprintf(rs, "%d", f->code);
- isdn_tty_at_cout(rs, info);
- info->faxonline = 0;
- break;
- case 6: /* +FDCS */
- rs[0] = 0;
- rp = &f->r_resolution;
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n",
- rs, info->line);
-#endif
- break;
- case 7: /* CONNECT */
- info->faxonline |= 2;
- break;
- case 9: /* FCFR */
- break;
- case 10: /* FPTS */
- isdn_tty_at_cout("1", info);
- break;
- case 11: /* FET */
- sprintf(rs, "%d", f->fet);
- isdn_tty_at_cout(rs, info);
- break;
- }
-
- isdn_tty_at_cout("\r\n", info);
-
- switch (code) {
- case 7: /* CONNECT */
- info->online = 2;
- if (info->faxonline & 1) {
- sprintf(rs, "%c", XON);
- isdn_tty_at_cout(rs, info);
- }
- break;
- }
-}
-
-static int
-isdn_tty_fax_command1(modem_info *info, isdn_ctrl *c)
-{
- static char *msg[] =
- {"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"};
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd);
-#endif
- if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) {
- if (info->online)
- info->online = 1;
- isdn_tty_at_cout("\r\n", info);
- isdn_tty_at_cout(msg[c->parm.aux.cmd], info);
- isdn_tty_at_cout("\r\n", info);
- }
- switch (c->parm.aux.cmd) {
- case ISDN_FAX_CLASS1_CONNECT:
- info->online = 2;
- break;
- case ISDN_FAX_CLASS1_OK:
- case ISDN_FAX_CLASS1_FCERROR:
- case ISDN_FAX_CLASS1_ERROR:
- case ISDN_FAX_CLASS1_NOCARR:
- break;
- case ISDN_FAX_CLASS1_QUERY:
- isdn_tty_at_cout("\r\n", info);
- if (!c->parm.aux.para[0]) {
- isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info);
- isdn_tty_at_cout("\r\n", info);
- } else {
- isdn_tty_at_cout(c->parm.aux.para, info);
- isdn_tty_at_cout("\r\nOK\r\n", info);
- }
- break;
- }
- return (0);
-}
-
-int
-isdn_tty_fax_command(modem_info *info, isdn_ctrl *c)
-{
- T30_s *f = info->fax;
- char rs[10];
-
- if (TTY_IS_FCLASS1(info))
- return (isdn_tty_fax_command1(info, c));
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n",
- f->r_code, info->line);
-#endif
- switch (f->r_code) {
- case ISDN_TTY_FAX_FCON:
- info->faxonline = 1;
- isdn_tty_fax_modem_result(2, info); /* +FCON */
- return (0);
- case ISDN_TTY_FAX_FCON_I:
- info->faxonline = 16;
- isdn_tty_fax_modem_result(2, info); /* +FCON */
- return (0);
- case ISDN_TTY_FAX_RID:
- if (info->faxonline & 1)
- isdn_tty_fax_modem_result(3, info); /* +FCSI */
- if (info->faxonline & 16)
- isdn_tty_fax_modem_result(8, info); /* +FTSI */
- return (0);
- case ISDN_TTY_FAX_DIS:
- isdn_tty_fax_modem_result(4, info); /* +FDIS */
- return (0);
- case ISDN_TTY_FAX_HNG:
- if (f->phase == ISDN_FAX_PHASE_C) {
- if (f->direction == ISDN_TTY_FAX_CONN_IN) {
- sprintf(rs, "%c%c", DLE, ETX);
- isdn_tty_at_cout(rs, info);
- } else {
- sprintf(rs, "%c", 0x18);
- isdn_tty_at_cout(rs, info);
- }
- info->faxonline &= ~2; /* leave data mode */
- info->online = 1;
- }
- f->phase = ISDN_FAX_PHASE_E;
- isdn_tty_fax_modem_result(5, info); /* +FHNG */
- isdn_tty_fax_modem_result(0, info); /* OK */
- return (0);
- case ISDN_TTY_FAX_DCS:
- isdn_tty_fax_modem_result(6, info); /* +FDCS */
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
- f->phase = ISDN_FAX_PHASE_C;
- return (0);
- case ISDN_TTY_FAX_TRAIN_OK:
- isdn_tty_fax_modem_result(6, info); /* +FDCS */
- isdn_tty_fax_modem_result(0, info); /* OK */
- return (0);
- case ISDN_TTY_FAX_SENT:
- isdn_tty_fax_modem_result(0, info); /* OK */
- return (0);
- case ISDN_TTY_FAX_CFR:
- isdn_tty_fax_modem_result(9, info); /* +FCFR */
- return (0);
- case ISDN_TTY_FAX_ET:
- sprintf(rs, "%c%c", DLE, ETX);
- isdn_tty_at_cout(rs, info);
- isdn_tty_fax_modem_result(10, info); /* +FPTS */
- isdn_tty_fax_modem_result(11, info); /* +FET */
- isdn_tty_fax_modem_result(0, info); /* OK */
- info->faxonline &= ~2; /* leave data mode */
- info->online = 1;
- f->phase = ISDN_FAX_PHASE_D;
- return (0);
- case ISDN_TTY_FAX_PTS:
- isdn_tty_fax_modem_result(10, info); /* +FPTS */
- if (f->direction == ISDN_TTY_FAX_CONN_OUT) {
- if (f->fet == 1)
- f->phase = ISDN_FAX_PHASE_B;
- if (f->fet == 0)
- isdn_tty_fax_modem_result(0, info); /* OK */
- }
- return (0);
- case ISDN_TTY_FAX_EOP:
- info->faxonline &= ~2; /* leave data mode */
- info->online = 1;
- f->phase = ISDN_FAX_PHASE_D;
- return (0);
-
- }
- return (-1);
-}
-
-
-void
-isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
-{
- __u8 LeftMask;
- __u8 RightMask;
- __u8 fBit;
- __u8 Data;
- int i;
-
- if (!info->fax->bor) {
- for (i = 0; i < skb->len; i++) {
- Data = skb->data[i];
- for (
- LeftMask = 0x80, RightMask = 0x01;
- LeftMask > RightMask;
- LeftMask >>= 1, RightMask <<= 1
- ) {
- fBit = (Data & LeftMask);
- if (Data & RightMask)
- Data |= LeftMask;
- else
- Data &= ~LeftMask;
- if (fBit)
- Data |= RightMask;
- else
- Data &= ~RightMask;
-
- }
- skb->data[i] = Data;
- }
- }
-}
-
-/*
- * Parse AT+F.. FAX class 1 commands
- */
-
-static int
-isdn_tty_cmd_FCLASS1(char **p, modem_info *info)
-{
- static char *cmd[] =
- {"AE", "TS", "RS", "TM", "RM", "TH", "RH"};
- isdn_ctrl c;
- int par, i;
- u_long flags;
-
- for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
- if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2))
- break;
-
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd);
-#endif
- if (c.parm.aux.cmd == 7)
- PARSE_ERROR1;
-
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- c.parm.aux.subcmd = AT_QUERY;
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- c.parm.aux.subcmd = AT_EQ_QUERY;
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- c.parm.aux.subcmd = AT_EQ_VALUE;
- c.parm.aux.para[0] = par;
- }
- break;
- case 0:
- c.parm.aux.subcmd = AT_COMMAND;
- break;
- default:
- PARSE_ERROR1;
- }
- c.command = ISDN_CMD_FAXCMD;
-#ifdef ISDN_TTY_FAX_CMD_DEBUG
- printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
- c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
-#endif
- if (info->isdn_driver < 0) {
- if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
- (c.parm.aux.subcmd == AT_COMMAND)) {
- PARSE_ERROR1;
- }
- spin_lock_irqsave(&dev->lock, flags);
- /* get a temporary connection to the first free fax driver */
- i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
- ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
- if (i < 0) {
- spin_unlock_irqrestore(&dev->lock, flags);
- PARSE_ERROR1;
- }
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- spin_unlock_irqrestore(&dev->lock, flags);
- c.driver = info->isdn_driver;
- c.arg = info->isdn_channel;
- isdn_command(&c);
- spin_lock_irqsave(&dev->lock, flags);
- isdn_free_channel(info->isdn_driver, info->isdn_channel,
- ISDN_USAGE_FAX);
- info->isdn_driver = -1;
- info->isdn_channel = -1;
- if (info->drv_index >= 0) {
- dev->m_idx[info->drv_index] = -1;
- info->drv_index = -1;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- } else {
- c.driver = info->isdn_driver;
- c.arg = info->isdn_channel;
- isdn_command(&c);
- }
- return 1;
-}
-
-/*
- * Parse AT+F.. FAX class 2 commands
- */
-
-static int
-isdn_tty_cmd_FCLASS2(char **p, modem_info *info)
-{
- atemu *m = &info->emu;
- T30_s *f = info->fax;
- isdn_ctrl cmd;
- int par;
- char rs[50];
- char rss[50];
- int maxdccval[] =
- {1, 5, 2, 2, 3, 2, 0, 7};
-
- /* FAA still unchanged */
- if (!strncmp(p[0], "AA", 2)) { /* TODO */
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", 0);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */
- if (!strncmp(p[0], "BADLIN", 6)) {
- p[0] += 6;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->badlin);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->badlin = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BADMUL=value - dummy 0=disable errorchk disabled (threshold multiplier) */
- if (!strncmp(p[0], "BADMUL", 6)) {
- p[0] += 6;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->badmul);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->badmul = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BOR=n - Phase C bit order, 0=direct, 1=reverse */
- if (!strncmp(p[0], "BOR", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->bor);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->bor = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* NBC=n - No Best Capabilities */
- if (!strncmp(p[0], "NBC", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->nbc);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->nbc = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* BUF? - Readonly buffersize readout */
- if (!strncmp(p[0], "BUF?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE]));
-#endif
- p[0]++;
- sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE]));
- isdn_tty_at_cout(rs, info);
- return 0;
- }
- /* CIG=string - local fax station id string for polling rx */
- if (!strncmp(p[0], "CIG", 3)) {
- int i, r;
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n\"%s\"", f->pollid);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n\"STRING\"");
- isdn_tty_at_cout(rs, info);
- } else {
- if (*p[0] == '"')
- p[0]++;
- for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
- f->pollid[i] = *p[0]++;
- }
- if (*p[0] == '"')
- p[0]++;
- for (r = i; r < FAXIDLEN; r++) {
- f->pollid[r] = 32;
- }
- f->pollid[FAXIDLEN - 1] = 0;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */
- if (!strncmp(p[0], "CQ", 2)) {
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->cq);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1,2");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 2))
- PARSE_ERROR1;
- f->cq = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */
- if (!strncmp(p[0], "CR", 2)) {
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1"); /* display online help */
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->cr = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* CTCRTY=value - ECM retry count */
- if (!strncmp(p[0], "CTCRTY", 6)) {
- p[0] += 6;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->ctcrty);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->ctcrty = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */
- if (!strncmp(p[0], "DCC", 3)) {
- char *rp = &f->resolution;
- int i;
-
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- strcpy(rs, "\r\n");
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
- p[0]++;
- } else {
- for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
- if (*p[0] != ',') {
- if ((*p[0] - 48) > maxdccval[i]) {
- PARSE_ERROR1;
- }
- rp[i] = *p[0] - 48;
- p[0]++;
- if (*p[0] == ',')
- p[0]++;
- } else
- p[0]++;
- }
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n",
- rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */
- if (!strncmp(p[0], "DIS", 3)) {
- char *rp = &f->resolution;
- int i;
-
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- strcpy(rs, "\r\n");
- for (i = 0; i < 8; i++) {
- sprintf(rss, "%c%s", rp[i] + 48,
- (i < 7) ? "," : "");
- strcat(rs, rss);
- }
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
- p[0]++;
- } else {
- for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
- if (*p[0] != ',') {
- if ((*p[0] - 48) > maxdccval[i]) {
- PARSE_ERROR1;
- }
- rp[i] = *p[0] - 48;
- p[0]++;
- if (*p[0] == ',')
- p[0]++;
- } else
- p[0]++;
- }
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n",
- rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* DR - Receive Phase C data command, initiates document reception */
- if (!strncmp(p[0], "DR", 2)) {
- p[0] += 2;
- if ((info->faxonline & 16) && /* incoming connection */
- ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) {
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
-#endif
- f->code = ISDN_TTY_FAX_DR;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_FAXCMD;
- isdn_command(&cmd);
- if (f->phase == ISDN_FAX_PHASE_B) {
- f->phase = ISDN_FAX_PHASE_C;
- } else if (f->phase == ISDN_FAX_PHASE_D) {
- switch (f->fet) {
- case 0: /* next page will be received */
- f->phase = ISDN_FAX_PHASE_C;
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
- break;
- case 1: /* next doc will be received */
- f->phase = ISDN_FAX_PHASE_B;
- break;
- case 2: /* fax session is terminating */
- f->phase = ISDN_FAX_PHASE_E;
- break;
- default:
- PARSE_ERROR1;
- }
- }
- } else {
- PARSE_ERROR1;
- }
- return 1;
- }
- /* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */
- if (!strncmp(p[0], "DT", 2)) {
- int i, val[] =
- {4, 0, 2, 3};
- char *rp = &f->resolution;
-
- p[0] += 2;
- if (!(info->faxonline & 1)) /* not outgoing connection */
- PARSE_ERROR1;
-
- for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
- if (*p[0] != ',') {
- if ((*p[0] - 48) > maxdccval[val[i]]) {
- PARSE_ERROR1;
- }
- rp[val[i]] = *p[0] - 48;
- p[0]++;
- if (*p[0] == ',')
- p[0]++;
- } else
- p[0]++;
- }
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n",
- rp[4], rp[0], rp[2], rp[3]);
-#endif
- if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) {
- f->code = ISDN_TTY_FAX_DT;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_FAXCMD;
- isdn_command(&cmd);
- if (f->phase == ISDN_FAX_PHASE_D) {
- f->phase = ISDN_FAX_PHASE_C;
- isdn_tty_fax_modem_result(7, info); /* CONNECT */
- }
- } else {
- PARSE_ERROR1;
- }
- return 1;
- }
- /* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */
- if (!strncmp(p[0], "ECM", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->ecm);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,2");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par != 0) && (par != 2))
- PARSE_ERROR1;
- f->ecm = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* ET=n - End of page or document */
- if (!strncmp(p[0], "ET=", 3)) {
- p[0] += 3;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-2");
- isdn_tty_at_cout(rs, info);
- } else {
- if ((f->phase != ISDN_FAX_PHASE_D) ||
- (!(info->faxonline & 1)))
- PARSE_ERROR1;
- par = isdn_getnum(p);
- if ((par < 0) || (par > 2))
- PARSE_ERROR1;
- f->fet = par;
- f->code = ISDN_TTY_FAX_ET;
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_FAXCMD;
- isdn_command(&cmd);
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par);
-#endif
- return 1;
- }
- return 0;
- }
- /* K - terminate */
- if (!strncmp(p[0], "K", 1)) {
- p[0] += 1;
- if ((f->phase == ISDN_FAX_PHASE_IDLE) || (f->phase == ISDN_FAX_PHASE_E))
- PARSE_ERROR1;
- isdn_tty_modem_hup(info, 1);
- return 1;
- }
- /* LID=string - local fax ID */
- if (!strncmp(p[0], "LID", 3)) {
- int i, r;
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n\"%s\"", f->id);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n\"STRING\"");
- isdn_tty_at_cout(rs, info);
- } else {
- if (*p[0] == '"')
- p[0]++;
- for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
- f->id[i] = *p[0]++;
- }
- if (*p[0] == '"')
- p[0]++;
- for (r = i; r < FAXIDLEN; r++) {
- f->id[r] = 32;
- }
- f->id[FAXIDLEN - 1] = 0;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-
- /* MDL? - DCE Model */
- if (!strncmp(p[0], "MDL?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FMDL?\n");
-#endif
- isdn_tty_at_cout("\r\nisdn4linux", info);
- return 0;
- }
- /* MFR? - DCE Manufacturer */
- if (!strncmp(p[0], "MFR?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FMFR?\n");
-#endif
- isdn_tty_at_cout("\r\nisdn4linux", info);
- return 0;
- }
- /* MINSP=n - Minimum Speed for Phase C */
- if (!strncmp(p[0], "MINSP", 5)) {
- p[0] += 5;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->minsp);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-5");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 5))
- PARSE_ERROR1;
- f->minsp = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* PHCTO=value - DTE phase C timeout */
- if (!strncmp(p[0], "PHCTO", 5)) {
- p[0] += 5;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->phcto);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0-255");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- f->phcto = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
-
- /* REL=n - Phase C received EOL alignment */
- if (!strncmp(p[0], "REL", 3)) {
- p[0] += 3;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs, "\r\n%d", f->rel);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- if (*p[0] == '?') {
- p[0]++;
- sprintf(rs, "\r\n0,1");
- isdn_tty_at_cout(rs, info);
- } else {
- par = isdn_getnum(p);
- if ((par < 0) || (par > 1))
- PARSE_ERROR1;
- f->rel = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
-#endif
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- /* REV? - DCE Revision */
- if (!strncmp(p[0], "REV?", 4)) {
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: FREV?\n");
-#endif
- strcpy(rss, isdn_tty_fax_revision);
- sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
- isdn_tty_at_cout(rs, info);
- return 0;
- }
-
- /* Phase C Transmit Data Block Size */
- if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */
- p[0] += 4;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
- printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
-#endif
- switch (*p[0]) {
- case '0':
- p[0]++;
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
- PARSE_ERROR1;
-}
-
-int
-isdn_tty_cmd_PLUSF_FAX(char **p, modem_info *info)
-{
- if (TTY_IS_FCLASS2(info))
- return (isdn_tty_cmd_FCLASS2(p, info));
- else if (TTY_IS_FCLASS1(info))
- return (isdn_tty_cmd_FCLASS1(p, info));
- PARSE_ERROR1;
-}
diff --git a/drivers/isdn/i4l/isdn_ttyfax.h b/drivers/isdn/i4l/isdn_ttyfax.h
deleted file mode 100644
index ccda4fcf8f7b..000000000000
--- a/drivers/isdn/i4l/isdn_ttyfax.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* $Id: isdn_ttyfax.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, tty_fax related functions (linklevel).
- *
- * Copyright 1999 by Armin Schindler (mac@melware.de)
- * Copyright 1999 by Ralf Spachmann (mel@melware.de)
- * Copyright 1999 by Cytronics & Melware
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-
-#define XON 0x11
-#define XOFF 0x13
-#define DC2 0x12
diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c
deleted file mode 100644
index d11fe76f138f..000000000000
--- a/drivers/isdn/i4l/isdn_v110.c
+++ /dev/null
@@ -1,625 +0,0 @@
-/* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, V.110 related functions (linklevel).
- *
- * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-
-#include <linux/isdn.h>
-#include "isdn_v110.h"
-
-#undef ISDN_V110_DEBUG
-
-char *isdn_v110_revision = "$Revision: 1.1.2.2 $";
-
-#define V110_38400 255
-#define V110_19200 15
-#define V110_9600 3
-
-/*
- * The following data are precoded matrices, online and offline matrix
- * for 9600, 19200 und 38400, respectively
- */
-static unsigned char V110_OnMatrix_9600[] =
-{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
- 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
- 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
- 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
-
-static unsigned char V110_OffMatrix_9600[] =
-{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-static unsigned char V110_OnMatrix_19200[] =
-{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
- 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
-
-static unsigned char V110_OffMatrix_19200[] =
-{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-static unsigned char V110_OnMatrix_38400[] =
-{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
-
-static unsigned char V110_OffMatrix_38400[] =
-{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
-
-/*
- * FlipBits reorders sequences of keylen bits in one byte.
- * E.g. source order 7654321 will be converted to 45670123 when keylen = 4,
- * and to 67452301 when keylen = 2. This is necessary because ordering on
- * the isdn line is the other way.
- */
-static inline unsigned char
-FlipBits(unsigned char c, int keylen)
-{
- unsigned char b = c;
- unsigned char bit = 128;
- int i;
- int j;
- int hunks = (8 / keylen);
-
- c = 0;
- for (i = 0; i < hunks; i++) {
- for (j = 0; j < keylen; j++) {
- if (b & (bit >> j))
- c |= bit >> (keylen - j - 1);
- }
- bit >>= keylen;
- }
- return c;
-}
-
-
-/* isdn_v110_open allocates and initializes private V.110 data
- * structures and returns a pointer to these.
- */
-static isdn_v110_stream *
-isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
-{
- int i;
- isdn_v110_stream *v;
-
- if ((v = kzalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
- return NULL;
- v->key = key;
- v->nbits = 0;
- for (i = 0; key & (1 << i); i++)
- v->nbits++;
-
- v->nbytes = 8 / v->nbits;
- v->decodelen = 0;
-
- switch (key) {
- case V110_38400:
- v->OnlineFrame = V110_OnMatrix_38400;
- v->OfflineFrame = V110_OffMatrix_38400;
- break;
- case V110_19200:
- v->OnlineFrame = V110_OnMatrix_19200;
- v->OfflineFrame = V110_OffMatrix_19200;
- break;
- default:
- v->OnlineFrame = V110_OnMatrix_9600;
- v->OfflineFrame = V110_OffMatrix_9600;
- break;
- }
- v->framelen = v->nbytes * 10;
- v->SyncInit = 5;
- v->introducer = 0;
- v->dbit = 1;
- v->b = 0;
- v->skbres = hdrlen;
- v->maxsize = maxsize - hdrlen;
- if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) {
- kfree(v);
- return NULL;
- }
- return v;
-}
-
-/* isdn_v110_close frees private V.110 data structures */
-void
-isdn_v110_close(isdn_v110_stream *v)
-{
- if (v == NULL)
- return;
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "v110 close\n");
-#endif
- kfree(v->encodebuf);
- kfree(v);
-}
-
-
-/*
- * ValidHeaderBytes return the number of valid bytes in v->decodebuf
- */
-static int
-ValidHeaderBytes(isdn_v110_stream *v)
-{
- int i;
- for (i = 0; (i < v->decodelen) && (i < v->nbytes); i++)
- if ((v->decodebuf[i] & v->key) != 0)
- break;
- return i;
-}
-
-/*
- * SyncHeader moves the decodebuf ptr to the next valid header
- */
-static void
-SyncHeader(isdn_v110_stream *v)
-{
- unsigned char *rbuf = v->decodebuf;
- int len = v->decodelen;
-
- if (len == 0)
- return;
- for (rbuf++, len--; len > 0; len--, rbuf++) /* such den SyncHeader in buf ! */
- if ((*rbuf & v->key) == 0) /* erstes byte gefunden ? */
- break; /* jupp! */
- if (len)
- memcpy(v->decodebuf, rbuf, len);
-
- v->decodelen = len;
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "isdn_v110: Header resync\n");
-#endif
-}
-
-/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
- len is the number of matrix-lines. len must be a multiple of 10, i.e.
- only complete matices must be given.
- From these, netto data is extracted and returned in buf. The return-value
- is the bytecount of the decoded data.
-*/
-static int
-DecodeMatrix(isdn_v110_stream *v, unsigned char *m, int len, unsigned char *buf)
-{
- int line = 0;
- int buflen = 0;
- int mbit = 64;
- int introducer = v->introducer;
- int dbit = v->dbit;
- unsigned char b = v->b;
-
- while (line < len) { /* Are we done with all lines of the matrix? */
- if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */
- if (m[line] != 0x00) { /* not 0 ? -> error! */
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
- /* returning now is not the right thing, though :-( */
-#endif
- }
- line++; /* next line of matrix */
- continue;
- } else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */
- if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */
-#ifdef ISDN_V110_DEBUG
- printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
- /* returning now is not the right thing, though :-( */
-#endif
- }
- line++; /* next line */
- continue;
- } else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */
- introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */
- next_byte:
- if (mbit > 2) { /* was it the last bit in this line ? */
- mbit >>= 1; /* no -> take next */
- continue;
- } /* otherwise start with leftmost bit in the next line */
- mbit = 64;
- line++;
- continue;
- } else { /* otherwise we need to set a data bit */
- if (m[line] & mbit) /* was that bit set in the matrix ? */
- b |= dbit; /* yes -> set it in the data byte */
- else
- b &= dbit - 1; /* no -> clear it in the data byte */
- if (dbit < 128) /* is that data byte done ? */
- dbit <<= 1; /* no, got the next bit */
- else { /* data byte is done */
- buf[buflen++] = b; /* copy byte into the output buffer */
- introducer = b = 0; /* init of the intro sequence and of the data byte */
- dbit = 1; /* next we look for the 0th bit */
- }
- goto next_byte; /* look for next bit in the matrix */
- }
- }
- v->introducer = introducer;
- v->dbit = dbit;
- v->b = b;
- return buflen; /* return number of bytes in the output buffer */
-}
-
-/*
- * DecodeStream receives V.110 coded data from the input stream. It recovers the
- * original frames.
- * The input stream doesn't need to be framed
- */
-struct sk_buff *
-isdn_v110_decode(isdn_v110_stream *v, struct sk_buff *skb)
-{
- int i;
- int j;
- int len;
- unsigned char *v110_buf;
- unsigned char *rbuf;
-
- if (!skb) {
- printk(KERN_WARNING "isdn_v110_decode called with NULL skb!\n");
- return NULL;
- }
- rbuf = skb->data;
- len = skb->len;
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_decode called with NULL stream!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- if (v->decodelen == 0) /* cache empty? */
- for (; len > 0; len--, rbuf++) /* scan for SyncHeader in buf */
- if ((*rbuf & v->key) == 0)
- break; /* found first byte */
- if (len == 0) {
- dev_kfree_skb(skb);
- return NULL;
- }
- /* copy new data to decode-buffer */
- memcpy(&(v->decodebuf[v->decodelen]), rbuf, len);
- v->decodelen += len;
-ReSync:
- if (v->decodelen < v->nbytes) { /* got a new header ? */
- dev_kfree_skb(skb);
- return NULL; /* no, try later */
- }
- if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */
- SyncHeader(v); /* no -> look for header */
- goto ReSync;
- }
- len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
- if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) {
- printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- for (i = 0; i < len; i++) {
- v110_buf[i] = 0;
- for (j = 0; j < v->nbytes; j++)
- v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits));
- v110_buf[i] = FlipBits(v110_buf[i], v->nbits);
- }
- v->decodelen = (v->decodelen % (10 * v->nbytes));
- memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen);
-
- skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data));
- kfree(v110_buf);
- if (skb->len)
- return skb;
- else {
- kfree_skb(skb);
- return NULL;
- }
-}
-
-/* EncodeMatrix takes input data in buf, len is the bytecount.
- Data is encoded into v110 frames in m. Return value is the number of
- matrix-lines generated.
-*/
-static int
-EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
-{
- int line = 0;
- int i = 0;
- int mbit = 128;
- int dbit = 1;
- int introducer = 3;
- int ibit[] = {0, 1, 1};
-
- while ((i < len) && (line < mlen)) { /* while we still have input data */
- switch (line % 10) { /* in which line of the matrix are we? */
- case 0:
- m[line++] = 0x00; /* line 0 is always 0 */
- mbit = 128; /* go on with the 7th bit */
- break;
- case 5:
- m[line++] = 0xbf; /* line 5 is always 10111111 */
- mbit = 128; /* go on with the 7th bit */
- break;
- }
- if (line >= mlen) {
- printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
- return line;
- }
- next_bit:
- switch (mbit) { /* leftmost or rightmost bit ? */
- case 1:
- line++; /* rightmost -> go to next line */
- if (line >= mlen) {
- printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
- return line;
- }
- /* fall through */
- case 128:
- m[line] = 128; /* leftmost -> set byte to 1000000 */
- mbit = 64; /* current bit in the matrix line */
- continue;
- }
- if (introducer) { /* set 110 sequence ? */
- introducer--; /* set on digit less */
- m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */
- mbit >>= 1; /* bit of matrix line >> 1 */
- goto next_bit; /* and go on there */
- } /* else push data bits into the matrix! */
- m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */
- if (dbit == 128) { /* was it the last one? */
- dbit = 1; /* then go on with first bit of */
- i++; /* next byte in input buffer */
- if (i < len) /* input buffer done ? */
- introducer = 3; /* no, write introducer 110 */
- else { /* input buffer done ! */
- m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */
- break;
- }
- } else /* not the last data bit */
- dbit <<= 1; /* then go to next data bit */
- mbit >>= 1; /* go to next bit of matrix */
- goto next_bit;
-
- }
- /* if necessary, generate remaining lines of the matrix... */
- if ((line) && ((line + 10) < mlen))
- switch (++line % 10) {
- case 1:
- m[line++] = 0xfe;
- /* fall through */
- case 2:
- m[line++] = 0xfe;
- /* fall through */
- case 3:
- m[line++] = 0xfe;
- /* fall through */
- case 4:
- m[line++] = 0xfe;
- /* fall through */
- case 5:
- m[line++] = 0xbf;
- /* fall through */
- case 6:
- m[line++] = 0xfe;
- /* fall through */
- case 7:
- m[line++] = 0xfe;
- /* fall through */
- case 8:
- m[line++] = 0xfe;
- /* fall through */
- case 9:
- m[line++] = 0xfe;
- }
- return line; /* that's how many lines we have */
-}
-
-/*
- * Build a sync frame.
- */
-static struct sk_buff *
-isdn_v110_sync(isdn_v110_stream *v)
-{
- struct sk_buff *skb;
-
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
- return NULL;
- }
- if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
- skb_reserve(skb, v->skbres);
- skb_put_data(skb, v->OfflineFrame, v->framelen);
- }
- return skb;
-}
-
-/*
- * Build an idle frame.
- */
-static struct sk_buff *
-isdn_v110_idle(isdn_v110_stream *v)
-{
- struct sk_buff *skb;
-
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
- return NULL;
- }
- if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
- skb_reserve(skb, v->skbres);
- skb_put_data(skb, v->OnlineFrame, v->framelen);
- }
- return skb;
-}
-
-struct sk_buff *
-isdn_v110_encode(isdn_v110_stream *v, struct sk_buff *skb)
-{
- int i;
- int j;
- int rlen;
- int mlen;
- int olen;
- int size;
- int sval1;
- int sval2;
- int nframes;
- unsigned char *v110buf;
- unsigned char *rbuf;
- struct sk_buff *nskb;
-
- if (v == NULL) {
- /* invalid handle, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_encode called with NULL stream!\n");
- return NULL;
- }
- if (!skb) {
- /* invalid skb, no chance to proceed */
- printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n");
- return NULL;
- }
- rlen = skb->len;
- nframes = (rlen + 3) / 4;
- v110buf = v->encodebuf;
- if ((nframes * 40) > v->maxsize) {
- size = v->maxsize;
- rlen = v->maxsize / 40;
- } else
- size = nframes * 40;
- if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) {
- printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n");
- return NULL;
- }
- skb_reserve(nskb, v->skbres + sizeof(int));
- if (skb->len == 0) {
- skb_put_data(nskb, v->OnlineFrame, v->framelen);
- *((int *)skb_push(nskb, sizeof(int))) = 0;
- return nskb;
- }
- mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
- /* now distribute 2 or 4 bits each to the output stream! */
- rbuf = skb_put(nskb, size);
- olen = 0;
- sval1 = 8 - v->nbits;
- sval2 = v->key << sval1;
- for (i = 0; i < mlen; i++) {
- v110buf[i] = FlipBits(v110buf[i], v->nbits);
- for (j = 0; j < v->nbytes; j++) {
- if (size--)
- *rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1);
- else {
- printk(KERN_WARNING "isdn_v110_encode: buffers full!\n");
- goto buffer_full;
- }
- olen++;
- }
- }
-buffer_full:
- skb_trim(nskb, olen);
- *((int *)skb_push(nskb, sizeof(int))) = rlen;
- return nskb;
-}
-
-int
-isdn_v110_stat_callback(int idx, isdn_ctrl *c)
-{
- isdn_v110_stream *v = NULL;
- int i;
- int ret = 0;
-
- if (idx < 0)
- return 0;
- switch (c->command) {
- case ISDN_STAT_BSENT:
- /* Keep the send-queue of the driver filled
- * with frames:
- * If number of outstanding frames < 3,
- * send down an Idle-Frame (or an Sync-Frame, if
- * v->SyncInit != 0).
- */
- if (!(v = dev->v110[idx]))
- return 0;
- atomic_inc(&dev->v110use[idx]);
- for (i = 0; i * v->framelen < c->parm.length; i++) {
- if (v->skbidle > 0) {
- v->skbidle--;
- ret = 1;
- } else {
- if (v->skbuser > 0)
- v->skbuser--;
- ret = 0;
- }
- }
- for (i = v->skbuser + v->skbidle; i < 2; i++) {
- struct sk_buff *skb;
- if (v->SyncInit > 0)
- skb = isdn_v110_sync(v);
- else
- skb = isdn_v110_idle(v);
- if (skb) {
- if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
- dev_kfree_skb(skb);
- break;
- } else {
- if (v->SyncInit)
- v->SyncInit--;
- v->skbidle++;
- }
- } else
- break;
- }
- atomic_dec(&dev->v110use[idx]);
- return ret;
- case ISDN_STAT_DHUP:
- case ISDN_STAT_BHUP:
- while (1) {
- atomic_inc(&dev->v110use[idx]);
- if (atomic_dec_and_test(&dev->v110use[idx])) {
- isdn_v110_close(dev->v110[idx]);
- dev->v110[idx] = NULL;
- break;
- }
- mdelay(1);
- }
- break;
- case ISDN_STAT_BCONN:
- if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
- int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
- int maxsize = dev->drv[c->driver]->interface->maxbufsize;
- atomic_inc(&dev->v110use[idx]);
- switch (dev->v110emu[idx]) {
- case ISDN_PROTO_L2_V11096:
- dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
- break;
- case ISDN_PROTO_L2_V11019:
- dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
- break;
- case ISDN_PROTO_L2_V11038:
- dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
- break;
- default:;
- }
- if ((v = dev->v110[idx])) {
- while (v->SyncInit) {
- struct sk_buff *skb = isdn_v110_sync(v);
- if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
- dev_kfree_skb(skb);
- /* Unable to send, try later */
- break;
- }
- v->SyncInit--;
- v->skbidle++;
- }
- } else
- printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
- atomic_dec(&dev->v110use[idx]);
- }
- break;
- default:
- return 0;
- }
- return 0;
-}
diff --git a/drivers/isdn/i4l/isdn_v110.h b/drivers/isdn/i4l/isdn_v110.h
deleted file mode 100644
index de774ab598c9..000000000000
--- a/drivers/isdn/i4l/isdn_v110.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* $Id: isdn_v110.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, V.110 related functions (linklevel).
- *
- * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _isdn_v110_h_
-#define _isdn_v110_h_
-
-/*
- * isdn_v110_encode will take raw data and encode it using V.110
- */
-extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
-
-/*
- * isdn_v110_decode receives V.110 coded data from the stream and rebuilds
- * frames from them. The source stream doesn't need to be framed.
- */
-extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
-
-extern int isdn_v110_stat_callback(int, isdn_ctrl *);
-extern void isdn_v110_close(isdn_v110_stream *v);
-
-#endif
diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c
deleted file mode 100644
index 48bfbcb4a09d..000000000000
--- a/drivers/isdn/i4l/isdn_x25iface.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * Linux ISDN subsystem, X.25 related functions
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * stuff needed to support the Linux X.25 PLP code on top of devices that
- * can provide a lab_b service using the concap_proto mechanism.
- * This module supports a network interface which provides lapb_sematics
- * -- as defined in Documentation/networking/x25-iface.txt -- to
- * the upper layer and assumes that the lower layer provides a reliable
- * data link service by means of the concap_device_ops callbacks.
- *
- * Only protocol specific stuff goes here. Device specific stuff
- * goes to another -- device related -- concap_proto support source file.
- *
- */
-
-/* #include <linux/isdn.h> */
-#include <linux/netdevice.h>
-#include <linux/concap.h>
-#include <linux/slab.h>
-#include <linux/wanrouter.h>
-#include <net/x25device.h>
-#include "isdn_x25iface.h"
-
-/* for debugging messages not to cause an oops when device pointer is NULL*/
-#define MY_DEVNAME(dev) ((dev) ? (dev)->name : "DEVICE UNSPECIFIED")
-
-
-typedef struct isdn_x25iface_proto_data {
- int magic;
- enum wan_states state;
- /* Private stuff, not to be accessed via proto_data. We provide the
- other storage for the concap_proto instance here as well,
- enabling us to allocate both with just one kmalloc(): */
- struct concap_proto priv;
-} ix25_pdata_t;
-
-
-
-/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
-static void isdn_x25iface_proto_del(struct concap_proto *);
-static int isdn_x25iface_proto_close(struct concap_proto *);
-static int isdn_x25iface_proto_restart(struct concap_proto *,
- struct net_device *,
- struct concap_device_ops *);
-static int isdn_x25iface_xmit(struct concap_proto *, struct sk_buff *);
-static int isdn_x25iface_receive(struct concap_proto *, struct sk_buff *);
-static int isdn_x25iface_connect_ind(struct concap_proto *);
-static int isdn_x25iface_disconn_ind(struct concap_proto *);
-
-
-static struct concap_proto_ops ix25_pops = {
- .proto_new = &isdn_x25iface_proto_new,
- .proto_del = &isdn_x25iface_proto_del,
- .restart = &isdn_x25iface_proto_restart,
- .close = &isdn_x25iface_proto_close,
- .encap_and_xmit = &isdn_x25iface_xmit,
- .data_ind = &isdn_x25iface_receive,
- .connect_ind = &isdn_x25iface_connect_ind,
- .disconn_ind = &isdn_x25iface_disconn_ind
-};
-
-/* error message helper function */
-static void illegal_state_warn(unsigned state, unsigned char firstbyte)
-{
- printk(KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
- "current state %d\n", firstbyte, state);
-}
-
-/* check protocol data field for consistency */
-static int pdata_is_bad(ix25_pdata_t *pda) {
-
- if (pda && pda->magic == ISDN_X25IFACE_MAGIC) return 0;
- printk(KERN_WARNING
- "isdn_x25iface_xxx: illegal pointer to proto data\n");
- return 1;
-}
-
-/* create a new x25 interface protocol instance
- */
-struct concap_proto *isdn_x25iface_proto_new(void)
-{
- ix25_pdata_t *tmp = kmalloc(sizeof(ix25_pdata_t), GFP_KERNEL);
- IX25DEBUG("isdn_x25iface_proto_new\n");
- if (tmp) {
- tmp->magic = ISDN_X25IFACE_MAGIC;
- tmp->state = WAN_UNCONFIGURED;
- /* private data space used to hold the concap_proto data.
- Only to be accessed via the returned pointer */
- spin_lock_init(&tmp->priv.lock);
- tmp->priv.dops = NULL;
- tmp->priv.net_dev = NULL;
- tmp->priv.pops = &ix25_pops;
- tmp->priv.flags = 0;
- tmp->priv.proto_data = tmp;
- return (&(tmp->priv));
- }
- return NULL;
-};
-
-/* close the x25iface encapsulation protocol
- */
-static int isdn_x25iface_proto_close(struct concap_proto *cprot) {
-
- ix25_pdata_t *tmp;
- int ret = 0;
- ulong flags;
-
- if (!cprot) {
- printk(KERN_ERR "isdn_x25iface_proto_close: "
- "invalid concap_proto pointer\n");
- return -1;
- }
- IX25DEBUG("isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot->net_dev));
- spin_lock_irqsave(&cprot->lock, flags);
- cprot->dops = NULL;
- cprot->net_dev = NULL;
- tmp = cprot->proto_data;
- if (pdata_is_bad(tmp)) {
- ret = -1;
- } else {
- tmp->state = WAN_UNCONFIGURED;
- }
- spin_unlock_irqrestore(&cprot->lock, flags);
- return ret;
-}
-
-/* Delete the x25iface encapsulation protocol instance
- */
-static void isdn_x25iface_proto_del(struct concap_proto *cprot) {
-
- ix25_pdata_t *tmp;
-
- IX25DEBUG("isdn_x25iface_proto_del \n");
- if (!cprot) {
- printk(KERN_ERR "isdn_x25iface_proto_del: "
- "concap_proto pointer is NULL\n");
- return;
- }
- tmp = cprot->proto_data;
- if (tmp == NULL) {
- printk(KERN_ERR "isdn_x25iface_proto_del: inconsistent "
- "proto_data pointer (maybe already deleted?)\n");
- return;
- }
- /* close if the protocol is still open */
- if (cprot->dops) isdn_x25iface_proto_close(cprot);
- /* freeing the storage should be sufficient now. But some additional
- settings might help to catch wild pointer bugs */
- tmp->magic = 0;
- cprot->proto_data = NULL;
-
- kfree(tmp);
- return;
-}
-
-/* (re-)initialize the data structures for x25iface encapsulation
- */
-static int isdn_x25iface_proto_restart(struct concap_proto *cprot,
- struct net_device *ndev,
- struct concap_device_ops *dops)
-{
- ix25_pdata_t *pda = cprot->proto_data;
- ulong flags;
-
- IX25DEBUG("isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev));
-
- if (pdata_is_bad(pda)) return -1;
-
- if (!(dops && dops->data_req && dops->connect_req
- && dops->disconn_req)) {
- printk(KERN_WARNING "isdn_x25iface_restart: required dops"
- " missing\n");
- isdn_x25iface_proto_close(cprot);
- return -1;
- }
- spin_lock_irqsave(&cprot->lock, flags);
- cprot->net_dev = ndev;
- cprot->pops = &ix25_pops;
- cprot->dops = dops;
- pda->state = WAN_DISCONNECTED;
- spin_unlock_irqrestore(&cprot->lock, flags);
- return 0;
-}
-
-/* deliver a dl_data frame received from i4l HL driver to the network layer
- */
-static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
-{
- IX25DEBUG("isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev));
- if (((ix25_pdata_t *)(cprot->proto_data))
- ->state == WAN_CONNECTED) {
- if (skb_push(skb, 1)) {
- skb->data[0] = X25_IFACE_DATA;
- skb->protocol = x25_type_trans(skb, cprot->net_dev);
- netif_rx(skb);
- return 0;
- }
- }
- printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev));
- dev_kfree_skb(skb);
- return -1;
-}
-
-/* a connection set up is indicated by lower layer
- */
-static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
-{
- struct sk_buff *skb;
- enum wan_states *state_p
- = &(((ix25_pdata_t *)(cprot->proto_data))->state);
- IX25DEBUG("isdn_x25iface_connect_ind %s \n"
- , MY_DEVNAME(cprot->net_dev));
- if (*state_p == WAN_UNCONFIGURED) {
- printk(KERN_WARNING
- "isdn_x25iface_connect_ind while unconfigured %s\n"
- , MY_DEVNAME(cprot->net_dev));
- return -1;
- }
- *state_p = WAN_CONNECTED;
-
- skb = dev_alloc_skb(1);
- if (skb) {
- skb_put_u8(skb, X25_IFACE_CONNECT);
- skb->protocol = x25_type_trans(skb, cprot->net_dev);
- netif_rx(skb);
- return 0;
- } else {
- printk(KERN_WARNING "isdn_x25iface_connect_ind: "
- " out of memory -- disconnecting\n");
- cprot->dops->disconn_req(cprot);
- return -1;
- }
-}
-
-/* a disconnect is indicated by lower layer
- */
-static int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
-{
- struct sk_buff *skb;
- enum wan_states *state_p
- = &(((ix25_pdata_t *)(cprot->proto_data))->state);
- IX25DEBUG("isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot->net_dev));
- if (*state_p == WAN_UNCONFIGURED) {
- printk(KERN_WARNING
- "isdn_x25iface_disconn_ind while unconfigured\n");
- return -1;
- }
- if (!cprot->net_dev) return -1;
- *state_p = WAN_DISCONNECTED;
- skb = dev_alloc_skb(1);
- if (skb) {
- skb_put_u8(skb, X25_IFACE_DISCONNECT);
- skb->protocol = x25_type_trans(skb, cprot->net_dev);
- netif_rx(skb);
- return 0;
- } else {
- printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
- " out of memory\n");
- return -1;
- }
-}
-
-/* process a frame handed over to us from linux network layer. First byte
- semantics as defined in Documentation/networking/x25-iface.txt
-*/
-static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
-{
- unsigned char firstbyte = skb->data[0];
- enum wan_states *state = &((ix25_pdata_t *)cprot->proto_data)->state;
- int ret = 0;
- IX25DEBUG("isdn_x25iface_xmit: %s first=%x state=%d\n",
- MY_DEVNAME(cprot->net_dev), firstbyte, *state);
- switch (firstbyte) {
- case X25_IFACE_DATA:
- if (*state == WAN_CONNECTED) {
- skb_pull(skb, 1);
- netif_trans_update(cprot->net_dev);
- ret = (cprot->dops->data_req(cprot, skb));
- /* prepare for future retransmissions */
- if (ret) skb_push(skb, 1);
- return ret;
- }
- illegal_state_warn(*state, firstbyte);
- break;
- case X25_IFACE_CONNECT:
- if (*state == WAN_DISCONNECTED) {
- *state = WAN_CONNECTING;
- ret = cprot->dops->connect_req(cprot);
- if (ret) {
- /* reset state and notify upper layer about
- * immidiatly failed attempts */
- isdn_x25iface_disconn_ind(cprot);
- }
- } else {
- illegal_state_warn(*state, firstbyte);
- }
- break;
- case X25_IFACE_DISCONNECT:
- switch (*state) {
- case WAN_DISCONNECTED:
- /* Should not happen. However, give upper layer a
- chance to recover from inconstistency but don't
- trust the lower layer sending the disconn_confirm
- when already disconnected */
- printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
- " requested while disconnected\n");
- isdn_x25iface_disconn_ind(cprot);
- break; /* prevent infinite loops */
- case WAN_CONNECTING:
- case WAN_CONNECTED:
- *state = WAN_DISCONNECTED;
- cprot->dops->disconn_req(cprot);
- break;
- default:
- illegal_state_warn(*state, firstbyte);
- }
- break;
- case X25_IFACE_PARAMS:
- printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
- " options not yet supported\n");
- break;
- default:
- printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
- " first byte %x ignored:\n", firstbyte);
- }
- dev_kfree_skb(skb);
- return 0;
-}
diff --git a/drivers/isdn/i4l/isdn_x25iface.h b/drivers/isdn/i4l/isdn_x25iface.h
deleted file mode 100644
index ca08e082cf7c..000000000000
--- a/drivers/isdn/i4l/isdn_x25iface.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* $Id: isdn_x25iface.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
- *
- * header for Linux ISDN subsystem, x.25 related functions
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef _LINUX_ISDN_X25IFACE_H
-#define _LINUX_ISDN_X25IFACE_H
-
-#define ISDN_X25IFACE_MAGIC 0x1e75a2b9
-/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */
-#ifdef DEBUG_ISDN_X25
-# define IX25DEBUG(fmt, args...) printk(KERN_DEBUG fmt, ##args)
-#else
-# define IX25DEBUG(fmt, args...)
-#endif
-
-#include <linux/skbuff.h>
-#include <linux/isdn.h>
-#include <linux/concap.h>
-
-extern struct concap_proto_ops *isdn_x25iface_concap_proto_ops_pt;
-extern struct concap_proto *isdn_x25iface_proto_new(void);
-
-
-
-#endif
diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c
deleted file mode 100644
index 382a6b24e6a3..000000000000
--- a/drivers/isdn/i4l/isdnhdlc.c
+++ /dev/null
@@ -1,617 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * isdnhdlc.c -- General purpose ISDN HDLC decoder.
- *
- * Copyright (C)
- * 2009 Karsten Keil <keil@b1-systems.de>
- * 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
- * 2001 Frode Isaksen <fisaksen@bewan.com>
- * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/crc-ccitt.h>
-#include <linux/isdn/hdlc.h>
-#include <linux/bitrev.h>
-
-/*-------------------------------------------------------------------*/
-
-MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
- "Frode Isaksen <fisaksen@bewan.com>, "
- "Kai Germaschewski <kai.germaschewski@gmx.de>");
-MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
-MODULE_LICENSE("GPL");
-
-/*-------------------------------------------------------------------*/
-
-enum {
- HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7,
- HDLC_GET_DATA, HDLC_FAST_FLAG
-};
-
-enum {
- HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG,
- HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG,
- HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0,
- HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE
-};
-
-void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features)
-{
- memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
- hdlc->state = HDLC_GET_DATA;
- if (features & HDLC_56KBIT)
- hdlc->do_adapt56 = 1;
- if (features & HDLC_BITREVERSE)
- hdlc->do_bitreverse = 1;
-}
-EXPORT_SYMBOL(isdnhdlc_out_init);
-
-void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features)
-{
- memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
- if (features & HDLC_DCHANNEL) {
- hdlc->dchannel = 1;
- hdlc->state = HDLC_SEND_FIRST_FLAG;
- } else {
- hdlc->dchannel = 0;
- hdlc->state = HDLC_SEND_FAST_FLAG;
- hdlc->ffvalue = 0x7e;
- }
- hdlc->cbin = 0x7e;
- if (features & HDLC_56KBIT) {
- hdlc->do_adapt56 = 1;
- hdlc->state = HDLC_SENDFLAG_B0;
- } else
- hdlc->data_bits = 8;
- if (features & HDLC_BITREVERSE)
- hdlc->do_bitreverse = 1;
-}
-EXPORT_SYMBOL(isdnhdlc_rcv_init);
-
-static int
-check_frame(struct isdnhdlc_vars *hdlc)
-{
- int status;
-
- if (hdlc->dstpos < 2) /* too small - framing error */
- status = -HDLC_FRAMING_ERROR;
- else if (hdlc->crc != 0xf0b8) /* crc error */
- status = -HDLC_CRC_ERROR;
- else {
- /* remove CRC */
- hdlc->dstpos -= 2;
- /* good frame */
- status = hdlc->dstpos;
- }
- return status;
-}
-
-/*
- isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
-
- The source buffer is scanned for valid HDLC frames looking for
- flags (01111110) to indicate the start of a frame. If the start of
- the frame is found, the bit stuffing is removed (0 after 5 1's).
- When a new flag is found, the complete frame has been received
- and the CRC is checked.
- If a valid frame is found, the function returns the frame length
- excluding the CRC with the bit HDLC_END_OF_FRAME set.
- If the beginning of a valid frame is found, the function returns
- the length.
- If a framing error is found (too many 1s and not a flag) the function
- returns the length with the bit HDLC_FRAMING_ERROR set.
- If a CRC error is found the function returns the length with the
- bit HDLC_CRC_ERROR set.
- If the frame length exceeds the destination buffer size, the function
- returns the length with the bit HDLC_LENGTH_ERROR set.
-
- src - source buffer
- slen - source buffer length
- count - number of bytes removed (decoded) from the source buffer
- dst _ destination buffer
- dsize - destination buffer size
- returns - number of decoded bytes in the destination buffer and status
- flag.
-*/
-int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen,
- int *count, u8 *dst, int dsize)
-{
- int status = 0;
-
- static const unsigned char fast_flag[] = {
- 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f
- };
-
- static const unsigned char fast_flag_value[] = {
- 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f
- };
-
- static const unsigned char fast_abort[] = {
- 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
- };
-
-#define handle_fast_flag(h) \
- do { \
- if (h->cbin == fast_flag[h->bit_shift]) { \
- h->ffvalue = fast_flag_value[h->bit_shift]; \
- h->state = HDLC_FAST_FLAG; \
- h->ffbit_shift = h->bit_shift; \
- h->bit_shift = 1; \
- } else { \
- h->state = HDLC_GET_DATA; \
- h->data_received = 0; \
- } \
- } while (0)
-
-#define handle_abort(h) \
- do { \
- h->shift_reg = fast_abort[h->ffbit_shift - 1]; \
- h->hdlc_bits1 = h->ffbit_shift - 2; \
- if (h->hdlc_bits1 < 0) \
- h->hdlc_bits1 = 0; \
- h->data_bits = h->ffbit_shift - 1; \
- h->state = HDLC_GET_DATA; \
- h->data_received = 0; \
- } while (0)
-
- *count = slen;
-
- while (slen > 0) {
- if (hdlc->bit_shift == 0) {
- /* the code is for bitreverse streams */
- if (hdlc->do_bitreverse == 0)
- hdlc->cbin = bitrev8(*src++);
- else
- hdlc->cbin = *src++;
- slen--;
- hdlc->bit_shift = 8;
- if (hdlc->do_adapt56)
- hdlc->bit_shift--;
- }
-
- switch (hdlc->state) {
- case STOPPED:
- return 0;
- case HDLC_FAST_IDLE:
- if (hdlc->cbin == 0xff) {
- hdlc->bit_shift = 0;
- break;
- }
- hdlc->state = HDLC_GET_FLAG_B0;
- hdlc->hdlc_bits1 = 0;
- hdlc->bit_shift = 8;
- break;
- case HDLC_GET_FLAG_B0:
- if (!(hdlc->cbin & 0x80)) {
- hdlc->state = HDLC_GETFLAG_B1A6;
- hdlc->hdlc_bits1 = 0;
- } else {
- if ((!hdlc->do_adapt56) &&
- (++hdlc->hdlc_bits1 >= 8) &&
- (hdlc->bit_shift == 1))
- hdlc->state = HDLC_FAST_IDLE;
- }
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- break;
- case HDLC_GETFLAG_B1A6:
- if (hdlc->cbin & 0x80) {
- hdlc->hdlc_bits1++;
- if (hdlc->hdlc_bits1 == 6)
- hdlc->state = HDLC_GETFLAG_B7;
- } else
- hdlc->hdlc_bits1 = 0;
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- break;
- case HDLC_GETFLAG_B7:
- if (hdlc->cbin & 0x80) {
- hdlc->state = HDLC_GET_FLAG_B0;
- } else {
- hdlc->state = HDLC_GET_DATA;
- hdlc->crc = 0xffff;
- hdlc->shift_reg = 0;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = 0;
- hdlc->data_received = 0;
- }
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- break;
- case HDLC_GET_DATA:
- if (hdlc->cbin & 0x80) {
- hdlc->hdlc_bits1++;
- switch (hdlc->hdlc_bits1) {
- case 6:
- break;
- case 7:
- if (hdlc->data_received)
- /* bad frame */
- status = -HDLC_FRAMING_ERROR;
- if (!hdlc->do_adapt56) {
- if (hdlc->cbin == fast_abort
- [hdlc->bit_shift + 1]) {
- hdlc->state =
- HDLC_FAST_IDLE;
- hdlc->bit_shift = 1;
- break;
- }
- } else
- hdlc->state = HDLC_GET_FLAG_B0;
- break;
- default:
- hdlc->shift_reg >>= 1;
- hdlc->shift_reg |= 0x80;
- hdlc->data_bits++;
- break;
- }
- } else {
- switch (hdlc->hdlc_bits1) {
- case 5:
- break;
- case 6:
- if (hdlc->data_received)
- status = check_frame(hdlc);
- hdlc->crc = 0xffff;
- hdlc->shift_reg = 0;
- hdlc->data_bits = 0;
- if (!hdlc->do_adapt56)
- handle_fast_flag(hdlc);
- else {
- hdlc->state = HDLC_GET_DATA;
- hdlc->data_received = 0;
- }
- break;
- default:
- hdlc->shift_reg >>= 1;
- hdlc->data_bits++;
- break;
- }
- hdlc->hdlc_bits1 = 0;
- }
- if (status) {
- hdlc->dstpos = 0;
- *count -= slen;
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- return status;
- }
- if (hdlc->data_bits == 8) {
- hdlc->data_bits = 0;
- hdlc->data_received = 1;
- hdlc->crc = crc_ccitt_byte(hdlc->crc,
- hdlc->shift_reg);
-
- /* good byte received */
- if (hdlc->dstpos < dsize)
- dst[hdlc->dstpos++] = hdlc->shift_reg;
- else {
- /* frame too long */
- status = -HDLC_LENGTH_ERROR;
- hdlc->dstpos = 0;
- }
- }
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- break;
- case HDLC_FAST_FLAG:
- if (hdlc->cbin == hdlc->ffvalue) {
- hdlc->bit_shift = 0;
- break;
- } else {
- if (hdlc->cbin == 0xff) {
- hdlc->state = HDLC_FAST_IDLE;
- hdlc->bit_shift = 0;
- } else if (hdlc->ffbit_shift == 8) {
- hdlc->state = HDLC_GETFLAG_B7;
- break;
- } else
- handle_abort(hdlc);
- }
- break;
- default:
- break;
- }
- }
- *count -= slen;
- return 0;
-}
-EXPORT_SYMBOL(isdnhdlc_decode);
-/*
- isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
-
- The bit stream starts with a beginning flag (01111110). After
- that each byte is added to the bit stream with bit stuffing added
- (0 after 5 1's).
- When the last byte has been removed from the source buffer, the
- CRC (2 bytes is added) and the frame terminates with the ending flag.
- For the dchannel, the idle character (all 1's) is also added at the end.
- If this function is called with empty source buffer (slen=0), flags or
- idle character will be generated.
-
- src - source buffer
- slen - source buffer length
- count - number of bytes removed (encoded) from source buffer
- dst _ destination buffer
- dsize - destination buffer size
- returns - number of encoded bytes in the destination buffer
-*/
-int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen,
- int *count, u8 *dst, int dsize)
-{
- static const unsigned char xfast_flag_value[] = {
- 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e
- };
-
- int len = 0;
-
- *count = slen;
-
- /* special handling for one byte frames */
- if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG))
- hdlc->state = HDLC_SENDFLAG_ONE;
- while (dsize > 0) {
- if (hdlc->bit_shift == 0) {
- if (slen && !hdlc->do_closing) {
- hdlc->shift_reg = *src++;
- slen--;
- if (slen == 0)
- /* closing sequence, CRC + flag(s) */
- hdlc->do_closing = 1;
- hdlc->bit_shift = 8;
- } else {
- if (hdlc->state == HDLC_SEND_DATA) {
- if (hdlc->data_received) {
- hdlc->state = HDLC_SEND_CRC1;
- hdlc->crc ^= 0xffff;
- hdlc->bit_shift = 8;
- hdlc->shift_reg =
- hdlc->crc & 0xff;
- } else if (!hdlc->do_adapt56)
- hdlc->state =
- HDLC_SEND_FAST_FLAG;
- else
- hdlc->state =
- HDLC_SENDFLAG_B0;
- }
-
- }
- }
-
- switch (hdlc->state) {
- case STOPPED:
- while (dsize--)
- *dst++ = 0xff;
- return dsize;
- case HDLC_SEND_FAST_FLAG:
- hdlc->do_closing = 0;
- if (slen == 0) {
- /* the code is for bitreverse streams */
- if (hdlc->do_bitreverse == 0)
- *dst++ = bitrev8(hdlc->ffvalue);
- else
- *dst++ = hdlc->ffvalue;
- len++;
- dsize--;
- break;
- }
- /* fall through */
- case HDLC_SENDFLAG_ONE:
- if (hdlc->bit_shift == 8) {
- hdlc->cbin = hdlc->ffvalue >>
- (8 - hdlc->data_bits);
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_received = 1;
- }
- break;
- case HDLC_SENDFLAG_B0:
- hdlc->do_closing = 0;
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- hdlc->hdlc_bits1 = 0;
- hdlc->state = HDLC_SENDFLAG_B1A6;
- break;
- case HDLC_SENDFLAG_B1A6:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- hdlc->cbin++;
- if (++hdlc->hdlc_bits1 == 6)
- hdlc->state = HDLC_SENDFLAG_B7;
- break;
- case HDLC_SENDFLAG_B7:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (slen == 0) {
- hdlc->state = HDLC_SENDFLAG_B0;
- break;
- }
- if (hdlc->bit_shift == 8) {
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_received = 1;
- }
- break;
- case HDLC_SEND_FIRST_FLAG:
- hdlc->data_received = 1;
- if (hdlc->data_bits == 8) {
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- break;
- }
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (hdlc->shift_reg & 0x01)
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- if (hdlc->bit_shift == 0) {
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- }
- break;
- case HDLC_SEND_DATA:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (hdlc->hdlc_bits1 == 5) {
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if (hdlc->bit_shift == 8)
- hdlc->crc = crc_ccitt_byte(hdlc->crc,
- hdlc->shift_reg);
- if (hdlc->shift_reg & 0x01) {
- hdlc->hdlc_bits1++;
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- } else {
- hdlc->hdlc_bits1 = 0;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- }
- break;
- case HDLC_SEND_CRC1:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (hdlc->hdlc_bits1 == 5) {
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if (hdlc->shift_reg & 0x01) {
- hdlc->hdlc_bits1++;
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- } else {
- hdlc->hdlc_bits1 = 0;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- }
- if (hdlc->bit_shift == 0) {
- hdlc->shift_reg = (hdlc->crc >> 8);
- hdlc->state = HDLC_SEND_CRC2;
- hdlc->bit_shift = 8;
- }
- break;
- case HDLC_SEND_CRC2:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (hdlc->hdlc_bits1 == 5) {
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if (hdlc->shift_reg & 0x01) {
- hdlc->hdlc_bits1++;
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- } else {
- hdlc->hdlc_bits1 = 0;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- }
- if (hdlc->bit_shift == 0) {
- hdlc->shift_reg = 0x7e;
- hdlc->state = HDLC_SEND_CLOSING_FLAG;
- hdlc->bit_shift = 8;
- }
- break;
- case HDLC_SEND_CLOSING_FLAG:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if (hdlc->hdlc_bits1 == 5) {
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if (hdlc->shift_reg & 0x01)
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- if (hdlc->bit_shift == 0) {
- hdlc->ffvalue =
- xfast_flag_value[hdlc->data_bits];
- if (hdlc->dchannel) {
- hdlc->ffvalue = 0x7e;
- hdlc->state = HDLC_SEND_IDLE1;
- hdlc->bit_shift = 8-hdlc->data_bits;
- if (hdlc->bit_shift == 0)
- hdlc->state =
- HDLC_SEND_FAST_IDLE;
- } else {
- if (!hdlc->do_adapt56) {
- hdlc->state =
- HDLC_SEND_FAST_FLAG;
- hdlc->data_received = 0;
- } else {
- hdlc->state = HDLC_SENDFLAG_B0;
- hdlc->data_received = 0;
- }
- /* Finished this frame, send flags */
- if (dsize > 1)
- dsize = 1;
- }
- }
- break;
- case HDLC_SEND_IDLE1:
- hdlc->do_closing = 0;
- hdlc->cbin <<= 1;
- hdlc->cbin++;
- hdlc->data_bits++;
- hdlc->bit_shift--;
- if (hdlc->bit_shift == 0) {
- hdlc->state = HDLC_SEND_FAST_IDLE;
- hdlc->bit_shift = 0;
- }
- break;
- case HDLC_SEND_FAST_IDLE:
- hdlc->do_closing = 0;
- hdlc->cbin = 0xff;
- hdlc->data_bits = 8;
- if (hdlc->bit_shift == 8) {
- hdlc->cbin = 0x7e;
- hdlc->state = HDLC_SEND_FIRST_FLAG;
- } else {
- /* the code is for bitreverse streams */
- if (hdlc->do_bitreverse == 0)
- *dst++ = bitrev8(hdlc->cbin);
- else
- *dst++ = hdlc->cbin;
- hdlc->bit_shift = 0;
- hdlc->data_bits = 0;
- len++;
- dsize = 0;
- }
- break;
- default:
- break;
- }
- if (hdlc->do_adapt56) {
- if (hdlc->data_bits == 7) {
- hdlc->cbin <<= 1;
- hdlc->cbin++;
- hdlc->data_bits++;
- }
- }
- if (hdlc->data_bits == 8) {
- /* the code is for bitreverse streams */
- if (hdlc->do_bitreverse == 0)
- *dst++ = bitrev8(hdlc->cbin);
- else
- *dst++ = hdlc->cbin;
- hdlc->data_bits = 0;
- len++;
- dsize--;
- }
- }
- *count -= slen;
-
- return len;
-}
-EXPORT_SYMBOL(isdnhdlc_encode);