mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 19:51:31 -04:00
isdn: remove isdn4linux
With all isdn4linux hardware drivers gone, this is only a wrapper around CAPI to support old user space. However, from looking at the mailing list, it seems that the last time anyone asked about it was in 2014, when the upgrade from a linux-2.4 installation failed, and mISDN was suggested as a replacement. The largest public ISDN network (Deutsche Telekom) was supposed to be shut down 2018, which must have drastically reduced the number of legacy installations. When we last discussed removing i4l in 2016, Karsten Keil suggested revisiting this in 2018. I guess this is overdue. Link: http://listserv.isdn4linux.de/pipermail/isdn4linux/2014-October/006165.html Link: https://patchwork.kernel.org/patch/8484861/#17900371 Link: https://listserv.isdn4linux.de/pipermail/isdn4linux/2019-April/thread.html Signed-off-by: Arnd Bergmann <[email protected]>
This commit is contained in:
parent
85993b8c97
commit
9c3c0c2048
59 changed files with 2 additions and 26860 deletions
|
|
@ -21,27 +21,6 @@ menuconfig ISDN
|
|||
|
||||
if ISDN
|
||||
|
||||
menuconfig ISDN_I4L
|
||||
tristate "Old ISDN4Linux (deprecated)"
|
||||
depends on TTY
|
||||
---help---
|
||||
This driver allows you to use an ISDN adapter for networking
|
||||
connections and as dialin/out device. The isdn-tty's have a built
|
||||
in AT-compatible modem emulator. Network devices support autodial,
|
||||
channel-bundling, callback and caller-authentication without having
|
||||
a daemon running. A reduced T.70 protocol is supported with tty's
|
||||
suitable for German BTX. On D-Channel, the protocols EDSS1
|
||||
(Euro-ISDN) and 1TR6 (German style) are supported. See
|
||||
<file:Documentation/isdn/README> for more information.
|
||||
|
||||
ISDN support in the linux kernel is moving towards a new API,
|
||||
called CAPI (Common ISDN Application Programming Interface).
|
||||
Therefore the old ISDN4Linux layer will eventually become obsolete.
|
||||
It is still available, though, for use with adapters that are not
|
||||
supported by the new CAPI subsystem yet.
|
||||
|
||||
source "drivers/isdn/i4l/Kconfig"
|
||||
|
||||
menuconfig ISDN_CAPI
|
||||
tristate "CAPI 2.0 subsystem"
|
||||
help
|
||||
|
|
@ -71,9 +50,4 @@ source "drivers/isdn/hysdn/Kconfig"
|
|||
|
||||
source "drivers/isdn/mISDN/Kconfig"
|
||||
|
||||
config ISDN_HDLC
|
||||
tristate
|
||||
select CRC_CCITT
|
||||
select BITREVERSE
|
||||
|
||||
endif # ISDN
|
||||
|
|
|
|||
|
|
@ -7,7 +7,5 @@ obj-$(CONFIG_ISDN_I4L) += i4l/
|
|||
obj-$(CONFIG_ISDN_CAPI) += capi/
|
||||
obj-$(CONFIG_MISDN) += mISDN/
|
||||
obj-$(CONFIG_ISDN) += hardware/
|
||||
obj-$(CONFIG_ISDN_DIVERSION) += divert/
|
||||
obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/
|
||||
obj-$(CONFIG_HYSDN) += hysdn/
|
||||
obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/
|
||||
|
|
|
|||
|
|
@ -27,15 +27,6 @@ config ISDN_CAPI_MIDDLEWARE
|
|||
device. If you want to use pppd with pppdcapiplugin to dial up to
|
||||
your ISP, say Y here.
|
||||
|
||||
config ISDN_CAPI_CAPIDRV
|
||||
tristate "CAPI2.0 capidrv interface support"
|
||||
depends on ISDN_I4L
|
||||
help
|
||||
This option provides the glue code to hook up CAPI driven cards to
|
||||
the legacy isdn4linux link layer. If you have a card which is
|
||||
supported by a CAPI driver, but still want to use old features like
|
||||
ippp interfaces or ttyI emulation, say Y/M here.
|
||||
|
||||
config ISDN_CAPI_CAPIDRV_VERBOSE
|
||||
bool "Verbose reason code reporting"
|
||||
depends on ISDN_CAPI_CAPIDRV
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,140 +0,0 @@
|
|||
/* $Id: capidrv.h,v 1.2.8.2 2001/09/23 22:24:33 kai Exp $
|
||||
*
|
||||
* ISDN4Linux Driver, using capi20 interface (kernelcapi)
|
||||
*
|
||||
* Copyright 1997 by Carsten Paeth <calle@calle.de>
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CAPIDRV_H__
|
||||
#define __CAPIDRV_H__
|
||||
|
||||
/*
|
||||
* LISTEN state machine
|
||||
*/
|
||||
#define ST_LISTEN_NONE 0 /* L-0 */
|
||||
#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */
|
||||
#define ST_LISTEN_ACTIVE 2 /* L-1 */
|
||||
#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */
|
||||
|
||||
|
||||
#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1
|
||||
L-1 -> L-1.1 */
|
||||
#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0
|
||||
L-1.1 -> L-1 */
|
||||
#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0
|
||||
L-1.1 -> L-0 */
|
||||
#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1
|
||||
L-1.1 -> L.1 */
|
||||
|
||||
/*
|
||||
* per plci state machine
|
||||
*/
|
||||
#define ST_PLCI_NONE 0 /* P-0 */
|
||||
#define ST_PLCI_OUTGOING 1 /* P-0.1 */
|
||||
#define ST_PLCI_ALLOCATED 2 /* P-1 */
|
||||
#define ST_PLCI_ACTIVE 3 /* P-ACT */
|
||||
#define ST_PLCI_INCOMING 4 /* P-2 */
|
||||
#define ST_PLCI_FACILITY_IND 5 /* P-3 */
|
||||
#define ST_PLCI_ACCEPTING 6 /* P-4 */
|
||||
#define ST_PLCI_DISCONNECTING 7 /* P-5 */
|
||||
#define ST_PLCI_DISCONNECTED 8 /* P-6 */
|
||||
#define ST_PLCI_RESUMEING 9 /* P-0.Res */
|
||||
#define ST_PLCI_RESUME 10 /* P-Res */
|
||||
#define ST_PLCI_HELD 11 /* P-HELD */
|
||||
|
||||
#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1
|
||||
*/
|
||||
#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0
|
||||
*/
|
||||
#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1
|
||||
*/
|
||||
#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1
|
||||
*/
|
||||
#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2
|
||||
*/
|
||||
#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT
|
||||
*/
|
||||
#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5
|
||||
P-3 -> P-5
|
||||
*/
|
||||
#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5
|
||||
P-2 -> P-5
|
||||
P-3 -> P-5
|
||||
P-4 -> P-5
|
||||
P-ACT -> P-5
|
||||
P-Res -> P-5 (*)
|
||||
P-HELD -> P-5 (*)
|
||||
*/
|
||||
#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6
|
||||
P-2 -> P-6
|
||||
P-3 -> P-6
|
||||
P-4 -> P-6
|
||||
P-5 -> P-6
|
||||
P-ACT -> P-6
|
||||
P-Res -> P-6 (*)
|
||||
P-HELD -> P-6 (*)
|
||||
*/
|
||||
#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5
|
||||
P-1 -> P-5
|
||||
P-ACT -> P-5
|
||||
P-2 -> P-5
|
||||
P-3 -> P-5
|
||||
P-4 -> P-5
|
||||
*/
|
||||
#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0
|
||||
*/
|
||||
#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0
|
||||
*/
|
||||
|
||||
#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res
|
||||
*/
|
||||
#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res
|
||||
*/
|
||||
#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0
|
||||
*/
|
||||
#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT
|
||||
*/
|
||||
#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD
|
||||
*/
|
||||
#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT
|
||||
*/
|
||||
#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5
|
||||
*/
|
||||
#define EV_PLCI_CD_IND 20 /* P-2 -> P-5
|
||||
*/
|
||||
|
||||
/*
|
||||
* per ncci state machine
|
||||
*/
|
||||
#define ST_NCCI_PREVIOUS -1
|
||||
#define ST_NCCI_NONE 0 /* N-0 */
|
||||
#define ST_NCCI_OUTGOING 1 /* N-0.1 */
|
||||
#define ST_NCCI_INCOMING 2 /* N-1 */
|
||||
#define ST_NCCI_ALLOCATED 3 /* N-2 */
|
||||
#define ST_NCCI_ACTIVE 4 /* N-ACT */
|
||||
#define ST_NCCI_RESETING 5 /* N-3 */
|
||||
#define ST_NCCI_DISCONNECTING 6 /* N-4 */
|
||||
#define ST_NCCI_DISCONNECTED 7 /* N-5 */
|
||||
|
||||
#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */
|
||||
#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */
|
||||
#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */
|
||||
#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */
|
||||
#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */
|
||||
#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */
|
||||
#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */
|
||||
#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */
|
||||
#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */
|
||||
#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */
|
||||
#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */
|
||||
#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4
|
||||
N-2 -> N-4
|
||||
N-3 -> N-4
|
||||
N-ACT -> N-4 */
|
||||
#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */
|
||||
|
||||
#endif /* __CAPIDRV_H__ */
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Makefile for the dss1_divert ISDN module
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o
|
||||
|
||||
# Multipart objects.
|
||||
|
||||
dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/* $Id divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $
|
||||
*
|
||||
* Module init for DSS1 diversion services for i4l.
|
||||
*
|
||||
* Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "isdn_divert.h"
|
||||
|
||||
MODULE_DESCRIPTION("ISDN4Linux: Call diversion support");
|
||||
MODULE_AUTHOR("Werner Cornelius");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/****************************************/
|
||||
/* structure containing interface to hl */
|
||||
/****************************************/
|
||||
isdn_divert_if divert_if = {
|
||||
DIVERT_IF_MAGIC, /* magic value */
|
||||
DIVERT_CMD_REG, /* register cmd */
|
||||
ll_callback, /* callback routine from ll */
|
||||
NULL, /* command still not specified */
|
||||
NULL, /* drv_to_name */
|
||||
NULL, /* name_to_drv */
|
||||
};
|
||||
|
||||
/*************************/
|
||||
/* Module interface code */
|
||||
/* no cmd line parms */
|
||||
/*************************/
|
||||
static int __init divert_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (divert_dev_init()) {
|
||||
printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
|
||||
return (-EIO);
|
||||
}
|
||||
if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
|
||||
divert_dev_deinit();
|
||||
printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n", i);
|
||||
return (-EIO);
|
||||
}
|
||||
printk(KERN_INFO "dss1_divert module successfully installed\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**********************/
|
||||
/* Module deinit code */
|
||||
/**********************/
|
||||
static void __exit divert_exit(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
divert_if.cmd = DIVERT_CMD_REL; /* release */
|
||||
if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
|
||||
printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i);
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
return;
|
||||
}
|
||||
if (divert_dev_deinit()) {
|
||||
printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
deleterule(-1); /* delete all rules and free mem */
|
||||
deleteprocs();
|
||||
printk(KERN_INFO "dss1_divert module successfully removed \n");
|
||||
}
|
||||
|
||||
module_init(divert_init);
|
||||
module_exit(divert_exit);
|
||||
|
|
@ -1,336 +0,0 @@
|
|||
/* $Id: divert_procfs.c,v 1.11.6.2 2001/09/23 22:24:36 kai Exp $
|
||||
*
|
||||
* Filesystem handling for the diversion supplementary services.
|
||||
*
|
||||
* Copyright 1998 by Werner Cornelius (werner@isdn4linux.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/slab.h>
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#include <linux/proc_fs.h>
|
||||
#else
|
||||
#include <linux/fs.h>
|
||||
#endif
|
||||
#include <linux/sched.h>
|
||||
#include <linux/isdnif.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "isdn_divert.h"
|
||||
|
||||
|
||||
/*********************************/
|
||||
/* Variables for interface queue */
|
||||
/*********************************/
|
||||
ulong if_used = 0; /* number of interface users */
|
||||
static DEFINE_MUTEX(isdn_divert_mutex);
|
||||
static struct divert_info *divert_info_head = NULL; /* head of queue */
|
||||
static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
|
||||
static DEFINE_SPINLOCK(divert_info_lock);/* lock for queue */
|
||||
static wait_queue_head_t rd_queue;
|
||||
|
||||
/*********************************/
|
||||
/* put an info buffer into queue */
|
||||
/*********************************/
|
||||
void
|
||||
put_info_buffer(char *cp)
|
||||
{
|
||||
struct divert_info *ib;
|
||||
unsigned long flags;
|
||||
|
||||
if (if_used <= 0)
|
||||
return;
|
||||
if (!cp)
|
||||
return;
|
||||
if (!*cp)
|
||||
return;
|
||||
if (!(ib = kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
|
||||
return; /* no memory */
|
||||
strcpy(ib->info_start, cp); /* set output string */
|
||||
ib->next = NULL;
|
||||
spin_lock_irqsave(&divert_info_lock, flags);
|
||||
ib->usage_cnt = if_used;
|
||||
if (!divert_info_head)
|
||||
divert_info_head = ib; /* new head */
|
||||
else
|
||||
divert_info_tail->next = ib; /* follows existing messages */
|
||||
divert_info_tail = ib; /* new tail */
|
||||
|
||||
/* delete old entrys */
|
||||
while (divert_info_head->next) {
|
||||
if ((divert_info_head->usage_cnt <= 0) &&
|
||||
(divert_info_head->next->usage_cnt <= 0)) {
|
||||
ib = divert_info_head;
|
||||
divert_info_head = divert_info_head->next;
|
||||
kfree(ib);
|
||||
} else
|
||||
break;
|
||||
} /* divert_info_head->next */
|
||||
spin_unlock_irqrestore(&divert_info_lock, flags);
|
||||
wake_up_interruptible(&(rd_queue));
|
||||
} /* put_info_buffer */
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
/**********************************/
|
||||
/* deflection device read routine */
|
||||
/**********************************/
|
||||
static ssize_t
|
||||
isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t *off)
|
||||
{
|
||||
struct divert_info *inf;
|
||||
int len;
|
||||
|
||||
if (!(inf = *((struct divert_info **) file->private_data))) {
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
wait_event_interruptible(rd_queue, (inf =
|
||||
*((struct divert_info **) file->private_data)));
|
||||
}
|
||||
if (!inf)
|
||||
return (0);
|
||||
|
||||
inf->usage_cnt--; /* new usage count */
|
||||
file->private_data = &inf->next; /* next structure */
|
||||
if ((len = strlen(inf->info_start)) <= count) {
|
||||
if (copy_to_user(buf, inf->info_start, len))
|
||||
return -EFAULT;
|
||||
*off += len;
|
||||
return (len);
|
||||
}
|
||||
return (0);
|
||||
} /* isdn_divert_read */
|
||||
|
||||
/**********************************/
|
||||
/* deflection device write routine */
|
||||
/**********************************/
|
||||
static ssize_t
|
||||
isdn_divert_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
|
||||
{
|
||||
return (-ENODEV);
|
||||
} /* isdn_divert_write */
|
||||
|
||||
|
||||
/***************************************/
|
||||
/* select routines for various kernels */
|
||||
/***************************************/
|
||||
static __poll_t
|
||||
isdn_divert_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
__poll_t mask = 0;
|
||||
|
||||
poll_wait(file, &(rd_queue), wait);
|
||||
/* mask = EPOLLOUT | EPOLLWRNORM; */
|
||||
if (*((struct divert_info **) file->private_data)) {
|
||||
mask |= EPOLLIN | EPOLLRDNORM;
|
||||
}
|
||||
return mask;
|
||||
} /* isdn_divert_poll */
|
||||
|
||||
/****************/
|
||||
/* Open routine */
|
||||
/****************/
|
||||
static int
|
||||
isdn_divert_open(struct inode *ino, struct file *filep)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&divert_info_lock, flags);
|
||||
if_used++;
|
||||
if (divert_info_head)
|
||||
filep->private_data = &(divert_info_tail->next);
|
||||
else
|
||||
filep->private_data = &divert_info_head;
|
||||
spin_unlock_irqrestore(&divert_info_lock, flags);
|
||||
/* start_divert(); */
|
||||
return nonseekable_open(ino, filep);
|
||||
} /* isdn_divert_open */
|
||||
|
||||
/*******************/
|
||||
/* close routine */
|
||||
/*******************/
|
||||
static int
|
||||
isdn_divert_close(struct inode *ino, struct file *filep)
|
||||
{
|
||||
struct divert_info *inf;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&divert_info_lock, flags);
|
||||
if_used--;
|
||||
inf = *((struct divert_info **) filep->private_data);
|
||||
while (inf) {
|
||||
inf->usage_cnt--;
|
||||
inf = inf->next;
|
||||
}
|
||||
if (if_used <= 0)
|
||||
while (divert_info_head) {
|
||||
inf = divert_info_head;
|
||||
divert_info_head = divert_info_head->next;
|
||||
kfree(inf);
|
||||
}
|
||||
spin_unlock_irqrestore(&divert_info_lock, flags);
|
||||
return (0);
|
||||
} /* isdn_divert_close */
|
||||
|
||||
/*********/
|
||||
/* IOCTL */
|
||||
/*********/
|
||||
static int isdn_divert_ioctl_unlocked(struct file *file, uint cmd, ulong arg)
|
||||
{
|
||||
divert_ioctl dioctl;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
divert_rule *rulep;
|
||||
char *cp;
|
||||
|
||||
if (copy_from_user(&dioctl, (void __user *) arg, sizeof(dioctl)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (cmd) {
|
||||
case IIOCGETVER:
|
||||
dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */
|
||||
break;
|
||||
|
||||
case IIOCGETDRV:
|
||||
if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
|
||||
return (-EINVAL);
|
||||
break;
|
||||
|
||||
case IIOCGETNAM:
|
||||
cp = divert_if.drv_to_name(dioctl.getid.drvid);
|
||||
if (!cp)
|
||||
return (-EINVAL);
|
||||
if (!*cp)
|
||||
return (-EINVAL);
|
||||
strcpy(dioctl.getid.drvnam, cp);
|
||||
break;
|
||||
|
||||
case IIOCGETRULE:
|
||||
if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
|
||||
return (-EINVAL);
|
||||
dioctl.getsetrule.rule = *rulep; /* copy data */
|
||||
break;
|
||||
|
||||
case IIOCMODRULE:
|
||||
if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
|
||||
return (-EINVAL);
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
*rulep = dioctl.getsetrule.rule; /* copy data */
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
return (0); /* no copy required */
|
||||
break;
|
||||
|
||||
case IIOCINSRULE:
|
||||
return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule));
|
||||
break;
|
||||
|
||||
case IIOCDELRULE:
|
||||
return (deleterule(dioctl.getsetrule.ruleidx));
|
||||
break;
|
||||
|
||||
case IIOCDODFACT:
|
||||
return (deflect_extern_action(dioctl.fwd_ctrl.subcmd,
|
||||
dioctl.fwd_ctrl.callid,
|
||||
dioctl.fwd_ctrl.to_nr));
|
||||
|
||||
case IIOCDOCFACT:
|
||||
case IIOCDOCFDIS:
|
||||
case IIOCDOCFINT:
|
||||
if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
|
||||
return (-EINVAL); /* invalid driver */
|
||||
if (strnlen(dioctl.cf_ctrl.msn, sizeof(dioctl.cf_ctrl.msn)) ==
|
||||
sizeof(dioctl.cf_ctrl.msn))
|
||||
return -EINVAL;
|
||||
if (strnlen(dioctl.cf_ctrl.fwd_nr, sizeof(dioctl.cf_ctrl.fwd_nr)) ==
|
||||
sizeof(dioctl.cf_ctrl.fwd_nr))
|
||||
return -EINVAL;
|
||||
if ((i = cf_command(dioctl.cf_ctrl.drvid,
|
||||
(cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2,
|
||||
dioctl.cf_ctrl.cfproc,
|
||||
dioctl.cf_ctrl.msn,
|
||||
dioctl.cf_ctrl.service,
|
||||
dioctl.cf_ctrl.fwd_nr,
|
||||
&dioctl.cf_ctrl.procid)))
|
||||
return (i);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-EINVAL);
|
||||
} /* switch cmd */
|
||||
return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0;
|
||||
} /* isdn_divert_ioctl */
|
||||
|
||||
static long isdn_divert_ioctl(struct file *file, uint cmd, ulong arg)
|
||||
{
|
||||
long ret;
|
||||
|
||||
mutex_lock(&isdn_divert_mutex);
|
||||
ret = isdn_divert_ioctl_unlocked(file, cmd, arg);
|
||||
mutex_unlock(&isdn_divert_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations isdn_fops =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.read = isdn_divert_read,
|
||||
.write = isdn_divert_write,
|
||||
.poll = isdn_divert_poll,
|
||||
.unlocked_ioctl = isdn_divert_ioctl,
|
||||
.open = isdn_divert_open,
|
||||
.release = isdn_divert_close,
|
||||
};
|
||||
|
||||
/****************************/
|
||||
/* isdn subdir in /proc/net */
|
||||
/****************************/
|
||||
static struct proc_dir_entry *isdn_proc_entry = NULL;
|
||||
static struct proc_dir_entry *isdn_divert_entry = NULL;
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
/***************************************************************************/
|
||||
/* divert_dev_init must be called before the proc filesystem may be used */
|
||||
/***************************************************************************/
|
||||
int
|
||||
divert_dev_init(void)
|
||||
{
|
||||
|
||||
init_waitqueue_head(&rd_queue);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net);
|
||||
if (!isdn_proc_entry)
|
||||
return (-1);
|
||||
isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO,
|
||||
isdn_proc_entry, &isdn_fops);
|
||||
if (!isdn_divert_entry) {
|
||||
remove_proc_entry("isdn", init_net.proc_net);
|
||||
return (-1);
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
return (0);
|
||||
} /* divert_dev_init */
|
||||
|
||||
/***************************************************************************/
|
||||
/* divert_dev_deinit must be called before leaving isdn when included as */
|
||||
/* a module. */
|
||||
/***************************************************************************/
|
||||
int
|
||||
divert_dev_deinit(void)
|
||||
{
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
remove_proc_entry("divert", isdn_proc_entry);
|
||||
remove_proc_entry("isdn", init_net.proc_net);
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
return (0);
|
||||
} /* divert_dev_deinit */
|
||||
|
|
@ -1,846 +0,0 @@
|
|||
/* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $
|
||||
*
|
||||
* DSS1 main diversion supplementary handling for i4l.
|
||||
*
|
||||
* Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include "isdn_divert.h"
|
||||
|
||||
/**********************************/
|
||||
/* structure keeping calling info */
|
||||
/**********************************/
|
||||
struct call_struc {
|
||||
isdn_ctrl ics; /* delivered setup + driver parameters */
|
||||
ulong divert_id; /* Id delivered to user */
|
||||
unsigned char akt_state; /* actual state */
|
||||
char deflect_dest[35]; /* deflection destination */
|
||||
struct timer_list timer; /* timer control structure */
|
||||
char info[90]; /* device info output */
|
||||
struct call_struc *next; /* pointer to next entry */
|
||||
struct call_struc *prev;
|
||||
};
|
||||
|
||||
|
||||
/********************************************/
|
||||
/* structure keeping deflection table entry */
|
||||
/********************************************/
|
||||
struct deflect_struc {
|
||||
struct deflect_struc *next, *prev;
|
||||
divert_rule rule; /* used rule */
|
||||
};
|
||||
|
||||
|
||||
/*****************************************/
|
||||
/* variables for main diversion services */
|
||||
/*****************************************/
|
||||
/* diversion/deflection processes */
|
||||
static struct call_struc *divert_head = NULL; /* head of remembered entrys */
|
||||
static ulong next_id = 1; /* next info id */
|
||||
static struct deflect_struc *table_head = NULL;
|
||||
static struct deflect_struc *table_tail = NULL;
|
||||
static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
|
||||
|
||||
DEFINE_SPINLOCK(divert_lock);
|
||||
|
||||
/***************************/
|
||||
/* timer callback function */
|
||||
/***************************/
|
||||
static void deflect_timer_expire(struct timer_list *t)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct call_struc *cs = from_timer(cs, t, timer);
|
||||
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
del_timer(&cs->timer); /* delete active timer */
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
|
||||
switch (cs->akt_state) {
|
||||
case DEFLECT_PROCEED:
|
||||
cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
|
||||
divert_if.ll_cmd(&cs->ics);
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
|
||||
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
|
||||
add_timer(&cs->timer);
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
break;
|
||||
|
||||
case DEFLECT_ALERT:
|
||||
cs->ics.command = ISDN_CMD_REDIR; /* protocol */
|
||||
strlcpy(cs->ics.parm.setup.phone, cs->deflect_dest, sizeof(cs->ics.parm.setup.phone));
|
||||
strcpy(cs->ics.parm.setup.eazmsn, "Testtext delayed");
|
||||
divert_if.ll_cmd(&cs->ics);
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
|
||||
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
|
||||
add_timer(&cs->timer);
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
break;
|
||||
|
||||
case DEFLECT_AUTODEL:
|
||||
default:
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
if (cs->prev)
|
||||
cs->prev->next = cs->next; /* forward link */
|
||||
else
|
||||
divert_head = cs->next;
|
||||
if (cs->next)
|
||||
cs->next->prev = cs->prev; /* back link */
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
kfree(cs);
|
||||
return;
|
||||
|
||||
} /* switch */
|
||||
} /* deflect_timer_func */
|
||||
|
||||
|
||||
/*****************************************/
|
||||
/* handle call forwarding de/activations */
|
||||
/* 0 = deact, 1 = act, 2 = interrogate */
|
||||
/*****************************************/
|
||||
int cf_command(int drvid, int mode,
|
||||
u_char proc, char *msn,
|
||||
u_char service, char *fwd_nr, ulong *procid)
|
||||
{
|
||||
unsigned long flags;
|
||||
int retval, msnlen;
|
||||
int fwd_len;
|
||||
char *p, *ielenp, tmp[60];
|
||||
struct call_struc *cs;
|
||||
|
||||
if (strchr(msn, '.')) return (-EINVAL); /* subaddress not allowed in msn */
|
||||
if ((proc & 0x7F) > 2) return (-EINVAL);
|
||||
proc &= 3;
|
||||
p = tmp;
|
||||
*p++ = 0x30; /* enumeration */
|
||||
ielenp = p++; /* remember total length position */
|
||||
*p++ = 0xa; /* proc tag */
|
||||
*p++ = 1; /* length */
|
||||
*p++ = proc & 0x7F; /* procedure to de/activate/interrogate */
|
||||
*p++ = 0xa; /* service tag */
|
||||
*p++ = 1; /* length */
|
||||
*p++ = service; /* service to handle */
|
||||
|
||||
if (mode == 1) {
|
||||
if (!*fwd_nr) return (-EINVAL); /* destination missing */
|
||||
if (strchr(fwd_nr, '.')) return (-EINVAL); /* subaddress not allowed */
|
||||
fwd_len = strlen(fwd_nr);
|
||||
*p++ = 0x30; /* number enumeration */
|
||||
*p++ = fwd_len + 2; /* complete forward to len */
|
||||
*p++ = 0x80; /* fwd to nr */
|
||||
*p++ = fwd_len; /* length of number */
|
||||
strcpy(p, fwd_nr); /* copy number */
|
||||
p += fwd_len; /* pointer beyond fwd */
|
||||
} /* activate */
|
||||
|
||||
msnlen = strlen(msn);
|
||||
*p++ = 0x80; /* msn number */
|
||||
if (msnlen > 1) {
|
||||
*p++ = msnlen; /* length */
|
||||
strcpy(p, msn);
|
||||
p += msnlen;
|
||||
} else
|
||||
*p++ = 0;
|
||||
|
||||
*ielenp = p - ielenp - 1; /* set total IE length */
|
||||
|
||||
/* allocate mem for information struct */
|
||||
if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
|
||||
return (-ENOMEM); /* no memory */
|
||||
timer_setup(&cs->timer, deflect_timer_expire, 0);
|
||||
cs->info[0] = '\0';
|
||||
cs->ics.driver = drvid;
|
||||
cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */
|
||||
cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */
|
||||
cs->ics.parm.dss1_io.proc = (mode == 1) ? 7 : (mode == 2) ? 11 : 8; /* operation */
|
||||
cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */
|
||||
cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */
|
||||
cs->ics.parm.dss1_io.data = tmp; /* start of buffer */
|
||||
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
*procid = cs->ics.parm.dss1_io.ll_id;
|
||||
|
||||
sprintf(cs->info, "%d 0x%lx %s%s 0 %s %02x %d%s%s\n",
|
||||
(!mode) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
|
||||
cs->ics.parm.dss1_io.ll_id,
|
||||
(mode != 2) ? "" : "0 ",
|
||||
divert_if.drv_to_name(cs->ics.driver),
|
||||
msn,
|
||||
service & 0xFF,
|
||||
proc,
|
||||
(mode != 1) ? "" : " 0 ",
|
||||
(mode != 1) ? "" : fwd_nr);
|
||||
|
||||
retval = divert_if.ll_cmd(&cs->ics); /* execute command */
|
||||
|
||||
if (!retval) {
|
||||
cs->prev = NULL;
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
cs->next = divert_head;
|
||||
divert_head = cs;
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
} else
|
||||
kfree(cs);
|
||||
return (retval);
|
||||
} /* cf_command */
|
||||
|
||||
|
||||
/****************************************/
|
||||
/* handle a external deflection command */
|
||||
/****************************************/
|
||||
int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
|
||||
{
|
||||
struct call_struc *cs;
|
||||
isdn_ctrl ic;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
if ((cmd & 0x7F) > 2) return (-EINVAL); /* invalid command */
|
||||
cs = divert_head; /* start of parameter list */
|
||||
while (cs) {
|
||||
if (cs->divert_id == callid) break; /* found */
|
||||
cs = cs->next;
|
||||
} /* search entry */
|
||||
if (!cs) return (-EINVAL); /* invalid callid */
|
||||
|
||||
ic.driver = cs->ics.driver;
|
||||
ic.arg = cs->ics.arg;
|
||||
i = -EINVAL;
|
||||
if (cs->akt_state == DEFLECT_AUTODEL) return (i); /* no valid call */
|
||||
switch (cmd & 0x7F) {
|
||||
case 0: /* hangup */
|
||||
del_timer(&cs->timer);
|
||||
ic.command = ISDN_CMD_HANGUP;
|
||||
i = divert_if.ll_cmd(&ic);
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
|
||||
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
|
||||
add_timer(&cs->timer);
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
break;
|
||||
|
||||
case 1: /* alert */
|
||||
if (cs->akt_state == DEFLECT_ALERT) return (0);
|
||||
cmd &= 0x7F; /* never wait */
|
||||
del_timer(&cs->timer);
|
||||
ic.command = ISDN_CMD_ALERT;
|
||||
if ((i = divert_if.ll_cmd(&ic))) {
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
|
||||
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
|
||||
add_timer(&cs->timer);
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
} else
|
||||
cs->akt_state = DEFLECT_ALERT;
|
||||
break;
|
||||
|
||||
case 2: /* redir */
|
||||
del_timer(&cs->timer);
|
||||
strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone));
|
||||
strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
|
||||
ic.command = ISDN_CMD_REDIR;
|
||||
if ((i = divert_if.ll_cmd(&ic))) {
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
|
||||
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
|
||||
add_timer(&cs->timer);
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
} else
|
||||
cs->akt_state = DEFLECT_ALERT;
|
||||
break;
|
||||
|
||||
} /* switch */
|
||||
return (i);
|
||||
} /* deflect_extern_action */
|
||||
|
||||
/********************************/
|
||||
/* insert a new rule before idx */
|
||||
/********************************/
|
||||
int insertrule(int idx, divert_rule *newrule)
|
||||
{
|
||||
struct deflect_struc *ds, *ds1 = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
if (!(ds = kmalloc(sizeof(struct deflect_struc), GFP_KERNEL)))
|
||||
return (-ENOMEM); /* no memory */
|
||||
|
||||
ds->rule = *newrule; /* set rule */
|
||||
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
|
||||
if (idx >= 0) {
|
||||
ds1 = table_head;
|
||||
while ((ds1) && (idx > 0))
|
||||
{ idx--;
|
||||
ds1 = ds1->next;
|
||||
}
|
||||
if (!ds1) idx = -1;
|
||||
}
|
||||
|
||||
if (idx < 0) {
|
||||
ds->prev = table_tail; /* previous entry */
|
||||
ds->next = NULL; /* end of chain */
|
||||
if (ds->prev)
|
||||
ds->prev->next = ds; /* last forward */
|
||||
else
|
||||
table_head = ds; /* is first entry */
|
||||
table_tail = ds; /* end of queue */
|
||||
} else {
|
||||
ds->next = ds1; /* next entry */
|
||||
ds->prev = ds1->prev; /* prev entry */
|
||||
ds1->prev = ds; /* backward chain old element */
|
||||
if (!ds->prev)
|
||||
table_head = ds; /* first element */
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
return (0);
|
||||
} /* insertrule */
|
||||
|
||||
/***********************************/
|
||||
/* delete the rule at position idx */
|
||||
/***********************************/
|
||||
int deleterule(int idx)
|
||||
{
|
||||
struct deflect_struc *ds, *ds1;
|
||||
unsigned long flags;
|
||||
|
||||
if (idx < 0) {
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
ds = table_head;
|
||||
table_head = NULL;
|
||||
table_tail = NULL;
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
while (ds) {
|
||||
ds1 = ds;
|
||||
ds = ds->next;
|
||||
kfree(ds1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
ds = table_head;
|
||||
|
||||
while ((ds) && (idx > 0)) {
|
||||
idx--;
|
||||
ds = ds->next;
|
||||
}
|
||||
|
||||
if (!ds) {
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
return (-EINVAL);
|
||||
}
|
||||
|
||||
if (ds->next)
|
||||
ds->next->prev = ds->prev; /* backward chain */
|
||||
else
|
||||
table_tail = ds->prev; /* end of chain */
|
||||
|
||||
if (ds->prev)
|
||||
ds->prev->next = ds->next; /* forward chain */
|
||||
else
|
||||
table_head = ds->next; /* start of chain */
|
||||
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
kfree(ds);
|
||||
return (0);
|
||||
} /* deleterule */
|
||||
|
||||
/*******************************************/
|
||||
/* get a pointer to a specific rule number */
|
||||
/*******************************************/
|
||||
divert_rule *getruleptr(int idx)
|
||||
{
|
||||
struct deflect_struc *ds = table_head;
|
||||
|
||||
if (idx < 0) return (NULL);
|
||||
while ((ds) && (idx >= 0)) {
|
||||
if (!(idx--)) {
|
||||
return (&ds->rule);
|
||||
break;
|
||||
}
|
||||
ds = ds->next;
|
||||
}
|
||||
return (NULL);
|
||||
} /* getruleptr */
|
||||
|
||||
/*************************************************/
|
||||
/* called from common module on an incoming call */
|
||||
/*************************************************/
|
||||
static int isdn_divert_icall(isdn_ctrl *ic)
|
||||
{
|
||||
int retval = 0;
|
||||
unsigned long flags;
|
||||
struct call_struc *cs = NULL;
|
||||
struct deflect_struc *dv;
|
||||
char *p, *p1;
|
||||
u_char accept;
|
||||
|
||||
/* first check the internal deflection table */
|
||||
for (dv = table_head; dv; dv = dv->next) {
|
||||
/* scan table */
|
||||
if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
|
||||
((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
|
||||
continue; /* call option check */
|
||||
if (!(dv->rule.drvid & (1L << ic->driver)))
|
||||
continue; /* driver not matching */
|
||||
if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1))
|
||||
continue; /* si1 not matching */
|
||||
if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2))
|
||||
continue; /* si2 not matching */
|
||||
|
||||
p = dv->rule.my_msn;
|
||||
p1 = ic->parm.setup.eazmsn;
|
||||
accept = 0;
|
||||
while (*p) {
|
||||
/* complete compare */
|
||||
if (*p == '-') {
|
||||
accept = 1; /* call accepted */
|
||||
break;
|
||||
}
|
||||
if (*p++ != *p1++)
|
||||
break; /* not accepted */
|
||||
if ((!*p) && (!*p1))
|
||||
accept = 1;
|
||||
} /* complete compare */
|
||||
if (!accept) continue; /* not accepted */
|
||||
|
||||
if ((strcmp(dv->rule.caller, "0")) ||
|
||||
(ic->parm.setup.phone[0])) {
|
||||
p = dv->rule.caller;
|
||||
p1 = ic->parm.setup.phone;
|
||||
accept = 0;
|
||||
while (*p) {
|
||||
/* complete compare */
|
||||
if (*p == '-') {
|
||||
accept = 1; /* call accepted */
|
||||
break;
|
||||
}
|
||||
if (*p++ != *p1++)
|
||||
break; /* not accepted */
|
||||
if ((!*p) && (!*p1))
|
||||
accept = 1;
|
||||
} /* complete compare */
|
||||
if (!accept) continue; /* not accepted */
|
||||
}
|
||||
|
||||
switch (dv->rule.action) {
|
||||
case DEFLECT_IGNORE:
|
||||
return 0;
|
||||
|
||||
case DEFLECT_ALERT:
|
||||
case DEFLECT_PROCEED:
|
||||
case DEFLECT_REPORT:
|
||||
case DEFLECT_REJECT:
|
||||
if (dv->rule.action == DEFLECT_PROCEED)
|
||||
if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
|
||||
return (0); /* no external deflection needed */
|
||||
if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
|
||||
return (0); /* no memory */
|
||||
timer_setup(&cs->timer, deflect_timer_expire, 0);
|
||||
cs->info[0] = '\0';
|
||||
|
||||
cs->ics = *ic; /* copy incoming data */
|
||||
if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone, "0");
|
||||
if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn, "0");
|
||||
cs->ics.parm.setup.screen = dv->rule.screen;
|
||||
if (dv->rule.waittime)
|
||||
cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
|
||||
else if (dv->rule.action == DEFLECT_PROCEED)
|
||||
cs->timer.expires = jiffies + (HZ * extern_wait_max);
|
||||
else
|
||||
cs->timer.expires = 0;
|
||||
cs->akt_state = dv->rule.action;
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
cs->divert_id = next_id++; /* new sequence number */
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
cs->prev = NULL;
|
||||
if (cs->akt_state == DEFLECT_ALERT) {
|
||||
strcpy(cs->deflect_dest, dv->rule.to_nr);
|
||||
if (!cs->timer.expires) {
|
||||
strcpy(ic->parm.setup.eazmsn,
|
||||
"Testtext direct");
|
||||
ic->parm.setup.screen = dv->rule.screen;
|
||||
strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone));
|
||||
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
|
||||
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
|
||||
retval = 5;
|
||||
} else
|
||||
retval = 1; /* alerting */
|
||||
} else {
|
||||
cs->deflect_dest[0] = '\0';
|
||||
retval = 4; /* only proceed */
|
||||
}
|
||||
snprintf(cs->info, sizeof(cs->info),
|
||||
"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
|
||||
cs->akt_state,
|
||||
cs->divert_id,
|
||||
divert_if.drv_to_name(cs->ics.driver),
|
||||
(ic->command == ISDN_STAT_ICALLW) ? "1" : "0",
|
||||
cs->ics.parm.setup.phone,
|
||||
cs->ics.parm.setup.eazmsn,
|
||||
cs->ics.parm.setup.si1,
|
||||
cs->ics.parm.setup.si2,
|
||||
cs->ics.parm.setup.screen,
|
||||
dv->rule.waittime,
|
||||
cs->deflect_dest);
|
||||
if ((dv->rule.action == DEFLECT_REPORT) ||
|
||||
(dv->rule.action == DEFLECT_REJECT)) {
|
||||
put_info_buffer(cs->info);
|
||||
kfree(cs); /* remove */
|
||||
return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0; /* ignore call */
|
||||
} /* switch action */
|
||||
break; /* will break the 'for' looping */
|
||||
} /* scan_table */
|
||||
|
||||
if (cs) {
|
||||
cs->prev = NULL;
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
cs->next = divert_head;
|
||||
divert_head = cs;
|
||||
if (cs->timer.expires) add_timer(&cs->timer);
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
|
||||
put_info_buffer(cs->info);
|
||||
return (retval);
|
||||
} else
|
||||
return (0);
|
||||
} /* isdn_divert_icall */
|
||||
|
||||
|
||||
void deleteprocs(void)
|
||||
{
|
||||
struct call_struc *cs, *cs1;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
cs = divert_head;
|
||||
divert_head = NULL;
|
||||
while (cs) {
|
||||
del_timer(&cs->timer);
|
||||
cs1 = cs;
|
||||
cs = cs->next;
|
||||
kfree(cs1);
|
||||
}
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
} /* deleteprocs */
|
||||
|
||||
/****************************************************/
|
||||
/* put a address including address type into buffer */
|
||||
/****************************************************/
|
||||
static int put_address(char *st, u_char *p, int len)
|
||||
{
|
||||
u_char retval = 0;
|
||||
u_char adr_typ = 0; /* network standard */
|
||||
|
||||
if (len < 2) return (retval);
|
||||
if (*p == 0xA1) {
|
||||
retval = *(++p) + 2; /* total length */
|
||||
if (retval > len) return (0); /* too short */
|
||||
len = retval - 2; /* remaining length */
|
||||
if (len < 3) return (0);
|
||||
if ((*(++p) != 0x0A) || (*(++p) != 1)) return (0);
|
||||
adr_typ = *(++p);
|
||||
len -= 3;
|
||||
p++;
|
||||
if (len < 2) return (0);
|
||||
if (*p++ != 0x12) return (0);
|
||||
if (*p > len) return (0); /* check number length */
|
||||
len = *p++;
|
||||
} else if (*p == 0x80) {
|
||||
retval = *(++p) + 2; /* total length */
|
||||
if (retval > len) return (0);
|
||||
len = retval - 2;
|
||||
p++;
|
||||
} else
|
||||
return (0); /* invalid address information */
|
||||
|
||||
sprintf(st, "%d ", adr_typ);
|
||||
st += strlen(st);
|
||||
if (!len)
|
||||
*st++ = '-';
|
||||
else
|
||||
while (len--)
|
||||
*st++ = *p++;
|
||||
*st = '\0';
|
||||
return (retval);
|
||||
} /* put_address */
|
||||
|
||||
/*************************************/
|
||||
/* report a successful interrogation */
|
||||
/*************************************/
|
||||
static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
|
||||
{
|
||||
char *src = ic->parm.dss1_io.data;
|
||||
int restlen = ic->parm.dss1_io.datalen;
|
||||
int cnt = 1;
|
||||
u_char n, n1;
|
||||
char st[90], *p, *stp;
|
||||
|
||||
if (restlen < 2) return (-100); /* frame too short */
|
||||
if (*src++ != 0x30) return (-101);
|
||||
if ((n = *src++) > 0x81) return (-102); /* invalid length field */
|
||||
restlen -= 2; /* remaining bytes */
|
||||
if (n == 0x80) {
|
||||
if (restlen < 2) return (-103);
|
||||
if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-104);
|
||||
restlen -= 2;
|
||||
} else if (n == 0x81) {
|
||||
n = *src++;
|
||||
restlen--;
|
||||
if (n > restlen) return (-105);
|
||||
restlen = n;
|
||||
} else if (n > restlen)
|
||||
return (-106);
|
||||
else
|
||||
restlen = n; /* standard format */
|
||||
if (restlen < 3) return (-107); /* no procedure */
|
||||
if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return (-108);
|
||||
restlen -= 3;
|
||||
if (restlen < 2) return (-109); /* list missing */
|
||||
if (*src == 0x31) {
|
||||
src++;
|
||||
if ((n = *src++) > 0x81) return (-110); /* invalid length field */
|
||||
restlen -= 2; /* remaining bytes */
|
||||
if (n == 0x80) {
|
||||
if (restlen < 2) return (-111);
|
||||
if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-112);
|
||||
restlen -= 2;
|
||||
} else if (n == 0x81) {
|
||||
n = *src++;
|
||||
restlen--;
|
||||
if (n > restlen) return (-113);
|
||||
restlen = n;
|
||||
} else if (n > restlen)
|
||||
return (-114);
|
||||
else
|
||||
restlen = n; /* standard format */
|
||||
} /* result list header */
|
||||
|
||||
while (restlen >= 2) {
|
||||
stp = st;
|
||||
sprintf(stp, "%d 0x%lx %d %s ", DIVERT_REPORT, ic->parm.dss1_io.ll_id,
|
||||
cnt++, divert_if.drv_to_name(ic->driver));
|
||||
stp += strlen(stp);
|
||||
if (*src++ != 0x30) return (-115); /* invalid enum */
|
||||
n = *src++;
|
||||
restlen -= 2;
|
||||
if (n > restlen) return (-116); /* enum length wrong */
|
||||
restlen -= n;
|
||||
p = src; /* one entry */
|
||||
src += n;
|
||||
if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
|
||||
stp += strlen(stp);
|
||||
p += n1;
|
||||
n -= n1;
|
||||
if (n < 6) continue; /* no service and proc */
|
||||
if ((*p++ != 0x0A) || (*p++ != 1)) continue;
|
||||
sprintf(stp, " 0x%02x ", (*p++) & 0xFF);
|
||||
stp += strlen(stp);
|
||||
if ((*p++ != 0x0A) || (*p++ != 1)) continue;
|
||||
sprintf(stp, "%d ", (*p++) & 0xFF);
|
||||
stp += strlen(stp);
|
||||
n -= 6;
|
||||
if (n > 2) {
|
||||
if (*p++ != 0x30) continue;
|
||||
if (*p > (n - 2)) continue;
|
||||
n = *p++;
|
||||
if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
|
||||
stp += strlen(stp);
|
||||
}
|
||||
sprintf(stp, "\n");
|
||||
put_info_buffer(st);
|
||||
} /* while restlen */
|
||||
if (restlen) return (-117);
|
||||
return (0);
|
||||
} /* interrogate_success */
|
||||
|
||||
/*********************************************/
|
||||
/* callback for protocol specific extensions */
|
||||
/*********************************************/
|
||||
static int prot_stat_callback(isdn_ctrl *ic)
|
||||
{
|
||||
struct call_struc *cs, *cs1;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
cs = divert_head; /* start of list */
|
||||
cs1 = NULL;
|
||||
while (cs) {
|
||||
if (ic->driver == cs->ics.driver) {
|
||||
switch (cs->ics.arg) {
|
||||
case DSS1_CMD_INVOKE:
|
||||
if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
|
||||
(cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) {
|
||||
switch (ic->arg) {
|
||||
case DSS1_STAT_INVOKE_ERR:
|
||||
sprintf(cs->info, "128 0x%lx 0x%x\n",
|
||||
ic->parm.dss1_io.ll_id,
|
||||
ic->parm.dss1_io.timeout);
|
||||
put_info_buffer(cs->info);
|
||||
break;
|
||||
|
||||
case DSS1_STAT_INVOKE_RES:
|
||||
switch (cs->ics.parm.dss1_io.proc) {
|
||||
case 7:
|
||||
case 8:
|
||||
put_info_buffer(cs->info);
|
||||
break;
|
||||
|
||||
case 11:
|
||||
i = interrogate_success(ic, cs);
|
||||
if (i)
|
||||
sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT,
|
||||
ic->parm.dss1_io.ll_id, i);
|
||||
put_info_buffer(cs->info);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg);
|
||||
break;
|
||||
}
|
||||
cs1 = cs; /* remember structure */
|
||||
cs = NULL;
|
||||
continue; /* abort search */
|
||||
} /* id found */
|
||||
break;
|
||||
|
||||
case DSS1_CMD_INVOKE_ABORT:
|
||||
printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n", cs->ics.arg);
|
||||
break;
|
||||
} /* switch ics.arg */
|
||||
cs = cs->next;
|
||||
} /* driver ok */
|
||||
}
|
||||
|
||||
if (!cs1) {
|
||||
printk(KERN_WARNING "dss1_divert unhandled process\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (cs1->ics.driver == -1) {
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
del_timer(&cs1->timer);
|
||||
if (cs1->prev)
|
||||
cs1->prev->next = cs1->next; /* forward link */
|
||||
else
|
||||
divert_head = cs1->next;
|
||||
if (cs1->next)
|
||||
cs1->next->prev = cs1->prev; /* back link */
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
kfree(cs1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
} /* prot_stat_callback */
|
||||
|
||||
|
||||
/***************************/
|
||||
/* status callback from HL */
|
||||
/***************************/
|
||||
static int isdn_divert_stat_callback(isdn_ctrl *ic)
|
||||
{
|
||||
struct call_struc *cs, *cs1;
|
||||
unsigned long flags;
|
||||
int retval;
|
||||
|
||||
retval = -1;
|
||||
cs = divert_head; /* start of list */
|
||||
while (cs) {
|
||||
if ((ic->driver == cs->ics.driver) &&
|
||||
(ic->arg == cs->ics.arg)) {
|
||||
switch (ic->command) {
|
||||
case ISDN_STAT_DHUP:
|
||||
sprintf(cs->info, "129 0x%lx\n", cs->divert_id);
|
||||
del_timer(&cs->timer);
|
||||
cs->ics.driver = -1;
|
||||
break;
|
||||
|
||||
case ISDN_STAT_CAUSE:
|
||||
sprintf(cs->info, "130 0x%lx %s\n", cs->divert_id, ic->parm.num);
|
||||
break;
|
||||
|
||||
case ISDN_STAT_REDIR:
|
||||
sprintf(cs->info, "131 0x%lx\n", cs->divert_id);
|
||||
del_timer(&cs->timer);
|
||||
cs->ics.driver = -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(cs->info, "999 0x%lx 0x%x\n", cs->divert_id, (int)(ic->command));
|
||||
break;
|
||||
}
|
||||
put_info_buffer(cs->info);
|
||||
retval = 0;
|
||||
}
|
||||
cs1 = cs;
|
||||
cs = cs->next;
|
||||
if (cs1->ics.driver == -1) {
|
||||
spin_lock_irqsave(&divert_lock, flags);
|
||||
if (cs1->prev)
|
||||
cs1->prev->next = cs1->next; /* forward link */
|
||||
else
|
||||
divert_head = cs1->next;
|
||||
if (cs1->next)
|
||||
cs1->next->prev = cs1->prev; /* back link */
|
||||
spin_unlock_irqrestore(&divert_lock, flags);
|
||||
kfree(cs1);
|
||||
}
|
||||
}
|
||||
return (retval); /* not found */
|
||||
} /* isdn_divert_stat_callback */
|
||||
|
||||
|
||||
/********************/
|
||||
/* callback from ll */
|
||||
/********************/
|
||||
int ll_callback(isdn_ctrl *ic)
|
||||
{
|
||||
switch (ic->command) {
|
||||
case ISDN_STAT_ICALL:
|
||||
case ISDN_STAT_ICALLW:
|
||||
return (isdn_divert_icall(ic));
|
||||
break;
|
||||
|
||||
case ISDN_STAT_PROT:
|
||||
if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) {
|
||||
if (ic->arg != DSS1_STAT_INVOKE_BRD)
|
||||
return (prot_stat_callback(ic));
|
||||
else
|
||||
return (0); /* DSS1 invoke broadcast */
|
||||
} else
|
||||
return (-1); /* protocol not euro */
|
||||
|
||||
default:
|
||||
return (isdn_divert_stat_callback(ic));
|
||||
}
|
||||
} /* ll_callback */
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
/* $Id: isdn_divert.h,v 1.5.6.1 2001/09/23 22:24:36 kai Exp $
|
||||
*
|
||||
* Header for the diversion supplementary ioctl interface.
|
||||
*
|
||||
* Copyright 1998 by Werner Cornelius (werner@ikt.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/******************************************/
|
||||
/* IOCTL codes for interface to user prog */
|
||||
/******************************************/
|
||||
#define DIVERT_IIOC_VERSION 0x01 /* actual version */
|
||||
#define IIOCGETVER _IO('I', 1) /* get version of interface */
|
||||
#define IIOCGETDRV _IO('I', 2) /* get driver number */
|
||||
#define IIOCGETNAM _IO('I', 3) /* get driver name */
|
||||
#define IIOCGETRULE _IO('I', 4) /* read one rule */
|
||||
#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */
|
||||
#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */
|
||||
#define IIOCDELRULE _IO('I', 7) /* delete a rule */
|
||||
#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */
|
||||
#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */
|
||||
#define IIOCDOCFDIS _IO('I', 10) /* deactivate control forwarding in PBX */
|
||||
#define IIOCDOCFINT _IO('I', 11) /* interrogate control forwarding in PBX */
|
||||
|
||||
/*************************************/
|
||||
/* states reported through interface */
|
||||
/*************************************/
|
||||
#define DEFLECT_IGNORE 0 /* ignore incoming call */
|
||||
#define DEFLECT_REPORT 1 /* only report */
|
||||
#define DEFLECT_PROCEED 2 /* deflect when externally triggered */
|
||||
#define DEFLECT_ALERT 3 /* alert and deflect after delay */
|
||||
#define DEFLECT_REJECT 4 /* reject immediately */
|
||||
#define DIVERT_ACTIVATE 5 /* diversion activate */
|
||||
#define DIVERT_DEACTIVATE 6 /* diversion deactivate */
|
||||
#define DIVERT_REPORT 7 /* interrogation result */
|
||||
#define DEFLECT_AUTODEL 255 /* only for internal use */
|
||||
|
||||
#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */
|
||||
|
||||
typedef struct {
|
||||
ulong drvid; /* driver ids, bit mapped */
|
||||
char my_msn[35]; /* desired msn, subaddr allowed */
|
||||
char caller[35]; /* caller id, partial string with * + subaddr allowed */
|
||||
char to_nr[35]; /* deflected to number incl. subaddress */
|
||||
u_char si1, si2; /* service indicators, si1=bitmask, si1+2 0 = all */
|
||||
u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */
|
||||
u_char callopt; /* option for call handling:
|
||||
0 = all calls
|
||||
1 = only non waiting calls
|
||||
2 = only waiting calls */
|
||||
u_char action; /* desired action:
|
||||
0 = don't report call -> ignore
|
||||
1 = report call, do not allow/proceed for deflection
|
||||
2 = report call, send proceed, wait max waittime secs
|
||||
3 = report call, alert and deflect after waittime
|
||||
4 = report call, reject immediately
|
||||
actions 1-2 only take place if interface is opened
|
||||
*/
|
||||
u_char waittime; /* maximum wait time for proceeding */
|
||||
} divert_rule;
|
||||
|
||||
typedef union {
|
||||
int drv_version; /* return of driver version */
|
||||
struct {
|
||||
int drvid; /* id of driver */
|
||||
char drvnam[30]; /* name of driver */
|
||||
} getid;
|
||||
struct {
|
||||
int ruleidx; /* index of rule */
|
||||
divert_rule rule; /* rule parms */
|
||||
} getsetrule;
|
||||
struct {
|
||||
u_char subcmd; /* 0 = hangup/reject,
|
||||
1 = alert,
|
||||
2 = deflect */
|
||||
ulong callid; /* id of call delivered by ascii output */
|
||||
char to_nr[35]; /* destination when deflect,
|
||||
else uus1 string (maxlen 31),
|
||||
data from rule used if empty */
|
||||
} fwd_ctrl;
|
||||
struct {
|
||||
int drvid; /* id of driver */
|
||||
u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */
|
||||
ulong procid; /* process id returned when no error */
|
||||
u_char service; /* basically coded service, 0 = all */
|
||||
char msn[25]; /* desired msn, empty = all */
|
||||
char fwd_nr[35];/* forwarded to number + subaddress */
|
||||
} cf_ctrl;
|
||||
} divert_ioctl;
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/isdnif.h>
|
||||
#include <linux/isdn_divertif.h>
|
||||
|
||||
#define AUTODEL_TIME 30 /* timeout in s to delete internal entries */
|
||||
|
||||
/**************************************************/
|
||||
/* structure keeping ascii info for device output */
|
||||
/**************************************************/
|
||||
struct divert_info {
|
||||
struct divert_info *next;
|
||||
ulong usage_cnt; /* number of files still to work */
|
||||
char info_start[2]; /* info string start */
|
||||
};
|
||||
|
||||
|
||||
/**************/
|
||||
/* Prototypes */
|
||||
/**************/
|
||||
extern spinlock_t divert_lock;
|
||||
|
||||
extern ulong if_used; /* number of interface users */
|
||||
extern int divert_dev_deinit(void);
|
||||
extern int divert_dev_init(void);
|
||||
extern void put_info_buffer(char *);
|
||||
extern int ll_callback(isdn_ctrl *);
|
||||
extern isdn_divert_if divert_if;
|
||||
extern divert_rule *getruleptr(int);
|
||||
extern int insertrule(int, divert_rule *);
|
||||
extern int deleterule(int);
|
||||
extern void deleteprocs(void);
|
||||
extern int deflect_extern_action(u_char, ulong, char *);
|
||||
extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Old ISDN4Linux config
|
||||
#
|
||||
|
||||
if ISDN_I4L
|
||||
|
||||
config ISDN_PPP
|
||||
bool "Support synchronous PPP"
|
||||
depends on INET
|
||||
select SLHC
|
||||
help
|
||||
Over digital connections such as ISDN, there is no need to
|
||||
synchronize sender and recipient's clocks with start and stop bits
|
||||
as is done over analog telephone lines. Instead, one can use
|
||||
"synchronous PPP". Saying Y here will include this protocol. This
|
||||
protocol is used by Cisco and Sun for example. So you want to say Y
|
||||
here if the other end of your ISDN connection supports it. You will
|
||||
need a special version of pppd (called ipppd) for using this
|
||||
feature. See <file:Documentation/isdn/README.syncppp> and
|
||||
<file:Documentation/isdn/syncPPP.FAQ> for more information.
|
||||
|
||||
config ISDN_PPP_VJ
|
||||
bool "Use VJ-compression with synchronous PPP"
|
||||
depends on ISDN_PPP
|
||||
help
|
||||
This enables Van Jacobson header compression for synchronous PPP.
|
||||
Say Y if the other end of the connection supports it.
|
||||
|
||||
config ISDN_MPP
|
||||
bool "Support generic MP (RFC 1717)"
|
||||
depends on ISDN_PPP
|
||||
help
|
||||
With synchronous PPP enabled, it is possible to increase throughput
|
||||
by bundling several ISDN-connections, using this protocol. See
|
||||
<file:Documentation/isdn/README.syncppp> for more information.
|
||||
|
||||
config IPPP_FILTER
|
||||
bool "Filtering for synchronous PPP"
|
||||
depends on ISDN_PPP
|
||||
help
|
||||
Say Y here if you want to be able to filter the packets passing over
|
||||
IPPP interfaces. This allows you to control which packets count as
|
||||
activity (i.e. which packets will reset the idle timer or bring up
|
||||
a demand-dialled link) and which packets are to be dropped entirely.
|
||||
You need to say Y here if you wish to use the pass-filter and
|
||||
active-filter options to ipppd.
|
||||
|
||||
config ISDN_PPP_BSDCOMP
|
||||
tristate "Support BSD compression"
|
||||
depends on ISDN_PPP
|
||||
help
|
||||
Support for the BSD-Compress compression method for PPP, which uses
|
||||
the LZW compression method to compress each PPP packet before it is
|
||||
sent over the wire. The machine at the other end of the PPP link
|
||||
(usually your ISP) has to support the BSD-Compress compression
|
||||
method as well for this to be useful. Even if they don't support it,
|
||||
it is safe to say Y here.
|
||||
|
||||
config ISDN_AUDIO
|
||||
bool "Support audio via ISDN"
|
||||
help
|
||||
If you say Y here, the modem-emulator will support a subset of the
|
||||
EIA Class 8 Voice commands. Using a getty with voice-support
|
||||
(mgetty+sendfax by <[email protected]> with an extension, available
|
||||
with the ISDN utility package for example), you will be able to use
|
||||
your Linux box as an ISDN-answering machine. Of course, this must be
|
||||
supported by the lowlevel driver also. Currently, the HiSax driver
|
||||
is the only voice-supporting driver. See
|
||||
<file:Documentation/isdn/README.audio> for more information.
|
||||
|
||||
config ISDN_TTY_FAX
|
||||
bool "Support AT-Fax Class 1 and 2 commands"
|
||||
depends on ISDN_AUDIO
|
||||
help
|
||||
If you say Y here, the modem-emulator will support a subset of the
|
||||
Fax Class 1 and 2 commands. Using a getty with fax-support
|
||||
(mgetty+sendfax, hylafax), you will be able to use your Linux box as
|
||||
an ISDN-fax-machine. This must be supported by the lowlevel driver
|
||||
also. See <file:Documentation/isdn/README.fax> for more information.
|
||||
|
||||
config ISDN_X25
|
||||
bool "X.25 PLP on top of ISDN"
|
||||
depends on X25
|
||||
help
|
||||
This feature provides the X.25 protocol over ISDN connections.
|
||||
See <file:Documentation/isdn/README.x25> for more information
|
||||
if you are thinking about using this.
|
||||
|
||||
|
||||
menu "ISDN feature submodules"
|
||||
|
||||
config ISDN_DRV_LOOP
|
||||
tristate "isdnloop support"
|
||||
depends on BROKEN_ON_SMP
|
||||
help
|
||||
This driver provides a virtual ISDN card. Its primary purpose is
|
||||
testing of linklevel features or configuration without getting
|
||||
charged by your service-provider for lots of phone calls.
|
||||
You need will need the loopctrl utility from the latest isdn4k-utils
|
||||
package to set up this driver.
|
||||
|
||||
config ISDN_DIVERSION
|
||||
tristate "Support isdn diversion services"
|
||||
help
|
||||
This option allows you to use some supplementary diversion
|
||||
services in conjunction with the HiSax driver on an EURO/DSS1
|
||||
line.
|
||||
|
||||
Supported options are CD (call deflection), CFU (Call forward
|
||||
unconditional), CFB (Call forward when busy) and CFNR (call forward
|
||||
not reachable). Additionally the actual CFU, CFB and CFNR state may
|
||||
be interrogated.
|
||||
|
||||
The use of CFU, CFB, CFNR and interrogation may be limited to some
|
||||
countries. The keypad protocol is still not implemented. CD should
|
||||
work in all countries if the service has been subscribed to.
|
||||
|
||||
Please read the file <file:Documentation/isdn/README.diversion>.
|
||||
|
||||
endmenu
|
||||
|
||||
comment "ISDN4Linux hardware drivers"
|
||||
|
||||
# end ISDN_I4L
|
||||
endif
|
||||
|
||||
|
|
@ -3,18 +3,4 @@
|
|||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_ISDN_I4L) += isdn.o
|
||||
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
|
||||
obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o
|
||||
|
||||
# Multipart objects.
|
||||
|
||||
isdn-y := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
|
||||
|
||||
# Optional parts of multipart objects.
|
||||
|
||||
isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o
|
||||
isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
|
||||
isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
|
||||
isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
|
||||
|
||||
|
|
|
|||
|
|
@ -1,711 +0,0 @@
|
|||
/* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, audio conversion and compression (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
* DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
|
||||
* Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/isdn.h>
|
||||
#include <linux/slab.h>
|
||||
#include "isdn_audio.h"
|
||||
#include "isdn_common.h"
|
||||
|
||||
char *isdn_audio_revision = "$Revision: 1.1.2.2 $";
|
||||
|
||||
/*
|
||||
* Misc. lookup-tables.
|
||||
*/
|
||||
|
||||
/* ulaw -> signed 16-bit */
|
||||
static short isdn_audio_ulaw_to_s16[] =
|
||||
{
|
||||
0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
|
||||
0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
|
||||
0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
|
||||
0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
|
||||
0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
|
||||
0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
|
||||
0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
|
||||
0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
|
||||
0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
|
||||
0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
|
||||
0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
|
||||
0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
|
||||
0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
|
||||
0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
|
||||
0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
|
||||
0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
|
||||
0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
|
||||
0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
|
||||
0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
|
||||
0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
|
||||
0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
|
||||
0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
|
||||
0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
|
||||
0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
|
||||
0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
|
||||
0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
|
||||
0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
|
||||
0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
|
||||
0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
|
||||
0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
|
||||
0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
|
||||
0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
|
||||
};
|
||||
|
||||
/* alaw -> signed 16-bit */
|
||||
static short isdn_audio_alaw_to_s16[] =
|
||||
{
|
||||
0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
|
||||
0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
|
||||
0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
|
||||
0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
|
||||
0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
|
||||
0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
|
||||
0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
|
||||
0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
|
||||
0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
|
||||
0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
|
||||
0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
|
||||
0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
|
||||
0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
|
||||
0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
|
||||
0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
|
||||
0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
|
||||
0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
|
||||
0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
|
||||
0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
|
||||
0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
|
||||
0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
|
||||
0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
|
||||
0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
|
||||
0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
|
||||
0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
|
||||
0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
|
||||
0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
|
||||
0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
|
||||
0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
|
||||
0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
|
||||
0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
|
||||
0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
|
||||
};
|
||||
|
||||
/* alaw -> ulaw */
|
||||
static char isdn_audio_alaw_to_ulaw[] =
|
||||
{
|
||||
0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
|
||||
0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
|
||||
0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
|
||||
0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
|
||||
0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
|
||||
0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
|
||||
0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
|
||||
0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
|
||||
0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
|
||||
0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
|
||||
0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
|
||||
0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
|
||||
0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
|
||||
0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
|
||||
0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
|
||||
0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
|
||||
0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
|
||||
0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
|
||||
0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
|
||||
0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
|
||||
0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
|
||||
0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
|
||||
0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
|
||||
0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
|
||||
0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
|
||||
0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
|
||||
0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
|
||||
0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
|
||||
0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
|
||||
0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
|
||||
0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
|
||||
0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
|
||||
};
|
||||
|
||||
/* ulaw -> alaw */
|
||||
static char isdn_audio_ulaw_to_alaw[] =
|
||||
{
|
||||
0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
|
||||
0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
|
||||
0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
|
||||
0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
|
||||
0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
|
||||
0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
|
||||
0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
|
||||
0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
|
||||
0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
|
||||
0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
|
||||
0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
|
||||
0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
|
||||
0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
|
||||
0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
|
||||
0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
|
||||
0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
|
||||
0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
|
||||
0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
|
||||
0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
|
||||
0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
|
||||
0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
|
||||
0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
|
||||
0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
|
||||
0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
|
||||
0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
|
||||
0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
|
||||
0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
|
||||
0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
|
||||
0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
|
||||
0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
|
||||
0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
|
||||
0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
|
||||
};
|
||||
|
||||
#define NCOEFF 8 /* number of frequencies to be analyzed */
|
||||
#define DTMF_TRESH 4000 /* above this is dtmf */
|
||||
#define SILENCE_TRESH 200 /* below this is silence */
|
||||
#define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */
|
||||
#define LOGRP 0
|
||||
#define HIGRP 1
|
||||
|
||||
/* For DTMF recognition:
|
||||
* 2 * cos(2 * PI * k / N) precalculated for all k
|
||||
*/
|
||||
static int cos2pik[NCOEFF] =
|
||||
{
|
||||
55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
|
||||
};
|
||||
|
||||
static char dtmf_matrix[4][4] =
|
||||
{
|
||||
{'1', '2', '3', 'A'},
|
||||
{'4', '5', '6', 'B'},
|
||||
{'7', '8', '9', 'C'},
|
||||
{'*', '0', '#', 'D'}
|
||||
};
|
||||
|
||||
static inline void
|
||||
isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n)
|
||||
{
|
||||
#ifdef __i386__
|
||||
unsigned long d0, d1, d2, d3;
|
||||
__asm__ __volatile__(
|
||||
"cld\n"
|
||||
"1:\tlodsb\n\t"
|
||||
"xlatb\n\t"
|
||||
"stosb\n\t"
|
||||
"loop 1b\n\t"
|
||||
: "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
|
||||
: "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
|
||||
: "memory", "ax");
|
||||
#else
|
||||
while (n--)
|
||||
*buff = table[*(unsigned char *)buff], buff++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
|
||||
{
|
||||
isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
|
||||
{
|
||||
isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* linear <-> adpcm conversion stuff
|
||||
* Most parts from the mgetty-package.
|
||||
* (C) by Gert Doering and Klaus Weidner
|
||||
* Used by permission of Gert Doering
|
||||
*/
|
||||
|
||||
|
||||
#define ZEROTRAP /* turn on the trap as per the MIL-STD */
|
||||
#undef ZEROTRAP
|
||||
#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
|
||||
#define CLIP 32635
|
||||
|
||||
static unsigned char
|
||||
isdn_audio_linear2ulaw(int sample)
|
||||
{
|
||||
static int exp_lut[256] =
|
||||
{
|
||||
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
|
||||
};
|
||||
int sign,
|
||||
exponent,
|
||||
mantissa;
|
||||
unsigned char ulawbyte;
|
||||
|
||||
/* Get the sample into sign-magnitude. */
|
||||
sign = (sample >> 8) & 0x80; /* set aside the sign */
|
||||
if (sign != 0)
|
||||
sample = -sample; /* get magnitude */
|
||||
if (sample > CLIP)
|
||||
sample = CLIP; /* clip the magnitude */
|
||||
|
||||
/* Convert from 16 bit linear to ulaw. */
|
||||
sample = sample + BIAS;
|
||||
exponent = exp_lut[(sample >> 7) & 0xFF];
|
||||
mantissa = (sample >> (exponent + 3)) & 0x0F;
|
||||
ulawbyte = ~(sign | (exponent << 4) | mantissa);
|
||||
#ifdef ZEROTRAP
|
||||
/* optional CCITT trap */
|
||||
if (ulawbyte == 0)
|
||||
ulawbyte = 0x02;
|
||||
#endif
|
||||
return (ulawbyte);
|
||||
}
|
||||
|
||||
|
||||
static int Mx[3][8] =
|
||||
{
|
||||
{0x3800, 0x5600, 0, 0, 0, 0, 0, 0},
|
||||
{0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0},
|
||||
{0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607},
|
||||
};
|
||||
|
||||
static int bitmask[9] =
|
||||
{
|
||||
0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
|
||||
};
|
||||
|
||||
static int
|
||||
isdn_audio_get_bits(adpcm_state *s, unsigned char **in, int *len)
|
||||
{
|
||||
while (s->nleft < s->nbits) {
|
||||
int d = *((*in)++);
|
||||
(*len)--;
|
||||
s->word = (s->word << 8) | d;
|
||||
s->nleft += 8;
|
||||
}
|
||||
s->nleft -= s->nbits;
|
||||
return (s->word >> s->nleft) & bitmask[s->nbits];
|
||||
}
|
||||
|
||||
static void
|
||||
isdn_audio_put_bits(int data, int nbits, adpcm_state *s,
|
||||
unsigned char **out, int *len)
|
||||
{
|
||||
s->word = (s->word << nbits) | (data & bitmask[nbits]);
|
||||
s->nleft += nbits;
|
||||
while (s->nleft >= 8) {
|
||||
int d = (s->word >> (s->nleft - 8));
|
||||
*(out[0]++) = d & 255;
|
||||
(*len)++;
|
||||
s->nleft -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
adpcm_state *
|
||||
isdn_audio_adpcm_init(adpcm_state *s, int nbits)
|
||||
{
|
||||
if (!s)
|
||||
s = kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
|
||||
if (s) {
|
||||
s->a = 0;
|
||||
s->d = 5;
|
||||
s->word = 0;
|
||||
s->nleft = 0;
|
||||
s->nbits = nbits;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
dtmf_state *
|
||||
isdn_audio_dtmf_init(dtmf_state *s)
|
||||
{
|
||||
if (!s)
|
||||
s = kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
|
||||
if (s) {
|
||||
s->idx = 0;
|
||||
s->last = ' ';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompression of adpcm data to a/u-law
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
isdn_audio_adpcm2xlaw(adpcm_state *s, int fmt, unsigned char *in,
|
||||
unsigned char *out, int len)
|
||||
{
|
||||
int a = s->a;
|
||||
int d = s->d;
|
||||
int nbits = s->nbits;
|
||||
int olen = 0;
|
||||
|
||||
while (len) {
|
||||
int e = isdn_audio_get_bits(s, &in, &len);
|
||||
int sign;
|
||||
|
||||
if (nbits == 4 && e == 0)
|
||||
d = 4;
|
||||
sign = (e >> (nbits - 1)) ? -1 : 1;
|
||||
e &= bitmask[nbits - 1];
|
||||
a += sign * ((e << 1) + 1) * d >> 1;
|
||||
if (d & 1)
|
||||
a++;
|
||||
if (fmt)
|
||||
*out++ = isdn_audio_ulaw_to_alaw[
|
||||
isdn_audio_linear2ulaw(a << 2)];
|
||||
else
|
||||
*out++ = isdn_audio_linear2ulaw(a << 2);
|
||||
olen++;
|
||||
d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
|
||||
if (d < 5)
|
||||
d = 5;
|
||||
}
|
||||
s->a = a;
|
||||
s->d = d;
|
||||
return olen;
|
||||
}
|
||||
|
||||
int
|
||||
isdn_audio_xlaw2adpcm(adpcm_state *s, int fmt, unsigned char *in,
|
||||
unsigned char *out, int len)
|
||||
{
|
||||
int a = s->a;
|
||||
int d = s->d;
|
||||
int nbits = s->nbits;
|
||||
int olen = 0;
|
||||
|
||||
while (len--) {
|
||||
int e = 0,
|
||||
nmax = 1 << (nbits - 1);
|
||||
int sign,
|
||||
delta;
|
||||
|
||||
if (fmt)
|
||||
delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
|
||||
else
|
||||
delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
|
||||
if (delta < 0) {
|
||||
e = nmax;
|
||||
delta = -delta;
|
||||
}
|
||||
while (--nmax && delta > d) {
|
||||
delta -= d;
|
||||
e++;
|
||||
}
|
||||
if (nbits == 4 && ((e & 0x0f) == 0))
|
||||
e = 8;
|
||||
isdn_audio_put_bits(e, nbits, s, &out, &olen);
|
||||
sign = (e >> (nbits - 1)) ? -1 : 1;
|
||||
e &= bitmask[nbits - 1];
|
||||
|
||||
a += sign * ((e << 1) + 1) * d >> 1;
|
||||
if (d & 1)
|
||||
a++;
|
||||
d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
|
||||
if (d < 5)
|
||||
d = 5;
|
||||
}
|
||||
s->a = a;
|
||||
s->d = d;
|
||||
return olen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Goertzel algorithm.
|
||||
* See http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/
|
||||
* for more info.
|
||||
* Result is stored into an sk_buff and queued up for later
|
||||
* evaluation.
|
||||
*/
|
||||
static void
|
||||
isdn_audio_goertzel(int *sample, modem_info *info)
|
||||
{
|
||||
int sk,
|
||||
sk1,
|
||||
sk2;
|
||||
int k,
|
||||
n;
|
||||
struct sk_buff *skb;
|
||||
int *result;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(int) * NCOEFF);
|
||||
if (!skb) {
|
||||
printk(KERN_WARNING
|
||||
"isdn_audio: Could not alloc DTMF result for ttyI%d\n",
|
||||
info->line);
|
||||
return;
|
||||
}
|
||||
result = skb_put(skb, sizeof(int) * NCOEFF);
|
||||
for (k = 0; k < NCOEFF; k++) {
|
||||
sk = sk1 = sk2 = 0;
|
||||
for (n = 0; n < DTMF_NPOINTS; n++) {
|
||||
sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;
|
||||
sk2 = sk1;
|
||||
sk1 = sk;
|
||||
}
|
||||
/* Avoid overflows */
|
||||
sk >>= 1;
|
||||
sk2 >>= 1;
|
||||
/* compute |X(k)|**2 */
|
||||
/* report overflows. This should not happen. */
|
||||
/* Comment this out if desired */
|
||||
if (sk < -32768 || sk > 32767)
|
||||
printk(KERN_DEBUG
|
||||
"isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
|
||||
if (sk2 < -32768 || sk2 > 32767)
|
||||
printk(KERN_DEBUG
|
||||
"isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
|
||||
result[k] =
|
||||
((sk * sk) >> AMP_BITS) -
|
||||
((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
|
||||
((sk2 * sk2) >> AMP_BITS);
|
||||
}
|
||||
skb_queue_tail(&info->dtmf_queue, skb);
|
||||
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_eval_dtmf(modem_info *info)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int *result;
|
||||
dtmf_state *s;
|
||||
int silence;
|
||||
int i;
|
||||
int di;
|
||||
int ch;
|
||||
int grp[2];
|
||||
char what;
|
||||
char *p;
|
||||
int thresh;
|
||||
|
||||
while ((skb = skb_dequeue(&info->dtmf_queue))) {
|
||||
result = (int *) skb->data;
|
||||
s = info->dtmf_state;
|
||||
grp[LOGRP] = grp[HIGRP] = -1;
|
||||
silence = 0;
|
||||
thresh = 0;
|
||||
for (i = 0; i < NCOEFF; i++) {
|
||||
if (result[i] > DTMF_TRESH) {
|
||||
if (result[i] > thresh)
|
||||
thresh = result[i];
|
||||
}
|
||||
else if (result[i] < SILENCE_TRESH)
|
||||
silence++;
|
||||
}
|
||||
if (silence == NCOEFF)
|
||||
what = ' ';
|
||||
else {
|
||||
if (thresh > 0) {
|
||||
thresh = thresh >> 4; /* touchtones must match within 12 dB */
|
||||
for (i = 0; i < NCOEFF; i++) {
|
||||
if (result[i] < thresh)
|
||||
continue; /* ignore */
|
||||
/* good level found. This is allowed only one time per group */
|
||||
if (i < NCOEFF / 2) {
|
||||
/* lowgroup*/
|
||||
if (grp[LOGRP] >= 0) {
|
||||
// Bad. Another tone found. */
|
||||
grp[LOGRP] = -1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
grp[LOGRP] = i;
|
||||
}
|
||||
else { /* higroup */
|
||||
if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
|
||||
grp[HIGRP] = -1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
grp[HIGRP] = i - NCOEFF/2;
|
||||
}
|
||||
}
|
||||
if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
|
||||
what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
|
||||
if (s->last != ' ' && s->last != '.')
|
||||
s->last = what; /* min. 1 non-DTMF between DTMF */
|
||||
} else
|
||||
what = '.';
|
||||
}
|
||||
else
|
||||
what = '.';
|
||||
}
|
||||
if ((what != s->last) && (what != ' ') && (what != '.')) {
|
||||
printk(KERN_DEBUG "dtmf: tt='%c'\n", what);
|
||||
p = skb->data;
|
||||
*p++ = 0x10;
|
||||
*p = what;
|
||||
skb_trim(skb, 2);
|
||||
ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
|
||||
ISDN_AUDIO_SKB_LOCK(skb) = 0;
|
||||
di = info->isdn_driver;
|
||||
ch = info->isdn_channel;
|
||||
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
|
||||
dev->drv[di]->rcvcount[ch] += 2;
|
||||
/* Schedule dequeuing */
|
||||
if ((dev->modempoll) && (info->rcvsched))
|
||||
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
|
||||
wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
|
||||
} else
|
||||
kfree_skb(skb);
|
||||
s->last = what;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode DTMF tones, queue result in separate sk_buf for
|
||||
* later examination.
|
||||
* Parameters:
|
||||
* s = pointer to state-struct.
|
||||
* buf = input audio data
|
||||
* len = size of audio data.
|
||||
* fmt = audio data format (0 = ulaw, 1 = alaw)
|
||||
*/
|
||||
void
|
||||
isdn_audio_calc_dtmf(modem_info *info, unsigned char *buf, int len, int fmt)
|
||||
{
|
||||
dtmf_state *s = info->dtmf_state;
|
||||
int i;
|
||||
int c;
|
||||
|
||||
while (len) {
|
||||
c = DTMF_NPOINTS - s->idx;
|
||||
if (c > len)
|
||||
c = len;
|
||||
if (c <= 0)
|
||||
break;
|
||||
for (i = 0; i < c; i++) {
|
||||
if (fmt)
|
||||
s->buf[s->idx++] =
|
||||
isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
|
||||
else
|
||||
s->buf[s->idx++] =
|
||||
isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
|
||||
}
|
||||
if (s->idx == DTMF_NPOINTS) {
|
||||
isdn_audio_goertzel(s->buf, info);
|
||||
s->idx = 0;
|
||||
}
|
||||
len -= c;
|
||||
}
|
||||
}
|
||||
|
||||
silence_state *
|
||||
isdn_audio_silence_init(silence_state *s)
|
||||
{
|
||||
if (!s)
|
||||
s = kmalloc(sizeof(silence_state), GFP_ATOMIC);
|
||||
if (s) {
|
||||
s->idx = 0;
|
||||
s->state = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_calc_silence(modem_info *info, unsigned char *buf, int len, int fmt)
|
||||
{
|
||||
silence_state *s = info->silence_state;
|
||||
int i;
|
||||
signed char c;
|
||||
|
||||
if (!info->emu.vpar[1]) return;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (fmt)
|
||||
c = isdn_audio_alaw_to_ulaw[*buf++];
|
||||
else
|
||||
c = *buf++;
|
||||
|
||||
if (c > 0) c -= 128;
|
||||
c = abs(c);
|
||||
|
||||
if (c > (info->emu.vpar[1] * 4)) {
|
||||
s->idx = 0;
|
||||
s->state = 1;
|
||||
} else {
|
||||
if (s->idx < 210000) s->idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_put_dle_code(modem_info *info, u_char code)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int di;
|
||||
int ch;
|
||||
char *p;
|
||||
|
||||
skb = dev_alloc_skb(2);
|
||||
if (!skb) {
|
||||
printk(KERN_WARNING
|
||||
"isdn_audio: Could not alloc skb for ttyI%d\n",
|
||||
info->line);
|
||||
return;
|
||||
}
|
||||
p = skb_put(skb, 2);
|
||||
p[0] = 0x10;
|
||||
p[1] = code;
|
||||
ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
|
||||
ISDN_AUDIO_SKB_LOCK(skb) = 0;
|
||||
di = info->isdn_driver;
|
||||
ch = info->isdn_channel;
|
||||
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
|
||||
dev->drv[di]->rcvcount[ch] += 2;
|
||||
/* Schedule dequeuing */
|
||||
if ((dev->modempoll) && (info->rcvsched))
|
||||
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
|
||||
wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
|
||||
}
|
||||
|
||||
void
|
||||
isdn_audio_eval_silence(modem_info *info)
|
||||
{
|
||||
silence_state *s = info->silence_state;
|
||||
char what;
|
||||
|
||||
what = ' ';
|
||||
|
||||
if (s->idx > (info->emu.vpar[2] * 800)) {
|
||||
s->idx = 0;
|
||||
if (!s->state) { /* silence from beginning of rec */
|
||||
what = 's';
|
||||
} else {
|
||||
what = 'q';
|
||||
}
|
||||
}
|
||||
if ((what == 's') || (what == 'q')) {
|
||||
printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
|
||||
(what == 's') ? "silence" : "quiet");
|
||||
isdn_audio_put_dle_code(info, what);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/* $Id: isdn_audio.h,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, audio conversion and compression (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
|
||||
typedef struct adpcm_state {
|
||||
int a;
|
||||
int d;
|
||||
int word;
|
||||
int nleft;
|
||||
int nbits;
|
||||
} adpcm_state;
|
||||
|
||||
typedef struct dtmf_state {
|
||||
char last;
|
||||
char llast;
|
||||
int idx;
|
||||
int buf[DTMF_NPOINTS];
|
||||
} dtmf_state;
|
||||
|
||||
typedef struct silence_state {
|
||||
int state;
|
||||
unsigned int idx;
|
||||
} silence_state;
|
||||
|
||||
extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long);
|
||||
extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
|
||||
extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
|
||||
extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
|
||||
extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
|
||||
extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
|
||||
extern void isdn_audio_eval_dtmf(modem_info *);
|
||||
dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
|
||||
extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int);
|
||||
extern void isdn_audio_eval_silence(modem_info *);
|
||||
silence_state *isdn_audio_silence_init(silence_state *);
|
||||
extern void isdn_audio_put_dle_code(modem_info *, u_char);
|
||||
|
|
@ -1,930 +0,0 @@
|
|||
/*
|
||||
* BSD compression module
|
||||
*
|
||||
* Patched version for ISDN syncPPP written 1997/1998 by Michael Hipp
|
||||
* The whole module is now SKB based.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Update: The Berkeley copyright was changed, and the change
|
||||
* is retroactive to all "true" BSD software (ie everything
|
||||
* from UCB as opposed to other peoples code that just carried
|
||||
* the same license). The new copyright doesn't clash with the
|
||||
* GPL, so the module-only restriction has been removed..
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original copyright notice:
|
||||
*
|
||||
* Copyright (c) 1985, 1986 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* James A. Woods, derived from original work by Spencer Thomas
|
||||
* and Joseph Orost.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h> /* used in new tty drivers */
|
||||
#include <linux/signal.h> /* used in new tty drivers */
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#include <linux/if.h>
|
||||
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <linux/ppp_defs.h>
|
||||
|
||||
#include <linux/isdn.h>
|
||||
#include <linux/isdn_ppp.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/ppp-comp.h>
|
||||
|
||||
#include "isdn_ppp.h"
|
||||
|
||||
MODULE_DESCRIPTION("ISDN4Linux: BSD Compression for PPP over ISDN");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
#define BSD_VERSION(x) ((x) >> 5)
|
||||
#define BSD_NBITS(x) ((x) & 0x1F)
|
||||
|
||||
#define BSD_CURRENT_VERSION 1
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
/*
|
||||
* A dictionary for doing BSD compress.
|
||||
*/
|
||||
|
||||
struct bsd_dict {
|
||||
u32 fcode;
|
||||
u16 codem1; /* output of hash table -1 */
|
||||
u16 cptr; /* map code to hash table entry */
|
||||
};
|
||||
|
||||
struct bsd_db {
|
||||
int totlen; /* length of this structure */
|
||||
unsigned int hsize; /* size of the hash table */
|
||||
unsigned char hshift; /* used in hash function */
|
||||
unsigned char n_bits; /* current bits/code */
|
||||
unsigned char maxbits; /* maximum bits/code */
|
||||
unsigned char debug; /* non-zero if debug desired */
|
||||
unsigned char unit; /* ppp unit number */
|
||||
u16 seqno; /* sequence # of next packet */
|
||||
unsigned int mru; /* size of receive (decompress) bufr */
|
||||
unsigned int maxmaxcode; /* largest valid code */
|
||||
unsigned int max_ent; /* largest code in use */
|
||||
unsigned int in_count; /* uncompressed bytes, aged */
|
||||
unsigned int bytes_out; /* compressed bytes, aged */
|
||||
unsigned int ratio; /* recent compression ratio */
|
||||
unsigned int checkpoint; /* when to next check the ratio */
|
||||
unsigned int clear_count; /* times dictionary cleared */
|
||||
unsigned int incomp_count; /* incompressible packets */
|
||||
unsigned int incomp_bytes; /* incompressible bytes */
|
||||
unsigned int uncomp_count; /* uncompressed packets */
|
||||
unsigned int uncomp_bytes; /* uncompressed bytes */
|
||||
unsigned int comp_count; /* compressed packets */
|
||||
unsigned int comp_bytes; /* compressed bytes */
|
||||
unsigned short *lens; /* array of lengths of codes */
|
||||
struct bsd_dict *dict; /* dictionary */
|
||||
int xmit;
|
||||
};
|
||||
|
||||
#define BSD_OVHD 2 /* BSD compress overhead/packet */
|
||||
#define MIN_BSD_BITS 9
|
||||
#define BSD_INIT_BITS MIN_BSD_BITS
|
||||
#define MAX_BSD_BITS 15
|
||||
|
||||
/*
|
||||
* the next two codes should not be changed lightly, as they must not
|
||||
* lie within the contiguous general code space.
|
||||
*/
|
||||
#define CLEAR 256 /* table clear output code */
|
||||
#define FIRST 257 /* first free entry */
|
||||
#define LAST 255
|
||||
|
||||
#define MAXCODE(b) ((1 << (b)) - 1)
|
||||
#define BADCODEM1 MAXCODE(MAX_BSD_BITS)
|
||||
|
||||
#define BSD_HASH(prefix, suffix, hshift) ((((unsigned long)(suffix)) << (hshift)) \
|
||||
^ (unsigned long)(prefix))
|
||||
#define BSD_KEY(prefix, suffix) ((((unsigned long)(suffix)) << 16) \
|
||||
+ (unsigned long)(prefix))
|
||||
|
||||
#define CHECK_GAP 10000 /* Ratio check interval */
|
||||
|
||||
#define RATIO_SCALE_LOG 8
|
||||
#define RATIO_SCALE (1 << RATIO_SCALE_LOG)
|
||||
#define RATIO_MAX (0x7fffffff >> RATIO_SCALE_LOG)
|
||||
|
||||
/*
|
||||
* clear the dictionary
|
||||
*/
|
||||
|
||||
static void bsd_clear(struct bsd_db *db)
|
||||
{
|
||||
db->clear_count++;
|
||||
db->max_ent = FIRST - 1;
|
||||
db->n_bits = BSD_INIT_BITS;
|
||||
db->bytes_out = 0;
|
||||
db->in_count = 0;
|
||||
db->incomp_count = 0;
|
||||
db->ratio = 0;
|
||||
db->checkpoint = CHECK_GAP;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the dictionary is full, then see if it is time to reset it.
|
||||
*
|
||||
* Compute the compression ratio using fixed-point arithmetic
|
||||
* with 8 fractional bits.
|
||||
*
|
||||
* Since we have an infinite stream instead of a single file,
|
||||
* watch only the local compression ratio.
|
||||
*
|
||||
* Since both peers must reset the dictionary at the same time even in
|
||||
* the absence of CLEAR codes (while packets are incompressible), they
|
||||
* must compute the same ratio.
|
||||
*/
|
||||
static int bsd_check(struct bsd_db *db) /* 1=output CLEAR */
|
||||
{
|
||||
unsigned int new_ratio;
|
||||
|
||||
if (db->in_count >= db->checkpoint)
|
||||
{
|
||||
/* age the ratio by limiting the size of the counts */
|
||||
if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX)
|
||||
{
|
||||
db->in_count -= (db->in_count >> 2);
|
||||
db->bytes_out -= (db->bytes_out >> 2);
|
||||
}
|
||||
|
||||
db->checkpoint = db->in_count + CHECK_GAP;
|
||||
|
||||
if (db->max_ent >= db->maxmaxcode)
|
||||
{
|
||||
/* Reset the dictionary only if the ratio is worse,
|
||||
* or if it looks as if it has been poisoned
|
||||
* by incompressible data.
|
||||
*
|
||||
* This does not overflow, because
|
||||
* db->in_count <= RATIO_MAX.
|
||||
*/
|
||||
|
||||
new_ratio = db->in_count << RATIO_SCALE_LOG;
|
||||
if (db->bytes_out != 0)
|
||||
{
|
||||
new_ratio /= db->bytes_out;
|
||||
}
|
||||
|
||||
if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
|
||||
{
|
||||
bsd_clear(db);
|
||||
return 1;
|
||||
}
|
||||
db->ratio = new_ratio;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return statistics.
|
||||
*/
|
||||
|
||||
static void bsd_stats(void *state, struct compstat *stats)
|
||||
{
|
||||
struct bsd_db *db = (struct bsd_db *) state;
|
||||
|
||||
stats->unc_bytes = db->uncomp_bytes;
|
||||
stats->unc_packets = db->uncomp_count;
|
||||
stats->comp_bytes = db->comp_bytes;
|
||||
stats->comp_packets = db->comp_count;
|
||||
stats->inc_bytes = db->incomp_bytes;
|
||||
stats->inc_packets = db->incomp_count;
|
||||
stats->in_count = db->in_count;
|
||||
stats->bytes_out = db->bytes_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset state, as on a CCP ResetReq.
|
||||
*/
|
||||
static void bsd_reset(void *state, unsigned char code, unsigned char id,
|
||||
unsigned char *data, unsigned len,
|
||||
struct isdn_ppp_resetparams *rsparm)
|
||||
{
|
||||
struct bsd_db *db = (struct bsd_db *) state;
|
||||
|
||||
bsd_clear(db);
|
||||
db->seqno = 0;
|
||||
db->clear_count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the compression structure
|
||||
*/
|
||||
static void bsd_free(void *state)
|
||||
{
|
||||
struct bsd_db *db = (struct bsd_db *) state;
|
||||
|
||||
if (db) {
|
||||
/*
|
||||
* Release the dictionary
|
||||
*/
|
||||
vfree(db->dict);
|
||||
db->dict = NULL;
|
||||
|
||||
/*
|
||||
* Release the string buffer
|
||||
*/
|
||||
vfree(db->lens);
|
||||
db->lens = NULL;
|
||||
|
||||
/*
|
||||
* Finally release the structure itself.
|
||||
*/
|
||||
kfree(db);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate space for a (de) compressor.
|
||||
*/
|
||||
static void *bsd_alloc(struct isdn_ppp_comp_data *data)
|
||||
{
|
||||
int bits;
|
||||
unsigned int hsize, hshift, maxmaxcode;
|
||||
struct bsd_db *db;
|
||||
int decomp;
|
||||
|
||||
static unsigned int htab[][2] = {
|
||||
{ 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } ,
|
||||
{ 9001 , 5 } , { 18013 , 6 } , { 35023 , 7 } , { 69001 , 8 }
|
||||
};
|
||||
|
||||
if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
|
||||
|| BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
|
||||
return NULL;
|
||||
|
||||
bits = BSD_NBITS(data->options[0]);
|
||||
|
||||
if (bits < 9 || bits > 15)
|
||||
return NULL;
|
||||
|
||||
hsize = htab[bits - 9][0];
|
||||
hshift = htab[bits - 9][1];
|
||||
|
||||
/*
|
||||
* Allocate the main control structure for this instance.
|
||||
*/
|
||||
maxmaxcode = MAXCODE(bits);
|
||||
db = kzalloc(sizeof(struct bsd_db), GFP_KERNEL);
|
||||
if (!db)
|
||||
return NULL;
|
||||
|
||||
db->xmit = data->flags & IPPP_COMP_FLAG_XMIT;
|
||||
decomp = db->xmit ? 0 : 1;
|
||||
|
||||
/*
|
||||
* Allocate space for the dictionary. This may be more than one page in
|
||||
* length.
|
||||
*/
|
||||
db->dict = vmalloc(array_size(hsize, sizeof(struct bsd_dict)));
|
||||
if (!db->dict) {
|
||||
bsd_free(db);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is the compression buffer then there is no length data.
|
||||
* For decompression, the length information is needed as well.
|
||||
*/
|
||||
if (!decomp)
|
||||
db->lens = NULL;
|
||||
else {
|
||||
db->lens = vmalloc(array_size(sizeof(db->lens[0]),
|
||||
maxmaxcode + 1));
|
||||
if (!db->lens) {
|
||||
bsd_free(db);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the data information for the compression code
|
||||
*/
|
||||
db->totlen = sizeof(struct bsd_db) + (sizeof(struct bsd_dict) * hsize);
|
||||
db->hsize = hsize;
|
||||
db->hshift = hshift;
|
||||
db->maxmaxcode = maxmaxcode;
|
||||
db->maxbits = bits;
|
||||
|
||||
return (void *)db;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the database.
|
||||
*/
|
||||
static int bsd_init(void *state, struct isdn_ppp_comp_data *data, int unit, int debug)
|
||||
{
|
||||
struct bsd_db *db = state;
|
||||
int indx;
|
||||
int decomp;
|
||||
|
||||
if (!state || !data) {
|
||||
printk(KERN_ERR "isdn_bsd_init: [%d] ERR, state %lx data %lx\n", unit, (long)state, (long)data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
decomp = db->xmit ? 0 : 1;
|
||||
|
||||
if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
|
||||
|| (BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
|
||||
|| (BSD_NBITS(data->options[0]) != db->maxbits)
|
||||
|| (decomp && db->lens == NULL)) {
|
||||
printk(KERN_ERR "isdn_bsd: %d %d %d %d %lx\n", data->optlen, data->num, data->options[0], decomp, (unsigned long)db->lens);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (decomp)
|
||||
for (indx = LAST; indx >= 0; indx--)
|
||||
db->lens[indx] = 1;
|
||||
|
||||
indx = db->hsize;
|
||||
while (indx-- != 0) {
|
||||
db->dict[indx].codem1 = BADCODEM1;
|
||||
db->dict[indx].cptr = 0;
|
||||
}
|
||||
|
||||
db->unit = unit;
|
||||
db->mru = 0;
|
||||
|
||||
db->debug = 1;
|
||||
|
||||
bsd_reset(db, 0, 0, NULL, 0, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain pointers to the various structures in the compression tables
|
||||
*/
|
||||
|
||||
#define dict_ptrx(p, idx) &(p->dict[idx])
|
||||
#define lens_ptrx(p, idx) &(p->lens[idx])
|
||||
|
||||
#ifdef DEBUG
|
||||
static unsigned short *lens_ptr(struct bsd_db *db, int idx)
|
||||
{
|
||||
if ((unsigned int) idx > (unsigned int) db->maxmaxcode) {
|
||||
printk(KERN_DEBUG "<9>ppp: lens_ptr(%d) > max\n", idx);
|
||||
idx = 0;
|
||||
}
|
||||
return lens_ptrx(db, idx);
|
||||
}
|
||||
|
||||
static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx)
|
||||
{
|
||||
if ((unsigned int) idx >= (unsigned int) db->hsize) {
|
||||
printk(KERN_DEBUG "<9>ppp: dict_ptr(%d) > max\n", idx);
|
||||
idx = 0;
|
||||
}
|
||||
return dict_ptrx(db, idx);
|
||||
}
|
||||
|
||||
#else
|
||||
#define lens_ptr(db, idx) lens_ptrx(db, idx)
|
||||
#define dict_ptr(db, idx) dict_ptrx(db, idx)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* compress a packet
|
||||
*/
|
||||
static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out, int proto)
|
||||
{
|
||||
struct bsd_db *db;
|
||||
int hshift;
|
||||
unsigned int max_ent;
|
||||
unsigned int n_bits;
|
||||
unsigned int bitno;
|
||||
unsigned long accm;
|
||||
int ent;
|
||||
unsigned long fcode;
|
||||
struct bsd_dict *dictp;
|
||||
unsigned char c;
|
||||
int hval, disp, ilen, mxcode;
|
||||
unsigned char *rptr = skb_in->data;
|
||||
int isize = skb_in->len;
|
||||
|
||||
#define OUTPUT(ent) \
|
||||
{ \
|
||||
bitno -= n_bits; \
|
||||
accm |= ((ent) << bitno); \
|
||||
do { \
|
||||
if (skb_out && skb_tailroom(skb_out) > 0) \
|
||||
skb_put_u8(skb_out, (u8)(accm >> 24)); \
|
||||
accm <<= 8; \
|
||||
bitno += 8; \
|
||||
} while (bitno <= 24); \
|
||||
}
|
||||
|
||||
/*
|
||||
* If the protocol is not in the range we're interested in,
|
||||
* just return without compressing the packet. If it is,
|
||||
* the protocol becomes the first byte to compress.
|
||||
*/
|
||||
printk(KERN_DEBUG "bsd_compress called with %x\n", proto);
|
||||
|
||||
ent = proto;
|
||||
if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1))
|
||||
return 0;
|
||||
|
||||
db = (struct bsd_db *) state;
|
||||
hshift = db->hshift;
|
||||
max_ent = db->max_ent;
|
||||
n_bits = db->n_bits;
|
||||
bitno = 32;
|
||||
accm = 0;
|
||||
mxcode = MAXCODE(n_bits);
|
||||
|
||||
/* This is the PPP header information */
|
||||
if (skb_out && skb_tailroom(skb_out) >= 2) {
|
||||
char *v = skb_put(skb_out, 2);
|
||||
/* we only push our own data on the header,
|
||||
AC,PC and protos is pushed by caller */
|
||||
v[0] = db->seqno >> 8;
|
||||
v[1] = db->seqno;
|
||||
}
|
||||
|
||||
ilen = ++isize; /* This is off by one, but that is what is in draft! */
|
||||
|
||||
while (--ilen > 0) {
|
||||
c = *rptr++;
|
||||
fcode = BSD_KEY(ent, c);
|
||||
hval = BSD_HASH(ent, c, hshift);
|
||||
dictp = dict_ptr(db, hval);
|
||||
|
||||
/* Validate and then check the entry. */
|
||||
if (dictp->codem1 >= max_ent)
|
||||
goto nomatch;
|
||||
|
||||
if (dictp->fcode == fcode) {
|
||||
ent = dictp->codem1 + 1;
|
||||
continue; /* found (prefix,suffix) */
|
||||
}
|
||||
|
||||
/* continue probing until a match or invalid entry */
|
||||
disp = (hval == 0) ? 1 : hval;
|
||||
|
||||
do {
|
||||
hval += disp;
|
||||
if (hval >= db->hsize)
|
||||
hval -= db->hsize;
|
||||
dictp = dict_ptr(db, hval);
|
||||
if (dictp->codem1 >= max_ent)
|
||||
goto nomatch;
|
||||
} while (dictp->fcode != fcode);
|
||||
|
||||
ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
|
||||
continue;
|
||||
|
||||
nomatch:
|
||||
OUTPUT(ent); /* output the prefix */
|
||||
|
||||
/* code -> hashtable */
|
||||
if (max_ent < db->maxmaxcode) {
|
||||
struct bsd_dict *dictp2;
|
||||
struct bsd_dict *dictp3;
|
||||
int indx;
|
||||
|
||||
/* expand code size if needed */
|
||||
if (max_ent >= mxcode) {
|
||||
db->n_bits = ++n_bits;
|
||||
mxcode = MAXCODE(n_bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate old hash table entry using
|
||||
* this code, and then take it over.
|
||||
*/
|
||||
dictp2 = dict_ptr(db, max_ent + 1);
|
||||
indx = dictp2->cptr;
|
||||
dictp3 = dict_ptr(db, indx);
|
||||
|
||||
if (dictp3->codem1 == max_ent)
|
||||
dictp3->codem1 = BADCODEM1;
|
||||
|
||||
dictp2->cptr = hval;
|
||||
dictp->codem1 = max_ent;
|
||||
dictp->fcode = fcode;
|
||||
db->max_ent = ++max_ent;
|
||||
|
||||
if (db->lens) {
|
||||
unsigned short *len1 = lens_ptr(db, max_ent);
|
||||
unsigned short *len2 = lens_ptr(db, ent);
|
||||
*len1 = *len2 + 1;
|
||||
}
|
||||
}
|
||||
ent = c;
|
||||
}
|
||||
|
||||
OUTPUT(ent); /* output the last code */
|
||||
|
||||
if (skb_out)
|
||||
db->bytes_out += skb_out->len; /* Do not count bytes from here */
|
||||
db->uncomp_bytes += isize;
|
||||
db->in_count += isize;
|
||||
++db->uncomp_count;
|
||||
++db->seqno;
|
||||
|
||||
if (bitno < 32)
|
||||
++db->bytes_out; /* must be set before calling bsd_check */
|
||||
|
||||
/*
|
||||
* Generate the clear command if needed
|
||||
*/
|
||||
|
||||
if (bsd_check(db))
|
||||
OUTPUT(CLEAR);
|
||||
|
||||
/*
|
||||
* Pad dribble bits of last code with ones.
|
||||
* Do not emit a completely useless byte of ones.
|
||||
*/
|
||||
if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0)
|
||||
skb_put_u8(skb_out,
|
||||
(unsigned char)((accm | (0xff << (bitno - 8))) >> 24));
|
||||
|
||||
/*
|
||||
* Increase code size if we would have without the packet
|
||||
* boundary because the decompressor will do so.
|
||||
*/
|
||||
if (max_ent >= mxcode && max_ent < db->maxmaxcode)
|
||||
db->n_bits++;
|
||||
|
||||
/* If output length is too large then this is an incompressible frame. */
|
||||
if (!skb_out || skb_out->len >= skb_in->len) {
|
||||
++db->incomp_count;
|
||||
db->incomp_bytes += isize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Count the number of compressed frames */
|
||||
++db->comp_count;
|
||||
db->comp_bytes += skb_out->len;
|
||||
return skb_out->len;
|
||||
|
||||
#undef OUTPUT
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the "BSD Compress" dictionary on the receiver for
|
||||
* incompressible data by pretending to compress the incoming data.
|
||||
*/
|
||||
static void bsd_incomp(void *state, struct sk_buff *skb_in, int proto)
|
||||
{
|
||||
bsd_compress(state, skb_in, NULL, proto);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompress "BSD Compress".
|
||||
*/
|
||||
static int bsd_decompress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,
|
||||
struct isdn_ppp_resetparams *rsparm)
|
||||
{
|
||||
struct bsd_db *db;
|
||||
unsigned int max_ent;
|
||||
unsigned long accm;
|
||||
unsigned int bitno; /* 1st valid bit in accm */
|
||||
unsigned int n_bits;
|
||||
unsigned int tgtbitno; /* bitno when we have a code */
|
||||
struct bsd_dict *dictp;
|
||||
int seq;
|
||||
unsigned int incode;
|
||||
unsigned int oldcode;
|
||||
unsigned int finchar;
|
||||
unsigned char *p, *ibuf;
|
||||
int ilen;
|
||||
int codelen;
|
||||
int extra;
|
||||
|
||||
db = (struct bsd_db *) state;
|
||||
max_ent = db->max_ent;
|
||||
accm = 0;
|
||||
bitno = 32; /* 1st valid bit in accm */
|
||||
n_bits = db->n_bits;
|
||||
tgtbitno = 32 - n_bits; /* bitno when we have a code */
|
||||
|
||||
printk(KERN_DEBUG "bsd_decompress called\n");
|
||||
|
||||
if (!skb_in || !skb_out) {
|
||||
printk(KERN_ERR "bsd_decompress called with NULL parameter\n");
|
||||
return DECOMP_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the sequence number.
|
||||
*/
|
||||
if ((p = skb_pull(skb_in, 2)) == NULL) {
|
||||
return DECOMP_ERROR;
|
||||
}
|
||||
p -= 2;
|
||||
seq = (p[0] << 8) + p[1];
|
||||
ilen = skb_in->len;
|
||||
ibuf = skb_in->data;
|
||||
|
||||
/*
|
||||
* Check the sequence number and give up if it differs from
|
||||
* the value we're expecting.
|
||||
*/
|
||||
if (seq != db->seqno) {
|
||||
if (db->debug) {
|
||||
printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n",
|
||||
db->unit, seq, db->seqno - 1);
|
||||
}
|
||||
return DECOMP_ERROR;
|
||||
}
|
||||
|
||||
++db->seqno;
|
||||
db->bytes_out += ilen;
|
||||
|
||||
if (skb_tailroom(skb_out) > 0)
|
||||
skb_put_u8(skb_out, 0);
|
||||
else
|
||||
return DECOMP_ERR_NOMEM;
|
||||
|
||||
oldcode = CLEAR;
|
||||
|
||||
/*
|
||||
* Keep the checkpoint correctly so that incompressible packets
|
||||
* clear the dictionary at the proper times.
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
if (ilen-- <= 0) {
|
||||
db->in_count += (skb_out->len - 1); /* don't count the header */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accumulate bytes until we have a complete code.
|
||||
* Then get the next code, relying on the 32-bit,
|
||||
* unsigned accm to mask the result.
|
||||
*/
|
||||
|
||||
bitno -= 8;
|
||||
accm |= *ibuf++ << bitno;
|
||||
if (tgtbitno < bitno)
|
||||
continue;
|
||||
|
||||
incode = accm >> tgtbitno;
|
||||
accm <<= n_bits;
|
||||
bitno += n_bits;
|
||||
|
||||
/*
|
||||
* The dictionary must only be cleared at the end of a packet.
|
||||
*/
|
||||
|
||||
if (incode == CLEAR) {
|
||||
if (ilen > 0) {
|
||||
if (db->debug)
|
||||
printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit);
|
||||
return DECOMP_FATALERROR; /* probably a bug */
|
||||
}
|
||||
bsd_clear(db);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((incode > max_ent + 2) || (incode > db->maxmaxcode)
|
||||
|| (incode > max_ent && oldcode == CLEAR)) {
|
||||
if (db->debug) {
|
||||
printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
|
||||
db->unit, incode, oldcode);
|
||||
printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n",
|
||||
max_ent, skb_out->len, db->seqno);
|
||||
}
|
||||
return DECOMP_FATALERROR; /* probably a bug */
|
||||
}
|
||||
|
||||
/* Special case for KwKwK string. */
|
||||
if (incode > max_ent) {
|
||||
finchar = oldcode;
|
||||
extra = 1;
|
||||
} else {
|
||||
finchar = incode;
|
||||
extra = 0;
|
||||
}
|
||||
|
||||
codelen = *(lens_ptr(db, finchar));
|
||||
if (skb_tailroom(skb_out) < codelen + extra) {
|
||||
if (db->debug) {
|
||||
printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit);
|
||||
#ifdef DEBUG
|
||||
printk(KERN_DEBUG " len=%d, finchar=0x%x, codelen=%d,skblen=%d\n",
|
||||
ilen, finchar, codelen, skb_out->len);
|
||||
#endif
|
||||
}
|
||||
return DECOMP_FATALERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode this code and install it in the decompressed buffer.
|
||||
*/
|
||||
|
||||
p = skb_put(skb_out, codelen);
|
||||
p += codelen;
|
||||
while (finchar > LAST) {
|
||||
struct bsd_dict *dictp2 = dict_ptr(db, finchar);
|
||||
|
||||
dictp = dict_ptr(db, dictp2->cptr);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (--codelen <= 0 || dictp->codem1 != finchar - 1) {
|
||||
if (codelen <= 0) {
|
||||
printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit);
|
||||
printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent);
|
||||
} else {
|
||||
if (dictp->codem1 != finchar - 1) {
|
||||
printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ", db->unit, incode, finchar);
|
||||
printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1);
|
||||
}
|
||||
}
|
||||
return DECOMP_FATALERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
u32 fcode = dictp->fcode;
|
||||
*--p = (fcode >> 16) & 0xff;
|
||||
finchar = fcode & 0xffff;
|
||||
}
|
||||
}
|
||||
*--p = finchar;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (--codelen != 0)
|
||||
printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent);
|
||||
#endif
|
||||
|
||||
if (extra) /* the KwKwK case again */
|
||||
skb_put_u8(skb_out, finchar);
|
||||
|
||||
/*
|
||||
* If not first code in a packet, and
|
||||
* if not out of code space, then allocate a new code.
|
||||
*
|
||||
* Keep the hash table correct so it can be used
|
||||
* with uncompressed packets.
|
||||
*/
|
||||
if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
|
||||
struct bsd_dict *dictp2, *dictp3;
|
||||
u16 *lens1, *lens2;
|
||||
unsigned long fcode;
|
||||
int hval, disp, indx;
|
||||
|
||||
fcode = BSD_KEY(oldcode, finchar);
|
||||
hval = BSD_HASH(oldcode, finchar, db->hshift);
|
||||
dictp = dict_ptr(db, hval);
|
||||
|
||||
/* look for a free hash table entry */
|
||||
if (dictp->codem1 < max_ent) {
|
||||
disp = (hval == 0) ? 1 : hval;
|
||||
do {
|
||||
hval += disp;
|
||||
if (hval >= db->hsize)
|
||||
hval -= db->hsize;
|
||||
dictp = dict_ptr(db, hval);
|
||||
} while (dictp->codem1 < max_ent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate previous hash table entry
|
||||
* assigned this code, and then take it over
|
||||
*/
|
||||
|
||||
dictp2 = dict_ptr(db, max_ent + 1);
|
||||
indx = dictp2->cptr;
|
||||
dictp3 = dict_ptr(db, indx);
|
||||
|
||||
if (dictp3->codem1 == max_ent)
|
||||
dictp3->codem1 = BADCODEM1;
|
||||
|
||||
dictp2->cptr = hval;
|
||||
dictp->codem1 = max_ent;
|
||||
dictp->fcode = fcode;
|
||||
db->max_ent = ++max_ent;
|
||||
|
||||
/* Update the length of this string. */
|
||||
lens1 = lens_ptr(db, max_ent);
|
||||
lens2 = lens_ptr(db, oldcode);
|
||||
*lens1 = *lens2 + 1;
|
||||
|
||||
/* Expand code size if needed. */
|
||||
if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
|
||||
db->n_bits = ++n_bits;
|
||||
tgtbitno = 32-n_bits;
|
||||
}
|
||||
}
|
||||
oldcode = incode;
|
||||
}
|
||||
|
||||
++db->comp_count;
|
||||
++db->uncomp_count;
|
||||
db->comp_bytes += skb_in->len - BSD_OVHD;
|
||||
db->uncomp_bytes += skb_out->len;
|
||||
|
||||
if (bsd_check(db)) {
|
||||
if (db->debug)
|
||||
printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n",
|
||||
db->unit, db->seqno - 1);
|
||||
}
|
||||
return skb_out->len;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Table of addresses for the BSD compression module
|
||||
*************************************************************/
|
||||
|
||||
static struct isdn_ppp_compressor ippp_bsd_compress = {
|
||||
.owner = THIS_MODULE,
|
||||
.num = CI_BSD_COMPRESS,
|
||||
.alloc = bsd_alloc,
|
||||
.free = bsd_free,
|
||||
.init = bsd_init,
|
||||
.reset = bsd_reset,
|
||||
.compress = bsd_compress,
|
||||
.decompress = bsd_decompress,
|
||||
.incomp = bsd_incomp,
|
||||
.stat = bsd_stats,
|
||||
};
|
||||
|
||||
/*************************************************************
|
||||
* Module support routines
|
||||
*************************************************************/
|
||||
|
||||
static int __init isdn_bsdcomp_init(void)
|
||||
{
|
||||
int answer = isdn_ppp_register_compressor(&ippp_bsd_compress);
|
||||
if (answer == 0)
|
||||
printk(KERN_INFO "PPP BSD Compression module registered\n");
|
||||
return answer;
|
||||
}
|
||||
|
||||
static void __exit isdn_bsdcomp_exit(void)
|
||||
{
|
||||
isdn_ppp_unregister_compressor(&ippp_bsd_compress);
|
||||
}
|
||||
|
||||
module_init(isdn_bsdcomp_init);
|
||||
module_exit(isdn_bsdcomp_exit);
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,47 +0,0 @@
|
|||
/* $Id: isdn_common.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem
|
||||
* common used functions and debugging-switches (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
|
||||
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#undef ISDN_DEBUG_MODEM_OPEN
|
||||
#undef ISDN_DEBUG_MODEM_IOCTL
|
||||
#undef ISDN_DEBUG_MODEM_WAITSENT
|
||||
#undef ISDN_DEBUG_MODEM_HUP
|
||||
#undef ISDN_DEBUG_MODEM_ICALL
|
||||
#undef ISDN_DEBUG_MODEM_DUMP
|
||||
#undef ISDN_DEBUG_MODEM_VOICE
|
||||
#undef ISDN_DEBUG_AT
|
||||
#undef ISDN_DEBUG_NET_DUMP
|
||||
#undef ISDN_DEBUG_NET_DIAL
|
||||
#undef ISDN_DEBUG_NET_ICALL
|
||||
|
||||
/* Prototypes */
|
||||
extern void isdn_lock_drivers(void);
|
||||
extern void isdn_unlock_drivers(void);
|
||||
extern void isdn_free_channel(int di, int ch, int usage);
|
||||
extern void isdn_all_eaz(int di, int ch);
|
||||
extern int isdn_command(isdn_ctrl *);
|
||||
extern int isdn_dc2minor(int di, int ch);
|
||||
extern void isdn_info_update(void);
|
||||
extern char *isdn_map_eaz2msn(char *msn, int di);
|
||||
extern void isdn_timer_ctrl(int tf, int onoff);
|
||||
extern void isdn_unexclusive_channel(int di, int ch);
|
||||
extern int isdn_getnum(char **);
|
||||
extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
|
||||
extern int isdn_readbchan_tty(int, int, struct tty_port *, int);
|
||||
extern int isdn_get_free_channel(int, int, int, int, int, char *);
|
||||
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
|
||||
extern int register_isdn(isdn_if *i);
|
||||
extern int isdn_msncmp(const char *, const char *);
|
||||
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
|
||||
extern void isdn_dumppkt(char *, u_char *, int, int);
|
||||
#endif
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
/* $Id: isdn_concap.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, protocol encapsulation
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
|
||||
* stuff goes here. Stuff that depends only on the concap protocol goes to
|
||||
* another -- protocol specific -- source file.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/isdn.h>
|
||||
#include "isdn_x25iface.h"
|
||||
#include "isdn_net.h"
|
||||
#include <linux/concap.h>
|
||||
#include "isdn_concap.h"
|
||||
|
||||
|
||||
/* The following set of device service operations are for encapsulation
|
||||
protocols that require for reliable datalink semantics. That means:
|
||||
|
||||
- before any data is to be submitted the connection must explicitly
|
||||
be set up.
|
||||
- after the successful set up of the connection is signalled the
|
||||
connection is considered to be reliably up.
|
||||
|
||||
Auto-dialing ist not compatible with this requirements. Thus, auto-dialing
|
||||
is completely bypassed.
|
||||
|
||||
It might be possible to implement a (non standardized) datalink protocol
|
||||
that provides a reliable data link service while using some auto dialing
|
||||
mechanism. Such a protocol would need an auxiliary channel (i.e. user-user-
|
||||
signaling on the D-channel) while the B-channel is down.
|
||||
*/
|
||||
|
||||
|
||||
static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *ndev = concap->net_dev;
|
||||
isdn_net_dev *nd = ((isdn_net_local *) netdev_priv(ndev))->netdev;
|
||||
isdn_net_local *lp = isdn_net_get_locked_lp(nd);
|
||||
|
||||
IX25DEBUG("isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
|
||||
if (!lp) {
|
||||
IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 1);
|
||||
return 1;
|
||||
}
|
||||
lp->huptimer = 0;
|
||||
isdn_net_writebuf_skb(lp, skb);
|
||||
spin_unlock_bh(&lp->xmit_lock);
|
||||
IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int isdn_concap_dl_connect_req(struct concap_proto *concap)
|
||||
{
|
||||
struct net_device *ndev = concap->net_dev;
|
||||
isdn_net_local *lp = netdev_priv(ndev);
|
||||
int ret;
|
||||
IX25DEBUG("isdn_concap_dl_connect_req: %s \n", ndev->name);
|
||||
|
||||
/* dial ... */
|
||||
ret = isdn_net_dial_req(lp);
|
||||
if (ret) IX25DEBUG("dialing failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isdn_concap_dl_disconn_req(struct concap_proto *concap)
|
||||
{
|
||||
IX25DEBUG("isdn_concap_dl_disconn_req: %s \n", concap->net_dev->name);
|
||||
|
||||
isdn_net_hangup(concap->net_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct concap_device_ops isdn_concap_reliable_dl_dops = {
|
||||
.data_req = &isdn_concap_dl_data_req,
|
||||
.connect_req = &isdn_concap_dl_connect_req,
|
||||
.disconn_req = &isdn_concap_dl_disconn_req
|
||||
};
|
||||
|
||||
/* The following should better go into a dedicated source file such that
|
||||
this sourcefile does not need to include any protocol specific header
|
||||
files. For now:
|
||||
*/
|
||||
struct concap_proto *isdn_concap_new(int encap)
|
||||
{
|
||||
switch (encap) {
|
||||
case ISDN_NET_ENCAP_X25IFACE:
|
||||
return isdn_x25iface_proto_new();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/* $Id: isdn_concap.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, protocol encapsulation
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
extern struct concap_device_ops isdn_concap_reliable_dl_dops;
|
||||
extern struct concap_proto *isdn_concap_new(int);
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,151 +0,0 @@
|
|||
/* $Id: isdn_net.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem, network related functions (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
|
||||
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Definitions for hupflags: */
|
||||
#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */
|
||||
#define ISDN_HAVECHARGE 2 /* We know a charge info */
|
||||
#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */
|
||||
#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */
|
||||
#define ISDN_MANCHARGE 16 /* Charge Interval manually set */
|
||||
|
||||
/*
|
||||
* Definitions for Cisco-HDLC header.
|
||||
*/
|
||||
|
||||
#define CISCO_ADDR_UNICAST 0x0f
|
||||
#define CISCO_ADDR_BROADCAST 0x8f
|
||||
#define CISCO_CTRL 0x00
|
||||
#define CISCO_TYPE_CDP 0x2000
|
||||
#define CISCO_TYPE_SLARP 0x8035
|
||||
#define CISCO_SLARP_REQUEST 0
|
||||
#define CISCO_SLARP_REPLY 1
|
||||
#define CISCO_SLARP_KEEPALIVE 2
|
||||
|
||||
extern char *isdn_net_new(char *, struct net_device *);
|
||||
extern char *isdn_net_newslave(char *);
|
||||
extern int isdn_net_rm(char *);
|
||||
extern int isdn_net_rmall(void);
|
||||
extern int isdn_net_stat_callback(int, isdn_ctrl *);
|
||||
extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
|
||||
extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
|
||||
extern int isdn_net_addphone(isdn_net_ioctl_phone *);
|
||||
extern int isdn_net_getphones(isdn_net_ioctl_phone *, char __user *);
|
||||
extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone __user *);
|
||||
extern int isdn_net_delphone(isdn_net_ioctl_phone *);
|
||||
extern int isdn_net_find_icall(int, int, int, setup_parm *);
|
||||
extern void isdn_net_hangup(struct net_device *);
|
||||
extern void isdn_net_dial(void);
|
||||
extern void isdn_net_autohup(void);
|
||||
extern int isdn_net_force_hangup(char *);
|
||||
extern int isdn_net_force_dial(char *);
|
||||
extern isdn_net_dev *isdn_net_findif(char *);
|
||||
extern int isdn_net_rcv_skb(int, struct sk_buff *);
|
||||
extern int isdn_net_dial_req(isdn_net_local *);
|
||||
extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
|
||||
extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
|
||||
|
||||
#define ISDN_NET_MAX_QUEUE_LENGTH 2
|
||||
|
||||
#define ISDN_MASTER_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->master))
|
||||
#define ISDN_SLAVE_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->slave))
|
||||
#define MASTER_TO_SLAVE(master) \
|
||||
(((isdn_net_local *) netdev_priv(master))->slave)
|
||||
|
||||
/*
|
||||
* is this particular channel busy?
|
||||
*/
|
||||
static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
|
||||
{
|
||||
if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the given net device, this will get a non-busy channel out of the
|
||||
* corresponding bundle. The returned channel is locked.
|
||||
*/
|
||||
static __inline__ isdn_net_local *isdn_net_get_locked_lp(isdn_net_dev *nd)
|
||||
{
|
||||
unsigned long flags;
|
||||
isdn_net_local *lp;
|
||||
|
||||
spin_lock_irqsave(&nd->queue_lock, flags);
|
||||
lp = nd->queue; /* get lp on top of queue */
|
||||
while (isdn_net_lp_busy(nd->queue)) {
|
||||
nd->queue = nd->queue->next;
|
||||
if (nd->queue == lp) { /* not found -- should never happen */
|
||||
lp = NULL;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
lp = nd->queue;
|
||||
nd->queue = nd->queue->next;
|
||||
spin_unlock_irqrestore(&nd->queue_lock, flags);
|
||||
spin_lock(&lp->xmit_lock);
|
||||
local_bh_disable();
|
||||
return lp;
|
||||
errout:
|
||||
spin_unlock_irqrestore(&nd->queue_lock, flags);
|
||||
return lp;
|
||||
}
|
||||
|
||||
/*
|
||||
* add a channel to a bundle
|
||||
*/
|
||||
static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
|
||||
{
|
||||
isdn_net_local *lp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&nd->queue_lock, flags);
|
||||
|
||||
lp = nd->queue;
|
||||
// printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n",
|
||||
// __func__, lp->name, lp, nlp->name, nlp, lp->last);
|
||||
nlp->last = lp->last;
|
||||
lp->last->next = nlp;
|
||||
lp->last = nlp;
|
||||
nlp->next = lp;
|
||||
nd->queue = nlp;
|
||||
|
||||
spin_unlock_irqrestore(&nd->queue_lock, flags);
|
||||
}
|
||||
/*
|
||||
* remove a channel from the bundle it belongs to
|
||||
*/
|
||||
static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
|
||||
{
|
||||
isdn_net_local *master_lp = lp;
|
||||
unsigned long flags;
|
||||
|
||||
if (lp->master)
|
||||
master_lp = ISDN_MASTER_PRIV(lp);
|
||||
|
||||
// printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
|
||||
// __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue);
|
||||
spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
|
||||
lp->last->next = lp->next;
|
||||
lp->next->last = lp->last;
|
||||
if (master_lp->netdev->queue == lp) {
|
||||
master_lp->netdev->queue = lp->next;
|
||||
if (lp->next == lp) { /* last in queue */
|
||||
master_lp->netdev->queue = master_lp->netdev->local;
|
||||
}
|
||||
}
|
||||
lp->next = lp->last = lp; /* (re)set own pointers */
|
||||
// printk(KERN_DEBUG "%s: mndq(%p)\n",
|
||||
// __func__, master_lp->netdev->queue);
|
||||
spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,41 +0,0 @@
|
|||
/* $Id: isdn_ppp.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
|
||||
*
|
||||
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
|
||||
#include <linux/isdn_ppp.h> /* for isdn_ppp info */
|
||||
|
||||
extern int isdn_ppp_read(int, struct file *, char __user *, int);
|
||||
extern int isdn_ppp_write(int, struct file *, const char __user *, int);
|
||||
extern int isdn_ppp_open(int, struct file *);
|
||||
extern int isdn_ppp_init(void);
|
||||
extern void isdn_ppp_cleanup(void);
|
||||
extern int isdn_ppp_free(isdn_net_local *);
|
||||
extern int isdn_ppp_bind(isdn_net_local *);
|
||||
extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *);
|
||||
extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
|
||||
extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
|
||||
extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
|
||||
extern __poll_t isdn_ppp_poll(struct file *, struct poll_table_struct *);
|
||||
extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
|
||||
extern void isdn_ppp_release(int, struct file *);
|
||||
extern int isdn_ppp_dial_slave(char *);
|
||||
extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
|
||||
|
||||
extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc);
|
||||
extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc);
|
||||
|
||||
#define IPPP_OPEN 0x01
|
||||
#define IPPP_CONNECT 0x02
|
||||
#define IPPP_CLOSEWAIT 0x04
|
||||
#define IPPP_NOBLOCK 0x08
|
||||
#define IPPP_ASSIGNED 0x10
|
||||
|
||||
#define IPPP_MAX_HEADER 10
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,120 +0,0 @@
|
|||
/* $Id: isdn_tty.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem, tty related functions (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define DLE 0x10
|
||||
#define ETX 0x03
|
||||
#define DC4 0x14
|
||||
|
||||
|
||||
/*
|
||||
* Definition of some special Registers of AT-Emulator
|
||||
*/
|
||||
#define REG_RINGATA 0
|
||||
#define REG_RINGCNT 1 /* ring counter register */
|
||||
#define REG_ESC 2
|
||||
#define REG_CR 3
|
||||
#define REG_LF 4
|
||||
#define REG_BS 5
|
||||
|
||||
#define REG_WAITC 7
|
||||
|
||||
#define REG_RESP 12 /* show response messages register */
|
||||
#define BIT_RESP 1 /* show response messages bit */
|
||||
#define REG_RESPNUM 12 /* show numeric responses register */
|
||||
#define BIT_RESPNUM 2 /* show numeric responses bit */
|
||||
#define REG_ECHO 12
|
||||
#define BIT_ECHO 4
|
||||
#define REG_DCD 12
|
||||
#define BIT_DCD 8
|
||||
#define REG_CTS 12
|
||||
#define BIT_CTS 16
|
||||
#define REG_DTRR 12
|
||||
#define BIT_DTRR 32
|
||||
#define REG_DSR 12
|
||||
#define BIT_DSR 64
|
||||
#define REG_CPPP 12
|
||||
#define BIT_CPPP 128
|
||||
|
||||
#define REG_DXMT 13
|
||||
#define BIT_DXMT 1
|
||||
#define REG_T70 13
|
||||
#define BIT_T70 2
|
||||
#define BIT_T70_EXT 32
|
||||
#define REG_DTRHUP 13
|
||||
#define BIT_DTRHUP 4
|
||||
#define REG_RESPXT 13
|
||||
#define BIT_RESPXT 8
|
||||
#define REG_CIDONCE 13
|
||||
#define BIT_CIDONCE 16
|
||||
#define REG_RUNG 13 /* show RUNG message register */
|
||||
#define BIT_RUNG 64 /* show RUNG message bit */
|
||||
#define REG_DISPLAY 13
|
||||
#define BIT_DISPLAY 128
|
||||
|
||||
#define REG_L2PROT 14
|
||||
#define REG_L3PROT 15
|
||||
#define REG_PSIZE 16
|
||||
#define REG_WSIZE 17
|
||||
#define REG_SI1 18
|
||||
#define REG_SI2 19
|
||||
#define REG_SI1I 20
|
||||
#define REG_PLAN 21
|
||||
#define REG_SCREEN 22
|
||||
|
||||
#define REG_CPN 23
|
||||
#define BIT_CPN 1
|
||||
#define REG_CPNFCON 23
|
||||
#define BIT_CPNFCON 2
|
||||
#define REG_CDN 23
|
||||
#define BIT_CDN 4
|
||||
|
||||
/* defines for result codes */
|
||||
#define RESULT_OK 0
|
||||
#define RESULT_CONNECT 1
|
||||
#define RESULT_RING 2
|
||||
#define RESULT_NO_CARRIER 3
|
||||
#define RESULT_ERROR 4
|
||||
#define RESULT_CONNECT64000 5
|
||||
#define RESULT_NO_DIALTONE 6
|
||||
#define RESULT_BUSY 7
|
||||
#define RESULT_NO_ANSWER 8
|
||||
#define RESULT_RINGING 9
|
||||
#define RESULT_NO_MSN_EAZ 10
|
||||
#define RESULT_VCON 11
|
||||
#define RESULT_RUNG 12
|
||||
|
||||
#define TTY_IS_FCLASS1(info) \
|
||||
((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
|
||||
(info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
|
||||
#define TTY_IS_FCLASS2(info) \
|
||||
((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
|
||||
(info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
|
||||
|
||||
extern void isdn_tty_modem_escape(void);
|
||||
extern void isdn_tty_modem_ring(void);
|
||||
extern void isdn_tty_carrier_timeout(void);
|
||||
extern void isdn_tty_modem_xmit(void);
|
||||
extern int isdn_tty_modem_init(void);
|
||||
extern void isdn_tty_exit(void);
|
||||
extern void isdn_tty_readmodem(void);
|
||||
extern int isdn_tty_find_icall(int, int, setup_parm *);
|
||||
extern int isdn_tty_stat_callback(int, isdn_ctrl *);
|
||||
extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
|
||||
extern int isdn_tty_capi_facility(capi_msg *cm);
|
||||
extern void isdn_tty_at_cout(char *, modem_info *);
|
||||
extern void isdn_tty_modem_hup(modem_info *, int);
|
||||
#ifdef CONFIG_ISDN_TTY_FAX
|
||||
extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
|
||||
extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
|
||||
extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,17 +0,0 @@
|
|||
/* $Id: isdn_ttyfax.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem, tty_fax related functions (linklevel).
|
||||
*
|
||||
* Copyright 1999 by Armin Schindler (mac@melware.de)
|
||||
* Copyright 1999 by Ralf Spachmann (mel@melware.de)
|
||||
* Copyright 1999 by Cytronics & Melware
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define XON 0x11
|
||||
#define XOFF 0x13
|
||||
#define DC2 0x12
|
||||
|
|
@ -1,625 +0,0 @@
|
|||
/* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, V.110 related functions (linklevel).
|
||||
*
|
||||
* Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/isdn.h>
|
||||
#include "isdn_v110.h"
|
||||
|
||||
#undef ISDN_V110_DEBUG
|
||||
|
||||
char *isdn_v110_revision = "$Revision: 1.1.2.2 $";
|
||||
|
||||
#define V110_38400 255
|
||||
#define V110_19200 15
|
||||
#define V110_9600 3
|
||||
|
||||
/*
|
||||
* The following data are precoded matrices, online and offline matrix
|
||||
* for 9600, 19200 und 38400, respectively
|
||||
*/
|
||||
static unsigned char V110_OnMatrix_9600[] =
|
||||
{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
|
||||
0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
|
||||
0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
|
||||
0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
|
||||
|
||||
static unsigned char V110_OffMatrix_9600[] =
|
||||
{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
static unsigned char V110_OnMatrix_19200[] =
|
||||
{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
|
||||
0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
|
||||
|
||||
static unsigned char V110_OffMatrix_19200[] =
|
||||
{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
static unsigned char V110_OnMatrix_38400[] =
|
||||
{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
|
||||
|
||||
static unsigned char V110_OffMatrix_38400[] =
|
||||
{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
/*
|
||||
* FlipBits reorders sequences of keylen bits in one byte.
|
||||
* E.g. source order 7654321 will be converted to 45670123 when keylen = 4,
|
||||
* and to 67452301 when keylen = 2. This is necessary because ordering on
|
||||
* the isdn line is the other way.
|
||||
*/
|
||||
static inline unsigned char
|
||||
FlipBits(unsigned char c, int keylen)
|
||||
{
|
||||
unsigned char b = c;
|
||||
unsigned char bit = 128;
|
||||
int i;
|
||||
int j;
|
||||
int hunks = (8 / keylen);
|
||||
|
||||
c = 0;
|
||||
for (i = 0; i < hunks; i++) {
|
||||
for (j = 0; j < keylen; j++) {
|
||||
if (b & (bit >> j))
|
||||
c |= bit >> (keylen - j - 1);
|
||||
}
|
||||
bit >>= keylen;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/* isdn_v110_open allocates and initializes private V.110 data
|
||||
* structures and returns a pointer to these.
|
||||
*/
|
||||
static isdn_v110_stream *
|
||||
isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
|
||||
{
|
||||
int i;
|
||||
isdn_v110_stream *v;
|
||||
|
||||
if ((v = kzalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
|
||||
return NULL;
|
||||
v->key = key;
|
||||
v->nbits = 0;
|
||||
for (i = 0; key & (1 << i); i++)
|
||||
v->nbits++;
|
||||
|
||||
v->nbytes = 8 / v->nbits;
|
||||
v->decodelen = 0;
|
||||
|
||||
switch (key) {
|
||||
case V110_38400:
|
||||
v->OnlineFrame = V110_OnMatrix_38400;
|
||||
v->OfflineFrame = V110_OffMatrix_38400;
|
||||
break;
|
||||
case V110_19200:
|
||||
v->OnlineFrame = V110_OnMatrix_19200;
|
||||
v->OfflineFrame = V110_OffMatrix_19200;
|
||||
break;
|
||||
default:
|
||||
v->OnlineFrame = V110_OnMatrix_9600;
|
||||
v->OfflineFrame = V110_OffMatrix_9600;
|
||||
break;
|
||||
}
|
||||
v->framelen = v->nbytes * 10;
|
||||
v->SyncInit = 5;
|
||||
v->introducer = 0;
|
||||
v->dbit = 1;
|
||||
v->b = 0;
|
||||
v->skbres = hdrlen;
|
||||
v->maxsize = maxsize - hdrlen;
|
||||
if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) {
|
||||
kfree(v);
|
||||
return NULL;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/* isdn_v110_close frees private V.110 data structures */
|
||||
void
|
||||
isdn_v110_close(isdn_v110_stream *v)
|
||||
{
|
||||
if (v == NULL)
|
||||
return;
|
||||
#ifdef ISDN_V110_DEBUG
|
||||
printk(KERN_DEBUG "v110 close\n");
|
||||
#endif
|
||||
kfree(v->encodebuf);
|
||||
kfree(v);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ValidHeaderBytes return the number of valid bytes in v->decodebuf
|
||||
*/
|
||||
static int
|
||||
ValidHeaderBytes(isdn_v110_stream *v)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; (i < v->decodelen) && (i < v->nbytes); i++)
|
||||
if ((v->decodebuf[i] & v->key) != 0)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* SyncHeader moves the decodebuf ptr to the next valid header
|
||||
*/
|
||||
static void
|
||||
SyncHeader(isdn_v110_stream *v)
|
||||
{
|
||||
unsigned char *rbuf = v->decodebuf;
|
||||
int len = v->decodelen;
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
for (rbuf++, len--; len > 0; len--, rbuf++) /* such den SyncHeader in buf ! */
|
||||
if ((*rbuf & v->key) == 0) /* erstes byte gefunden ? */
|
||||
break; /* jupp! */
|
||||
if (len)
|
||||
memcpy(v->decodebuf, rbuf, len);
|
||||
|
||||
v->decodelen = len;
|
||||
#ifdef ISDN_V110_DEBUG
|
||||
printk(KERN_DEBUG "isdn_v110: Header resync\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
|
||||
len is the number of matrix-lines. len must be a multiple of 10, i.e.
|
||||
only complete matices must be given.
|
||||
From these, netto data is extracted and returned in buf. The return-value
|
||||
is the bytecount of the decoded data.
|
||||
*/
|
||||
static int
|
||||
DecodeMatrix(isdn_v110_stream *v, unsigned char *m, int len, unsigned char *buf)
|
||||
{
|
||||
int line = 0;
|
||||
int buflen = 0;
|
||||
int mbit = 64;
|
||||
int introducer = v->introducer;
|
||||
int dbit = v->dbit;
|
||||
unsigned char b = v->b;
|
||||
|
||||
while (line < len) { /* Are we done with all lines of the matrix? */
|
||||
if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */
|
||||
if (m[line] != 0x00) { /* not 0 ? -> error! */
|
||||
#ifdef ISDN_V110_DEBUG
|
||||
printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
|
||||
/* returning now is not the right thing, though :-( */
|
||||
#endif
|
||||
}
|
||||
line++; /* next line of matrix */
|
||||
continue;
|
||||
} else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */
|
||||
if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */
|
||||
#ifdef ISDN_V110_DEBUG
|
||||
printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
|
||||
/* returning now is not the right thing, though :-( */
|
||||
#endif
|
||||
}
|
||||
line++; /* next line */
|
||||
continue;
|
||||
} else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */
|
||||
introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */
|
||||
next_byte:
|
||||
if (mbit > 2) { /* was it the last bit in this line ? */
|
||||
mbit >>= 1; /* no -> take next */
|
||||
continue;
|
||||
} /* otherwise start with leftmost bit in the next line */
|
||||
mbit = 64;
|
||||
line++;
|
||||
continue;
|
||||
} else { /* otherwise we need to set a data bit */
|
||||
if (m[line] & mbit) /* was that bit set in the matrix ? */
|
||||
b |= dbit; /* yes -> set it in the data byte */
|
||||
else
|
||||
b &= dbit - 1; /* no -> clear it in the data byte */
|
||||
if (dbit < 128) /* is that data byte done ? */
|
||||
dbit <<= 1; /* no, got the next bit */
|
||||
else { /* data byte is done */
|
||||
buf[buflen++] = b; /* copy byte into the output buffer */
|
||||
introducer = b = 0; /* init of the intro sequence and of the data byte */
|
||||
dbit = 1; /* next we look for the 0th bit */
|
||||
}
|
||||
goto next_byte; /* look for next bit in the matrix */
|
||||
}
|
||||
}
|
||||
v->introducer = introducer;
|
||||
v->dbit = dbit;
|
||||
v->b = b;
|
||||
return buflen; /* return number of bytes in the output buffer */
|
||||
}
|
||||
|
||||
/*
|
||||
* DecodeStream receives V.110 coded data from the input stream. It recovers the
|
||||
* original frames.
|
||||
* The input stream doesn't need to be framed
|
||||
*/
|
||||
struct sk_buff *
|
||||
isdn_v110_decode(isdn_v110_stream *v, struct sk_buff *skb)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int len;
|
||||
unsigned char *v110_buf;
|
||||
unsigned char *rbuf;
|
||||
|
||||
if (!skb) {
|
||||
printk(KERN_WARNING "isdn_v110_decode called with NULL skb!\n");
|
||||
return NULL;
|
||||
}
|
||||
rbuf = skb->data;
|
||||
len = skb->len;
|
||||
if (v == NULL) {
|
||||
/* invalid handle, no chance to proceed */
|
||||
printk(KERN_WARNING "isdn_v110_decode called with NULL stream!\n");
|
||||
dev_kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
if (v->decodelen == 0) /* cache empty? */
|
||||
for (; len > 0; len--, rbuf++) /* scan for SyncHeader in buf */
|
||||
if ((*rbuf & v->key) == 0)
|
||||
break; /* found first byte */
|
||||
if (len == 0) {
|
||||
dev_kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
/* copy new data to decode-buffer */
|
||||
memcpy(&(v->decodebuf[v->decodelen]), rbuf, len);
|
||||
v->decodelen += len;
|
||||
ReSync:
|
||||
if (v->decodelen < v->nbytes) { /* got a new header ? */
|
||||
dev_kfree_skb(skb);
|
||||
return NULL; /* no, try later */
|
||||
}
|
||||
if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */
|
||||
SyncHeader(v); /* no -> look for header */
|
||||
goto ReSync;
|
||||
}
|
||||
len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
|
||||
if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) {
|
||||
printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n");
|
||||
dev_kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
v110_buf[i] = 0;
|
||||
for (j = 0; j < v->nbytes; j++)
|
||||
v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits));
|
||||
v110_buf[i] = FlipBits(v110_buf[i], v->nbits);
|
||||
}
|
||||
v->decodelen = (v->decodelen % (10 * v->nbytes));
|
||||
memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen);
|
||||
|
||||
skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data));
|
||||
kfree(v110_buf);
|
||||
if (skb->len)
|
||||
return skb;
|
||||
else {
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* EncodeMatrix takes input data in buf, len is the bytecount.
|
||||
Data is encoded into v110 frames in m. Return value is the number of
|
||||
matrix-lines generated.
|
||||
*/
|
||||
static int
|
||||
EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
|
||||
{
|
||||
int line = 0;
|
||||
int i = 0;
|
||||
int mbit = 128;
|
||||
int dbit = 1;
|
||||
int introducer = 3;
|
||||
int ibit[] = {0, 1, 1};
|
||||
|
||||
while ((i < len) && (line < mlen)) { /* while we still have input data */
|
||||
switch (line % 10) { /* in which line of the matrix are we? */
|
||||
case 0:
|
||||
m[line++] = 0x00; /* line 0 is always 0 */
|
||||
mbit = 128; /* go on with the 7th bit */
|
||||
break;
|
||||
case 5:
|
||||
m[line++] = 0xbf; /* line 5 is always 10111111 */
|
||||
mbit = 128; /* go on with the 7th bit */
|
||||
break;
|
||||
}
|
||||
if (line >= mlen) {
|
||||
printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
|
||||
return line;
|
||||
}
|
||||
next_bit:
|
||||
switch (mbit) { /* leftmost or rightmost bit ? */
|
||||
case 1:
|
||||
line++; /* rightmost -> go to next line */
|
||||
if (line >= mlen) {
|
||||
printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
|
||||
return line;
|
||||
}
|
||||
/* fall through */
|
||||
case 128:
|
||||
m[line] = 128; /* leftmost -> set byte to 1000000 */
|
||||
mbit = 64; /* current bit in the matrix line */
|
||||
continue;
|
||||
}
|
||||
if (introducer) { /* set 110 sequence ? */
|
||||
introducer--; /* set on digit less */
|
||||
m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */
|
||||
mbit >>= 1; /* bit of matrix line >> 1 */
|
||||
goto next_bit; /* and go on there */
|
||||
} /* else push data bits into the matrix! */
|
||||
m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */
|
||||
if (dbit == 128) { /* was it the last one? */
|
||||
dbit = 1; /* then go on with first bit of */
|
||||
i++; /* next byte in input buffer */
|
||||
if (i < len) /* input buffer done ? */
|
||||
introducer = 3; /* no, write introducer 110 */
|
||||
else { /* input buffer done ! */
|
||||
m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */
|
||||
break;
|
||||
}
|
||||
} else /* not the last data bit */
|
||||
dbit <<= 1; /* then go to next data bit */
|
||||
mbit >>= 1; /* go to next bit of matrix */
|
||||
goto next_bit;
|
||||
|
||||
}
|
||||
/* if necessary, generate remaining lines of the matrix... */
|
||||
if ((line) && ((line + 10) < mlen))
|
||||
switch (++line % 10) {
|
||||
case 1:
|
||||
m[line++] = 0xfe;
|
||||
/* fall through */
|
||||
case 2:
|
||||
m[line++] = 0xfe;
|
||||
/* fall through */
|
||||
case 3:
|
||||
m[line++] = 0xfe;
|
||||
/* fall through */
|
||||
case 4:
|
||||
m[line++] = 0xfe;
|
||||
/* fall through */
|
||||
case 5:
|
||||
m[line++] = 0xbf;
|
||||
/* fall through */
|
||||
case 6:
|
||||
m[line++] = 0xfe;
|
||||
/* fall through */
|
||||
case 7:
|
||||
m[line++] = 0xfe;
|
||||
/* fall through */
|
||||
case 8:
|
||||
m[line++] = 0xfe;
|
||||
/* fall through */
|
||||
case 9:
|
||||
m[line++] = 0xfe;
|
||||
}
|
||||
return line; /* that's how many lines we have */
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a sync frame.
|
||||
*/
|
||||
static struct sk_buff *
|
||||
isdn_v110_sync(isdn_v110_stream *v)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (v == NULL) {
|
||||
/* invalid handle, no chance to proceed */
|
||||
printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
|
||||
return NULL;
|
||||
}
|
||||
if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
|
||||
skb_reserve(skb, v->skbres);
|
||||
skb_put_data(skb, v->OfflineFrame, v->framelen);
|
||||
}
|
||||
return skb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build an idle frame.
|
||||
*/
|
||||
static struct sk_buff *
|
||||
isdn_v110_idle(isdn_v110_stream *v)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (v == NULL) {
|
||||
/* invalid handle, no chance to proceed */
|
||||
printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
|
||||
return NULL;
|
||||
}
|
||||
if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
|
||||
skb_reserve(skb, v->skbres);
|
||||
skb_put_data(skb, v->OnlineFrame, v->framelen);
|
||||
}
|
||||
return skb;
|
||||
}
|
||||
|
||||
struct sk_buff *
|
||||
isdn_v110_encode(isdn_v110_stream *v, struct sk_buff *skb)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int rlen;
|
||||
int mlen;
|
||||
int olen;
|
||||
int size;
|
||||
int sval1;
|
||||
int sval2;
|
||||
int nframes;
|
||||
unsigned char *v110buf;
|
||||
unsigned char *rbuf;
|
||||
struct sk_buff *nskb;
|
||||
|
||||
if (v == NULL) {
|
||||
/* invalid handle, no chance to proceed */
|
||||
printk(KERN_WARNING "isdn_v110_encode called with NULL stream!\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!skb) {
|
||||
/* invalid skb, no chance to proceed */
|
||||
printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n");
|
||||
return NULL;
|
||||
}
|
||||
rlen = skb->len;
|
||||
nframes = (rlen + 3) / 4;
|
||||
v110buf = v->encodebuf;
|
||||
if ((nframes * 40) > v->maxsize) {
|
||||
size = v->maxsize;
|
||||
rlen = v->maxsize / 40;
|
||||
} else
|
||||
size = nframes * 40;
|
||||
if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) {
|
||||
printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n");
|
||||
return NULL;
|
||||
}
|
||||
skb_reserve(nskb, v->skbres + sizeof(int));
|
||||
if (skb->len == 0) {
|
||||
skb_put_data(nskb, v->OnlineFrame, v->framelen);
|
||||
*((int *)skb_push(nskb, sizeof(int))) = 0;
|
||||
return nskb;
|
||||
}
|
||||
mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
|
||||
/* now distribute 2 or 4 bits each to the output stream! */
|
||||
rbuf = skb_put(nskb, size);
|
||||
olen = 0;
|
||||
sval1 = 8 - v->nbits;
|
||||
sval2 = v->key << sval1;
|
||||
for (i = 0; i < mlen; i++) {
|
||||
v110buf[i] = FlipBits(v110buf[i], v->nbits);
|
||||
for (j = 0; j < v->nbytes; j++) {
|
||||
if (size--)
|
||||
*rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1);
|
||||
else {
|
||||
printk(KERN_WARNING "isdn_v110_encode: buffers full!\n");
|
||||
goto buffer_full;
|
||||
}
|
||||
olen++;
|
||||
}
|
||||
}
|
||||
buffer_full:
|
||||
skb_trim(nskb, olen);
|
||||
*((int *)skb_push(nskb, sizeof(int))) = rlen;
|
||||
return nskb;
|
||||
}
|
||||
|
||||
int
|
||||
isdn_v110_stat_callback(int idx, isdn_ctrl *c)
|
||||
{
|
||||
isdn_v110_stream *v = NULL;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if (idx < 0)
|
||||
return 0;
|
||||
switch (c->command) {
|
||||
case ISDN_STAT_BSENT:
|
||||
/* Keep the send-queue of the driver filled
|
||||
* with frames:
|
||||
* If number of outstanding frames < 3,
|
||||
* send down an Idle-Frame (or an Sync-Frame, if
|
||||
* v->SyncInit != 0).
|
||||
*/
|
||||
if (!(v = dev->v110[idx]))
|
||||
return 0;
|
||||
atomic_inc(&dev->v110use[idx]);
|
||||
for (i = 0; i * v->framelen < c->parm.length; i++) {
|
||||
if (v->skbidle > 0) {
|
||||
v->skbidle--;
|
||||
ret = 1;
|
||||
} else {
|
||||
if (v->skbuser > 0)
|
||||
v->skbuser--;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
for (i = v->skbuser + v->skbidle; i < 2; i++) {
|
||||
struct sk_buff *skb;
|
||||
if (v->SyncInit > 0)
|
||||
skb = isdn_v110_sync(v);
|
||||
else
|
||||
skb = isdn_v110_idle(v);
|
||||
if (skb) {
|
||||
if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
} else {
|
||||
if (v->SyncInit)
|
||||
v->SyncInit--;
|
||||
v->skbidle++;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
atomic_dec(&dev->v110use[idx]);
|
||||
return ret;
|
||||
case ISDN_STAT_DHUP:
|
||||
case ISDN_STAT_BHUP:
|
||||
while (1) {
|
||||
atomic_inc(&dev->v110use[idx]);
|
||||
if (atomic_dec_and_test(&dev->v110use[idx])) {
|
||||
isdn_v110_close(dev->v110[idx]);
|
||||
dev->v110[idx] = NULL;
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
break;
|
||||
case ISDN_STAT_BCONN:
|
||||
if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
|
||||
int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
|
||||
int maxsize = dev->drv[c->driver]->interface->maxbufsize;
|
||||
atomic_inc(&dev->v110use[idx]);
|
||||
switch (dev->v110emu[idx]) {
|
||||
case ISDN_PROTO_L2_V11096:
|
||||
dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
|
||||
break;
|
||||
case ISDN_PROTO_L2_V11019:
|
||||
dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
|
||||
break;
|
||||
case ISDN_PROTO_L2_V11038:
|
||||
dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
if ((v = dev->v110[idx])) {
|
||||
while (v->SyncInit) {
|
||||
struct sk_buff *skb = isdn_v110_sync(v);
|
||||
if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
|
||||
dev_kfree_skb(skb);
|
||||
/* Unable to send, try later */
|
||||
break;
|
||||
}
|
||||
v->SyncInit--;
|
||||
v->skbidle++;
|
||||
}
|
||||
} else
|
||||
printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
|
||||
atomic_dec(&dev->v110use[idx]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/* $Id: isdn_v110.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, V.110 related functions (linklevel).
|
||||
*
|
||||
* Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _isdn_v110_h_
|
||||
#define _isdn_v110_h_
|
||||
|
||||
/*
|
||||
* isdn_v110_encode will take raw data and encode it using V.110
|
||||
*/
|
||||
extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
|
||||
|
||||
/*
|
||||
* isdn_v110_decode receives V.110 coded data from the stream and rebuilds
|
||||
* frames from them. The source stream doesn't need to be framed.
|
||||
*/
|
||||
extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
|
||||
|
||||
extern int isdn_v110_stat_callback(int, isdn_ctrl *);
|
||||
extern void isdn_v110_close(isdn_v110_stream *v);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,332 +0,0 @@
|
|||
/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* Linux ISDN subsystem, X.25 related functions
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
* stuff needed to support the Linux X.25 PLP code on top of devices that
|
||||
* can provide a lab_b service using the concap_proto mechanism.
|
||||
* This module supports a network interface which provides lapb_sematics
|
||||
* -- as defined in Documentation/networking/x25-iface.txt -- to
|
||||
* the upper layer and assumes that the lower layer provides a reliable
|
||||
* data link service by means of the concap_device_ops callbacks.
|
||||
*
|
||||
* Only protocol specific stuff goes here. Device specific stuff
|
||||
* goes to another -- device related -- concap_proto support source file.
|
||||
*
|
||||
*/
|
||||
|
||||
/* #include <linux/isdn.h> */
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/concap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wanrouter.h>
|
||||
#include <net/x25device.h>
|
||||
#include "isdn_x25iface.h"
|
||||
|
||||
/* for debugging messages not to cause an oops when device pointer is NULL*/
|
||||
#define MY_DEVNAME(dev) ((dev) ? (dev)->name : "DEVICE UNSPECIFIED")
|
||||
|
||||
|
||||
typedef struct isdn_x25iface_proto_data {
|
||||
int magic;
|
||||
enum wan_states state;
|
||||
/* Private stuff, not to be accessed via proto_data. We provide the
|
||||
other storage for the concap_proto instance here as well,
|
||||
enabling us to allocate both with just one kmalloc(): */
|
||||
struct concap_proto priv;
|
||||
} ix25_pdata_t;
|
||||
|
||||
|
||||
|
||||
/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
|
||||
static void isdn_x25iface_proto_del(struct concap_proto *);
|
||||
static int isdn_x25iface_proto_close(struct concap_proto *);
|
||||
static int isdn_x25iface_proto_restart(struct concap_proto *,
|
||||
struct net_device *,
|
||||
struct concap_device_ops *);
|
||||
static int isdn_x25iface_xmit(struct concap_proto *, struct sk_buff *);
|
||||
static int isdn_x25iface_receive(struct concap_proto *, struct sk_buff *);
|
||||
static int isdn_x25iface_connect_ind(struct concap_proto *);
|
||||
static int isdn_x25iface_disconn_ind(struct concap_proto *);
|
||||
|
||||
|
||||
static struct concap_proto_ops ix25_pops = {
|
||||
.proto_new = &isdn_x25iface_proto_new,
|
||||
.proto_del = &isdn_x25iface_proto_del,
|
||||
.restart = &isdn_x25iface_proto_restart,
|
||||
.close = &isdn_x25iface_proto_close,
|
||||
.encap_and_xmit = &isdn_x25iface_xmit,
|
||||
.data_ind = &isdn_x25iface_receive,
|
||||
.connect_ind = &isdn_x25iface_connect_ind,
|
||||
.disconn_ind = &isdn_x25iface_disconn_ind
|
||||
};
|
||||
|
||||
/* error message helper function */
|
||||
static void illegal_state_warn(unsigned state, unsigned char firstbyte)
|
||||
{
|
||||
printk(KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
|
||||
"current state %d\n", firstbyte, state);
|
||||
}
|
||||
|
||||
/* check protocol data field for consistency */
|
||||
static int pdata_is_bad(ix25_pdata_t *pda) {
|
||||
|
||||
if (pda && pda->magic == ISDN_X25IFACE_MAGIC) return 0;
|
||||
printk(KERN_WARNING
|
||||
"isdn_x25iface_xxx: illegal pointer to proto data\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* create a new x25 interface protocol instance
|
||||
*/
|
||||
struct concap_proto *isdn_x25iface_proto_new(void)
|
||||
{
|
||||
ix25_pdata_t *tmp = kmalloc(sizeof(ix25_pdata_t), GFP_KERNEL);
|
||||
IX25DEBUG("isdn_x25iface_proto_new\n");
|
||||
if (tmp) {
|
||||
tmp->magic = ISDN_X25IFACE_MAGIC;
|
||||
tmp->state = WAN_UNCONFIGURED;
|
||||
/* private data space used to hold the concap_proto data.
|
||||
Only to be accessed via the returned pointer */
|
||||
spin_lock_init(&tmp->priv.lock);
|
||||
tmp->priv.dops = NULL;
|
||||
tmp->priv.net_dev = NULL;
|
||||
tmp->priv.pops = &ix25_pops;
|
||||
tmp->priv.flags = 0;
|
||||
tmp->priv.proto_data = tmp;
|
||||
return (&(tmp->priv));
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
/* close the x25iface encapsulation protocol
|
||||
*/
|
||||
static int isdn_x25iface_proto_close(struct concap_proto *cprot) {
|
||||
|
||||
ix25_pdata_t *tmp;
|
||||
int ret = 0;
|
||||
ulong flags;
|
||||
|
||||
if (!cprot) {
|
||||
printk(KERN_ERR "isdn_x25iface_proto_close: "
|
||||
"invalid concap_proto pointer\n");
|
||||
return -1;
|
||||
}
|
||||
IX25DEBUG("isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot->net_dev));
|
||||
spin_lock_irqsave(&cprot->lock, flags);
|
||||
cprot->dops = NULL;
|
||||
cprot->net_dev = NULL;
|
||||
tmp = cprot->proto_data;
|
||||
if (pdata_is_bad(tmp)) {
|
||||
ret = -1;
|
||||
} else {
|
||||
tmp->state = WAN_UNCONFIGURED;
|
||||
}
|
||||
spin_unlock_irqrestore(&cprot->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Delete the x25iface encapsulation protocol instance
|
||||
*/
|
||||
static void isdn_x25iface_proto_del(struct concap_proto *cprot) {
|
||||
|
||||
ix25_pdata_t *tmp;
|
||||
|
||||
IX25DEBUG("isdn_x25iface_proto_del \n");
|
||||
if (!cprot) {
|
||||
printk(KERN_ERR "isdn_x25iface_proto_del: "
|
||||
"concap_proto pointer is NULL\n");
|
||||
return;
|
||||
}
|
||||
tmp = cprot->proto_data;
|
||||
if (tmp == NULL) {
|
||||
printk(KERN_ERR "isdn_x25iface_proto_del: inconsistent "
|
||||
"proto_data pointer (maybe already deleted?)\n");
|
||||
return;
|
||||
}
|
||||
/* close if the protocol is still open */
|
||||
if (cprot->dops) isdn_x25iface_proto_close(cprot);
|
||||
/* freeing the storage should be sufficient now. But some additional
|
||||
settings might help to catch wild pointer bugs */
|
||||
tmp->magic = 0;
|
||||
cprot->proto_data = NULL;
|
||||
|
||||
kfree(tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* (re-)initialize the data structures for x25iface encapsulation
|
||||
*/
|
||||
static int isdn_x25iface_proto_restart(struct concap_proto *cprot,
|
||||
struct net_device *ndev,
|
||||
struct concap_device_ops *dops)
|
||||
{
|
||||
ix25_pdata_t *pda = cprot->proto_data;
|
||||
ulong flags;
|
||||
|
||||
IX25DEBUG("isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev));
|
||||
|
||||
if (pdata_is_bad(pda)) return -1;
|
||||
|
||||
if (!(dops && dops->data_req && dops->connect_req
|
||||
&& dops->disconn_req)) {
|
||||
printk(KERN_WARNING "isdn_x25iface_restart: required dops"
|
||||
" missing\n");
|
||||
isdn_x25iface_proto_close(cprot);
|
||||
return -1;
|
||||
}
|
||||
spin_lock_irqsave(&cprot->lock, flags);
|
||||
cprot->net_dev = ndev;
|
||||
cprot->pops = &ix25_pops;
|
||||
cprot->dops = dops;
|
||||
pda->state = WAN_DISCONNECTED;
|
||||
spin_unlock_irqrestore(&cprot->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* deliver a dl_data frame received from i4l HL driver to the network layer
|
||||
*/
|
||||
static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
|
||||
{
|
||||
IX25DEBUG("isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev));
|
||||
if (((ix25_pdata_t *)(cprot->proto_data))
|
||||
->state == WAN_CONNECTED) {
|
||||
if (skb_push(skb, 1)) {
|
||||
skb->data[0] = X25_IFACE_DATA;
|
||||
skb->protocol = x25_type_trans(skb, cprot->net_dev);
|
||||
netif_rx(skb);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev));
|
||||
dev_kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* a connection set up is indicated by lower layer
|
||||
*/
|
||||
static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
enum wan_states *state_p
|
||||
= &(((ix25_pdata_t *)(cprot->proto_data))->state);
|
||||
IX25DEBUG("isdn_x25iface_connect_ind %s \n"
|
||||
, MY_DEVNAME(cprot->net_dev));
|
||||
if (*state_p == WAN_UNCONFIGURED) {
|
||||
printk(KERN_WARNING
|
||||
"isdn_x25iface_connect_ind while unconfigured %s\n"
|
||||
, MY_DEVNAME(cprot->net_dev));
|
||||
return -1;
|
||||
}
|
||||
*state_p = WAN_CONNECTED;
|
||||
|
||||
skb = dev_alloc_skb(1);
|
||||
if (skb) {
|
||||
skb_put_u8(skb, X25_IFACE_CONNECT);
|
||||
skb->protocol = x25_type_trans(skb, cprot->net_dev);
|
||||
netif_rx(skb);
|
||||
return 0;
|
||||
} else {
|
||||
printk(KERN_WARNING "isdn_x25iface_connect_ind: "
|
||||
" out of memory -- disconnecting\n");
|
||||
cprot->dops->disconn_req(cprot);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* a disconnect is indicated by lower layer
|
||||
*/
|
||||
static int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
enum wan_states *state_p
|
||||
= &(((ix25_pdata_t *)(cprot->proto_data))->state);
|
||||
IX25DEBUG("isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot->net_dev));
|
||||
if (*state_p == WAN_UNCONFIGURED) {
|
||||
printk(KERN_WARNING
|
||||
"isdn_x25iface_disconn_ind while unconfigured\n");
|
||||
return -1;
|
||||
}
|
||||
if (!cprot->net_dev) return -1;
|
||||
*state_p = WAN_DISCONNECTED;
|
||||
skb = dev_alloc_skb(1);
|
||||
if (skb) {
|
||||
skb_put_u8(skb, X25_IFACE_DISCONNECT);
|
||||
skb->protocol = x25_type_trans(skb, cprot->net_dev);
|
||||
netif_rx(skb);
|
||||
return 0;
|
||||
} else {
|
||||
printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
|
||||
" out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* process a frame handed over to us from linux network layer. First byte
|
||||
semantics as defined in Documentation/networking/x25-iface.txt
|
||||
*/
|
||||
static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
|
||||
{
|
||||
unsigned char firstbyte = skb->data[0];
|
||||
enum wan_states *state = &((ix25_pdata_t *)cprot->proto_data)->state;
|
||||
int ret = 0;
|
||||
IX25DEBUG("isdn_x25iface_xmit: %s first=%x state=%d\n",
|
||||
MY_DEVNAME(cprot->net_dev), firstbyte, *state);
|
||||
switch (firstbyte) {
|
||||
case X25_IFACE_DATA:
|
||||
if (*state == WAN_CONNECTED) {
|
||||
skb_pull(skb, 1);
|
||||
netif_trans_update(cprot->net_dev);
|
||||
ret = (cprot->dops->data_req(cprot, skb));
|
||||
/* prepare for future retransmissions */
|
||||
if (ret) skb_push(skb, 1);
|
||||
return ret;
|
||||
}
|
||||
illegal_state_warn(*state, firstbyte);
|
||||
break;
|
||||
case X25_IFACE_CONNECT:
|
||||
if (*state == WAN_DISCONNECTED) {
|
||||
*state = WAN_CONNECTING;
|
||||
ret = cprot->dops->connect_req(cprot);
|
||||
if (ret) {
|
||||
/* reset state and notify upper layer about
|
||||
* immidiatly failed attempts */
|
||||
isdn_x25iface_disconn_ind(cprot);
|
||||
}
|
||||
} else {
|
||||
illegal_state_warn(*state, firstbyte);
|
||||
}
|
||||
break;
|
||||
case X25_IFACE_DISCONNECT:
|
||||
switch (*state) {
|
||||
case WAN_DISCONNECTED:
|
||||
/* Should not happen. However, give upper layer a
|
||||
chance to recover from inconstistency but don't
|
||||
trust the lower layer sending the disconn_confirm
|
||||
when already disconnected */
|
||||
printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
|
||||
" requested while disconnected\n");
|
||||
isdn_x25iface_disconn_ind(cprot);
|
||||
break; /* prevent infinite loops */
|
||||
case WAN_CONNECTING:
|
||||
case WAN_CONNECTED:
|
||||
*state = WAN_DISCONNECTED;
|
||||
cprot->dops->disconn_req(cprot);
|
||||
break;
|
||||
default:
|
||||
illegal_state_warn(*state, firstbyte);
|
||||
}
|
||||
break;
|
||||
case X25_IFACE_PARAMS:
|
||||
printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
|
||||
" options not yet supported\n");
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
|
||||
" first byte %x ignored:\n", firstbyte);
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/* $Id: isdn_x25iface.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
|
||||
*
|
||||
* header for Linux ISDN subsystem, x.25 related functions
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_ISDN_X25IFACE_H
|
||||
#define _LINUX_ISDN_X25IFACE_H
|
||||
|
||||
#define ISDN_X25IFACE_MAGIC 0x1e75a2b9
|
||||
/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */
|
||||
#ifdef DEBUG_ISDN_X25
|
||||
# define IX25DEBUG(fmt, args...) printk(KERN_DEBUG fmt, ##args)
|
||||
#else
|
||||
# define IX25DEBUG(fmt, args...)
|
||||
#endif
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/isdn.h>
|
||||
#include <linux/concap.h>
|
||||
|
||||
extern struct concap_proto_ops *isdn_x25iface_concap_proto_ops_pt;
|
||||
extern struct concap_proto *isdn_x25iface_proto_new(void);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Makefile for the isdnloop ISDN device driver
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop.o
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,112 +0,0 @@
|
|||
/* $Id: isdnloop.h,v 1.5.6.3 2001/09/23 22:24:56 kai Exp $
|
||||
*
|
||||
* Loopback lowlevel module for testing of linklevel.
|
||||
*
|
||||
* Copyright 1997 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef isdnloop_h
|
||||
#define isdnloop_h
|
||||
|
||||
#define ISDNLOOP_IOCTL_DEBUGVAR 0
|
||||
#define ISDNLOOP_IOCTL_ADDCARD 1
|
||||
#define ISDNLOOP_IOCTL_LEASEDCFG 2
|
||||
#define ISDNLOOP_IOCTL_STARTUP 3
|
||||
|
||||
/* Struct for adding new cards */
|
||||
typedef struct isdnloop_cdef {
|
||||
char id1[10];
|
||||
} isdnloop_cdef;
|
||||
|
||||
/* Struct for configuring cards */
|
||||
typedef struct isdnloop_sdef {
|
||||
int ptype;
|
||||
char num[3][20];
|
||||
} isdnloop_sdef;
|
||||
|
||||
#if defined(__KERNEL__) || defined(__DEBUGVAR__)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/* Kernel includes */
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/major.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/isdnif.h>
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#define ISDNLOOP_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */
|
||||
#define ISDNLOOP_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */
|
||||
#define ISDNLOOP_FLAGS_RUNNING 4 /* Cards driver activated */
|
||||
#define ISDNLOOP_FLAGS_RBTIMER 8 /* scheduling of B-Channel-poll */
|
||||
#define ISDNLOOP_TIMER_BCREAD 1 /* B-Channel poll-cycle */
|
||||
#define ISDNLOOP_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle */
|
||||
#define ISDNLOOP_TIMER_ALERTWAIT (10 * HZ) /* Alert timeout */
|
||||
#define ISDNLOOP_MAX_SQUEUE 65536 /* Max. outstanding send-data */
|
||||
#define ISDNLOOP_BCH 2 /* channels per card */
|
||||
|
||||
/*
|
||||
* Per card driver data
|
||||
*/
|
||||
typedef struct isdnloop_card {
|
||||
struct isdnloop_card *next; /* Pointer to next device struct */
|
||||
struct isdnloop_card
|
||||
*rcard[ISDNLOOP_BCH]; /* Pointer to 'remote' card */
|
||||
int rch[ISDNLOOP_BCH]; /* 'remote' channel */
|
||||
int myid; /* Driver-Nr. assigned by linklevel */
|
||||
int leased; /* Flag: This Adapter is connected */
|
||||
/* to a leased line */
|
||||
int sil[ISDNLOOP_BCH]; /* SI's to listen for */
|
||||
char eazlist[ISDNLOOP_BCH][11];
|
||||
/* EAZ's to listen for */
|
||||
char s0num[3][20]; /* 1TR6 base-number or MSN's */
|
||||
unsigned short flags; /* Statusflags */
|
||||
int ptype; /* Protocol type (1TR6 or Euro) */
|
||||
struct timer_list st_timer; /* Timer for Status-Polls */
|
||||
struct timer_list rb_timer; /* Timer for B-Channel-Polls */
|
||||
struct timer_list
|
||||
c_timer[ISDNLOOP_BCH]; /* Timer for Alerting */
|
||||
int l2_proto[ISDNLOOP_BCH]; /* Current layer-2-protocol */
|
||||
isdn_if interface; /* Interface to upper layer */
|
||||
int iptr; /* Index to imsg-buffer */
|
||||
char imsg[60]; /* Internal buf for status-parsing */
|
||||
int optr; /* Index to omsg-buffer */
|
||||
char omsg[60]; /* Internal buf for cmd-parsing */
|
||||
char msg_buf[2048]; /* Buffer for status-messages */
|
||||
char *msg_buf_write; /* Writepointer for statusbuffer */
|
||||
char *msg_buf_read; /* Readpointer for statusbuffer */
|
||||
char *msg_buf_end; /* Pointer to end of statusbuffer */
|
||||
int sndcount[ISDNLOOP_BCH]; /* Byte-counters for B-Ch.-send */
|
||||
struct sk_buff_head
|
||||
bqueue[ISDNLOOP_BCH]; /* B-Channel queues */
|
||||
struct sk_buff_head dqueue; /* D-Channel queue */
|
||||
spinlock_t isdnloop_lock;
|
||||
} isdnloop_card;
|
||||
|
||||
/*
|
||||
* Main driver data
|
||||
*/
|
||||
#ifdef __KERNEL__
|
||||
static isdnloop_card *cards = (isdnloop_card *) 0;
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/* Utility-Macros */
|
||||
|
||||
#define CID (card->interface.id)
|
||||
|
||||
#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
|
||||
#endif /* isdnloop_h */
|
||||
Loading…
Reference in a new issue