Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
This commit is contained in:
Linus Torvalds
2005-04-16 15:20:36 -07:00
commit 1da177e4c3
17291 changed files with 6718755 additions and 0 deletions

141
drivers/isdn/i4l/Kconfig Normal file
View File

@@ -0,0 +1,141 @@
#
# Old ISDN4Linux config
#
config ISDN_PPP
bool "Support synchronous PPP"
depends on INET
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"
depends on ISDN
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"
depends on ISDN && ISDN_I4L
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"
depends on NET && ISDN && ISDN_I4L
source "drivers/isdn/hisax/Kconfig"
menu "Active cards"
depends on NET && ISDN && ISDN_I4L!=n
source "drivers/isdn/icn/Kconfig"
source "drivers/isdn/pcbit/Kconfig"
source "drivers/isdn/sc/Kconfig"
source "drivers/isdn/act2000/Kconfig"
source "drivers/isdn/hysdn/Kconfig"
endmenu

18
drivers/isdn/i4l/Makefile Normal file
View File

@@ -0,0 +1,18 @@
# 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
# 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

View File

@@ -0,0 +1,720 @@
/* $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 "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 = (adpcm_state *) 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 = (dtmf_state *) 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_2adpcm_flush(adpcm_state * s, unsigned char *out)
{
int olen = 0;
if (s->nleft)
isdn_audio_put_bits(0, 8 - s->nleft, s, &out, &olen);
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/~pino/Ptolemy/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 = (int *) 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 = (silence_state *) 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 = (char *) 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);
}
}

View File

@@ -0,0 +1,45 @@
/* $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 int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out);
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);

View File

@@ -0,0 +1,937 @@
/*
* 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/sched.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/system.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
*/
if (db->dict) {
vfree (db->dict);
db->dict = NULL;
}
/*
* Release the string buffer
*/
if (db->lens) {
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 = (struct bsd_db *) kmalloc (sizeof (struct bsd_db),GFP_KERNEL);
if (!db)
return NULL;
memset (db, 0, sizeof(struct bsd_db));
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 = (struct bsd_dict *) vmalloc (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 = (unsigned short *) vmalloc ((maxmaxcode + 1) *
sizeof (db->lens[0]));
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(skb_out,1)) = (unsigned char) (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(skb_out,1)) = (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 && 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(skb_out,1)) = 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(skb_out,1)) = 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);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
/* $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_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 *);
extern int isdn_add_channels(isdn_driver_t *, int, int, int);
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
extern void isdn_dumppkt(char *, u_char *, int, int);
#endif

View File

@@ -0,0 +1,108 @@
/* $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.
*/
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 *) ndev->priv)->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;
}
int isdn_concap_dl_connect_req(struct concap_proto *concap)
{
struct net_device *ndev = concap -> net_dev;
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
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;
}
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 = {
&isdn_concap_dl_data_req,
&isdn_concap_dl_connect_req,
&isdn_concap_dl_disconn_req
};
struct concap_device_ops isdn_concap_demand_dial_dops = {
NULL, /* set this first entry to something like &isdn_net_start_xmit,
but the entry part of the current isdn_net_start_xmit must be
separated first. */
/* no connection control for demand dial semantics */
NULL,
NULL,
};
/* 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;
}

View File

@@ -0,0 +1,14 @@
/* $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_device_ops isdn_concap_demand_dial_dops;
extern struct concap_proto * isdn_concap_new( int );

3222
drivers/isdn/i4l/isdn_net.c Normal file

File diff suppressed because it is too large Load Diff

190
drivers/isdn/i4l/isdn_net.h Normal file
View File

@@ -0,0 +1,190 @@
/* $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
/*
* 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 */
spin_lock(&nd->queue->xmit_lock);
while (isdn_net_lp_busy(nd->queue)) {
spin_unlock(&nd->queue->xmit_lock);
nd->queue = nd->queue->next;
if (nd->queue == lp) { /* not found -- should never happen */
lp = NULL;
goto errout;
}
spin_lock(&nd->queue->xmit_lock);
}
lp = nd->queue;
nd->queue = nd->queue->next;
local_bh_disable();
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",
// __FUNCTION__, 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_net_local *) lp->master->priv;
// printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
// __FUNCTION__, 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",
// __FUNCTION__, master_lp->netdev->queue);
spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
}
static inline int
put_u8(unsigned char *p, u8 x)
{
*p = x;
return 1;
}
static inline int
put_u16(unsigned char *p, u16 x)
{
*((u16 *)p) = htons(x);
return 2;
}
static inline int
put_u32(unsigned char *p, u32 x)
{
*((u32 *)p) = htonl(x);
return 4;
}
static inline int
get_u8(unsigned char *p, u8 *x)
{
*x = *p;
return 1;
}
static inline int
get_u16(unsigned char *p, u16 *x)
{
*x = ntohs(*((u16 *)p));
return 2;
}
static inline int
get_u32(unsigned char *p, u32 *x)
{
*x = ntohl(*((u32 *)p));
return 4;
}

3020
drivers/isdn/i4l/isdn_ppp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
/* $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 unsigned int 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

3911
drivers/isdn/i4l/isdn_tty.c Normal file

File diff suppressed because it is too large Load Diff

122
drivers/isdn/i4l/isdn_tty.h Normal file
View File

@@ -0,0 +1,122 @@
/* $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.
*
*/
#include <linux/config.h>
#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 void isdn_tty_cleanup_xmit(modem_info *);
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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
/* $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

View File

@@ -0,0 +1,617 @@
/* $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 = kmalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
return NULL;
memset(v, 0, sizeof(isdn_v110_stream));
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;
}
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;
case 2:
m[line++] = 0xfe;
case 3:
m[line++] = 0xfe;
case 4:
m[line++] = 0xfe;
case 5:
m[line++] = 0xbf;
case 6:
m[line++] = 0xfe;
case 7:
m[line++] = 0xfe;
case 8:
m[line++] = 0xfe;
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);
memcpy(skb_put(skb, v->framelen), 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);
memcpy(skb_put(skb, v->framelen), 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) {
memcpy(skb_put(nskb, v->framelen), 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;
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;
}

View File

@@ -0,0 +1,29 @@
/* $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

View File

@@ -0,0 +1,328 @@
/* $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 wich 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/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); */
void isdn_x25iface_proto_del( struct concap_proto * );
int isdn_x25iface_proto_close( struct concap_proto * );
int isdn_x25iface_proto_restart( struct concap_proto *,
struct net_device *,
struct concap_device_ops *);
int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * );
int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * );
int isdn_x25iface_connect_ind( struct concap_proto * );
int isdn_x25iface_disconn_ind( struct concap_proto * );
static struct concap_proto_ops ix25_pops = {
&isdn_x25iface_proto_new,
&isdn_x25iface_proto_del,
&isdn_x25iface_proto_restart,
&isdn_x25iface_proto_close,
&isdn_x25iface_xmit,
&isdn_x25iface_receive,
&isdn_x25iface_connect_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
*/
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
*/
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
*/
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
*/
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]=0x00;
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
*/
int isdn_x25iface_connect_ind(struct concap_proto *cprot)
{
struct sk_buff * skb = dev_alloc_skb(1);
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;
if( skb ){
*( skb_put(skb, 1) ) = 0x01;
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
*/
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(skb, 1) ) = 0x02;
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
*/
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 0x00: /* dl_data request */
if( *state == WAN_CONNECTED ){
skb_pull(skb, 1);
cprot -> net_dev -> trans_start = jiffies;
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 0x01: /* dl_connect request */
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 0x02: /* dl_disconnect request */
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 0x03: /* changing lapb parameters requested */
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;
}

View File

@@ -0,0 +1,39 @@
/* $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/wanrouter.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