summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2002-10-06 19:18:52 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-10-06 19:18:52 -0700
commit6e7aa9f00e155b5ffb39ca6342c9ea96a1cc5051 (patch)
treed50d8d2115c3c6d96f3c50d1c76462f006248312
parentc27b8aa3ddd2be97dda447b324a5f0bc545c717c (diff)
parent9c06758cdc72e6c445fa6488a660cb8a3c7d008c (diff)
Merge http://linux-isdn.bkbits.net/linux-2.5.isdn
into home.transmeta.com:/home/torvalds/v2.5/linux
-rw-r--r--Makefile2
-rw-r--r--drivers/isdn/eicon/Divas_mod.c6
-rw-r--r--drivers/isdn/eicon/adapter.h3
-rw-r--r--drivers/isdn/eicon/common.c7
-rw-r--r--drivers/isdn/eicon/eicon.h14
-rw-r--r--drivers/isdn/eicon/eicon_dsp.h2
-rw-r--r--drivers/isdn/eicon/eicon_idi.c4
-rw-r--r--drivers/isdn/eicon/eicon_idi.h2
-rw-r--r--drivers/isdn/eicon/eicon_io.c2
-rw-r--r--drivers/isdn/eicon/eicon_isa.c4
-rw-r--r--drivers/isdn/eicon/eicon_isa.h2
-rw-r--r--drivers/isdn/eicon/eicon_mod.c27
-rw-r--r--drivers/isdn/eicon/eicon_pci.c4
-rw-r--r--drivers/isdn/eicon/eicon_pci.h2
-rw-r--r--drivers/isdn/eicon/linio.c16
-rw-r--r--drivers/isdn/eicon/linsys.c17
-rw-r--r--drivers/isdn/i4l/Makefile8
-rw-r--r--drivers/isdn/i4l/isdn_ciscohdlck.c171
-rw-r--r--drivers/isdn/i4l/isdn_common.c199
-rw-r--r--drivers/isdn/i4l/isdn_common.h20
-rw-r--r--drivers/isdn/i4l/isdn_concap.c21
-rw-r--r--drivers/isdn/i4l/isdn_concap.h14
-rw-r--r--drivers/isdn/i4l/isdn_fsm.c169
-rw-r--r--drivers/isdn/i4l/isdn_fsm.h61
-rw-r--r--drivers/isdn/i4l/isdn_net.c2039
-rw-r--r--drivers/isdn/i4l/isdn_net.h146
-rw-r--r--drivers/isdn/i4l/isdn_net_lib.c1665
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c331
-rw-r--r--drivers/isdn/i4l/isdn_ppp.h14
-rw-r--r--include/linux/isdn.h90
-rw-r--r--include/linux/isdn_ppp.h13
31 files changed, 2503 insertions, 2572 deletions
diff --git a/Makefile b/Makefile
index c6d561c4f105..8900d2c218be 100644
--- a/Makefile
+++ b/Makefile
@@ -81,7 +81,7 @@ ifneq ($(filter all,$(MAKECMDGOALS)),)
KBUILD_MODULES := 1
endif
-export KBUILD_MODULES KBUILD_BUILTIN
+export KBUILD_MODULES KBUILD_BUILTIN KBUILD_VERBOSE
# Beautify output
# ---------------------------------------------------------------------------
diff --git a/drivers/isdn/eicon/Divas_mod.c b/drivers/isdn/eicon/Divas_mod.c
index 3bfa23b57591..c1443a676dfd 100644
--- a/drivers/isdn/eicon/Divas_mod.c
+++ b/drivers/isdn/eicon/Divas_mod.c
@@ -10,7 +10,7 @@
#undef N_DATA
#include <linux/kernel.h>
-
+#include <linux/tqueue.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/ioport.h>
@@ -25,6 +25,8 @@ MODULE_DESCRIPTION("ISDN4Linux: Driver for Eicon Diva Server cards");
MODULE_AUTHOR("Armin Schindler");
MODULE_LICENSE("GPL");
+void DivasInitDpc(void);
+
#ifdef MODULE
#include "idi.h"
void DIVA_DIDD_Write(DESCRIPTOR *, int);
@@ -47,6 +49,8 @@ divas_init(void)
return -ENODEV;
#endif
+ DivasInitDpc();
+
if (pci_present())
{
if (DivasCardsDiscover() < 0)
diff --git a/drivers/isdn/eicon/adapter.h b/drivers/isdn/eicon/adapter.h
index 761aebcd5f5b..b861d3557904 100644
--- a/drivers/isdn/eicon/adapter.h
+++ b/drivers/isdn/eicon/adapter.h
@@ -176,8 +176,7 @@ extern void DivasLogAdd(void *buffer, int length);
/*------------------------------------------------------------------*/
int DivasDpcSchedule(void);
-void DivasDoDpc(void *);
-void DivasDoRequestDpc(void *pData);
+void DivasDoDpc(unsigned long);
int DivasScheduleRequestDpc(void);
/* table of IDI request functions */
diff --git a/drivers/isdn/eicon/common.c b/drivers/isdn/eicon/common.c
index 77d3a50b922a..b9ec4041d3b3 100644
--- a/drivers/isdn/eicon/common.c
+++ b/drivers/isdn/eicon/common.c
@@ -801,7 +801,7 @@ void DivaDoCardDpc(card_t *card)
}
-void DivasDoDpc(void *pData)
+void DivasDoDpc(unsigned long dummy)
{
card_t *card = DivasCards;
int i = DivasCardNext;
@@ -814,11 +814,6 @@ void DivasDoDpc(void *pData)
}
}
-void DivasDoRequestDpc(void *pData)
-{
- DivasDoDpc(pData);
-}
-
/*
* DivasGetNum
* Returns the number of active adapters
diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h
index c925f21b2f70..f2c6a043a056 100644
--- a/drivers/isdn/eicon/eicon.h
+++ b/drivers/isdn/eicon/eicon.h
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.23.6.5 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon.h,v 1.1.4.1.2.3 2002/10/01 11:29:13 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
*
@@ -321,9 +321,9 @@ typedef struct eicon_card {
struct sk_buff_head sackq; /* Data-Ack-Message queue */
struct sk_buff_head statq; /* Status-Message queue */
int statq_entries;
- struct work_struct snd_tq; /* Task struct for xmit bh */
- struct work_struct rcv_tq; /* Task struct for rcv bh */
- struct work_struct ack_tq; /* Task struct for ack bh */
+ struct tasklet_struct snd_tq; /* Task struct for xmit bh */
+ struct tasklet_struct rcv_tq; /* Task struct for rcv bh */
+ struct tasklet_struct ack_tq; /* Task struct for ack bh */
eicon_chan* IdTable[256]; /* Table to find entity */
__u16 ref_in;
__u16 ref_out;
@@ -349,17 +349,17 @@ extern char *eicon_ctype_name[];
extern __inline__ void eicon_schedule_tx(eicon_card *card)
{
- schedule_work(&card->snd_tq);
+ tasklet_schedule(&card->snd_tq);
}
extern __inline__ void eicon_schedule_rx(eicon_card *card)
{
- schedule_work(&card->rcv_tq);
+ tasklet_schedule(&card->rcv_tq);
}
extern __inline__ void eicon_schedule_ack(eicon_card *card)
{
- schedule_work(&card->ack_tq);
+ tasklet_schedule(&card->ack_tq);
}
extern int eicon_addcard(int, int, int, char *, int);
diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h
index 2ccfeb0fb815..299edcaab27b 100644
--- a/drivers/isdn/eicon/eicon_dsp.h
+++ b/drivers/isdn/eicon/eicon_dsp.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_dsp.h,v 1.7.6.1 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_dsp.h,v 1.1.4.1.2.2 2002/10/01 11:29:13 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
* DSP definitions
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c
index cfa93399deab..fc341e1b396c 100644
--- a/drivers/isdn/eicon/eicon_idi.c
+++ b/drivers/isdn/eicon/eicon_idi.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.41.6.4 2001/11/06 20:58:29 kai Exp $
+/* $Id: eicon_idi.c,v 1.1.4.1.2.4 2002/10/01 11:29:13 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
* IDI interface
@@ -24,7 +24,7 @@
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.41.6.4 $";
+char *eicon_idi_revision = "$Revision: 1.1.4.1.2.4 $";
eicon_manifbuf *manbuf;
diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h
index c0cab657b4d9..d39484be78ce 100644
--- a/drivers/isdn/eicon/eicon_idi.h
+++ b/drivers/isdn/eicon/eicon_idi.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.h,v 1.11.6.1 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_idi.h,v 1.1.4.1.2.2 2002/10/01 11:29:13 armin Exp $
*
* ISDN lowlevel-module for the Eicon active cards.
* IDI-Interface
diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c
index ff61c5f10c5a..806e3771b503 100644
--- a/drivers/isdn/eicon/eicon_io.c
+++ b/drivers/isdn/eicon/eicon_io.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_io.c,v 1.13.6.2 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_io.c,v 1.1.4.1.2.2 2002/10/01 11:29:13 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Code for communicating with hardware.
diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c
index a925d1f3e962..1b0ff98d150b 100644
--- a/drivers/isdn/eicon/eicon_isa.c
+++ b/drivers/isdn/eicon/eicon_isa.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.c,v 1.16.6.2 2001/11/06 20:58:29 kai Exp $
+/* $Id: eicon_isa.c,v 1.1.4.1.2.3 2002/10/01 11:29:13 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for old ISA cards.
@@ -20,7 +20,7 @@
#define release_shmem release_region
#define request_shmem request_region
-char *eicon_isa_revision = "$Revision: 1.16.6.2 $";
+char *eicon_isa_revision = "$Revision: 1.1.4.1.2.3 $";
#undef EICON_MCA_DEBUG
diff --git a/drivers/isdn/eicon/eicon_isa.h b/drivers/isdn/eicon/eicon_isa.h
index 7502aabecb8c..47aa5650601e 100644
--- a/drivers/isdn/eicon/eicon_isa.h
+++ b/drivers/isdn/eicon/eicon_isa.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.h,v 1.10.6.1 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_isa.h,v 1.1.4.1.2.2 2002/10/01 11:29:13 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
*
diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
index f51cffef1d6a..02d594281783 100644
--- a/drivers/isdn/eicon/eicon_mod.c
+++ b/drivers/isdn/eicon/eicon_mod.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.37.6.6 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_mod.c,v 1.1.4.1.2.4 2002/10/01 11:29:13 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
*
@@ -44,7 +44,7 @@
static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains
start of card-list */
-static char *eicon_revision = "$Revision: 1.37.6.6 $";
+static char *eicon_revision = "$Revision: 1.1.4.1.2.4 $";
extern char *eicon_pci_revision;
extern char *eicon_isa_revision;
@@ -142,8 +142,10 @@ eicon_findnpcicard(int driverid)
#endif /* CONFIG_PCI */
static void
-eicon_rcv_dispatch(struct eicon_card *card)
+eicon_rcv_dispatch(unsigned long context)
{
+ struct eicon_card *card = (struct eicon_card *)context;
+
switch (card->bus) {
case EICON_BUS_ISA:
case EICON_BUS_MCA:
@@ -152,13 +154,15 @@ eicon_rcv_dispatch(struct eicon_card *card)
break;
default:
eicon_log(card, 1,
- "eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
+ "eicon_rcv_dispatch: Illegal bustype %d\n", card->bus);
}
}
static void
-eicon_ack_dispatch(struct eicon_card *card)
+eicon_ack_dispatch(unsigned long context)
{
+ struct eicon_card *card = (struct eicon_card *)context;
+
switch (card->bus) {
case EICON_BUS_ISA:
case EICON_BUS_MCA:
@@ -172,8 +176,10 @@ eicon_ack_dispatch(struct eicon_card *card)
}
static void
-eicon_transmit(struct eicon_card *card)
+eicon_transmit(unsigned long context)
{
+ struct eicon_card *card = (struct eicon_card *)context;
+
switch (card->bus) {
case EICON_BUS_ISA:
case EICON_BUS_MCA:
@@ -868,12 +874,9 @@ eicon_alloccard(int Type, int membase, int irq, char *id, int card_id)
skb_queue_head_init(&card->sackq);
skb_queue_head_init(&card->statq);
card->statq_entries = 0;
- card->snd_tq.routine = (void *) (void *) eicon_transmit;
- card->snd_tq.data = card;
- card->rcv_tq.routine = (void *) (void *) eicon_rcv_dispatch;
- card->rcv_tq.data = card;
- card->ack_tq.routine = (void *) (void *) eicon_ack_dispatch;
- card->ack_tq.data = card;
+ tasklet_init(&card->snd_tq, eicon_transmit, (unsigned long)card);
+ tasklet_init(&card->rcv_tq, eicon_rcv_dispatch, (unsigned long)card);
+ tasklet_init(&card->ack_tq, eicon_ack_dispatch, (unsigned long)card);
card->interface.maxbufsize = 4000;
card->interface.command = if_command;
card->interface.writebuf_skb = if_sendbuf;
diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c
index 69c0a0b790a6..6246162dcda4 100644
--- a/drivers/isdn/eicon/eicon_pci.c
+++ b/drivers/isdn/eicon/eicon_pci.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.c,v 1.15.6.3 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_pci.c,v 1.1.4.1.2.3 2002/10/01 11:29:13 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for PCI cards.
@@ -24,7 +24,7 @@
#include "adapter.h"
#include "uxio.h"
-char *eicon_pci_revision = "$Revision: 1.15.6.3 $";
+char *eicon_pci_revision = "$Revision: 1.1.4.1.2.3 $";
#if CONFIG_PCI /* intire stuff is only for PCI */
#ifdef CONFIG_ISDN_DRV_EICON_PCI
diff --git a/drivers/isdn/eicon/eicon_pci.h b/drivers/isdn/eicon/eicon_pci.h
index 7e615c6f3e0b..7f58e9b636b3 100644
--- a/drivers/isdn/eicon/eicon_pci.h
+++ b/drivers/isdn/eicon/eicon_pci.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.h,v 1.6.6.1 2001/09/23 22:24:37 kai Exp $
+/* $Id: eicon_pci.h,v 1.1.4.1.2.2 2002/10/01 11:29:13 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards (PCI part).
*
diff --git a/drivers/isdn/eicon/linio.c b/drivers/isdn/eicon/linio.c
index b20057bb279d..1756c671045c 100644
--- a/drivers/isdn/eicon/linio.c
+++ b/drivers/isdn/eicon/linio.c
@@ -10,6 +10,10 @@
#define N_DATA
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/slab.h>
@@ -24,7 +28,7 @@ int log_on=0;
int Divasdevflag = 0;
-//spinlock_t diva_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t diva_lock = SPIN_LOCK_UNLOCKED;
static
ux_diva_card_t card_pool[MAX_CARDS];
@@ -673,20 +677,14 @@ long UxCardLock(ux_diva_card_t *card)
{
unsigned long flags;
- //spin_lock_irqsave(&diva_lock, flags);
+ spin_lock_irqsave(&diva_lock, flags);
- save_flags(flags);
- cli();
return flags;
-
}
void UxCardUnlock(ux_diva_card_t *card, long ipl)
{
- //spin_unlock_irqrestore(&diva_lock, ipl);
-
- restore_flags(ipl);
-
+ spin_unlock_irqrestore(&diva_lock, ipl);
}
dword UxTimeGet(void)
diff --git a/drivers/isdn/eicon/linsys.c b/drivers/isdn/eicon/linsys.c
index 30680c6c9086..afe772fbb5d5 100644
--- a/drivers/isdn/eicon/linsys.c
+++ b/drivers/isdn/eicon/linsys.c
@@ -24,6 +24,8 @@ struct pt_regs;
#include "uxio.h"
+static struct tasklet_struct DivasTask;
+
int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg)
{
/* Use UxPciConfigWrite routines to initialise PCI config space */
@@ -79,24 +81,23 @@ int DivasBRIInitPCI(card_t *card, dia_card_t *cfg)
int DivasDpcSchedule(void)
{
- static struct work_struct DivasTask;
-
- INIT_WORK(&DivasTask, DivasDoDpc, NULL);
- schedule_work(&DivasTask);
+ tasklet_schedule(&DivasTask);
return 0;
}
int DivasScheduleRequestDpc(void)
{
- static struct work_struct DivasTask;
-
- INIT_WORK(&DivasTask, DivasDoRequestDpc, NULL);
- schedule_work(&DivasTask);
+ tasklet_schedule(&DivasTask);
return 0;
}
+void DivasInitDpc(void)
+{
+ tasklet_init(&DivasTask, DivasDoDpc, 0);
+}
+
void DivasLogAdd(void *buffer, int length)
{
static
diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile
index 65055e42faf2..407501c0d6b1 100644
--- a/drivers/isdn/i4l/Makefile
+++ b/drivers/isdn/i4l/Makefile
@@ -11,9 +11,11 @@ obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
# Multipart objects.
-isdn-objs := isdn_net.o isdn_tty.o \
- isdn_v110.o isdn_common.o \
- isdn_ciscohdlck.o
+isdn-objs := isdn_net.o isdn_net_lib.o \
+ isdn_fsm.o \
+ isdn_ciscohdlck.o \
+ isdn_tty.o isdn_v110.o \
+ isdn_common.o \
# Optional parts of multipart objects.
diff --git a/drivers/isdn/i4l/isdn_ciscohdlck.c b/drivers/isdn/i4l/isdn_ciscohdlck.c
index 6a72d3bc1cf1..0f08f3daea88 100644
--- a/drivers/isdn/i4l/isdn_ciscohdlck.c
+++ b/drivers/isdn/i4l/isdn_ciscohdlck.c
@@ -24,9 +24,8 @@
* CISCO HDLC keepalive specific stuff
*/
static struct sk_buff*
-isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
+isdn_net_ciscohdlck_alloc_skb(isdn_net_dev *idev, int len)
{
- isdn_net_dev *idev = lp->netdev;
unsigned short hl = isdn_slot_hdrlen(idev->isdn_slot);
struct sk_buff *skb;
@@ -43,62 +42,59 @@ isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
static int
isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- isdn_net_local *lp = (isdn_net_local *) dev->priv;
- isdn_net_dev *idev = lp->netdev;
+ isdn_net_local *mlp = dev->priv;
unsigned long len = 0;
- unsigned long expires = 0;
- int tmp = 0;
- int period = lp->cisco_keepalive_period;
- char debserint = lp->cisco_debserint;
+ int period;
+ char debserint;
int rc = 0;
- if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
+ if (mlp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
return -EINVAL;
switch (cmd) {
/* get/set keepalive period */
case SIOCGKEEPPERIOD:
- len = (unsigned long)sizeof(lp->cisco_keepalive_period);
+ len = sizeof(mlp->cisco_keepalive_period);
if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
- (int *)&lp->cisco_keepalive_period, len))
+ (char *)&mlp->cisco_keepalive_period, len))
rc = -EFAULT;
break;
case SIOCSKEEPPERIOD:
- tmp = lp->cisco_keepalive_period;
- len = (unsigned long)sizeof(lp->cisco_keepalive_period);
- if (copy_from_user((int *)&period,
- (char *)ifr->ifr_ifru.ifru_data, len))
+ len = sizeof(mlp->cisco_keepalive_period);
+ if (copy_from_user((char *)&period,
+ (char *)ifr->ifr_ifru.ifru_data, len)) {
rc = -EFAULT;
- if ((period > 0) && (period <= 32767))
- lp->cisco_keepalive_period = period;
- else
+ break;
+ }
+ if (period <= 0 || period > 32767) {
rc = -EINVAL;
- if (!rc && (tmp != lp->cisco_keepalive_period)) {
- expires = (unsigned long)(jiffies +
- lp->cisco_keepalive_period * HZ);
- mod_timer(&lp->cisco_timer, expires);
- printk(KERN_INFO "%s: Keepalive period set "
- "to %d seconds.\n",
- idev->name, lp->cisco_keepalive_period);
+ break;
}
+ mod_timer(&mlp->cisco_timer, jiffies + period * HZ);
+ printk(KERN_INFO "%s: Keepalive period set "
+ "to %d seconds.\n", dev->name, period);
+ mlp->cisco_keepalive_period = period;
break;
/* get/set debugging */
case SIOCGDEBSERINT:
- len = (unsigned long)sizeof(lp->cisco_debserint);
+ len = sizeof(mlp->cisco_debserint);
if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
- (char *)&lp->cisco_debserint, len))
+ (char *)&mlp->cisco_debserint, len))
rc = -EFAULT;
break;
case SIOCSDEBSERINT:
- len = (unsigned long)sizeof(lp->cisco_debserint);
+ len = sizeof(mlp->cisco_debserint);
if (copy_from_user((char *)&debserint,
- (char *)ifr->ifr_ifru.ifru_data, len))
+ (char *)ifr->ifr_ifru.ifru_data, len)) {
rc = -EFAULT;
- if ((debserint >= 0) && (debserint <= 64))
- lp->cisco_debserint = debserint;
- else
+ break;
+ }
+ if (debserint < 0 || debserint > 64) {
rc = -EINVAL;
+ break;
+ }
+ mlp->cisco_debserint = debserint;
break;
default:
@@ -112,42 +108,47 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static void
isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
{
- isdn_net_local *lp = (isdn_net_local *) data;
- isdn_net_dev *idev = lp->netdev;
+ isdn_net_local *mlp = (isdn_net_local *) data;
+ isdn_net_dev *idev;
struct sk_buff *skb;
unsigned char *p;
- unsigned long last_cisco_myseq = lp->cisco_myseq;
+ unsigned long last_cisco_myseq = mlp->cisco_myseq;
int myseq_diff = 0;
- lp->cisco_myseq++;
+ if (list_empty(&mlp->online)) {
+ isdn_BUG();
+ return;
+ }
+ idev = list_entry(mlp->online.next, isdn_net_dev, online);
+ mlp->cisco_myseq++;
- myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
- if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) {
+ myseq_diff = (mlp->cisco_myseq - mlp->cisco_mineseen);
+ if (mlp->cisco_line_state && (myseq_diff >= 3 || myseq_diff <= -3)) {
/* line up -> down */
- lp->cisco_line_state = 0;
+ mlp->cisco_line_state = 0;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to down\n", idev->name);
/* should stop routing higher-level data accross */
- } else if ((!lp->cisco_line_state) &&
- (myseq_diff >= 0) && (myseq_diff <= 2)) {
+ } else if (!mlp->cisco_line_state &&
+ myseq_diff >= 0 && myseq_diff <= 2) {
/* line down -> up */
- lp->cisco_line_state = 1;
+ mlp->cisco_line_state = 1;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to up\n", idev->name);
/* restart routing higher-level data accross */
}
- if (lp->cisco_debserint)
+ if (mlp->cisco_debserint)
printk (KERN_DEBUG "%s: HDLC "
"myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
- idev->name, last_cisco_myseq, lp->cisco_mineseen,
- (last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040,
- lp->cisco_yourseq,
- (lp->cisco_line_state) ? "line up" : "line down");
+ idev->name, last_cisco_myseq, mlp->cisco_mineseen,
+ (last_cisco_myseq == mlp->cisco_mineseen) ? '*' : 040,
+ mlp->cisco_yourseq,
+ (mlp->cisco_line_state) ? "line up" : "line down");
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+ skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14);
if (!skb)
return;
@@ -160,24 +161,29 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
/* slarp keepalive */
p += put_u32(p, CISCO_SLARP_KEEPALIVE);
- p += put_u32(p, lp->cisco_myseq);
- p += put_u32(p, lp->cisco_yourseq);
+ p += put_u32(p, mlp->cisco_myseq);
+ p += put_u32(p, mlp->cisco_yourseq);
p += put_u16(p, 0xffff); // reliablity, always 0xffff
- isdn_net_write_super(lp, skb);
+ isdn_net_write_super(idev, skb);
- lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
-
- add_timer(&lp->cisco_timer);
+ mod_timer(&mlp->cisco_timer, jiffies + mlp->cisco_keepalive_period * HZ);
}
static void
-isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
+isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *mlp)
{
+ isdn_net_dev *idev;
struct sk_buff *skb;
unsigned char *p;
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+ if (list_empty(&mlp->online)) {
+ isdn_BUG();
+ return;
+ }
+ idev = list_entry(mlp->online.next, isdn_net_dev, online);
+
+ skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14);
if (!skb)
return;
@@ -194,12 +200,14 @@ isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
p += put_u32(p, 0); // netmask
p += put_u16(p, 0); // unused
- isdn_net_write_super(lp, skb);
+ isdn_net_write_super(idev, skb);
}
static void
-isdn_ciscohdlck_connected(isdn_net_local *lp)
+isdn_ciscohdlck_connected(isdn_net_dev *idev)
{
+ isdn_net_local *lp = idev->mlp;
+
lp->cisco_myseq = 0;
lp->cisco_mineseen = 0;
lp->cisco_yourseq = 0;
@@ -218,27 +226,30 @@ isdn_ciscohdlck_connected(isdn_net_local *lp)
lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
add_timer(&lp->cisco_timer);
}
- isdn_net_device_wake_queue(lp);
+ netif_wake_queue(&lp->dev);
}
static void
-isdn_ciscohdlck_disconnected(isdn_net_local *lp)
+isdn_ciscohdlck_disconnected(isdn_net_dev *idev)
{
+ isdn_net_local *lp = idev->mlp;
+
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) {
del_timer(&lp->cisco_timer);
}
}
static void
-isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
+isdn_net_ciscohdlck_slarp_send_reply(isdn_net_dev *idev)
{
+ isdn_net_local *mlp = idev->mlp;
struct sk_buff *skb;
unsigned char *p;
struct in_device *in_dev = NULL;
u32 addr = 0; /* local ipv4 address */
u32 mask = 0; /* local netmask */
- if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
+ if ((in_dev = mlp->dev.ip_ptr) != NULL) {
/* take primary(first) address of interface */
struct in_ifaddr *ifa = in_dev->ifa_list;
if (ifa != NULL) {
@@ -247,7 +258,7 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
}
}
- skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+ skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14);
if (!skb)
return;
@@ -265,13 +276,13 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
p += put_u32(p, mask); // netmask
p += put_u16(p, 0); // unused
- isdn_net_write_super(lp, skb);
+ isdn_net_write_super(idev, skb);
}
static void
-isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
+isdn_net_ciscohdlck_slarp_in(isdn_net_dev *idev, struct sk_buff *skb)
{
- isdn_net_dev *idev = lp->netdev;
+ isdn_net_local *mlp = idev->mlp;
unsigned char *p;
int period;
u32 code;
@@ -288,8 +299,8 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
switch (code) {
case CISCO_SLARP_REQUEST:
- lp->cisco_yourseq = 0;
- isdn_net_ciscohdlck_slarp_send_reply(lp);
+ mlp->cisco_yourseq = 0;
+ isdn_net_ciscohdlck_slarp_send_reply(idev);
break;
case CISCO_SLARP_REPLY:
addr = ntohl(*(u32 *)p);
@@ -315,30 +326,29 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
HIPQUAD(addr), HIPQUAD(mask));
break;
case CISCO_SLARP_KEEPALIVE:
- period = (int)((jiffies - lp->cisco_last_slarp_in
+ period = (int)((jiffies - mlp->cisco_last_slarp_in
+ HZ/2 - 1) / HZ);
- if (lp->cisco_debserint &&
- (period != lp->cisco_keepalive_period) &&
- lp->cisco_last_slarp_in) {
+ if (mlp->cisco_debserint &&
+ (period != mlp->cisco_keepalive_period) &&
+ mlp->cisco_last_slarp_in) {
printk(KERN_DEBUG "%s: Keepalive period mismatch - "
"is %d but should be %d.\n",
- idev->name, period, lp->cisco_keepalive_period);
+ idev->name, period, mlp->cisco_keepalive_period);
}
- lp->cisco_last_slarp_in = jiffies;
+ mlp->cisco_last_slarp_in = jiffies;
p += get_u32(p, &my_seq);
p += get_u32(p, &your_seq);
p += get_u16(p, &unused);
- lp->cisco_yourseq = my_seq;
- lp->cisco_mineseen = your_seq;
+ mlp->cisco_yourseq = my_seq;
+ mlp->cisco_mineseen = your_seq;
break;
}
}
static void
-isdn_ciscohdlck_receive(isdn_net_dev *idev, isdn_net_local *olp,
+isdn_ciscohdlck_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
- isdn_net_local *lp = &idev->local;
unsigned char *p;
u8 addr;
u8 ctrl;
@@ -362,7 +372,7 @@ isdn_ciscohdlck_receive(isdn_net_dev *idev, isdn_net_local *olp,
switch (type) {
case CISCO_TYPE_SLARP:
- isdn_net_ciscohdlck_slarp_in(lp, skb);
+ isdn_net_ciscohdlck_slarp_in(idev, skb);
goto out_free;
case CISCO_TYPE_CDP:
if (lp->cisco_debserint)
@@ -371,7 +381,7 @@ isdn_ciscohdlck_receive(isdn_net_dev *idev, isdn_net_local *olp,
goto out_free;
default:
/* no special cisco protocol */
- isdn_net_reset_huptimer(idev, olp->netdev);
+ idev->huptimer = 0;
skb->protocol = htons(type);
netif_rx(skb);
return;
@@ -396,6 +406,7 @@ isdn_ciscohdlck_header(struct sk_buff *skb, struct net_device *dev,
}
struct isdn_netif_ops ciscohdlck_ops = {
+ .hard_start_xmit = isdn_net_start_xmit,
.hard_header = isdn_ciscohdlck_header,
.do_ioctl = isdn_ciscohdlck_dev_ioctl,
.flags = IFF_NOARP | IFF_POINTOPOINT,
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index d8709313dc56..5a2b4b527a29 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -46,8 +46,7 @@ struct isdn_slot {
unsigned long obytes; /* Statistics outgoing bytes */
struct isdn_v110 iv110; /* For V.110 */
int m_idx; /* Index for mdm.... */
- isdn_net_dev *rx_netdev; /* rx netdev-pointers */
- isdn_net_dev *st_netdev; /* stat netdev-pointers */
+ isdn_net_dev *idev; /* pointer to isdn_net_dev */
};
static struct isdn_slot slot[ISDN_MAX_CHANNELS];
@@ -508,7 +507,7 @@ isdn_status_callback(isdn_ctrl * c)
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
if (p->isdn_slot == i) {
- strcpy(cmd.parm.setup.eazmsn, p->local.msn);
+ strcpy(cmd.parm.setup.eazmsn, p->mlp->msn);
isdn_slot_command(i, ISDN_CMD_ACCEPTD, &cmd);
retval = 1;
break;
@@ -1010,19 +1009,6 @@ static int
isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
{
int ret;
- union iocpar {
- char name[10];
- char bname[22];
- isdn_ioctl_struct iocts;
- isdn_net_ioctl_phone phone;
- isdn_net_ioctl_cfg cfg;
- } iocpar;
-
-#define name iocpar.name
-#define bname iocpar.bname
-#define iocts iocpar.iocts
-#define phone iocpar.phone
-#define cfg iocpar.cfg
switch (cmd) {
case IIOCGETDVR:
@@ -1044,26 +1030,11 @@ isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
} else
return -EINVAL;
break;
-#ifdef CONFIG_NETDEVICES
case IIOCNETGPN:
- /* Get peer phone number of a connected
- * isdn network interface */
- if (arg) {
- if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
- return -EFAULT;
- return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
- } else
- return -EINVAL;
-#endif
+ return isdn_net_ioctl(inode, file, cmd, arg);
default:
return -EINVAL;
}
-
-#undef name
-#undef bname
-#undef iocts
-#undef phone
-#undef cfg
}
static struct file_operations isdn_status_fops =
@@ -1221,19 +1192,15 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
int ret;
int i;
char *p;
- union iocpar {
- char name[10];
+ /* save stack space */
+ union {
char bname[20];
isdn_ioctl_struct iocts;
- isdn_net_ioctl_phone phone;
- isdn_net_ioctl_cfg cfg;
} iocpar;
-#define name iocpar.name
-#define bname iocpar.bname
#define iocts iocpar.iocts
-#define phone iocpar.phone
-#define cfg iocpar.cfg
+#define bname iocpar.bname
+
/*
* isdn net devices manage lots of configuration variables as linked lists.
* Those lists must only be manipulated from user space. Some of the ioctl's
@@ -1242,134 +1209,19 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
* are serialized by means of a semaphore.
*/
switch (cmd) {
- case IIOCNETDWRSET:
- printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
- return(-EINVAL);
- case IIOCNETLCR:
- printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
- return -ENODEV;
-#ifdef CONFIG_NETDEVICES
case IIOCNETAIF:
- /* Add a network-interface */
- if (copy_from_user(name, (char *) arg, sizeof(name) - 1))
- return -EFAULT;
- name[sizeof(name)-1] = 0;
- ret = down_interruptible(&dev->sem);
- if (ret)
- return ret;
- ret = isdn_net_new(name, NULL);
- up(&dev->sem);
- return ret;
case IIOCNETASL:
- /* Add a slave to a network-interface */
- if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
- return -EFAULT;
- bname[sizeof(bname)-1] = 0;
- ret = down_interruptible(&dev->sem);
- if (ret)
- return ret;
- ret = isdn_net_newslave(bname);
- up(&dev->sem);
- return ret;
case IIOCNETDIF:
- /* Delete a network-interface */
- if (arg) {
- if (copy_from_user(name, (char *) arg, sizeof(name)))
- return -EFAULT;
- ret = down_interruptible(&dev->sem);
- if( ret ) return ret;
- ret = isdn_net_rm(name);
- up(&dev->sem);
- return ret;
- } else
- return -EINVAL;
case IIOCNETSCF:
- /* Set configurable parameters of a network-interface */
- if (arg) {
- if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
- return -EFAULT;
- return isdn_net_setcfg(&cfg);
- } else
- return -EINVAL;
case IIOCNETGCF:
- /* Get configurable parameters of a network-interface */
- if (arg) {
- if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
- return -EFAULT;
- if (!(ret = isdn_net_getcfg(&cfg))) {
- if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
- return -EFAULT;
- }
- return ret;
- } else
- return -EINVAL;
case IIOCNETANM:
- /* Add a phone-number to a network-interface */
- if (arg) {
- if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
- return -EFAULT;
- ret = down_interruptible(&dev->sem);
- if( ret ) return ret;
- ret = isdn_net_addphone(&phone);
- up(&dev->sem);
- return ret;
- } else
- return -EINVAL;
case IIOCNETGNM:
- /* Get list of phone-numbers of a network-interface */
- if (arg) {
- if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
- return -EFAULT;
- ret = down_interruptible(&dev->sem);
- if( ret ) return ret;
- ret = isdn_net_getphones(&phone, (char *) arg);
- up(&dev->sem);
- return ret;
- } else
- return -EINVAL;
case IIOCNETDNM:
- /* Delete a phone-number of a network-interface */
- if (arg) {
- if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
- return -EFAULT;
- ret = down_interruptible(&dev->sem);
- if( ret ) return ret;
- ret = isdn_net_delphone(&phone);
- up(&dev->sem);
- return ret;
- } else
- return -EINVAL;
case IIOCNETDIL:
- /* Force dialing of a network-interface */
- if (arg) {
- if (copy_from_user(name, (char *) arg, sizeof(name)))
- return -EFAULT;
- return isdn_net_force_dial(name);
- } else
- return -EINVAL;
-#ifdef CONFIG_ISDN_PPP
case IIOCNETALN:
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, (char *) arg, sizeof(name)))
- return -EFAULT;
- return isdn_ppp_dial_slave(name);
case IIOCNETDLN:
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, (char *) arg, sizeof(name)))
- return -EFAULT;
- return isdn_ppp_hangup_slave(name);
-#endif
case IIOCNETHUP:
- /* Force hangup of a network-interface */
- if (!arg)
- return -EINVAL;
- if (copy_from_user(name, (char *) arg, sizeof(name)))
- return -EFAULT;
- return isdn_net_force_hangup(name);
- break;
-#endif /* CONFIG_NETDEVICES */
+ return isdn_net_ioctl(inode, file, cmd, arg);
case IIOCSETVER:
dev->net_verbose = arg;
printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
@@ -1577,12 +1429,8 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
} else
return -EINVAL;
}
-
-#undef name
-#undef bname
#undef iocts
-#undef phone
-#undef cfg
+#undef bname
}
static struct file_operations isdn_ctrl_fops =
@@ -2218,35 +2066,19 @@ isdn_slot_num(int sl)
}
void
-isdn_slot_set_rx_netdev(int sl, isdn_net_dev *nd)
+isdn_slot_set_idev(int sl, isdn_net_dev *idev)
{
BUG_ON(sl < 0);
- slot[sl].rx_netdev = nd;
+ slot[sl].idev = idev;
}
isdn_net_dev *
-isdn_slot_rx_netdev(int sl)
+isdn_slot_idev(int sl)
{
BUG_ON(sl < 0);
- return slot[sl].rx_netdev;
-}
-
-void
-isdn_slot_set_st_netdev(int sl, isdn_net_dev *nd)
-{
- BUG_ON(sl < 0);
-
- slot[sl].st_netdev = nd;
-}
-
-isdn_net_dev *
-isdn_slot_st_netdev(int sl)
-{
- BUG_ON(sl < 0);
-
- return slot[sl].st_netdev;
+ return slot[sl].idev;
}
int
@@ -2430,7 +2262,7 @@ static int __init isdn_init(void)
printk("\n");
#endif
isdn_info_update();
- isdn_net_init_module();
+ isdn_net_init();
return 0;
err_tty_modem:
@@ -2456,8 +2288,7 @@ static void __exit isdn_exit(void)
#endif
save_flags(flags);
cli();
- if (isdn_net_rmall() < 0)
- BUG();
+ isdn_net_exit();
isdn_tty_exit();
if (unregister_chrdev(ISDN_MAJOR, "isdn"))
diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h
index 9e4b37b0c7ce..d0ea6f37088c 100644
--- a/drivers/isdn/i4l/isdn_common.h
+++ b/drivers/isdn/i4l/isdn_common.h
@@ -22,11 +22,11 @@
#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
-#undef ISDN_DEBUG_STATCALLB
-#undef ISDN_DEBUG_COMMAND
+#define ISDN_DEBUG_NET_DUMP
+#define ISDN_DEBUG_NET_DIAL
+#define ISDN_DEBUG_NET_ICALL
+#define ISDN_DEBUG_STATCALLB
+#define ISDN_DEBUG_COMMAND
#ifdef ISDN_DEBUG_NET_DIAL
#define dbg_net_dial(arg...) printk(KERN_DEBUG arg)
@@ -52,6 +52,8 @@ do { printk(KERN_WARNING "ISDN Bug at %s:%d\n", __FILE__, __LINE__); \
#define HERE printk("%s:%d (%s)\n", __FILE__, __LINE__, __FUNCTION__)
+extern struct list_head isdn_net_devs;
+
/* Prototypes */
extern void isdn_MOD_INC_USE_COUNT(void);
extern void isdn_MOD_DEC_USE_COUNT(void);
@@ -82,8 +84,6 @@ struct dial_info {
unsigned char *phone;
};
-extern struct list_head isdn_net_devs;
-
extern int isdn_get_free_slot(int, int, int, int, int, char *);
extern void isdn_slot_free(int slot, int usage);
extern void isdn_slot_all_eaz(int slot);
@@ -100,8 +100,6 @@ extern void isdn_slot_set_usage(int slot, int usage);
extern char *isdn_slot_num(int slot);
extern int isdn_slot_m_idx(int slot);
extern void isdn_slot_set_m_idx(int slot, int midx);
-extern void isdn_slot_set_rx_netdev(int sl, isdn_net_dev *nd);
-extern void isdn_slot_set_st_netdev(int sl, isdn_net_dev *nd);
-extern isdn_net_dev *isdn_slot_rx_netdev(int sl);
-extern isdn_net_dev *isdn_slot_st_netdev(int sl);
+extern void isdn_slot_set_idev(int sl, isdn_net_dev *);
+extern isdn_net_dev *isdn_slot_idev(int sl);
extern int isdn_hard_header_len(void);
diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
index e325ce283cea..c7db6ce74843 100644
--- a/drivers/isdn/i4l/isdn_concap.c
+++ b/drivers/isdn/i4l/isdn_concap.c
@@ -39,7 +39,8 @@
*/
-int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
+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 *) ndev->priv)->netdev;
@@ -58,7 +59,8 @@ int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
}
-int isdn_concap_dl_connect_req(struct concap_proto *concap)
+static int
+isdn_concap_dl_connect_req(struct concap_proto *concap)
{
struct net_device *ndev = concap -> net_dev;
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
@@ -71,7 +73,8 @@ int isdn_concap_dl_connect_req(struct concap_proto *concap)
return ret;
}
-int isdn_concap_dl_disconn_req(struct concap_proto *concap)
+static int
+isdn_concap_dl_disconn_req(struct concap_proto *concap)
{
IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name);
@@ -98,7 +101,8 @@ struct concap_device_ops isdn_concap_demand_dial_dops = {
this sourcefile does not need to include any protocol specific header
files. For now:
*/
-struct concap_proto * isdn_concap_new( int encap )
+struct concap_proto *
+isdn_concap_new( int encap )
{
switch ( encap ) {
case ISDN_NET_ENCAP_X25IFACE:
@@ -158,7 +162,7 @@ isdn_x25_disconnected(isdn_net_local *lp)
pops -> disconn_ind(cprot);
}
-int
+static int
isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
/* At this point hard_start_xmit() passes control to the encapsulation
@@ -237,13 +241,8 @@ isdn_x25_cleanup(isdn_net_dev *p)
restore_flags(flags);
}
-void isdn_x25_realrm(isdn_net_dev *p)
-{
- if( p -> cprot && p -> cprot -> pops )
- p -> cprot -> pops -> proto_del ( p -> cprot );
-}
-
struct isdn_netif_ops isdn_x25_ops = {
+ .hard_start_xmit = isdn_x25_start_xmit,
.flags = IFF_NOARP | IFF_POINTOPOINT,
.type = ARPHRD_X25,
.receive = isdn_x25_receive,
diff --git a/drivers/isdn/i4l/isdn_concap.h b/drivers/isdn/i4l/isdn_concap.h
index 94c7c83374cb..8150d6f595e0 100644
--- a/drivers/isdn/i4l/isdn_concap.h
+++ b/drivers/isdn/i4l/isdn_concap.h
@@ -12,18 +12,4 @@ extern struct concap_device_ops isdn_concap_demand_dial_dops;
struct concap_proto *isdn_concap_new(int);
-#ifdef CONFIG_ISDN_X25
-
extern struct isdn_netif_ops isdn_x25_ops;
-
-int isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev);
-
-#else
-
-static inline int
-isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- return 0;
-}
-
-#endif
diff --git a/drivers/isdn/i4l/isdn_fsm.c b/drivers/isdn/i4l/isdn_fsm.c
new file mode 100644
index 000000000000..52de59763fe8
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_fsm.c
@@ -0,0 +1,169 @@
+/* $Id: fsm.c,v 1.14.6.4 2001/09/23 22:24:47 kai Exp $
+ *
+ * Finite state machine
+ *
+ * Author Karsten Keil
+ * Copyright by Karsten Keil <keil@isdn4linux.de>
+ * by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include "isdn_fsm.h"
+
+int
+fsm_new(struct fsm *fsm)
+{
+ int i;
+ int size = sizeof(fsm_fn) * fsm->st_cnt * fsm->ev_cnt;
+
+ fsm->jumpmatrix = kmalloc(size, GFP_KERNEL);
+ if (!fsm->jumpmatrix)
+ return -ENOMEM;
+
+ memset(fsm->jumpmatrix, 0, size);
+
+ for (i = 0; i < fsm->fn_cnt; i++) {
+ if (fsm->fn_tbl[i].st >= fsm->st_cnt ||
+ fsm->fn_tbl[i].ev >= fsm->ev_cnt) {
+ printk(KERN_ERR "FsmNew Error line %d st(%d/%d) ev(%d/%d)\n", i,
+ fsm->fn_tbl[i].st, fsm->st_cnt,
+ fsm->fn_tbl[i].ev, fsm->ev_cnt);
+ continue;
+ }
+ fsm->jumpmatrix[fsm->st_cnt * fsm->fn_tbl[i].ev + fsm->fn_tbl[i].st] = fsm->fn_tbl[i].fn;
+ }
+ return 0;
+}
+
+void
+fsm_free(struct fsm *fsm)
+{
+ kfree(fsm->jumpmatrix);
+}
+
+int
+fsm_event(struct fsm_inst *fi, int event, void *arg)
+{
+ fsm_fn fn;
+
+ if (fi->state >= fi->fsm->st_cnt ||
+ event >= fi->fsm->ev_cnt) {
+ printk(KERN_ERR "FsmEvent Error st(%d/%d) ev(%d/%d)\n",
+ fi->state, fi->fsm->st_cnt,event,
+ fi->fsm->ev_cnt);
+ return -EINVAL;
+ }
+ fn = fi->fsm->jumpmatrix[fi->fsm->st_cnt * event + fi->state];
+ if (!fn) {
+ if (fi->debug)
+ fi->printdebug(fi, "State %s Event %s no routine",
+ fi->fsm->st_str[fi->state],
+ fi->fsm->ev_str[event]);
+ return -ESRCH;
+ }
+ if (fi->debug)
+ fi->printdebug(fi, "State %s Event %s",
+ fi->fsm->st_str[fi->state],
+ fi->fsm->ev_str[event]);
+
+ return fn(fi, event, arg);
+}
+
+void
+fsm_change_state(struct fsm_inst *fi, int newstate)
+{
+ fi->state = newstate;
+ if (fi->debug)
+ fi->printdebug(fi, "ChangeState %s",
+ fi->fsm->st_str[newstate]);
+}
+
+#if 0
+static void
+FsmExpireTimer(struct FsmTimer *ft)
+{
+#if FSM_TIMER_DEBUG
+ if (ft->fi->debug)
+ ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
+#endif
+ FsmEvent(ft->fi, ft->event, ft->arg);
+}
+
+void
+FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
+{
+ ft->fi = fi;
+ ft->tl.function = (void *) FsmExpireTimer;
+ ft->tl.data = (long) ft;
+#if FSM_TIMER_DEBUG
+ if (ft->fi->debug)
+ ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
+#endif
+ init_timer(&ft->tl);
+}
+
+void
+FsmDelTimer(struct FsmTimer *ft, int where)
+{
+#if FSM_TIMER_DEBUG
+ if (ft->fi->debug)
+ ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
+#endif
+ del_timer(&ft->tl);
+}
+
+int
+FsmAddTimer(struct FsmTimer *ft,
+ int millisec, int event, void *arg, int where)
+{
+
+#if FSM_TIMER_DEBUG
+ if (ft->fi->debug)
+ ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d",
+ (long) ft, millisec, where);
+#endif
+
+ if (timer_pending(&ft->tl)) {
+ printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
+ ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
+ return -1;
+ }
+ init_timer(&ft->tl);
+ ft->event = event;
+ ft->arg = arg;
+ ft->tl.expires = jiffies + (millisec * HZ) / 1000;
+ add_timer(&ft->tl);
+ return 0;
+}
+
+void
+FsmRestartTimer(struct FsmTimer *ft,
+ int millisec, int event, void *arg, int where)
+{
+
+#if FSM_TIMER_DEBUG
+ if (ft->fi->debug)
+ ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d",
+ (long) ft, millisec, where);
+#endif
+
+ if (timer_pending(&ft->tl))
+ del_timer(&ft->tl);
+ init_timer(&ft->tl);
+ ft->event = event;
+ ft->arg = arg;
+ ft->tl.expires = jiffies + (millisec * HZ) / 1000;
+ add_timer(&ft->tl);
+}
+#endif
diff --git a/drivers/isdn/i4l/isdn_fsm.h b/drivers/isdn/i4l/isdn_fsm.h
new file mode 100644
index 000000000000..4a48a401da45
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_fsm.h
@@ -0,0 +1,61 @@
+/* $Id: fsm.h,v 1.3.2.2 2001/09/23 22:24:47 kai Exp $
+ *
+ * Finite state machine
+ *
+ * Author Karsten Keil
+ * Copyright by Karsten Keil <keil@isdn4linux.de>
+ * by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#ifndef __ISDN_FSM_H__
+#define __ISDN_FSM_H__
+
+#include <linux/kernel.h>
+#include <linux/timer.h>
+
+struct fsm_inst;
+
+typedef int (*fsm_fn)(struct fsm_inst *, int, void *);
+
+struct fsm {
+ fsm_fn *jumpmatrix;
+ int st_cnt, ev_cnt, fn_cnt;
+ char **st_str, **ev_str;
+ struct fsm_node *fn_tbl;
+};
+
+struct fsm_inst {
+ struct fsm *fsm;
+ int state;
+ int debug;
+ void *userdata;
+ int userint;
+ void (*printdebug) (struct fsm_inst *, char *, ...);
+};
+
+struct fsm_node {
+ int st, ev;
+ fsm_fn fn;
+};
+
+struct fsm_timer {
+ struct fsm_inst *fi;
+ struct timer_list tl;
+ int ev;
+ void *arg;
+};
+
+int fsm_new(struct fsm *fsm);
+void fsm_free(struct fsm *fsm);
+int fsm_event(struct fsm_inst *fi, int event, void *arg);
+void fsm_change_state(struct fsm_inst *fi, int newstate);
+void fsm_init_timer(struct fsm_inst *fi, struct fsm_timer *ft);
+int fsm_add_timer(struct fsm_timer *ft, int timeout, int event);
+void fsm_mod_timer(struct fsm_timer *ft, int timeout, int event);
+void fsm_del_timer(struct fsm_timer *ft);
+
+#endif
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index a64b0e3d8b6f..43da8a9e46e8 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -33,34 +33,6 @@
#include "isdn_concap.h"
#include "isdn_ciscohdlck.h"
-enum {
- ST_NULL,
- ST_OUT_WAIT_DCONN,
- ST_OUT_WAIT_BCONN,
- ST_IN_WAIT_DCONN,
- ST_IN_WAIT_BCONN,
- ST_ACTIVE,
- ST_WAIT_BEFORE_CB,
-};
-
-enum {
- ST_CHARGE_NULL,
- ST_CHARGE_GOT_CINF, /* got a first charge info */
- ST_CHARGE_HAVE_CINT, /* got a second chare info and thus the timing */
-};
-
-/* keep clear of ISDN_CMD_* and ISDN_STAT_* */
-enum {
- EV_NET_DIAL = 0x200,
- EV_NET_TIMER_IN_DCONN = 0x201,
- EV_NET_TIMER_IN_BCONN = 0x202,
- EV_NET_TIMER_OUT_DCONN = 0x203,
- EV_NET_TIMER_OUT_BCONN = 0x204,
- EV_NET_TIMER_CB = 0x205,
-};
-
-LIST_HEAD(isdn_net_devs); /* Linked list of isdn_net_dev's */
-
/*
* Outline of new tbusy handling:
*
@@ -90,30 +62,20 @@ LIST_HEAD(isdn_net_devs); /* Linked list of isdn_net_dev's */
/*
* Find out if the netdevice has been ifup-ed yet.
- * For slaves, look at the corresponding master.
*/
-static __inline__ int isdn_net_device_started(isdn_net_dev *n)
+static inline int
+isdn_net_device_started(isdn_net_dev *idev)
{
- isdn_net_local *lp = &n->local;
- struct net_device *dev;
-
- if (lp->master)
- dev = lp->master;
- else
- dev = &n->dev;
- return netif_running(dev);
+ return netif_running(&idev->mlp->dev);
}
/*
* stop the network -> net_device queue.
- * For slaves, stop the corresponding master interface.
*/
-static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
+static inline void
+isdn_net_dev_stop_queue(isdn_net_dev *idev)
{
- if (lp->master)
- netif_stop_queue(lp->master);
- else
- netif_stop_queue(&lp->netdev->dev);
+ netif_stop_queue(&idev->mlp->dev);
}
/*
@@ -121,104 +83,73 @@ static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
* master or slave) is busy. It's busy iff all (master and slave)
* queues are busy
*/
-static __inline__ int isdn_net_device_busy(isdn_net_local *lp)
+static inline int
+isdn_net_device_busy(isdn_net_dev *idev)
{
- isdn_net_local *nlp;
- isdn_net_dev *nd;
+ isdn_net_local *mlp = idev->mlp;
unsigned long flags;
+ int retval = 1;
- if (!isdn_net_lp_busy(lp))
+ if (!isdn_net_dev_busy(idev))
return 0;
- if (lp->master)
- nd = ((isdn_net_local *) lp->master->priv)->netdev;
- else
- nd = lp->netdev;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
- nlp = lp->next;
- while (nlp != lp) {
- if (!isdn_net_lp_busy(nlp)) {
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return 0;
+ spin_lock_irqsave(&mlp->online_lock, flags);
+ list_for_each_entry(idev, &mlp->online, online) {
+ if (!isdn_net_dev_busy(idev)) {
+ retval = 0;
+ break;
}
- nlp = nlp->next;
}
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return 1;
+ spin_unlock_irqrestore(&mlp->online_lock, flags);
+ return retval;
}
-static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp)
+static inline
+void isdn_net_inc_frame_cnt(isdn_net_dev *idev)
{
- atomic_inc(&lp->frame_cnt);
- if (isdn_net_device_busy(lp))
- isdn_net_device_stop_queue(lp);
+ atomic_inc(&idev->frame_cnt);
+ if (isdn_net_device_busy(idev))
+ isdn_net_dev_stop_queue(idev);
}
-static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
+static inline void
+isdn_net_dec_frame_cnt(isdn_net_dev *idev)
{
- atomic_dec(&lp->frame_cnt);
+ atomic_dec(&idev->frame_cnt);
- if (!(isdn_net_device_busy(lp))) {
- if (!skb_queue_empty(&lp->super_tx_queue)) {
- schedule_work(&lp->tqueue);
- } else {
- isdn_net_device_wake_queue(lp);
- }
+ if (!isdn_net_device_busy(idev)) {
+ if (!skb_queue_empty(&idev->super_tx_queue))
+ tasklet_schedule(&idev->tlet);
+ else
+ isdn_net_dev_wake_queue(idev);
}
}
-static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
+static inline
+void isdn_net_zero_frame_cnt(isdn_net_dev *idev)
{
- atomic_set(&lp->frame_cnt, 0);
+ atomic_set(&idev->frame_cnt, 0);
}
-/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
- * to be safe.
- * For 2.3.x we push it up to 20 secs, because call establishment
- * (in particular callback) may take such a long time, and we
- * don't want confusing messages in the log. However, there is a slight
- * possibility that this large timeout will break other things like MPPP,
- * which might rely on the tx timeout. If so, we'll find out this way...
- */
+/* Prototypes */
-#define ISDN_NET_TX_TIMEOUT (20*HZ)
+int isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg);
+
+char *isdn_net_revision = "$Revision: 1.140.6.11 $";
-static struct isdn_netif_ops *netif_ops[ISDN_NET_ENCAP_NR];
+/* A packet has successfully been sent out. */
int
-register_isdn_netif(int encap, struct isdn_netif_ops *ops)
+isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c)
{
- if (encap < 0 || encap >= ISDN_NET_ENCAP_NR)
- return -EINVAL;
+ isdn_net_local *mlp = idev->mlp;
- if (netif_ops[encap])
- return -EBUSY;
-
- netif_ops[encap] = ops;
-
- return 0;
-}
-
-int isdn_net_online(isdn_net_dev *idev)
-{
- return idev->dialstate == ST_ACTIVE;
+ isdn_net_dec_frame_cnt(idev);
+ mlp->stats.tx_packets++;
+ mlp->stats.tx_bytes += c->parm.length;
+ return 1;
}
-/* Prototypes */
-
-static int isdn_net_force_dial_lp(isdn_net_local *);
-static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
-static void do_dialout(isdn_net_local *lp);
-static int isdn_net_set_encap(isdn_net_dev *p, int encap);
-static int isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg);
-
-char *isdn_net_revision = "$Revision: 1.140.6.11 $";
-
- /*
- * Code for raw-networking over ISDN
- */
-
static void
isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
{
@@ -232,611 +163,48 @@ isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
dst_link_failure(skb);
}
-/* Open/initialize the board. */
-static int
-isdn_net_open(struct net_device *dev)
-{
- isdn_net_local *lp = dev->priv;
- int retval = 0;
-
- if (!lp->ops)
- return -ENODEV;
-
- if (lp->ops->open)
- retval = lp->ops->open(lp);
-
- if (!retval)
- return retval;
-
- netif_start_queue(dev);
- isdn_MOD_INC_USE_COUNT();
- return 0;
-}
-
-/*
- * unbind a net-interface (resets interface after an error)
- */
static void
-isdn_net_unbind_channel(isdn_net_local * lp)
-{
- isdn_net_dev *idev = lp->netdev;
- ulong flags;
-
- save_flags(flags);
- cli();
-
- if (lp->ops->unbind)
- lp->ops->unbind(lp);
-
- skb_queue_purge(&lp->super_tx_queue);
-
- if (!lp->master) { /* reset only master device */
- /* Moral equivalent of dev_purge_queues():
- BEWARE! This chunk of code cannot be called from hardware
- interrupt handler. I hope it is true. --ANK
- */
- qdisc_reset(lp->netdev->dev.qdisc);
- }
- idev->dialstate = ST_NULL;
- if (idev->isdn_slot >= 0) {
- isdn_slot_set_rx_netdev(idev->isdn_slot, NULL);
- isdn_slot_set_st_netdev(idev->isdn_slot, NULL);
- isdn_slot_free(idev->isdn_slot, ISDN_USAGE_NET);
- }
- idev->isdn_slot = -1;
-
- restore_flags(flags);
-}
-
-/*
- * Assign an ISDN-channel to a net-interface
- */
-static int
-isdn_net_bind_channel(isdn_net_local *lp, int idx)
+isdn_net_log_skb(struct sk_buff *skb, isdn_net_dev *idev)
{
- isdn_net_dev *idev = lp->netdev;
- int retval = 0;
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- idev->isdn_slot = idx;
- isdn_slot_set_rx_netdev(idev->isdn_slot, lp->netdev);
- isdn_slot_set_st_netdev(idev->isdn_slot, lp->netdev);
-
- if (lp->ops->bind)
- retval = lp->ops->bind(lp);
-
- if (retval < 0)
- isdn_net_unbind_channel(lp);
-
- restore_flags(flags);
- return retval;
-}
-
-/*
- * Perform auto-hangup for net-interfaces.
- *
- * auto-hangup:
- * Increment idle-counter (this counter is reset on any incoming or
- * outgoing packet), if counter exceeds configured limit either do a
- * hangup immediately or - if configured - wait until just before the next
- * charge-info.
- */
-
-static void isdn_net_hup_timer(unsigned long data)
-{
- isdn_net_dev *idev = (isdn_net_dev *) data;
- isdn_net_local *lp = &idev->local;
-
- if (!isdn_net_online(idev)) {
- isdn_BUG();
- return;
- }
-
- dbg_net_dial("%s: huptimer %d, onhtime %d, chargetime %ld, chargeint %d\n",
- l->name, l->huptimer, l->onhtime, l->chargetime, l->chargeint);
-
- if (lp->onhtime == 0)
- return;
-
- if (idev->huptimer++ <= lp->onhtime)
- goto mod_timer;
-
- if ((lp->hupflags & (ISDN_MANCHARGE | ISDN_CHARGEHUP)) == (ISDN_MANCHARGE | ISDN_CHARGEHUP)) {
- while (time_after(jiffies, idev->chargetime + idev->chargeint))
- idev->chargetime += idev->chargeint;
-
- if (time_after(jiffies, idev->chargetime + idev->chargeint - 2 * HZ)) {
- if (idev->outgoing || lp->hupflags & ISDN_INHUP) {
- isdn_net_hangup(idev);
- return;
- }
- }
- } else if (idev->outgoing) {
- if (lp->hupflags & ISDN_CHARGEHUP) {
- if (idev->charge_state != ST_CHARGE_HAVE_CINT) {
- dbg_net_dial("%s: did not get CINT\n", lp->name);
- isdn_net_hangup(idev);
- return;
- } else if (time_after(jiffies, idev->chargetime + idev->chargeint)) {
- dbg_net_dial("%s: chtime = %lu, chint = %d\n",
- lp->name, lp->chargetime, lp->chargeint);
- isdn_net_hangup(idev);
- return;
- }
- }
- } else if (lp->hupflags & ISDN_INHUP) {
- isdn_net_hangup(idev);
- return;
- }
- mod_timer:
- mod_timer(&idev->hup_timer, idev->hup_timer.expires + HZ);
-}
-
-static void isdn_net_lp_disconnected(isdn_net_local *lp)
-{
- isdn_net_rm_from_bundle(lp);
-}
-
-static void isdn_net_connected(isdn_net_local *lp)
-{
- isdn_net_dev *idev = lp->netdev;
-
- idev->dialstate = ST_ACTIVE;
- idev->hup_timer.expires = jiffies + HZ;
- add_timer(&idev->hup_timer);
-
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
- if (lp->master) { /* is lp a slave? */
- isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev;
- isdn_net_add_to_bundle(nd, lp);
- }
- }
- printk(KERN_INFO "isdn_net: %s connected\n", idev->name);
- /* If first Chargeinfo comes before B-Channel connect,
- * we correct the timestamp here.
- */
- idev->chargetime = jiffies;
-
- /* reset dial-timeout */
- idev->dialstarted = 0;
- idev->dialwait_timer = 0;
-
- idev->transcount = 0;
- idev->cps = 0;
- idev->last_jiffies = jiffies;
-
- if (lp->ops->connected)
- lp->ops->connected(lp);
- else
- isdn_net_device_wake_queue(lp);
-}
-
-/*
- * Handle status-messages from ISDN-interfacecard.
- * This function is called from within the main-status-dispatcher
- * isdn_status_callback, which itself is called from the low-level driver.
- * Return: 1 = Event handled, 0 = not for us or unknown Event.
- */
-int
-isdn_net_stat_callback(int idx, isdn_ctrl *c)
-{
- isdn_net_dev *p = isdn_slot_st_netdev(idx);
- isdn_net_local *lp;
- int cmd = c->command;
-
- if (!p) {
- HERE;
- return 0;
- }
- lp = &p->local;
-
- return isdn_net_handle_event(lp, cmd, c);
-}
-
-static void
-isdn_net_dial_timer(unsigned long data)
-{
- isdn_net_dev *idev = (isdn_net_dev *) data;
-
- isdn_net_handle_event(&idev->local, idev->dial_event, NULL);
-}
-
-/* Initiate dialout. Set phone-number-pointer to first number
- * of interface.
- */
-static void
-init_dialout(isdn_net_local *lp)
-{
- isdn_net_dev *idev = lp->netdev;
-
- idev->dial = 0;
-
- if (lp->dialtimeout > 0 &&
- (idev->dialstarted == 0 ||
- time_after(jiffies, idev->dialstarted + lp->dialtimeout + lp->dialwait))) {
- idev->dialstarted = jiffies;
- idev->dialwait_timer = 0;
- }
- lp->dialretry = 0;
- do_dialout(lp);
-}
-
-/* Setup interface, dial current phone-number, switch to next number.
- * If list of phone-numbers is exhausted, increment
- * retry-counter.
- */
-static void
-do_dialout(isdn_net_local *lp)
-{
- isdn_net_dev *idev = lp->netdev;
- int i;
- unsigned long flags;
- struct isdn_net_phone *phone;
- struct dial_info dial = {
- .l2_proto = lp->l2_proto,
- .l3_proto = lp->l3_proto,
- .si1 = 7,
- .si2 = 0,
- .msn = lp->msn,
- };
-
- if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)
- return;
-
- spin_lock_irqsave(&lp->lock, flags);
- if (list_empty(&lp->phone[1])) {
- spin_unlock_irqrestore(&lp->lock, flags);
- return;
- }
- i = 0;
- list_for_each_entry(phone, &lp->phone[1], list) {
- if (i++ == idev->dial)
- goto found;
- }
- /* otherwise start in front */
- phone = list_entry(lp->phone[1].next, struct isdn_net_phone, list);
- idev->dial = 0;
- lp->dialretry++;
-
- found:
- idev->dial++;
- dial.phone = phone->num;
- spin_unlock_irqrestore(&lp->lock, flags);
-
- if (lp->dialretry > lp->dialmax) {
- if (lp->dialtimeout == 0) {
- idev->dialwait_timer = jiffies + lp->dialwait;
- idev->dialstarted = 0;
- }
- isdn_net_hangup(idev);
- return;
- }
- if(lp->dialtimeout > 0 &&
- time_after(jiffies, idev->dialstarted + lp->dialtimeout)) {
- idev->dialwait_timer = jiffies + lp->dialwait;
- idev->dialstarted = 0;
- isdn_net_hangup(idev);
- return;
- }
- /*
- * Switch to next number or back to start if at end of list.
- */
- isdn_slot_dial(idev->isdn_slot, &dial);
-
- idev->huptimer = 0;
- idev->outgoing = 1;
- if (idev->chargeint)
- idev->charge_state = ST_CHARGE_HAVE_CINT;
- else
- idev->charge_state = ST_CHARGE_NULL;
-
- if (lp->cbdelay && (lp->flags & ISDN_NET_CBOUT)) {
- idev->dial_timer.expires = jiffies + lp->cbdelay;
- idev->dial_event = EV_NET_TIMER_CB;
- } else {
- idev->dial_timer.expires = jiffies + 10 * HZ;
- idev->dial_event = EV_NET_TIMER_OUT_DCONN;
- }
- idev->dialstate = ST_OUT_WAIT_DCONN;
- add_timer(&idev->dial_timer);
-}
-
-/* For EV_NET_DIAL, returns 1 if timer callback is needed
- * For ISDN_STAT_*, returns 1 if event was for us
- */
-static int
-isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
-{
- isdn_net_dev *idev = lp->netdev;
- isdn_ctrl *c = arg;
- isdn_ctrl cmd;
-
- dbg_net_dial("%s: dialstate=%d pr=%#x\n", lp->name, lp->dialstate,pr);
-
- switch (idev->dialstate) {
- case ST_ACTIVE:
- switch (pr) {
- case ISDN_STAT_BSENT:
- /* A packet has successfully been sent out */
- isdn_net_dec_frame_cnt(lp);
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += c->parm.length;
- return 1;
- case ISDN_STAT_DHUP:
- if (lp->ops->disconnected)
- lp->ops->disconnected(lp);
-
- isdn_net_lp_disconnected(lp);
- isdn_slot_all_eaz(idev->isdn_slot);
- printk(KERN_INFO "%s: remote hangup\n", idev->name);
- printk(KERN_INFO "%s: Chargesum is %d\n", idev->name,
- idev->charge);
- isdn_net_unbind_channel(lp);
- return 1;
- case ISDN_STAT_CINF:
- /* Charge-info from TelCo. Calculate interval between
- * charge-infos and set timestamp for last info for
- * usage by isdn_net_autohup()
- */
- idev->charge++;
- switch (idev->charge_state) {
- case ST_CHARGE_NULL:
- idev->charge_state = ST_CHARGE_GOT_CINF;
- break;
- case ST_CHARGE_GOT_CINF:
- idev->charge_state = ST_CHARGE_HAVE_CINT;
- /* fall through */
- case ST_CHARGE_HAVE_CINT:
- idev->chargeint = jiffies - idev->chargetime - 2 * HZ;
- break;
- }
- idev->chargetime = jiffies;
- dbg_net_dial("%s: got CINF\n", lp->name);
- return 1;
- }
- break;
- case ST_OUT_WAIT_DCONN:
- switch (pr) {
- case EV_NET_TIMER_OUT_DCONN:
- /* try again */
- do_dialout(lp);
- return 1;
- case EV_NET_TIMER_CB:
- /* Remote does callback. Hangup after cbdelay,
- * then wait for incoming call */
- printk(KERN_INFO "%s: hangup waiting for callback ...\n", idev->name);
- isdn_net_hangup(idev);
- return 1;
- case ISDN_STAT_DCONN:
- /* Got D-Channel-Connect, send B-Channel-request */
- del_timer(&idev->dial_timer);
- idev->dialstate = ST_OUT_WAIT_BCONN;
- isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
- idev->dial_timer.expires = jiffies + 10 * HZ;
- idev->dial_event = EV_NET_TIMER_OUT_BCONN;
- add_timer(&idev->dial_timer);
- return 1;
- case ISDN_STAT_DHUP:
- del_timer(&idev->dial_timer);
- isdn_slot_all_eaz(idev->isdn_slot);
- printk(KERN_INFO "%s: remote hangup\n", idev->name);
- isdn_net_unbind_channel(lp);
- return 1;
- }
- break;
- case ST_OUT_WAIT_BCONN:
- switch (pr) {
- case EV_NET_TIMER_OUT_BCONN:
- /* try again */
- do_dialout(lp);
- return 1;
- case ISDN_STAT_BCONN:
- del_timer(&idev->dial_timer);
- isdn_slot_set_usage(idev->isdn_slot, isdn_slot_usage(idev->isdn_slot) | ISDN_USAGE_OUTGOING);
- isdn_net_connected(lp);
- return 1;
- case ISDN_STAT_DHUP:
- del_timer(&idev->dial_timer);
- isdn_slot_all_eaz(idev->isdn_slot);
- printk(KERN_INFO "%s: remote hangup\n", idev->name);
- isdn_net_unbind_channel(lp);
- return 1;
- }
- break;
- case ST_IN_WAIT_DCONN:
- switch (pr) {
- case EV_NET_TIMER_IN_DCONN:
- isdn_net_hangup(idev);
- return 1;
- case ISDN_STAT_DCONN:
- del_timer(&idev->dial_timer);
- idev->dialstate = ST_IN_WAIT_BCONN;
- isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
- idev->dial_timer.expires = jiffies + 10 * HZ;
- idev->dial_event = EV_NET_TIMER_IN_BCONN;
- add_timer(&idev->dial_timer);
- return 1;
- case ISDN_STAT_DHUP:
- del_timer(&idev->dial_timer);
- isdn_slot_all_eaz(idev->isdn_slot);
- printk(KERN_INFO "%s: remote hangup\n", idev->name);
- isdn_net_unbind_channel(lp);
- return 1;
- }
- break;
- case ST_IN_WAIT_BCONN:
- switch (pr) {
- case EV_NET_TIMER_IN_BCONN:
- isdn_net_hangup(idev);
- break;
- case ISDN_STAT_BCONN:
- del_timer(&idev->dial_timer);
- isdn_slot_set_rx_netdev(idev->isdn_slot, idev);
- isdn_net_connected(lp);
- return 1;
- case ISDN_STAT_DHUP:
- del_timer(&idev->dial_timer);
- isdn_slot_all_eaz(idev->isdn_slot);
- printk(KERN_INFO "%s: remote hangup\n", idev->name);
- isdn_net_unbind_channel(lp);
- return 1;
- }
- break;
- case ST_WAIT_BEFORE_CB:
- switch (pr) {
- case EV_NET_TIMER_CB:
- /* Callback Delay */
- init_dialout(lp);
- return 1;
- }
- break;
- default:
- isdn_BUG();
- break;
- }
- printk("NOT HANDLED?\n");
- return 0;
-}
-
-/*
- * Perform hangup for a net-interface.
- */
-void
-isdn_net_hangup(isdn_net_dev *idev)
-{
- isdn_net_local *lp = &idev->local;
- isdn_ctrl cmd;
-
- del_timer_sync(&idev->hup_timer);
- if (!isdn_net_bound(idev))
- return;
-
- // FIXME ugly and recursive
- if (lp->slave != NULL) {
- isdn_net_local *slp = (isdn_net_local *)lp->slave->priv;
- isdn_net_dev *sidev = slp->netdev;
- if (isdn_net_bound(sidev)) {
- printk(KERN_INFO
- "isdn_net: hang up slave %s before %s\n",
- sidev->name, idev->name);
- isdn_net_hangup(sidev);
- }
- }
- printk(KERN_INFO "isdn_net: local hangup %s\n", idev->name);
- if (lp->ops->disconnected)
- lp->ops->disconnected(lp);
-
- isdn_net_lp_disconnected(lp);
-
- isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd);
- printk(KERN_INFO "%s: Chargesum is %d\n", idev->name, idev->charge);
- isdn_slot_all_eaz(idev->isdn_slot);
- isdn_net_unbind_channel(lp);
-}
-
-void
-isdn_net_hangup_all()
-{
- struct list_head *l;
-
- list_for_each(l, &isdn_net_devs) {
- isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
- isdn_net_hangup(p);
- }
-}
-
-typedef struct {
- unsigned short source;
- unsigned short dest;
-} ip_ports;
-
-static void
-isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
-{
- isdn_net_dev *idev = lp->netdev;
- u_char *p = skb->nh.raw; /* hopefully, this was set correctly */
+ unsigned char *p = skb->nh.raw; /* hopefully, this was set correctly */
unsigned short proto = ntohs(skb->protocol);
int data_ofs;
- ip_ports *ipp;
+ struct ip_ports {
+ unsigned short source;
+ unsigned short dest;
+ } *ipp;
char addinfo[100];
- addinfo[0] = '\0';
- /* This check stolen from 2.1.72 dev_queue_xmit_nit() */
- if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) {
- /* fall back to old isdn_net_log_packet method() */
- char * buf = skb->data;
-
- printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, idev->name);
- p = buf;
- proto = ETH_P_IP;
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_IPTYP:
- proto = ntohs(*(unsigned short *) &buf[0]);
- p = &buf[2];
- break;
- case ISDN_NET_ENCAP_ETHER:
- proto = ntohs(*(unsigned short *) &buf[12]);
- p = &buf[14];
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- proto = ntohs(*(unsigned short *) &buf[2]);
- p = &buf[4];
- break;
- case ISDN_NET_ENCAP_SYNCPPP:
- proto = ntohs(skb->protocol);
- p = &buf[IPPP_MAX_HEADER];
- break;
- }
- }
data_ofs = ((p[0] & 15) * 4);
switch (proto) {
- case ETH_P_IP:
- switch (p[9]) {
- case 1:
- strcpy(addinfo, " ICMP");
- break;
- case 2:
- strcpy(addinfo, " IGMP");
- break;
- case 4:
- strcpy(addinfo, " IPIP");
- break;
- case 6:
- ipp = (ip_ports *) (&p[data_ofs]);
- sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source),
- ntohs(ipp->dest));
- break;
- case 8:
- strcpy(addinfo, " EGP");
- break;
- case 12:
- strcpy(addinfo, " PUP");
- break;
- case 17:
- ipp = (ip_ports *) (&p[data_ofs]);
- sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source),
- ntohs(ipp->dest));
- break;
- case 22:
- strcpy(addinfo, " IDP");
- break;
- }
- printk(KERN_INFO
- "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
-
- p[12], p[13], p[14], p[15],
- p[16], p[17], p[18], p[19],
- addinfo);
+ case ETH_P_IP:
+ switch (p[9]) {
+ case IPPROTO_ICMP:
+ strcpy(addinfo, "ICMP");
break;
- case ETH_P_ARP:
- printk(KERN_INFO
- "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
- p[14], p[15], p[16], p[17],
- p[24], p[25], p[26], p[27]);
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ ipp = (struct ip_ports *) (&p[data_ofs]);
+ sprintf(addinfo, "%s, port: %d -> %d",
+ p[9] == IPPROTO_TCP ? "TCP" : "UDP",
+ ntohs(ipp->source), ntohs(ipp->dest));
break;
+ default:
+ sprintf(addinfo, "type %d", p[9]);
+ }
+ printk(KERN_INFO
+ "OPEN: %u.%u.%u.%u -> %u.%u.%u.%u %s\n",
+
+ NIPQUAD(*(u32 *)(p + 12)), NIPQUAD(*(u32 *)(p + 16)),
+ addinfo);
+ break;
+ case ETH_P_ARP:
+ printk(KERN_INFO
+ "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
+ NIPQUAD(*(u32 *)(p + 14)), NIPQUAD(*(u32 *)(p + 24)));
+ break;
+ default:
+ printk(KERN_INFO "OPEN: unknown proto %#x\n", proto);
}
}
@@ -845,56 +213,40 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
* not received from the network layer, but e.g. frames from ipppd, CCP
* reset frames etc.
*/
-void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
+void
+isdn_net_write_super(isdn_net_dev *idev, struct sk_buff *skb)
{
if (in_irq()) {
// we can't grab the lock from irq context,
// so we just queue the packet
- skb_queue_tail(&lp->super_tx_queue, skb);
- schedule_work(&lp->tqueue);
+ skb_queue_tail(&idev->super_tx_queue, skb);
+
+ tasklet_schedule(&idev->tlet);
return;
}
- spin_lock_bh(&lp->xmit_lock);
- if (!isdn_net_lp_busy(lp)) {
- isdn_net_writebuf_skb(lp, skb);
+ spin_lock_bh(&idev->xmit_lock);
+ if (!isdn_net_dev_busy(idev)) {
+ isdn_net_writebuf_skb(idev, skb);
} else {
- skb_queue_tail(&lp->super_tx_queue, skb);
+ skb_queue_tail(&idev->super_tx_queue, skb);
}
- spin_unlock_bh(&lp->xmit_lock);
-}
-
-/*
- * called from tq_immediate
- */
-static void isdn_net_softint(void *private)
-{
- isdn_net_local *lp = private;
- struct sk_buff *skb;
-
- spin_lock_bh(&lp->xmit_lock);
- while (!isdn_net_lp_busy(lp)) {
- skb = skb_dequeue(&lp->super_tx_queue);
- if (!skb)
- break;
- isdn_net_writebuf_skb(lp, skb);
- }
- spin_unlock_bh(&lp->xmit_lock);
+ spin_unlock_bh(&idev->xmit_lock);
}
/*
* all frames sent from the (net) LL to a HL driver should go via this function
- * it's serialized by the caller holding the lp->xmit_lock spinlock
+ * it's serialized by the caller holding the idev->xmit_lock spinlock
*/
-void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
+void isdn_net_writebuf_skb(isdn_net_dev *idev, struct sk_buff *skb)
{
- isdn_net_dev *idev = lp->netdev;
+ isdn_net_local *mlp = idev->mlp;
int ret;
int len = skb->len; /* save len */
/* before obtaining the lock the caller should have checked that
the lp isn't busy */
- if (isdn_net_lp_busy(lp)) {
+ if (isdn_net_dev_busy(idev)) {
isdn_BUG();
goto error;
}
@@ -911,18 +263,28 @@ void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
}
idev->transcount += len;
- isdn_net_inc_frame_cnt(lp);
+ isdn_net_inc_frame_cnt(idev);
return;
error:
dev_kfree_skb(skb);
- lp->stats.tx_errors++;
+ mlp->stats.tx_errors++;
}
+static void
+isdn_net_dial_slave(isdn_net_local *mlp)
+{
+ isdn_net_dev *idev;
+
+ list_for_each_entry(idev, &mlp->slaves, slaves) {
+ if (!isdn_net_bound(idev)) {
+ isdn_net_dial(idev);
+ break;
+ }
+ }
+}
/*
- * Helper function for isdn_net_start_xmit.
- * When called, the connection is already established.
* Based on cps-calculation, check if device is overloaded.
* If so, and if a slave exists, trigger dialing for it.
* If any slave is online, deliver packets using a simple round robin
@@ -931,37 +293,27 @@ void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
* Return: 0 on success, !0 on failure.
*/
-static int
-isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
+int
+isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
- isdn_net_dev *nd, *idev;
- isdn_net_local *slp;
- isdn_net_local *lp = ndev->priv;
- int retv = 0;
+ isdn_net_dev *idev;
+ isdn_net_local *mlp = ndev->priv;
- if (lp->master) {
- isdn_BUG();
- dev_kfree_skb(skb);
- return 0;
- }
+ ndev->trans_start = jiffies;
- /* For the other encaps the header has already been built */
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
- return isdn_ppp_xmit(skb, ndev);
- }
- nd = ((isdn_net_local *) ndev->priv)->netdev;
- lp = isdn_net_get_locked_lp(nd);
- if (!lp) {
+ if (list_empty(&mlp->online))
+ return isdn_net_autodial(skb, ndev);
+
+ idev = isdn_net_get_locked_dev(mlp);
+ if (!idev) {
printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
+ netif_stop_queue(ndev);
return 1;
}
- idev = lp->netdev;
- /* we have our lp locked from now on */
+ /* we have our idev locked from now on */
- /* Reset hangup-timeout */
- idev->huptimer = 0; // FIXME?
- isdn_net_writebuf_skb(lp, skb);
- spin_unlock_bh(&lp->xmit_lock);
+ isdn_net_writebuf_skb(idev, skb);
+ spin_unlock_bh(&idev->xmit_lock);
/* the following stuff is here for backwards compatibility.
* in future, start-up and hangup of slaves (based on current load)
@@ -976,88 +328,50 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
if (dev->net_verbose > 3)
printk(KERN_DEBUG "%s: %d bogocps\n", idev->name, idev->cps);
- if (idev->cps > lp->triggercps) {
- if (lp->slave) {
- if (!lp->sqfull) {
- /* First time overload: set timestamp only */
- lp->sqfull = 1;
- lp->sqfull_stamp = jiffies;
- } else {
- /* subsequent overload: if slavedelay exceeded, start dialing */
- if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) {
- slp = lp->slave->priv;
- if (!isdn_net_bound(slp->netdev)) {
- isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
- }
- }
+ if (idev->cps > mlp->triggercps) {
+ if (!idev->sqfull) {
+ /* First time overload: set timestamp only */
+ idev->sqfull = 1;
+ idev->sqfull_stamp = jiffies;
+ } else {
+ /* subsequent overload: if slavedelay exceeded, start dialing */
+ if (time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay)) {
+ isdn_net_dial_slave(mlp);
}
}
} else {
- if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) {
- lp->sqfull = 0;
+ if (idev->sqfull && time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay + 10 * HZ)) {
+ idev->sqfull = 0;
}
/* this is a hack to allow auto-hangup for slaves on moderate loads */
- nd->queue = &nd->local;
- }
-
- return retv;
-
-}
-
-static void
-isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
-{
- isdn_net_local *lp = dev->priv;
- if (!skb)
- return;
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
- int pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN;
- if (pullsize > 0) {
- printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize);
- skb_pull(skb, pullsize);
- }
+ list_del(&mlp->online);
+ list_add_tail(&mlp->online, &idev->online);
}
-}
-
-
-void isdn_net_tx_timeout(struct net_device * ndev)
-{
- isdn_net_local *lp = ndev->priv;
- isdn_net_dev *idev = lp->netdev;
- printk(KERN_WARNING "isdn_tx_timeout dev %s %d\n",
- ndev->name, idev->dialstate);
-
- netif_wake_queue(ndev);
+ return 0;
}
-static int
+int
isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev)
{
- isdn_net_local *lp = ndev->priv;
- isdn_net_dev *idev = lp->netdev;
+ isdn_net_local *mlp = ndev->priv;
+ isdn_net_dev *idev = list_entry(mlp->slaves.next, isdn_net_dev, slaves);
- if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO))
- goto discard;
-
- if (idev->dialwait_timer <= 0)
- if (idev->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, idev->dialstarted + lp->dialtimeout + lp->dialwait))
- idev->dialwait_timer = idev->dialstarted + lp->dialtimeout + lp->dialwait;
-
- if (idev->dialwait_timer > 0) {
- if(time_before(jiffies, idev->dialwait_timer))
- goto discard;
+ /* are we dialing already? */
+ if (isdn_net_bound(idev))
+ goto stop_queue;
- idev->dialwait_timer = 0;
- }
+ if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO)
+ goto discard;
- if (isdn_net_force_dial_lp(lp) < 0)
+ if (isdn_net_dial(idev) < 0)
goto discard;
/* Log packet, which triggered dialing */
if (dev->net_verbose)
- isdn_net_log_skb(skb, lp);
+ isdn_net_log_skb(skb, idev);
+ stop_queue:
netif_stop_queue(ndev);
return 1;
@@ -1069,103 +383,23 @@ isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev)
/*
- * Try sending a packet.
- * If this interface isn't connected to a ISDN-Channel, find a free channel,
- * and start dialing.
- */
-static int
-isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
- isdn_net_local *lp = ndev->priv;
- isdn_net_dev *idev = lp->netdev;
- int retval;
-
- if (lp->p_encap == ISDN_NET_ENCAP_X25IFACE)
- return isdn_x25_start_xmit(skb, ndev);
-
- /* auto-dialing xmit function */
- isdn_net_adjust_hdr(skb, ndev);
- isdn_dumppkt("S:", skb->data, skb->len, 40);
-
- if (!isdn_net_bound(idev))
- return isdn_net_autodial(skb, ndev);
-
- /* Device is bound to an ISDN channel */
- ndev->trans_start = jiffies;
-
- if (idev->dialstate != ST_ACTIVE) {
- netif_stop_queue(ndev);
- return 1;
- }
- /* ISDN connection is established, try sending */
- retval = isdn_net_xmit(ndev, skb);
- if (retval)
- netif_stop_queue(ndev);
-
- return retval;
-}
-
-/*
- * Shutdown a net-interface.
- */
-static int
-isdn_net_close(struct net_device *dev)
-{
- struct net_device *p;
- isdn_net_local *lp = dev->priv;
-
- if (lp->ops->close)
- lp->ops->close(lp);
-
- netif_stop_queue(dev);
-
- for (p = lp->slave; p; p = ((isdn_net_local *) p->priv)->slave)
- isdn_net_hangup(p->priv);
-
- isdn_net_hangup(dev->priv);
- isdn_MOD_DEC_USE_COUNT();
- return 0;
-}
-
-/*
- * Get statistics
- */
-static struct net_device_stats *
-isdn_net_get_stats(struct net_device *dev)
-{
- isdn_net_local *lp = (isdn_net_local *) dev->priv;
- return &lp->stats;
-}
-
-/*
* Got a packet from ISDN-Channel.
*/
static void
-isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
+isdn_net_receive(isdn_net_dev *idev, struct sk_buff *skb)
{
- isdn_net_local *lp = (isdn_net_local *) ndev->priv;
- isdn_net_dev *idev = lp->netdev;
- isdn_net_local *olp = lp; /* original 'lp' */
+ isdn_net_local *mlp = idev->mlp;
idev->transcount += skb->len;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
- if (lp->master) {
- /* Bundling: If device is a slave-device, deliver to master, also
- * handle master's statistics and hangup-timeout
- */
- ndev = lp->master;
- lp = (isdn_net_local *) ndev->priv;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
- }
- skb->dev = ndev;
+ mlp->stats.rx_packets++;
+ mlp->stats.rx_bytes += skb->len;
+ skb->dev = &mlp->dev;
skb->pkt_type = PACKET_HOST;
skb->mac.raw = skb->data;
isdn_dumppkt("R:", skb->data, skb->len, 40);
- lp->ops->receive(lp->netdev, olp, skb);
+ mlp->ops->receive(mlp, idev, skb);
}
/*
@@ -1176,73 +410,16 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
int
isdn_net_rcv_skb(int idx, struct sk_buff *skb)
{
- isdn_net_dev *idev = isdn_slot_rx_netdev(idx);
+ isdn_net_dev *idev = isdn_slot_idev(idx);
- if (!idev)
+ if (!idev) {
+ HERE;
return 0;
-
+ }
if (!isdn_net_online(idev))
return 0;
- isdn_net_receive(&idev->dev, skb);
- return 0;
-}
-
-/*
- * Interface-setup. (just after registering a new interface)
- */
-static int
-isdn_net_init(struct net_device *ndev)
-{
- /* Setup the generic properties */
-
- ndev->mtu = 1500;
- ndev->tx_queue_len = 10;
- ndev->open = &isdn_net_open;
- ndev->hard_start_xmit = &isdn_net_start_xmit;
- ndev->hard_header_len = ETH_HLEN + isdn_hard_header_len();
- ndev->stop = &isdn_net_close;
- ndev->get_stats = &isdn_net_get_stats;
-
- return 0;
-}
-
-static int
-isdn_net_do_callback(isdn_net_local *lp)
-{
- isdn_net_dev *idev = lp->netdev;
- int slot;
- /*
- * Is the state MANUAL?
- * If so, no callback can be made,
- * so reject actively.
- */
- if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
- printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
- idev->name);
- return 3;
- }
- printk(KERN_DEBUG "%s: start callback\n", idev->name);
-
- /* Grab a free ISDN-Channel */
- slot = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto, lp->l3_proto,
- idev->pre_device, idev->pre_channel, lp->msn);
- if (slot < 0)
- goto err;
-
- if (isdn_net_bind_channel(lp, slot) < 0)
- goto err;
-
- /* Setup dialstate. */
- idev->dial_timer.expires = jiffies + lp->cbdelay;
- idev->dial_event = EV_NET_TIMER_CB;
- add_timer(&idev->dial_timer);
- idev->dialstate = ST_WAIT_BEFORE_CB;
-
- /* Initiate dialing by returning 2 or 4 */
- return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
-
- err:
+ isdn_net_receive(idev, skb);
return 0;
}
@@ -1268,13 +445,12 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
char *eaz;
unsigned char si1, si2;
int match_more = 0;
+ int retval;
struct list_head *l;
struct isdn_net_phone *n;
ulong flags;
char nr[32];
char *my_eaz;
- int retval;
- isdn_ctrl cmd;
int slot = isdn_dc2minor(di, ch);
/* Search name in netdev-chain */
@@ -1312,13 +488,13 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *idev = list_entry(l, isdn_net_dev, global_list);
- isdn_net_local *lp = &idev->local;
+ isdn_net_local *mlp = idev->mlp;
/* check acceptable call types for DOV */
- dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
- lp->name, lp->msn, lp->flags, lp->dialstate);
+ dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%#x, l.dstate=%d\n",
+ idev->name, mlp->msn, mlp->flags, idev->fi.state);
- my_eaz = isdn_slot_map_eaz2msn(slot, lp->msn);
+ my_eaz = isdn_slot_map_eaz2msn(slot, mlp->msn);
if (si1 == 1) { /* it's a DOV call, check if we allow it */
if (*my_eaz == 'v' || *my_eaz == 'V' ||
*my_eaz == 'b' || *my_eaz == 'B')
@@ -1345,7 +521,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
continue;
dbg_net_icall("n_fi: match1, pdev=%d pch=%d\n",
- lp->pre_device, lp->pre_channel);
+ idev->pre_device, idev->pre_channel);
if (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE &&
(idev->pre_channel != ch || idev->pre_device != di)) {
@@ -1353,15 +529,12 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
continue;
}
dbg_net_icall("n_fi: match2\n");
- if (lp->flags & ISDN_NET_SECURE) {
- spin_lock_irqsave(&lp->lock, flags);
- list_for_each_entry(n, &lp->phone[0], list) {
+ if (mlp->flags & ISDN_NET_SECURE) {
+ list_for_each_entry(n, &mlp->phone[0], list) {
if (!isdn_msncmp(nr, n->num)) {
- spin_unlock_irqrestore(&lp->lock, flags);
goto found;
}
}
- spin_unlock_irqrestore(&lp->lock, flags);
continue;
}
found:
@@ -1373,7 +546,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
* If so, no dialin is allowed,
* so reject actively.
* */
- if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
+ if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) {
restore_flags(flags);
printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
idev->name);
@@ -1389,58 +562,15 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
idev->name);
return 3;
}
- /* Interface is up, now see if it's a slave. If so, see if
- * it's master and parent slave is online. If not, reject the call.
- */
- if (lp->master) {
- isdn_net_local *mlp = (isdn_net_local *) lp->master->priv;
- printk(KERN_DEBUG "ICALLslv: %s\n", idev->name);
- printk(KERN_DEBUG "master=%s\n", mlp->netdev->name);
- if (isdn_net_bound(mlp->netdev)) {
- printk(KERN_DEBUG "master online\n");
- /* Master is online, find parent-slave (master if first slave) */
- while (mlp->slave) {
- if ((isdn_net_local *) mlp->slave->priv == lp)
- break;
- mlp = (isdn_net_local *) mlp->slave->priv;
- }
- } else
- printk(KERN_DEBUG "master offline\n");
- /* Found parent, if it's offline iterate next device */
- printk(KERN_DEBUG "mlpf: %d\n", isdn_net_bound(mlp->netdev));
- if (!isdn_net_bound(mlp->netdev)) {
- continue;
- }
- }
- if (lp->flags & ISDN_NET_CALLBACK) {
- retval = isdn_net_do_callback(lp);
- restore_flags(flags);
- return retval;
- }
- printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", idev->name,
- nr, eaz);
-
- strcpy(isdn_slot_num(idx), nr);
- isdn_slot_set_usage(idx, (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET);
+ if (mlp->flags & ISDN_NET_CALLBACK) {
+ retval = isdn_net_do_callback(idev);
+ restore_flags(flags);
+ return retval;
+ }
+ printk(KERN_DEBUG "%s: call from %s -> %s accepted\n",
+ idev->name, nr, eaz);
- isdn_net_bind_channel(lp, idx);
-
- idev->outgoing = 0;
- idev->huptimer = 0;
- idev->charge_state = ST_CHARGE_NULL;
- /* Got incoming Call, setup L2 and L3 protocols,
- * then wait for D-Channel-connect
- */
- cmd.arg = lp->l2_proto << 8;
- isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL2, &cmd);
- cmd.arg = lp->l3_proto << 8;
- isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL3, &cmd);
-
- idev->dial_timer.expires = jiffies + 15 * HZ;
- idev->dial_event = EV_NET_TIMER_IN_DCONN;
- add_timer(&idev->dial_timer);
- idev->dialstate = ST_IN_WAIT_DCONN;
-
+ isdn_net_accept(idev, idx, nr);
restore_flags(flags);
return 1;
}
@@ -1451,751 +581,19 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
}
/*
- * Search list of net-interfaces for an interface with given name.
- */
-isdn_net_dev *
-isdn_net_findif(char *name)
-{
- struct list_head *l;
-
- list_for_each(l, &isdn_net_devs) {
- isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
- if (!strcmp(p->name, name))
- return p;
- }
- return NULL;
-}
-
-/*
- * Force a net-interface to dial out.
- * This is called from the userlevel-routine below or
- * from isdn_net_start_xmit().
- */
-static int
-isdn_net_force_dial_lp(isdn_net_local *lp)
-{
- isdn_net_dev *idev = lp->netdev;
- int slot;
- unsigned long flags;
-
- if (isdn_net_bound(idev))
- return -EBUSY;
-
- save_flags(flags);
- cli();
-
- if (idev->exclusive >= 0)
- slot = idev->exclusive;
- else
- slot = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto,
- lp->l3_proto, idev->pre_device,
- idev->pre_channel, lp->msn);
- if (slot < 0)
- goto err;
-
- if (isdn_net_bind_channel(lp, slot) < 0)
- goto err;;
-
- /* Initiate dialing */
- restore_flags(flags);
- init_dialout(lp);
-
- return 0;
-
- err:
- restore_flags(flags);
- return -EAGAIN;
-}
-
-/*
* This is called from certain upper protocol layers (multilink ppp
* and x25iface encapsulation module) that want to initiate dialing
* themselves.
*/
int
-isdn_net_dial_req(isdn_net_local * lp)
+isdn_net_dial_req(isdn_net_dev *idev)
{
+ isdn_net_local *mlp = idev->mlp;
/* is there a better error code? */
- if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY;
-
- return isdn_net_force_dial_lp(lp);
-}
-
-/*
- * Force a net-interface to dial out.
- * This is always called from within userspace (ISDN_IOCTL_NET_DIAL).
- */
-int
-isdn_net_force_dial(char *name)
-{
- isdn_net_dev *p = isdn_net_findif(name);
-
- if (!p)
- return -ENODEV;
- return (isdn_net_force_dial_lp(&p->local));
-}
-
-/*
- * Allocate a new network-interface and initialize its data structures.
- */
-int
-isdn_net_new(char *name, struct net_device *master)
-{
- int retval;
- isdn_net_dev *netdev;
-
- /* Avoid creating an existing interface */
- if (isdn_net_findif(name)) {
- printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
- return -EEXIST;
- }
- if (!(netdev = kmalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
- return -ENOMEM;
- }
- memset(netdev, 0, sizeof(isdn_net_dev));
- strcpy(netdev->name, name);
- strcpy(netdev->dev.name, name);
- netdev->dev.priv = &netdev->local;
- netdev->dev.init = isdn_net_init;
- if (master) {
- /* Device shall be a slave */
- struct net_device *p = (((isdn_net_local *) master->priv)->slave);
- struct net_device *q = master;
-
- netdev->local.master = master;
- /* Put device at end of slave-chain */
- while (p) {
- q = p;
- p = (((isdn_net_local *) p->priv)->slave);
- }
- ((isdn_net_local *) q->priv)->slave = &(netdev->dev);
- } else {
- /* Device shall be a master */
- /*
- * Watchdog timer (currently) for master only.
- */
- netdev->dev.tx_timeout = isdn_net_tx_timeout;
- netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
- retval = register_netdev(&netdev->dev);
- if (retval) {
- printk(KERN_WARNING "isdn_net: Could not register net-device\n");
- kfree(netdev);
- return retval;
- }
- }
- netdev->local.magic = ISDN_NET_MAGIC;
-
- netdev->queue = &netdev->local;
- spin_lock_init(&netdev->queue_lock);
-
- netdev->local.last = &netdev->local;
- netdev->local.netdev = netdev;
- netdev->local.next = &netdev->local;
-
- INIT_WORK(&netdev->local.tqueue, isdn_net_softint, &netdev->local);
- spin_lock_init(&netdev->local.xmit_lock);
-
- netdev->isdn_slot = -1;
- netdev->pre_device = -1;
- netdev->pre_channel = -1;
- netdev->exclusive = -1;
-
- netdev->ppp_slot = -1;
- netdev->pppbind = -1;
-
- netdev->local.p_encap = -1;
- skb_queue_head_init(&netdev->local.super_tx_queue);
- netdev->local.l2_proto = ISDN_PROTO_L2_X75I;
- netdev->local.l3_proto = ISDN_PROTO_L3_TRANS;
- netdev->local.triggercps = 6000;
- netdev->local.slavedelay = 10 * HZ;
- netdev->local.hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
- netdev->local.onhtime = 10; /* Default hangup-time for saving costs
- of those who forget configuring this */
- netdev->local.dialmax = 1;
- netdev->local.flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */
- netdev->local.cbdelay = 5 * HZ; /* Wait 5 secs before Callback */
- netdev->local.dialtimeout = -1; /* Infinite Dial-Timeout */
- netdev->local.dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
- netdev->dialstarted = 0; /* Jiffies of last dial-start */
- netdev->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
-
- init_timer(&netdev->dial_timer);
- netdev->dial_timer.data = (unsigned long) netdev;
- netdev->dial_timer.function = isdn_net_dial_timer;
- init_timer(&netdev->hup_timer);
- netdev->hup_timer.data = (unsigned long) netdev;
- netdev->hup_timer.function = isdn_net_hup_timer;
- spin_lock_init(&netdev->local.lock);
- INIT_LIST_HEAD(&netdev->local.phone[0]);
- INIT_LIST_HEAD(&netdev->local.phone[1]);
- isdn_net_set_encap(netdev, ISDN_NET_ENCAP_RAWIP);
-
- /* Put into to netdev-chain */
- list_add(&netdev->global_list, &isdn_net_devs);
- return 0;
-}
-
-int
-isdn_net_newslave(char *parm)
-{
- char *p = strchr(parm, ',');
- isdn_net_dev *m;
-
- /* Slave-Name MUST not be empty */
- if (!p || !p[1])
- return -EINVAL;
-
- *p = 0;
- /* Master must already exist */
- if (!(m = isdn_net_findif(parm)))
- return -ESRCH;
- /* Master must be a real interface, not a slave */
- if (m->local.master)
- return -ENXIO;
- /* Master must not be started yet */
- if (isdn_net_device_started(m))
+ if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO)
return -EBUSY;
- return isdn_net_new(p+1, &m->dev);
-}
-
-static int
-isdn_net_set_encap(isdn_net_dev *p, int encap)
-{
- isdn_net_local *lp = &p->local;
- int retval = 0;
-
- if (lp->p_encap == encap){
- /* nothing to do */
- retval = 0;
- goto out;
- }
- if (isdn_net_device_started(p)) {
- retval = -EBUSY;
- goto out;
- }
- if (lp->ops && lp->ops->cleanup)
- lp->ops->cleanup(lp);
-
- if (encap < 0 || encap >= ISDN_NET_ENCAP_NR) {
- lp->p_encap = -1;
- lp->ops = NULL;
- retval = -EINVAL;
- goto out;
- }
-
- lp->p_encap = encap;
- lp->ops = netif_ops[encap];
-
- p->dev.hard_header = lp->ops->hard_header;
- p->dev.do_ioctl = lp->ops->do_ioctl;
- p->dev.flags = lp->ops->flags;
- p->dev.type = lp->ops->type;
- p->dev.addr_len = lp->ops->addr_len;
- if (lp->ops->init)
- retval = lp->ops->init(lp);
-
- if (retval != 0) {
- lp->p_encap = -1;
- lp->ops = NULL;
- }
- out:
- return retval;
-}
-
-static int
-isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
-{
- isdn_net_local *lp = &idev->local;
- int i, retval;
- int drvidx = -1;
- int chidx = -1;
- char drvid[25];
-
- strncpy(drvid, cfg->drvid, 24);
- drvid[24] = 0;
-
- if (cfg->exclusive && !strlen(drvid)) {
- /* If we want to bind exclusively, need to specify drv/chan */
- retval = -ENODEV;
- goto out;
- }
- if (strlen(drvid)) {
- /* A bind has been requested ... */
- char *c = strchr(drvid, ',');
- if (!c) {
- retval = -ENODEV;
- goto out;
- }
- /* The channel-number is appended to the driver-Id with a comma */
- *c = 0;
- chidx = simple_strtol(c + 1, NULL, 10);
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- /* Lookup driver-Id in array */
- if (!strcmp(dev->drvid[i], drvid)) {
- drvidx = i;
- break;
- }
- }
- if (drvidx == -1 || chidx == -1) {
- /* Either driver-Id or channel-number invalid */
- retval = -ENODEV;
- goto out;
- }
- }
- if (cfg->exclusive == (idev->exclusive >= 0) &&
- drvidx == idev->pre_device && chidx == idev->pre_channel) {
- /* no change */
- retval = 0;
- goto out;
- }
- if (idev->exclusive >= 0) {
- isdn_unexclusive_channel(idev->pre_device, idev->pre_channel);
- isdn_free_channel(idev->pre_device, idev->pre_channel, ISDN_USAGE_NET);
- idev->exclusive = -1;
- }
- if (cfg->exclusive) {
- /* If binding is exclusive, try to grab the channel */
- idev->exclusive = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto,
- lp->l3_proto, drvidx, chidx, cfg->eaz);
- if (idev->exclusive < 0) {
- /* Grab failed, because desired channel is in use */
- retval = -EBUSY;
- goto out;
- }
- /* All went ok, so update isdninfo */
- isdn_slot_set_usage(idev->exclusive, ISDN_USAGE_EXCLUSIVE);
- }
- idev->pre_device = drvidx;
- idev->pre_channel = chidx;
- retval = 0;
- out:
- return retval;
-}
-
-/*
- * Set interface-parameters.
- * Always set all parameters, so the user-level application is responsible
- * for not overwriting existing setups. It has to get the current
- * setup first, if only selected parameters are to be changed.
- */
-int
-isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
-{
- isdn_net_dev *idev = isdn_net_findif(cfg->name);
- isdn_net_local *lp = &idev->local;
- ulong features;
- int i, retval;
-
- if (!idev) {
- retval = -ENODEV;
- goto out;
- }
- /* See if any registered driver supports the features we want */
- features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
- ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (dev->drv[i] &&
- (dev->drv[i]->interface->features & features) == features)
- break;
-
- if (i == ISDN_MAX_DRIVERS) {
- printk(KERN_WARNING "isdn_net: No driver with selected features\n");
- retval = -ENODEV;
- goto out;
- }
-
- retval = isdn_net_set_encap(idev, cfg->p_encap);
- if (retval)
- goto out;
-
- retval = isdn_net_bind(idev, cfg);
- if (retval)
- goto out;
-
- strncpy(lp->msn, cfg->eaz, ISDN_MSNLEN-1);
- lp->msn[ISDN_MSNLEN-1] = 0;
- lp->onhtime = cfg->onhtime;
- idev->charge = cfg->charge;
- lp->l2_proto = cfg->l2_proto;
- lp->l3_proto = cfg->l3_proto;
- lp->cbdelay = cfg->cbdelay * HZ / 5;
- lp->dialmax = cfg->dialmax;
- lp->triggercps = cfg->triggercps;
- lp->slavedelay = cfg->slavedelay * HZ;
- idev->pppbind = cfg->pppbind;
- lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
- lp->dialwait = cfg->dialwait * HZ;
- if (cfg->secure)
- lp->flags |= ISDN_NET_SECURE;
- else
- lp->flags &= ~ISDN_NET_SECURE;
- if (cfg->cbhup)
- lp->flags |= ISDN_NET_CBHUP;
- else
- lp->flags &= ~ISDN_NET_CBHUP;
- switch (cfg->callback) {
- case 0:
- lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
- break;
- case 1:
- lp->flags |= ISDN_NET_CALLBACK;
- lp->flags &= ~ISDN_NET_CBOUT;
- break;
- case 2:
- lp->flags |= ISDN_NET_CBOUT;
- lp->flags &= ~ISDN_NET_CALLBACK;
- break;
- }
- lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */
- if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
- retval = -EINVAL;
- goto out;
- }
-
- lp->flags |= cfg->dialmode; /* turn on selected bits */
- if (lp->flags & ISDN_NET_DM_OFF)
- isdn_net_hangup(idev);
-
- if (cfg->chargehup)
- lp->hupflags |= ISDN_CHARGEHUP;
- else
- lp->hupflags &= ~ISDN_CHARGEHUP;
-
- if (cfg->ihup)
- lp->hupflags |= ISDN_INHUP;
- else
- lp->hupflags &= ~ISDN_INHUP;
-
- if (cfg->chargeint > 10) {
- idev->chargeint = cfg->chargeint * HZ;
- idev->charge_state = ST_CHARGE_HAVE_CINT;
- lp->hupflags |= ISDN_MANCHARGE;
- }
- retval = 0;
-
- out:
- return retval;
-}
-
-/*
- * Perform get-interface-parameters.ioctl
- */
-int
-isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
-{
- isdn_net_dev *idev = isdn_net_findif(cfg->name);
- isdn_net_local *lp = &idev->local;
-
- if (!idev)
- return -ENODEV;
-
- strcpy(cfg->eaz, lp->msn);
- cfg->exclusive = idev->exclusive >= 0;
- if (idev->pre_device >= 0) {
- sprintf(cfg->drvid, "%s,%d", dev->drvid[idev->pre_device],
- idev->pre_channel);
- } else
- cfg->drvid[0] = '\0';
- cfg->onhtime = lp->onhtime;
- cfg->charge = idev->charge;
- cfg->l2_proto = lp->l2_proto;
- cfg->l3_proto = lp->l3_proto;
- cfg->p_encap = lp->p_encap;
- cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
- cfg->callback = 0;
- if (lp->flags & ISDN_NET_CALLBACK)
- cfg->callback = 1;
- if (lp->flags & ISDN_NET_CBOUT)
- cfg->callback = 2;
- cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
- cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
- cfg->chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
- cfg->ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0;
- cfg->cbdelay = lp->cbdelay * 5 / HZ;
- cfg->dialmax = lp->dialmax;
- cfg->triggercps = lp->triggercps;
- cfg->slavedelay = lp->slavedelay / HZ;
- cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
- (idev->chargeint / HZ) : 0;
- cfg->pppbind = idev->pppbind;
- cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
- cfg->dialwait = lp->dialwait / HZ;
- if (lp->slave)
- strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->netdev->name);
- else
- cfg->slave[0] = '\0';
- if (lp->master)
- strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->netdev->name);
- else
- cfg->master[0] = '\0';
-
- return 0;
-}
-
-/*
- * Add a phone-number to an interface.
- */
-int
-isdn_net_addphone(isdn_net_ioctl_phone * phone)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- unsigned long flags;
- struct isdn_net_phone *n;
-
- if (!p)
- return -ENODEV;
-
- n = kmalloc(sizeof(*n), GFP_KERNEL);
- if (!n)
- return -ENOMEM;
-
- strcpy(n->num, phone->phone);
- spin_lock_irqsave(&p->local.lock, flags);
- list_add_tail(&n->list, &p->local.phone[phone->outgoing & 1]);
- spin_unlock_irqrestore(&p->local.lock, flags);
- return 0;
-}
-
-/*
- * Copy a string of all phone-numbers of an interface to user space.
- * This might sleep and must be called with the isdn semaphore down.
- */
-int
-isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- unsigned long flags;
- int inout = phone->outgoing & 1;
- int count = 0;
- char *buf = (char *)__get_free_page(GFP_KERNEL);
- struct isdn_net_phone *n;
-
- if (!p)
- return -ENODEV;
-
- if (!buf)
- return -ENOMEM;
-
- inout &= 1;
- spin_lock_irqsave(&p->local.lock, flags);
- list_for_each_entry(n, &p->local.phone[inout], list) {
- strcpy(&buf[count], n->num);
- count += strlen(n->num);
- buf[count++] = ' ';
- if (count > PAGE_SIZE - ISDN_MSNLEN - 1)
- break;
- }
- spin_unlock_irqrestore(&p->local.lock, flags);
- if (!count)
- count++;
-
- buf[count-1] = 0;
-
- if (copy_to_user(phones, buf, count))
- count = -EFAULT;
-
- free_page((unsigned long)buf);
- return count;
-}
-
-/*
- * Copy a string containing the peer's phone number of a connected interface
- * to user space.
- */
-int
-isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int idx;
-
- if (!p) return -ENODEV;
- /*
- * Theoretical race: while this executes, the remote number might
- * become invalid (hang up) or change (new connection), resulting
- * in (partially) wrong number copied to user. This race
- * currently ignored.
- */
- idx = p->isdn_slot;
- if (idx<0) return -ENOTCONN;
- /* for pre-bound channels, we need this extra check */
- if (strncmp(isdn_slot_num(idx),"???",3) == 0 ) return -ENOTCONN;
- strncpy(phone->phone,isdn_slot_num(idx),ISDN_MSNLEN);
- phone->outgoing=USG_OUTGOING(isdn_slot_usage(idx));
- if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT;
- return 0;
-}
-/*
- * Delete a phone-number from an interface.
- */
-int
-isdn_net_delphone(isdn_net_ioctl_phone * phone)
-{
- isdn_net_dev *p = isdn_net_findif(phone->name);
- int inout = phone->outgoing & 1;
- struct isdn_net_phone *n;
- unsigned long flags;
- int retval;
-
- if (!p)
- return -ENODEV;
-
- retval = -EINVAL;
- spin_lock_irqsave(&p->local.lock, flags);
- list_for_each_entry(n, &p->local.phone[inout], list) {
- if (!strcmp(n->num, phone->phone)) {
- list_del(&n->list);
- kfree(n);
- retval = 0;
- break;
- }
- }
- spin_unlock_irqrestore(&p->local.lock, flags);
- return retval;
-}
-
-/*
- * Delete all phone-numbers of an interface.
- */
-static int
-isdn_net_rmallphone(isdn_net_dev * p)
-{
- struct isdn_net_phone *n;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&p->local.lock, flags);
- for (i = 0; i < 2; i++) {
- while (!list_empty(&p->local.phone[i])) {
- n = list_entry(p->local.phone[i].next, struct isdn_net_phone, list);
- list_del(&n->list);
- kfree(n);
- }
- }
- spin_lock_irqsave(&p->local.lock, flags);
- return 0;
-}
-
-/*
- * Force a hangup of a network-interface.
- */
-int
-isdn_net_force_hangup(char *name)
-{
- isdn_net_dev *idev = isdn_net_findif(name);
- struct net_device *q;
-
- if (!idev)
- return -ENODEV;
-
- if (idev->isdn_slot < 0)
- return -ENOTCONN;
-
- q = idev->local.slave;
- /* If this interface has slaves, do a hangup for them also. */
- while (q) {
- isdn_net_hangup(((isdn_net_local *) q->priv)->netdev);
- q = (((isdn_net_local *) q->priv)->slave);
- }
- isdn_net_hangup(idev);
- return 0;
-}
-
-/*
- * Helper-function for isdn_net_rm: Do the real work.
- */
-static int
-isdn_net_realrm(isdn_net_dev *p)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (isdn_net_device_started(p)) {
- restore_flags(flags);
- return -EBUSY;
- }
- isdn_net_set_encap(p, -1);
-
- /* Free all phone-entries */
- isdn_net_rmallphone(p);
- /* If interface is bound exclusive, free channel-usage */
- if (p->exclusive >= 0)
- isdn_unexclusive_channel(p->pre_device, p->pre_channel);
- if (p->local.master) {
- /* It's a slave-device, so update master's slave-pointer if necessary */
- if (((isdn_net_local *) (p->local.master->priv))->slave == &p->dev)
- ((isdn_net_local *) (p->local.master->priv))->slave = p->local.slave;
- } else {
- /* Unregister only if it's a master-device */
- unregister_netdev(&p->dev);
- }
- /* Unlink device from chain */
- list_del(&p->global_list);
- if (p->local.slave) {
- /* If this interface has a slave, remove it also */
- char *slavename = ((isdn_net_local *) (p->local.slave->priv))->netdev->name;
- struct list_head *l;
-
- list_for_each(l, &isdn_net_devs) {
- isdn_net_dev *n = list_entry(l, isdn_net_dev, global_list);
- if (!strcmp(n->name, slavename)) {
- isdn_net_realrm(n);
- break;
- }
- }
- }
- restore_flags(flags);
- kfree(p);
-
- return 0;
-}
-
-/*
- * Remove a single network-interface.
- */
-int
-isdn_net_rm(char *name)
-{
- struct list_head *l;
-
- /* Search name in netdev-chain */
- list_for_each(l, &isdn_net_devs) {
- isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
- if (!strcmp(p->name, name))
- return isdn_net_realrm(p);
- }
- return -ENODEV;
-}
-
-/*
- * Remove all network-interfaces
- */
-int
-isdn_net_rmall(void)
-{
- unsigned long flags;
- int ret;
-
- /* Walk through netdev-chain */
- save_flags(flags);
- cli();
- while (!list_empty(&isdn_net_devs)) {
- isdn_net_dev *p = list_entry(isdn_net_devs.next, isdn_net_dev, global_list);
-
- /* Remove master-devices only, slaves get removed with their master */
- if (!p->local.master) {
- if ((ret = isdn_net_realrm(p))) {
- restore_flags(flags);
- return ret;
- }
- }
- }
- restore_flags(flags);
- return 0;
+ return isdn_net_dial(idev);
}
// ISDN_NET_ENCAP_IPTYP
@@ -2212,16 +610,17 @@ isdn_iptyp_header(struct sk_buff *skb, struct net_device *dev,
}
static void
-isdn_iptyp_receive(isdn_net_dev *p, isdn_net_local *olp,
+isdn_iptyp_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
- isdn_net_reset_huptimer(p, olp->netdev);
+ idev->huptimer = 0;
get_u16(skb->data, &skb->protocol);
skb_pull(skb, 2);
netif_rx(skb);
}
static struct isdn_netif_ops iptyp_ops = {
+ .hard_start_xmit = isdn_net_start_xmit,
.hard_header = isdn_iptyp_header,
.flags = IFF_NOARP | IFF_POINTOPOINT,
.type = ARPHRD_PPP,
@@ -2243,16 +642,17 @@ isdn_uihdlc_header(struct sk_buff *skb, struct net_device *dev,
}
static void
-isdn_uihdlc_receive(isdn_net_dev *p, isdn_net_local *olp,
+isdn_uihdlc_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
- isdn_net_reset_huptimer(p, olp->netdev);
+ idev->huptimer = 0;
skb_pull(skb, 2);
skb->protocol = htons(ETH_P_IP);
netif_rx(skb);
}
static struct isdn_netif_ops uihdlc_ops = {
+ .hard_start_xmit = isdn_net_start_xmit,
.hard_header = isdn_uihdlc_header,
.flags = IFF_NOARP | IFF_POINTOPOINT,
.type = ARPHRD_HDLC,
@@ -2265,15 +665,16 @@ static struct isdn_netif_ops uihdlc_ops = {
// ======================================================================
static void
-isdn_rawip_receive(isdn_net_dev *p, isdn_net_local *olp,
+isdn_rawip_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
- isdn_net_reset_huptimer(p, olp->netdev);
+ idev->huptimer = 0;
skb->protocol = htons(ETH_P_IP);
netif_rx(skb);
}
static struct isdn_netif_ops rawip_ops = {
+ .hard_start_xmit = isdn_net_start_xmit,
.flags = IFF_NOARP | IFF_POINTOPOINT,
.type = ARPHRD_PPP,
.receive = isdn_rawip_receive,
@@ -2283,73 +684,19 @@ static struct isdn_netif_ops rawip_ops = {
// Ethernet over ISDN
// ======================================================================
-/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
- * instead of dev->hard_header_len off. This is done because the
- * lowlevel-driver has already pulled off its stuff when we get
- * here and this routine only gets called with p_encap == ETHER.
- * Determine the packet's protocol ID. The rule here is that we
- * assume 802.3 if the type field is short enough to be a length.
- * This is normal practice and works for any 'now in use' protocol.
- * FIXME
- */
-
-static unsigned short
-isdn_eth_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
- struct ethhdr *eth;
- unsigned char *rawp;
-
- skb->mac.raw = skb->data;
- skb_pull(skb, ETH_HLEN);
- eth = skb->mac.ethernet;
-
- if (*eth->h_dest & 1) {
- if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
- skb->pkt_type = PACKET_BROADCAST;
- else
- skb->pkt_type = PACKET_MULTICAST;
- }
- /*
- * This ALLMULTI check should be redundant by 1.4
- * so don't forget to remove it.
- */
-
- else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
- if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
- skb->pkt_type = PACKET_OTHERHOST;
- }
- if (ntohs(eth->h_proto) >= 1536)
- return eth->h_proto;
-
- rawp = skb->data;
-
- /*
- * This is a magic hack to spot IPX packets. Older Novell breaks
- * the protocol design and runs IPX over 802.3 without an 802.2 LLC
- * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
- * won't work for fault tolerant netware but does for the rest.
- */
- if (*(unsigned short *) rawp == 0xFFFF)
- return htons(ETH_P_802_3);
- /*
- * Real 802.2 LLC
- */
- return htons(ETH_P_802_2);
-}
-
static void
-isdn_ether_receive(isdn_net_dev *p, isdn_net_local *olp,
+isdn_ether_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
- isdn_net_reset_huptimer(p, olp->netdev);
- skb->protocol = isdn_eth_type_trans(skb, skb->dev);
+ idev->huptimer = 0;
+ skb->protocol = eth_type_trans(skb, skb->dev);
netif_rx(skb);
}
static int
isdn_ether_open(isdn_net_local *lp)
{
- struct net_device *dev = &lp->netdev->dev;
+ struct net_device *dev = &lp->dev;
struct in_device *in_dev;
int i;
@@ -2369,7 +716,7 @@ isdn_ether_open(isdn_net_local *lp)
static int
isdn_ether_init(isdn_net_local *lp)
{
- struct net_device *dev = &lp->netdev->dev;
+ struct net_device *dev = &lp->dev;
ether_setup(dev);
dev->tx_queue_len = 10;
@@ -2379,6 +726,7 @@ isdn_ether_init(isdn_net_local *lp)
}
static struct isdn_netif_ops ether_ops = {
+ .hard_start_xmit = isdn_net_start_xmit,
.hard_header = eth_header,
.receive = isdn_ether_receive,
.init = isdn_ether_init,
@@ -2388,7 +736,7 @@ static struct isdn_netif_ops ether_ops = {
// ======================================================================
void
-isdn_net_init_module(void)
+isdn_net_init(void)
{
register_isdn_netif(ISDN_NET_ENCAP_ETHER, &ether_ops);
register_isdn_netif(ISDN_NET_ENCAP_RAWIP, &rawip_ops);
@@ -2402,4 +750,7 @@ isdn_net_init_module(void)
#ifdef CONFIG_ISDN_PPP
register_isdn_netif(ISDN_NET_ENCAP_SYNCPPP, &isdn_ppp_ops);
#endif
+
+ isdn_net_lib_init();
}
+
diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
index 5b80bd7dbd97..cf7917a8922a 100644
--- a/drivers/isdn/i4l/isdn_net.h
+++ b/drivers/isdn/i4l/isdn_net.h
@@ -32,46 +32,49 @@
#define CISCO_SLARP_REPLY 1
#define CISCO_SLARP_KEEPALIVE 2
-extern void isdn_net_init_module(void);
+extern void isdn_net_init(void);
+extern void isdn_net_exit(void);
+extern void isdn_net_lib_init(void);
+extern void isdn_net_lib_exit(void);
+extern void isdn_net_hangup_all(void);
+extern int isdn_net_ioctl(struct inode *, struct file *, uint, ulong);
+
+extern int register_isdn_netif(int encap, struct isdn_netif_ops *ops);
+extern int isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev);
+extern int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+
+extern int isdn_net_bind_channel(isdn_net_dev *idev, int slot);
+extern void isdn_net_unbind_channel(isdn_net_dev *idev);
+extern int isdn_net_dial(isdn_net_dev *idev);
+extern void isdn_net_accept(isdn_net_dev *idev, int slot, char *nr);
+extern int isdn_net_do_callback(isdn_net_dev *idev);
+
+extern int isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c);
-extern int isdn_net_new(char *, struct net_device *);
-extern int 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 *);
-extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *);
-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(isdn_net_dev *);
-extern void isdn_net_hangup_all(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_hangup(isdn_net_dev *);
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);
-extern int isdn_net_online(isdn_net_dev *idev);
+extern int isdn_net_dial_req(isdn_net_dev *);
+extern void isdn_net_writebuf_skb(isdn_net_dev *, struct sk_buff *skb);
+extern void isdn_net_write_super(isdn_net_dev *, struct sk_buff *skb);
+extern int isdn_net_online(isdn_net_dev *);
-static inline void
-isdn_net_reset_huptimer(isdn_net_dev *idev, isdn_net_dev *idev2)
-{
- idev->huptimer = 0;
- idev2->huptimer = 0;
-}
+enum {
+ ST_CHARGE_NULL,
+ ST_CHARGE_GOT_CINF, /* got a first charge info */
+ ST_CHARGE_HAVE_CINT, /* got a second chare info and thus the timing */
+};
#define ISDN_NET_MAX_QUEUE_LENGTH 2
/*
* is this particular channel busy?
*/
-static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
+static inline int
+isdn_net_dev_busy(isdn_net_dev *idev)
{
- if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
+ if (atomic_read(&idev->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
return 0;
else
return 1;
@@ -81,86 +84,69 @@ static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
* 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)
+static inline isdn_net_dev *
+isdn_net_get_locked_dev(isdn_net_local *mlp)
{
unsigned long flags;
- isdn_net_local *lp;
-
- spin_lock_irqsave(&nd->queue_lock, flags);
- lp = nd->queue; /* get lp on top of queue */
- spin_lock_bh(&nd->queue->xmit_lock);
- while (isdn_net_lp_busy(nd->queue)) {
- spin_unlock_bh(&nd->queue->xmit_lock);
- nd->queue = nd->queue->next;
- if (nd->queue == lp) { /* not found -- should never happen */
- lp = NULL;
- goto errout;
+ isdn_net_dev *idev;
+
+ spin_lock_irqsave(&mlp->online_lock, flags);
+
+ list_for_each_entry(idev, &mlp->online, online) {
+ spin_lock_bh(&idev->xmit_lock);
+ if (!isdn_net_dev_busy(idev)) {
+ /* point the head to next online channel */
+ list_del(&mlp->online);
+ list_add(&mlp->online, &idev->online);
+ goto found;
}
- spin_lock_bh(&nd->queue->xmit_lock);
+ spin_unlock_bh(&idev->xmit_lock);
}
- lp = nd->queue;
- nd->queue = nd->queue->next;
-errout:
- spin_unlock_irqrestore(&nd->queue_lock, flags);
- return lp;
+ idev = NULL;
+
+ found:
+ spin_unlock_irqrestore(&mlp->online_lock, flags);
+ return idev;
}
/*
* add a channel to a bundle
*/
-static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
+static inline void
+isdn_net_add_to_bundle(isdn_net_local *mlp, isdn_net_dev *idev)
{
- isdn_net_local *lp;
unsigned long flags;
- spin_lock_irqsave(&nd->queue_lock, flags);
-
- lp = nd->queue;
- nlp->last = lp->last;
- lp->last->next = nlp;
- lp->last = nlp;
- nlp->next = lp;
- nd->queue = nlp;
-
- spin_unlock_irqrestore(&nd->queue_lock, flags);
+ spin_lock_irqsave(&mlp->online_lock, flags);
+ list_add(&idev->online, &mlp->online);
+ spin_unlock_irqrestore(&mlp->online_lock, flags);
}
/*
* remove a channel from the bundle it belongs to
*/
-static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
+static inline void
+isdn_net_rm_from_bundle(isdn_net_dev *idev)
{
- isdn_net_local *master_lp = lp;
+ isdn_net_local *mlp = idev->mlp;
unsigned long flags;
- if (lp->master)
- master_lp = (isdn_net_local *) lp->master->priv;
-
- 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 */
- spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
+ spin_lock_irqsave(&mlp->online_lock, flags);
+ // list_del(&idev->online); FIXME
+ spin_unlock_irqrestore(&mlp->online_lock, flags);
}
/*
* wake up the network -> net_device queue.
* For slaves, wake the corresponding master interface.
*/
-static inline void isdn_net_device_wake_queue(isdn_net_local *lp)
+static inline void
+isdn_net_dev_wake_queue(isdn_net_dev *idev)
{
- if (lp->master)
- netif_wake_queue(lp->master);
- else
- netif_wake_queue(&lp->netdev->dev);
+ netif_wake_queue(&idev->mlp->dev);
}
-static inline int isdn_net_bound(isdn_net_dev *idev)
+static inline int
+isdn_net_bound(isdn_net_dev *idev)
{
return idev->isdn_slot >= 0;
}
diff --git a/drivers/isdn/i4l/isdn_net_lib.c b/drivers/isdn/i4l/isdn_net_lib.c
new file mode 100644
index 000000000000..fa7eb8b08b4b
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_net_lib.c
@@ -0,0 +1,1665 @@
+/*
+ * Linux ISDN subsystem, Network interface configuration
+ *
+ * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
+ * 1995,96 by Thinking Objects Software GmbH Wuerzburg
+ * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/capability.h>
+#include <linux/rtnetlink.h>
+#include "isdn_common.h"
+#include "isdn_net.h"
+#include "isdn_ppp.h"
+#include "isdn_fsm.h"
+
+#define ISDN_NET_TX_TIMEOUT (20*HZ)
+
+/* All of this configuration code is globally serialized */
+
+static DECLARE_MUTEX(sem);
+LIST_HEAD(isdn_net_devs); /* Linked list of isdn_net_dev's */ // FIXME static
+
+int isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg); /* FIXME */
+
+static void isdn_net_tasklet(unsigned long data);
+static void isdn_net_dial_timer(unsigned long data);
+static int isdn_init_netif(struct net_device *ndev);
+static void isdn_net_dev_debug(struct fsm_inst *fi, char *fmt, ...);
+
+static struct fsm isdn_net_fsm;
+
+enum {
+ ST_NULL,
+ ST_OUT_WAIT_DCONN,
+ ST_OUT_WAIT_BCONN,
+ ST_IN_WAIT_DCONN,
+ ST_IN_WAIT_BCONN,
+ ST_ACTIVE,
+ ST_WAIT_DHUP,
+ ST_WAIT_BEFORE_CB,
+ ST_OUT_DIAL_WAIT,
+};
+
+static char *isdn_net_st_str[] = {
+ "ST_NULL",
+ "ST_OUT_WAIT_DCONN",
+ "ST_OUT_WAIT_BCONN",
+ "ST_IN_WAIT_DCONN",
+ "ST_IN_WAIT_BCONN",
+ "ST_ACTIVE",
+ "ST_WAIT_DHUP",
+ "ST_WAIT_BEFORE_CB",
+ "ST_OUT_DIAL_WAIT",
+};
+
+enum {
+ EV_TIMER_INCOMING,
+ EV_TIMER_DIAL,
+ EV_TIMER_DIAL_WAIT,
+ EV_TIMER_CB_OUT,
+ EV_TIMER_CB_IN,
+ EV_TIMER_HUP,
+ EV_STAT_DCONN,
+ EV_STAT_BCONN,
+ EV_STAT_DHUP,
+ EV_STAT_BHUP,
+ EV_STAT_CINF,
+ EV_STAT_BSENT,
+ EV_CMD_DIAL,
+};
+
+static char *isdn_net_ev_str[] = {
+ "EV_NET_TIMER_INCOMING",
+ "EV_NET_TIMER_DIAL",
+ "EV_NET_TIMER_DIAL_WAIT",
+ "EV_NET_TIMER_CB_OUT",
+ "EV_NET_TIMER_CB_IN",
+ "EV_NET_TIMER_HUP",
+ "EV_STAT_DCONN",
+ "EV_STAT_BCONN",
+ "EV_STAT_DHUP",
+ "EV_STAT_BHUP",
+ "EV_STAT_CINF",
+ "EV_STAT_BSENT",
+ "EV_CMD_DIAL",
+};
+
+/* ====================================================================== */
+/* Registration of ISDN network interface types */
+/* ====================================================================== */
+
+static struct isdn_netif_ops *isdn_netif_ops[ISDN_NET_ENCAP_NR];
+
+int
+register_isdn_netif(int encap, struct isdn_netif_ops *ops)
+{
+ if (encap < 0 || encap >= ISDN_NET_ENCAP_NR)
+ return -EINVAL;
+
+ if (isdn_netif_ops[encap])
+ return -EBUSY;
+
+ isdn_netif_ops[encap] = ops;
+
+ return 0;
+}
+
+/* ====================================================================== */
+/* Helpers */
+/* ====================================================================== */
+
+/* Search list of net-interfaces for an interface with given name. */
+
+static isdn_net_dev *
+isdn_net_findif(char *name)
+{
+ isdn_net_dev *idev;
+
+ list_for_each_entry(idev, &isdn_net_devs, global_list) {
+ if (!strcmp(idev->name, name))
+ return idev;
+ }
+ return NULL;
+}
+
+/* Set up a certain encapsulation */
+
+static int
+isdn_net_set_encap(isdn_net_local *lp, int encap)
+{
+ int retval = 0;
+
+ if (lp->p_encap == encap){
+ /* nothing to do */
+ retval = 0;
+ goto out;
+ }
+ if (netif_running(&lp->dev)) {
+ retval = -EBUSY;
+ goto out;
+ }
+ if (lp->ops && lp->ops->cleanup)
+ lp->ops->cleanup(lp);
+
+ if (encap < 0 || encap >= ISDN_NET_ENCAP_NR) {
+ lp->p_encap = -1;
+ lp->ops = NULL;
+ retval = -EINVAL;
+ goto out;
+ }
+
+ lp->p_encap = encap;
+ lp->ops = isdn_netif_ops[encap];
+
+ lp->dev.hard_start_xmit = lp->ops->hard_start_xmit;
+ lp->dev.hard_header = lp->ops->hard_header;
+ lp->dev.do_ioctl = lp->ops->do_ioctl;
+ lp->dev.flags = lp->ops->flags;
+ lp->dev.type = lp->ops->type;
+ lp->dev.addr_len = lp->ops->addr_len;
+ if (lp->ops->init)
+ retval = lp->ops->init(lp);
+
+ if (retval != 0) {
+ lp->p_encap = -1;
+ lp->ops = NULL;
+ }
+ out:
+ return retval;
+}
+
+static int
+isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
+{
+ isdn_net_local *mlp = idev->mlp;
+ int i, retval;
+ int drvidx = -1;
+ int chidx = -1;
+ char drvid[25];
+
+ strncpy(drvid, cfg->drvid, 24);
+ drvid[24] = 0;
+
+ if (cfg->exclusive && !strlen(drvid)) {
+ /* If we want to bind exclusively, need to specify drv/chan */
+ retval = -ENODEV;
+ goto out;
+ }
+ if (strlen(drvid)) {
+ /* A bind has been requested ... */
+ char *c = strchr(drvid, ',');
+ if (!c) {
+ retval = -ENODEV;
+ goto out;
+ }
+ /* The channel-number is appended to the driver-Id with a comma */
+ *c = 0;
+ chidx = simple_strtol(c + 1, NULL, 10);
+
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
+ /* Lookup driver-Id in array */
+ if (!strcmp(dev->drvid[i], drvid)) {
+ drvidx = i;
+ break;
+ }
+ }
+ if (drvidx == -1 || chidx == -1) {
+ /* Either driver-Id or channel-number invalid */
+ retval = -ENODEV;
+ goto out;
+ }
+ }
+ if (cfg->exclusive == (idev->exclusive >= 0) &&
+ drvidx == idev->pre_device && chidx == idev->pre_channel) {
+ /* no change */
+ retval = 0;
+ goto out;
+ }
+ if (idev->exclusive >= 0) {
+ isdn_unexclusive_channel(idev->pre_device, idev->pre_channel);
+ isdn_free_channel(idev->pre_device, idev->pre_channel, ISDN_USAGE_NET);
+ idev->exclusive = -1;
+ }
+ if (cfg->exclusive) {
+ /* If binding is exclusive, try to grab the channel */
+ idev->exclusive = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto,
+ mlp->l3_proto, drvidx, chidx, cfg->eaz);
+ if (idev->exclusive < 0) {
+ /* Grab failed, because desired channel is in use */
+ retval = -EBUSY;
+ goto out;
+ }
+ /* All went ok, so update isdninfo */
+ isdn_slot_set_usage(idev->exclusive, ISDN_USAGE_EXCLUSIVE);
+ }
+ idev->pre_device = drvidx;
+ idev->pre_channel = chidx;
+ retval = 0;
+ out:
+ return retval;
+}
+
+/*
+ * Delete all phone-numbers of an interface.
+ */
+static void
+isdn_net_rmallphone(isdn_net_dev *idev)
+{
+ isdn_net_local *mlp = idev->mlp;
+ struct isdn_net_phone *n;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ while (!list_empty(&mlp->phone[i])) {
+ n = list_entry(mlp->phone[i].next, struct isdn_net_phone, list);
+ list_del(&n->list);
+ kfree(n);
+ }
+ }
+}
+
+/* ====================================================================== */
+/* /dev/isdnctrl net ioctl interface */
+/* ====================================================================== */
+
+/*
+ * Allocate a new network-interface and initialize its data structures
+ */
+static int
+isdn_net_addif(char *name, isdn_net_local *mlp)
+{
+ int retval;
+ struct net_device *dev = NULL;
+ isdn_net_dev *idev;
+
+ /* Avoid creating an existing interface */
+ if (isdn_net_findif(name))
+ return -EEXIST;
+
+ idev = kmalloc(sizeof(*idev), GFP_KERNEL);
+ if (!idev)
+ return -ENOMEM;
+
+ memset(idev, 0, sizeof(*idev));
+ strcpy(idev->name, name);
+
+ tasklet_init(&idev->tlet, isdn_net_tasklet, (unsigned long) idev);
+ spin_lock_init(&idev->xmit_lock);
+ skb_queue_head_init(&idev->super_tx_queue);
+
+ idev->isdn_slot = -1;
+ idev->pre_device = -1;
+ idev->pre_channel = -1;
+ idev->exclusive = -1;
+
+ idev->ppp_slot = -1;
+ idev->pppbind = -1;
+
+ init_timer(&idev->dial_timer);
+ idev->dial_timer.data = (unsigned long) idev;
+ idev->dial_timer.function = isdn_net_dial_timer;
+
+ idev->fi.fsm = &isdn_net_fsm;
+ idev->fi.state = ST_NULL;
+ idev->fi.debug = 1;
+ idev->fi.userdata = idev;
+ idev->fi.printdebug = isdn_net_dev_debug;
+
+ if (!mlp) {
+ /* Device shall be a master */
+ mlp = kmalloc(sizeof(*mlp), GFP_KERNEL);
+ if (!mlp)
+ return -ENOMEM;
+
+ memset(mlp, 0, sizeof(*mlp));
+
+ mlp->magic = ISDN_NET_MAGIC;
+ INIT_LIST_HEAD(&mlp->slaves);
+ INIT_LIST_HEAD(&mlp->online);
+
+ mlp->p_encap = -1;
+ isdn_net_set_encap(mlp, ISDN_NET_ENCAP_RAWIP);
+
+ mlp->l2_proto = ISDN_PROTO_L2_X75I;
+ mlp->l3_proto = ISDN_PROTO_L3_TRANS;
+ mlp->triggercps = 6000;
+ mlp->slavedelay = 10 * HZ;
+ mlp->hupflags = ISDN_INHUP;
+ mlp->onhtime = 10;
+ mlp->dialmax = 1;
+ mlp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;
+ mlp->cbdelay = 5 * HZ; /* Wait 5 secs before call-back */
+ mlp->dialtimeout = 60 * HZ;/* Wait 1 min for connection */
+ mlp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
+ INIT_LIST_HEAD(&mlp->phone[0]);
+ INIT_LIST_HEAD(&mlp->phone[1]);
+ dev = &mlp->dev;
+ }
+ idev->mlp = mlp;
+ list_add_tail(&idev->slaves, &mlp->slaves);
+
+ if (dev) {
+ strcpy(dev->name, name);
+ dev->priv = mlp;
+ dev->init = isdn_init_netif;
+ SET_MODULE_OWNER(dev);
+ retval = register_netdev(dev);
+ if (retval) {
+ kfree(mlp);
+ kfree(idev);
+ return retval;
+ }
+ }
+ list_add(&idev->global_list, &isdn_net_devs);
+ return 0;
+}
+
+/*
+ * Add a new slave interface to an existing one
+ */
+static int
+isdn_net_addslave(char *parm)
+{
+ char *p = strchr(parm, ',');
+ isdn_net_dev *idev;
+ isdn_net_local *mlp;
+ int retval;
+
+ /* get slave name */
+ if (!p || !p[1])
+ return -EINVAL;
+
+ *p++ = 0;
+
+ /* find master */
+ idev = isdn_net_findif(parm);
+ if (!idev)
+ return -ESRCH;
+
+ mlp = idev->mlp;
+
+ rtnl_lock();
+
+ if (netif_running(&mlp->dev))
+ return -EBUSY;
+
+ retval = isdn_net_addif(p, mlp);
+
+ rtnl_unlock();
+ return retval;
+}
+
+/*
+ * Delete a single network-interface
+ */
+static int
+isdn_net_dev_delete(isdn_net_dev *idev)
+{
+ isdn_net_local *mlp = idev->mlp;
+ int retval;
+
+ rtnl_lock();
+
+ if (netif_running(&mlp->dev)) {
+ retval = -EBUSY;
+ goto unlock;
+ }
+ isdn_net_set_encap(mlp, -1);
+ isdn_net_rmallphone(idev);
+
+ if (idev->exclusive >= 0)
+ isdn_unexclusive_channel(idev->pre_device, idev->pre_channel);
+
+ list_del(&idev->slaves);
+
+ rtnl_unlock();
+
+ if (list_empty(&mlp->slaves)) {
+ unregister_netdev(&mlp->dev);
+ kfree(mlp);
+ }
+
+ list_del(&idev->global_list);
+ kfree(idev);
+ return 0;
+
+ unlock:
+ rtnl_unlock();
+ return retval;
+}
+
+/*
+ * Delete a single network-interface
+ */
+static int
+isdn_net_delif(char *name)
+{
+ /* FIXME: For compatibility, if a master isdn_net_dev is rm'ed,
+ * kill all slaves, too */
+
+ isdn_net_dev *idev = isdn_net_findif(name);
+
+ if (!idev)
+ return -ENODEV;
+
+ return isdn_net_dev_delete(idev);
+}
+
+/*
+ * Set interface-parameters.
+ * Always set all parameters, so the user-level application is responsible
+ * for not overwriting existing setups. It has to get the current
+ * setup first, if only selected parameters are to be changed.
+ */
+static int
+isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
+{
+ isdn_net_dev *idev = isdn_net_findif(cfg->name);
+ isdn_net_local *mlp;
+ ulong features;
+ int i, retval;
+
+ if (!idev)
+ return -ENODEV;
+
+ mlp = idev->mlp;
+
+ rtnl_lock();
+
+ if (netif_running(&mlp->dev)) {
+ retval = -EBUSY;
+ goto out;
+ }
+ /* See if any registered driver supports the features we want */
+ features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
+ ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ if (dev->drv[i] &&
+ (dev->drv[i]->interface->features & features) == features)
+ break;
+
+ if (i == ISDN_MAX_DRIVERS) {
+ printk(KERN_WARNING "isdn_net: No driver with selected features\n");
+ retval = -ENODEV;
+ goto out;
+ }
+
+ retval = isdn_net_set_encap(mlp, cfg->p_encap);
+ if (retval)
+ goto out;
+
+ retval = isdn_net_bind(idev, cfg);
+ if (retval)
+ goto out;
+
+ strncpy(mlp->msn, cfg->eaz, ISDN_MSNLEN-1);
+ mlp->msn[ISDN_MSNLEN-1] = 0;
+ mlp->onhtime = cfg->onhtime;
+ idev->charge = cfg->charge;
+ mlp->l2_proto = cfg->l2_proto;
+ mlp->l3_proto = cfg->l3_proto;
+ mlp->cbdelay = cfg->cbdelay * HZ / 5;
+ mlp->dialmax = cfg->dialmax;
+ mlp->triggercps = cfg->triggercps;
+ mlp->slavedelay = cfg->slavedelay * HZ;
+ idev->pppbind = cfg->pppbind;
+ mlp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
+ mlp->dialwait = cfg->dialwait * HZ;
+ if (cfg->secure)
+ mlp->flags |= ISDN_NET_SECURE;
+ else
+ mlp->flags &= ~ISDN_NET_SECURE;
+ if (cfg->cbhup)
+ mlp->flags |= ISDN_NET_CBHUP;
+ else
+ mlp->flags &= ~ISDN_NET_CBHUP;
+ switch (cfg->callback) {
+ case 0:
+ mlp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
+ break;
+ case 1:
+ mlp->flags |= ISDN_NET_CALLBACK;
+ mlp->flags &= ~ISDN_NET_CBOUT;
+ break;
+ case 2:
+ mlp->flags |= ISDN_NET_CBOUT;
+ mlp->flags &= ~ISDN_NET_CALLBACK;
+ break;
+ }
+ mlp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */
+ if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ mlp->flags |= cfg->dialmode; /* turn on selected bits */
+ if (mlp->flags & ISDN_NET_DM_OFF)
+ isdn_net_hangup(idev);
+
+ if (cfg->chargehup)
+ mlp->hupflags |= ISDN_CHARGEHUP;
+ else
+ mlp->hupflags &= ~ISDN_CHARGEHUP;
+
+ if (cfg->ihup)
+ mlp->hupflags |= ISDN_INHUP;
+ else
+ mlp->hupflags &= ~ISDN_INHUP;
+
+ if (cfg->chargeint > 10) {
+ idev->chargeint = cfg->chargeint * HZ;
+ idev->charge_state = ST_CHARGE_HAVE_CINT;
+ mlp->hupflags |= ISDN_MANCHARGE;
+ }
+ retval = 0;
+
+ out:
+ rtnl_unlock();
+
+ return retval;
+}
+
+/*
+ * Perform get-interface-parameters.ioctl
+ */
+static int
+isdn_net_getcfg(isdn_net_ioctl_cfg *cfg)
+{
+ isdn_net_dev *idev = isdn_net_findif(cfg->name);
+ isdn_net_local *mlp;
+
+ if (!idev)
+ return -ENODEV;
+
+ mlp = idev->mlp;
+
+ strcpy(cfg->eaz, mlp->msn);
+ cfg->exclusive = idev->exclusive >= 0;
+ if (idev->pre_device >= 0) {
+ sprintf(cfg->drvid, "%s,%d", dev->drvid[idev->pre_device],
+ idev->pre_channel);
+ } else {
+ cfg->drvid[0] = '\0';
+ }
+ cfg->onhtime = mlp->onhtime;
+ cfg->charge = idev->charge;
+ cfg->l2_proto = mlp->l2_proto;
+ cfg->l3_proto = mlp->l3_proto;
+ cfg->p_encap = mlp->p_encap;
+ cfg->secure = (mlp->flags & ISDN_NET_SECURE) ? 1 : 0;
+ cfg->callback = 0;
+ if (mlp->flags & ISDN_NET_CALLBACK)
+ cfg->callback = 1;
+ if (mlp->flags & ISDN_NET_CBOUT)
+ cfg->callback = 2;
+ cfg->cbhup = (mlp->flags & ISDN_NET_CBHUP) ? 1 : 0;
+ cfg->dialmode = mlp->flags & ISDN_NET_DIALMODE_MASK;
+ cfg->chargehup = (mlp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
+ cfg->ihup = (mlp->hupflags & ISDN_INHUP) ? 1 : 0;
+ cfg->cbdelay = mlp->cbdelay * 5 / HZ;
+ cfg->dialmax = mlp->dialmax;
+ cfg->triggercps = mlp->triggercps;
+ cfg->slavedelay = mlp->slavedelay / HZ;
+ cfg->chargeint = (mlp->hupflags & ISDN_CHARGEHUP) ?
+ (idev->chargeint / HZ) : 0;
+ cfg->pppbind = idev->pppbind;
+ cfg->dialtimeout = mlp->dialtimeout >= 0 ? mlp->dialtimeout / HZ : -1;
+ cfg->dialwait = mlp->dialwait / HZ;
+
+ if (idev->slaves.next != &mlp->slaves)
+ strcpy(cfg->slave, list_entry(idev->slaves.next, isdn_net_dev, slaves)->name);
+ else
+ cfg->slave[0] = '\0';
+ if (strcmp(mlp->dev.name, idev->name))
+ strcpy(cfg->master, mlp->dev.name);
+ else
+ cfg->master[0] = '\0';
+
+ return 0;
+}
+
+/*
+ * Add a phone-number to an interface.
+ */
+static int
+isdn_net_addphone(isdn_net_ioctl_phone *phone)
+{
+ isdn_net_dev *idev = isdn_net_findif(phone->name);
+ struct isdn_net_phone *n;
+ int retval = 0;
+
+ if (!idev)
+ return -ENODEV;
+
+ rtnl_lock();
+
+ if (netif_running(&idev->mlp->dev)) {
+ retval = -EBUSY;
+ goto out;
+ }
+ n = kmalloc(sizeof(*n), GFP_KERNEL);
+ if (!n) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ strcpy(n->num, phone->phone);
+ list_add_tail(&n->list, &idev->mlp->phone[phone->outgoing & 1]);
+
+ out:
+ rtnl_unlock();
+ return retval;
+}
+
+/*
+ * Delete a phone-number from an interface.
+ */
+static int
+isdn_net_delphone(isdn_net_ioctl_phone *phone)
+{
+ isdn_net_dev *idev = isdn_net_findif(phone->name);
+ struct isdn_net_phone *n;
+ int retval;
+
+ if (!idev)
+ return -ENODEV;
+
+ rtnl_lock();
+
+ if (netif_running(&idev->mlp->dev)) {
+ retval = -EBUSY;
+ goto out;
+ }
+ retval = -EINVAL;
+ list_for_each_entry(n, &idev->mlp->phone[phone->outgoing & 1], list) {
+ if (!strcmp(n->num, phone->phone)) {
+ list_del(&n->list);
+ kfree(n);
+ retval = 0;
+ break;
+ }
+ }
+ out:
+ rtnl_unlock();
+ return retval;
+}
+
+/*
+ * Copy a string of all phone-numbers of an interface to user space.
+ */
+static int
+isdn_net_getphone(isdn_net_ioctl_phone * phone, char *phones)
+{
+ isdn_net_dev *idev = isdn_net_findif(phone->name);
+ int count = 0;
+ char *buf = (char *)__get_free_page(GFP_KERNEL);
+ struct isdn_net_phone *n;
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (!idev) {
+ count = -ENODEV;
+ goto free;
+ }
+ list_for_each_entry(n, &idev->mlp->phone[phone->outgoing & 1], list) {
+ strcpy(&buf[count], n->num);
+ count += strlen(n->num);
+ buf[count++] = ' ';
+ if (count > PAGE_SIZE - ISDN_MSNLEN - 1)
+ break;
+ }
+ if (!count) /* list was empty? */
+ count++;
+
+ buf[count-1] = 0;
+
+ if (copy_to_user(phones, buf, count))
+ count = -EFAULT;
+
+ free:
+ free_page((unsigned long)buf);
+ return count;
+}
+
+/*
+ * Force a net-interface to dial out.
+ */
+static int
+isdn_net_dial_out(char *name)
+{
+ isdn_net_dev *idev = isdn_net_findif(name);
+
+ if (!idev)
+ return -ENODEV;
+
+ return isdn_net_dial(idev);
+}
+
+/*
+ * Force a hangup of a network-interface.
+ */
+static int
+isdn_net_force_hangup(char *name) // FIXME rename?
+{
+ isdn_net_dev *idev = isdn_net_findif(name);
+
+ if (!idev)
+ return -ENODEV;
+
+ if (idev->isdn_slot < 0)
+ return -ENOTCONN;
+
+ isdn_net_hangup(idev);
+ return 0;
+}
+
+/*
+ * Copy a string containing the peer's phone number of a connected interface
+ * to user space.
+ */
+static int
+isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer)
+{
+ isdn_net_dev *idev = isdn_net_findif(phone->name);
+ int idx;
+
+ if (!idev)
+ return -ENODEV;
+ /* FIXME
+ * Theoretical race: while this executes, the remote number might
+ * become invalid (hang up) or change (new connection), resulting
+ * in (partially) wrong number copied to user. This race
+ * currently ignored.
+ */
+ idx = idev->isdn_slot;
+ if (idx < 0)
+ return -ENOTCONN;
+ /* for pre-bound channels, we need this extra check */
+ if (strncmp(isdn_slot_num(idx), "???", 3) == 0 )
+ return -ENOTCONN;
+
+ strncpy(phone->phone, isdn_slot_num(idx), ISDN_MSNLEN);
+ phone->outgoing = USG_OUTGOING(isdn_slot_usage(idx));
+
+ if (copy_to_user(peer, phone, sizeof(*peer)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * ioctl on /dev/isdnctrl, used to configure ISDN net interfaces
+ */
+int
+isdn_net_ioctl(struct inode *ino, struct file *file, uint cmd, ulong arg)
+{
+ /* Save stack space */
+ union {
+ char name[10];
+ char bname[20];
+ isdn_net_ioctl_phone phone;
+ isdn_net_ioctl_cfg cfg;
+ } iocpar;
+ int retval;
+
+#define name iocpar.name
+#define bname iocpar.bname
+#define phone iocpar.phone
+#define cfg iocpar.cfg
+
+ name[sizeof(name)-1] = 0;
+ bname[sizeof(bname)-1] = 0;
+
+ down(&sem);
+
+ switch (cmd) {
+ case IIOCNETAIF: /* add an interface */
+ if (copy_from_user(name, (char *) arg, sizeof(name) - 1)) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_net_addif(name, NULL);
+ break;
+ case IIOCNETASL: /* add slave to an interface */
+ if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1)) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_net_addslave(bname);
+ break;
+ case IIOCNETDIF: /* delete an interface */
+ if (copy_from_user(name, (char *) arg, sizeof(name) - 1)) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_net_delif(name);
+ break;
+ case IIOCNETSCF: /* set config */
+ if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_net_setcfg(&cfg);
+ break;
+ case IIOCNETGCF: /* get config */
+ if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_net_getcfg(&cfg);
+ if (retval)
+ break;
+ if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
+ retval = -EFAULT;
+ break;
+ case IIOCNETANM: /* add a phone number */
+ if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_net_addphone(&phone);
+ break;
+ case IIOCNETGNM: /* get list of phone numbers */
+ if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_net_getphone(&phone, (char *) arg);
+ break;
+ case IIOCNETDNM: /* delete a phone number */
+ if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_net_delphone(&phone);
+ break;
+ case IIOCNETDIL: /* trigger dial-out */
+ if (copy_from_user(name, (char *) arg, sizeof(name))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_net_dial_out(name);
+ break;
+ case IIOCNETHUP: /* hangup */
+ if (copy_from_user(name, (char *) arg, sizeof(name))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_net_force_hangup(name);
+ break;
+ case IIOCNETGPN: /* Get peer phone number of a connected interface */
+ if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) {
+ retval = -EFAULT;
+ }
+ retval = isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
+ break;
+#ifdef CONFIG_ISDN_PPP
+ case IIOCNETALN: /* Add link */
+ if (copy_from_user(name, (char *) arg, sizeof(name))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_ppp_dial_slave(name);
+ break;
+ case IIOCNETDLN: /* Delete link */
+ if (copy_from_user(name, (char *) arg, sizeof(name))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = isdn_ppp_hangup_slave(name);
+ break;
+#endif
+ default:
+ retval = -ENOTTY;
+ }
+ up(&sem);
+ return retval;
+
+#undef name
+#undef bname
+#undef iocts
+#undef phone
+#undef cfg
+}
+
+/*
+ * Hang up all network-interfaces
+ */
+void
+isdn_net_hangup_all(void)
+{
+ isdn_net_dev *idev;
+
+ down(&sem);
+
+ list_for_each_entry(idev, &isdn_net_devs, global_list)
+ isdn_net_hangup(idev);
+
+ up(&sem);
+}
+
+/*
+ * Remove all network-interfaces
+ */
+void
+isdn_net_exit(void)
+{
+ isdn_net_dev *idev;
+ int retval;
+
+ down(&sem);
+
+ while (!list_empty(&isdn_net_devs)) {
+ idev = list_entry(isdn_net_devs.next, isdn_net_dev, global_list);
+ retval = isdn_net_dev_delete(idev);
+ /* can only fail if an interface is still running.
+ * In this case, an elevated module use count should
+ * have prevented this function from being called in
+ * the first place */
+ if (retval)
+ isdn_BUG();
+ }
+ up(&sem);
+
+ // FIXME
+ isdn_net_lib_exit();
+}
+
+/* ====================================================================== */
+/* interface to network layer */
+/* ====================================================================== */
+
+/*
+ * Open/initialize the board.
+ */
+static int
+isdn_net_open(struct net_device *dev)
+{
+ isdn_net_local *lp = dev->priv;
+ int retval = 0;
+
+ if (!lp->ops)
+ return -ENODEV;
+
+ if (lp->ops->open)
+ retval = lp->ops->open(lp);
+
+ if (!retval)
+ return retval;
+
+ netif_start_queue(dev);
+ return 0;
+}
+
+/*
+ * Shutdown a net-interface.
+ */
+// FIXME share?
+static int
+isdn_net_close(struct net_device *dev)
+{
+ isdn_net_local *lp = dev->priv;
+ struct list_head *l, *n;
+ isdn_net_dev *sdev;
+
+ if (lp->ops->close)
+ lp->ops->close(lp);
+
+ netif_stop_queue(dev);
+
+ list_for_each_safe(l, n, &lp->online) {
+ sdev = list_entry(l, isdn_net_dev, online);
+ isdn_net_hangup(sdev);
+ }
+ return 0;
+}
+
+/*
+ * Get statistics
+ */
+static struct net_device_stats *
+isdn_net_get_stats(struct net_device *dev)
+{
+ isdn_net_local *lp = dev->priv;
+
+ return &lp->stats;
+}
+
+/*
+ * Transmit timeout
+ */
+static void
+isdn_net_tx_timeout(struct net_device *dev)
+{
+ printk(KERN_WARNING "isdn_tx_timeout dev %s\n", dev->name);
+
+ netif_wake_queue(dev);
+}
+
+/*
+ * Interface-setup. (just after registering a new interface)
+ */
+static int
+isdn_init_netif(struct net_device *ndev)
+{
+ /* Setup the generic properties */
+
+ ndev->mtu = 1500;
+ ndev->tx_queue_len = 10;
+ ndev->open = &isdn_net_open;
+ ndev->hard_header_len = ETH_HLEN + isdn_hard_header_len();
+ ndev->stop = &isdn_net_close;
+ ndev->get_stats = &isdn_net_get_stats;
+ ndev->tx_timeout = isdn_net_tx_timeout;
+ ndev->watchdog_timeo = ISDN_NET_TX_TIMEOUT;
+
+ return 0;
+}
+
+/* ====================================================================== */
+
+static void
+isdn_net_tasklet(unsigned long data)
+{
+ isdn_net_dev *idev = (isdn_net_dev *) data;
+ struct sk_buff *skb;
+
+ spin_lock_bh(&idev->xmit_lock);
+ while (!isdn_net_dev_busy(idev)) {
+ skb = skb_dequeue(&idev->super_tx_queue);
+ if (!skb)
+ break;
+ isdn_net_writebuf_skb(idev, skb);
+ }
+ spin_unlock_bh(&idev->xmit_lock);
+}
+
+/* ====================================================================== */
+/* call control state machine */
+/* ====================================================================== */
+
+// FIXME
+int isdn_net_online(isdn_net_dev *idev)
+{
+ return idev->fi.state == ST_ACTIVE;
+}
+
+static void
+isdn_net_dial_timer(unsigned long data)
+{
+ isdn_net_dev *idev = (isdn_net_dev *) data;
+
+ isdn_net_handle_event(idev, idev->dial_event, NULL);
+}
+
+/*
+ * Assign an ISDN-channel to a net-interface
+ */
+int
+isdn_net_bind_channel(isdn_net_dev *idev, int slot)
+{
+ isdn_net_local *mlp = idev->mlp;
+ int retval = 0;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ idev->isdn_slot = slot;
+ isdn_slot_set_idev(idev->isdn_slot, idev);
+
+ if (mlp->ops->bind)
+ retval = mlp->ops->bind(idev);
+
+ if (retval < 0)
+ isdn_net_unbind_channel(idev);
+
+ restore_flags(flags);
+ return retval;
+}
+
+/*
+ * Unbind a net-interface
+ */
+void
+isdn_net_unbind_channel(isdn_net_dev *idev)
+{
+ isdn_net_local *mlp = idev->mlp;
+ ulong flags;
+
+ save_flags(flags);
+ cli();
+
+ if (idev->isdn_slot < 0) {
+ isdn_BUG();
+ return;
+ }
+
+ if (mlp->ops->unbind)
+ mlp->ops->unbind(idev);
+
+ skb_queue_purge(&idev->super_tx_queue);
+
+ fsm_change_state(&idev->fi, ST_NULL);
+
+ isdn_slot_set_idev(idev->isdn_slot, NULL);
+ isdn_slot_free(idev->isdn_slot, ISDN_USAGE_NET);
+
+ idev->isdn_slot = -1;
+
+ restore_flags(flags);
+}
+
+int
+isdn_net_dial(isdn_net_dev *idev)
+{
+ int slot;
+ isdn_net_local *mlp = idev->mlp;
+
+ if (isdn_net_bound(idev))
+ return -EBUSY;
+
+ if (idev->exclusive >= 0)
+ slot = idev->exclusive;
+ else
+ slot = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto,
+ mlp->l3_proto, idev->pre_device,
+ idev->pre_channel, mlp->msn);
+ if (slot < 0)
+ goto err;
+
+ isdn_slot_set_usage(slot, isdn_slot_usage(slot) | ISDN_USAGE_OUTGOING);
+
+ if (isdn_net_bind_channel(idev, slot) < 0)
+ goto err;
+
+ /* Initiate dialing */
+ fsm_event(&idev->fi, EV_CMD_DIAL, NULL);
+ return 0;
+
+ err:
+ return -EAGAIN;
+}
+
+void
+isdn_net_accept(isdn_net_dev *idev, int slot, char *nr)
+{
+ isdn_net_local *mlp = idev->mlp;
+ isdn_ctrl cmd;
+
+ strcpy(isdn_slot_num(slot), nr);
+ isdn_slot_set_usage(slot, (isdn_slot_usage(slot) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET);
+
+ isdn_net_bind_channel(idev, slot);
+
+ idev->outgoing = 0;
+ idev->charge_state = ST_CHARGE_NULL;
+ /* Got incoming call, setup L2 and L3 protocols,
+ * then wait for D-Channel-connect
+ */
+ cmd.arg = mlp->l2_proto << 8;
+ isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL2, &cmd);
+ cmd.arg = mlp->l3_proto << 8;
+ isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL3, &cmd);
+
+ idev->dial_timer.expires = jiffies + mlp->dialtimeout;
+ idev->dial_event = EV_TIMER_INCOMING;
+ add_timer(&idev->dial_timer);
+ fsm_change_state(&idev->fi, ST_IN_WAIT_DCONN);
+}
+
+int
+isdn_net_do_callback(isdn_net_dev *idev)
+{
+ isdn_net_local *mlp = idev->mlp;
+ int slot;
+ /*
+ * Is the state MANUAL?
+ * If so, no callback can be made,
+ * so reject actively.
+ */
+ if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) {
+ printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
+ idev->name);
+ return 3;
+ }
+ printk(KERN_DEBUG "%s: start callback\n", idev->name);
+
+ /* Grab a free ISDN-Channel */
+ slot = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto, mlp->l3_proto,
+ idev->pre_device, idev->pre_channel, mlp->msn);
+ if (slot < 0)
+ goto err;
+
+ isdn_slot_set_usage(slot, isdn_slot_usage(slot) | ISDN_USAGE_OUTGOING);
+
+ if (isdn_net_bind_channel(idev, slot) < 0)
+ goto err;
+
+ /* Setup dialstate. */
+ idev->dial_timer.expires = jiffies + mlp->cbdelay;
+ idev->dial_event = EV_TIMER_CB_IN;
+ add_timer(&idev->dial_timer);
+ fsm_change_state(&idev->fi, ST_WAIT_BEFORE_CB);
+
+ /* Initiate dialing by returning 2 or 4 */
+ return (mlp->flags & ISDN_NET_CBHUP) ? 2 : 4;
+
+ err:
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* callbacks in the state machine */
+/* ---------------------------------------------------------------------- */
+
+/* Find the idev->dial'th outgoing number. */
+
+static struct isdn_net_phone *
+get_outgoing_phone(isdn_net_dev *idev)
+{
+ isdn_net_local *mlp = idev->mlp;
+ struct isdn_net_phone *phone;
+ int i = 0;
+
+ list_for_each_entry(phone, &mlp->phone[1], list) {
+ if (i++ == idev->dial)
+ return phone;
+ }
+ return NULL;
+}
+
+static int dialout_next(struct fsm_inst *fi, int pr, void *arg);
+
+/* Initiate dialout. */
+
+static int
+dialout_first(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+ isdn_net_local *mlp = idev->mlp;
+
+ if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) {
+ isdn_net_unbind_channel(idev);
+ return -EPERM;
+ }
+ if (list_empty(&mlp->phone[1])) {
+ isdn_net_unbind_channel(idev);
+ return -EINVAL;
+ }
+
+ idev->dial = 0;
+ idev->dialretry = 0;
+ return dialout_next(fi, pr, arg);
+}
+
+/* Try dialing the next number. */
+
+static int
+dialout_next(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+ isdn_net_local *mlp = idev->mlp;
+ struct dial_info dial = {
+ .l2_proto = mlp->l2_proto,
+ .l3_proto = mlp->l3_proto,
+ .si1 = 7,
+ .si2 = 0,
+ .msn = mlp->msn,
+ .phone = get_outgoing_phone(idev)->num,
+ };
+
+ /* next time, try next number */
+ idev->dial++;
+
+ idev->outgoing = 1;
+ if (idev->chargeint)
+ idev->charge_state = ST_CHARGE_HAVE_CINT;
+ else
+ idev->charge_state = ST_CHARGE_NULL;
+
+ /* For outgoing callback, use cbdelay instead of dialtimeout */
+ if (mlp->cbdelay && (mlp->flags & ISDN_NET_CBOUT)) {
+ idev->dial_timer.expires = jiffies + mlp->cbdelay;
+ idev->dial_event = EV_TIMER_CB_OUT;
+ } else {
+ idev->dial_timer.expires = jiffies + mlp->dialtimeout;
+ idev->dial_event = EV_TIMER_DIAL;
+ }
+ fsm_change_state(&idev->fi, ST_OUT_WAIT_DCONN);
+ add_timer(&idev->dial_timer);
+
+ /* Dial */
+ isdn_slot_dial(idev->isdn_slot, &dial);
+ return 0;
+}
+
+/* If we didn't connect within dialtimeout, we give up for now
+ * and wait for dialwait jiffies before trying again.
+ */
+static int
+dial_timeout(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+ isdn_net_local *mlp = idev->mlp;
+ isdn_ctrl cmd;
+
+ fsm_change_state(&idev->fi, ST_OUT_DIAL_WAIT);
+ isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd);
+
+ /* get next phone number */
+ if (!get_outgoing_phone(idev)) {
+ /* otherwise start over at first entry */
+ idev->dial = 0;
+ idev->dialretry++;
+ }
+ if (idev->dialretry >= mlp->dialmax) {
+ isdn_net_hangup(idev);
+ return 0;
+ }
+ idev->dial_event = EV_TIMER_DIAL_WAIT;
+ mod_timer(&idev->dial_timer, jiffies + mlp->dialwait);
+ return 0;
+}
+
+static int
+connect_fail(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+
+ del_timer(&idev->dial_timer);
+ isdn_slot_all_eaz(idev->isdn_slot);
+ printk(KERN_INFO "%s: connection failed\n", idev->name);
+ isdn_net_unbind_channel(idev);
+ return 0;
+}
+
+static int
+out_dconn(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+ isdn_ctrl cmd;
+
+ fsm_change_state(&idev->fi, ST_OUT_WAIT_BCONN);
+ isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
+ return 0;
+}
+
+static int
+in_dconn(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+ isdn_ctrl cmd;
+
+ fsm_change_state(&idev->fi, ST_IN_WAIT_BCONN);
+ isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
+ return 0;
+}
+
+static int
+bconn(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+ isdn_net_local *mlp = idev->mlp;
+
+ fsm_change_state(&idev->fi, ST_ACTIVE);
+
+ if (mlp->onhtime) {
+ idev->huptimer = 0;
+ idev->dial_event = EV_TIMER_HUP;
+ mod_timer(&idev->dial_timer, jiffies + HZ);
+ } else {
+ del_timer(&idev->dial_timer);
+ }
+
+ isdn_net_add_to_bundle(mlp, idev);
+
+ printk(KERN_INFO "%s connected\n", idev->name);
+ /* If first Chargeinfo comes before B-Channel connect,
+ * we correct the timestamp here.
+ */
+ idev->chargetime = jiffies;
+
+ idev->transcount = 0;
+ idev->cps = 0;
+ idev->last_jiffies = jiffies;
+
+ if (mlp->ops->connected)
+ mlp->ops->connected(idev);
+ else
+ isdn_net_dev_wake_queue(idev);
+
+ return 0;
+}
+
+static int
+bhup(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+ isdn_net_local *mlp = idev->mlp;
+
+ del_timer(&idev->dial_timer);
+ if (mlp->ops->disconnected)
+ mlp->ops->disconnected(idev);
+
+ printk(KERN_INFO "%s: disconnected\n", idev->name);
+ fsm_change_state(fi, ST_WAIT_DHUP);
+ isdn_net_rm_from_bundle(idev);
+ return 0;
+}
+
+static int
+dhup(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+
+ printk(KERN_INFO "%s: Chargesum is %d\n", idev->name, idev->charge);
+ isdn_slot_all_eaz(idev->isdn_slot);
+ isdn_net_unbind_channel(idev);
+ return 0;
+}
+
+/* Check if it's time for idle hang-up */
+
+static int
+check_hup(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+ isdn_net_local *mlp = idev->mlp;
+
+ dbg_net_dial("%s: huptimer %d onhtime %d chargetime %ld chargeint %d\n",
+ idev->name, idev->huptimer, mlp->onhtime, idev->chargetime, idev->chargeint);
+
+ if (idev->huptimer++ <= mlp->onhtime)
+ goto mod_timer;
+
+ if (mlp->hupflags & ISDN_CHARGEHUP &&
+ idev->charge_state == ST_CHARGE_HAVE_CINT) {
+ if (!time_after(jiffies, idev->chargetime
+ + idev->chargeint - 2 * HZ))
+ goto mod_timer;
+ }
+ if (idev->outgoing || mlp->hupflags & ISDN_INHUP) {
+ isdn_net_hangup(idev);
+ return 0;
+ }
+ mod_timer:
+ mod_timer(&idev->dial_timer, idev->dial_timer.expires + HZ);
+ return 0;
+}
+
+/* Charge-info from TelCo. */
+
+static int
+got_cinf(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+
+ idev->charge++;
+ switch (idev->charge_state) {
+ case ST_CHARGE_NULL:
+ idev->charge_state = ST_CHARGE_GOT_CINF;
+ break;
+ case ST_CHARGE_GOT_CINF:
+ idev->charge_state = ST_CHARGE_HAVE_CINT;
+ /* fall through */
+ case ST_CHARGE_HAVE_CINT:
+ idev->chargeint = jiffies - idev->chargetime;
+ break;
+ }
+ idev->chargetime = jiffies;
+ dbg_net_dial("%s: got CINF\n", idev->name);
+ return 0;
+}
+
+/* Perform hangup for a net-interface. */
+
+int
+isdn_net_hangup(isdn_net_dev *idev)
+{
+ isdn_ctrl cmd;
+
+ del_timer(&idev->dial_timer);
+ if (!isdn_net_bound(idev)) {
+ isdn_BUG();
+ return 1;
+ }
+ printk(KERN_INFO "%s: local hangup\n", idev->name);
+ isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd);
+ return 1;
+}
+
+/*
+ * Handle status-messages from ISDN-interfacecard.
+ * This function is called from within the main-status-dispatcher
+ * isdn_status_callback, which itself is called from the low-level driver.
+ * Return: 1 = event handled, 0 = not handled
+ */
+int
+isdn_net_stat_callback(int idx, isdn_ctrl *c)
+{
+ isdn_net_dev *idev = isdn_slot_idev(idx);
+
+ if (!idev) {
+ HERE;
+ return 0;
+ }
+ switch (c->command) {
+ case ISDN_STAT_DCONN:
+ return fsm_event(&idev->fi, EV_STAT_DCONN, c);
+ case ISDN_STAT_BCONN:
+ return fsm_event(&idev->fi, EV_STAT_BCONN, c);
+ case ISDN_STAT_BHUP:
+ return fsm_event(&idev->fi, EV_STAT_BHUP, c);
+ case ISDN_STAT_DHUP:
+ return fsm_event(&idev->fi, EV_STAT_DHUP, c);
+ case ISDN_STAT_CINF:
+ return fsm_event(&idev->fi, EV_STAT_CINF, c);
+ case ISDN_STAT_BSENT:
+ return fsm_event(&idev->fi, EV_STAT_BSENT, c);
+ default:
+ printk("unknown stat %d\n", c->command);
+ return 0;
+ }
+}
+
+int
+isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg)
+{
+ fsm_event(&idev->fi, pr, arg);
+}
+
+static int
+hang_up(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+
+ isdn_net_hangup(idev);
+ return 0;
+}
+
+static int
+got_bsent(struct fsm_inst *fi, int pr, void *arg)
+{
+ isdn_net_dev *idev = fi->userdata;
+ isdn_ctrl *c = arg;
+
+ isdn_net_bsent(idev, c);
+ return 0;
+}
+
+static struct fsm_node isdn_net_fn_tbl[] = {
+ { ST_NULL, EV_CMD_DIAL, dialout_first },
+
+ { ST_OUT_WAIT_DCONN, EV_TIMER_DIAL, dial_timeout },
+ { ST_OUT_WAIT_DCONN, EV_STAT_DCONN, out_dconn },
+ { ST_OUT_WAIT_DCONN, EV_STAT_DHUP, connect_fail },
+ { ST_OUT_WAIT_DCONN, EV_TIMER_CB_OUT, hang_up },
+
+ { ST_OUT_WAIT_BCONN, EV_TIMER_DIAL, dial_timeout },
+ { ST_OUT_WAIT_BCONN, EV_STAT_BCONN, bconn },
+ { ST_OUT_WAIT_BCONN, EV_STAT_DHUP, connect_fail },
+
+ { ST_IN_WAIT_DCONN, EV_TIMER_INCOMING, hang_up },
+ { ST_IN_WAIT_DCONN, EV_STAT_DCONN, in_dconn },
+ { ST_IN_WAIT_DCONN, EV_STAT_DHUP, connect_fail },
+
+ { ST_IN_WAIT_BCONN, EV_TIMER_INCOMING, hang_up },
+ { ST_IN_WAIT_BCONN, EV_STAT_BCONN, bconn },
+ { ST_IN_WAIT_BCONN, EV_STAT_DHUP, connect_fail },
+
+ { ST_ACTIVE, EV_TIMER_HUP, check_hup },
+ { ST_ACTIVE, EV_STAT_BHUP, bhup },
+ { ST_ACTIVE, EV_STAT_CINF, got_cinf },
+ { ST_ACTIVE, EV_STAT_BSENT, got_bsent },
+
+ { ST_WAIT_DHUP, EV_STAT_DHUP, dhup },
+
+ { ST_WAIT_BEFORE_CB, EV_TIMER_CB_IN, dialout_first },
+
+ { ST_OUT_DIAL_WAIT, EV_TIMER_DIAL_WAIT, dialout_next },
+};
+
+static struct fsm isdn_net_fsm = {
+ .st_cnt = ARRAY_SIZE(isdn_net_st_str),
+ .st_str = isdn_net_st_str,
+ .ev_cnt = ARRAY_SIZE(isdn_net_ev_str),
+ .ev_str = isdn_net_ev_str,
+ .fn_cnt = ARRAY_SIZE(isdn_net_fn_tbl),
+ .fn_tbl = isdn_net_fn_tbl,
+};
+
+static void isdn_net_dev_debug(struct fsm_inst *fi, char *fmt, ...)
+{
+ va_list args;
+ isdn_net_dev *idev = fi->userdata;
+ char buf[128];
+ char *p = buf;
+
+ va_start(args, fmt);
+ p += sprintf(p, "%s: ", idev->name);
+ p += vsprintf(p, fmt, args);
+ va_end(args);
+ printk(KERN_DEBUG "%s\n", buf);
+}
+
+void
+isdn_net_lib_init(void)
+{
+ fsm_new(&isdn_net_fsm);
+}
+
+void
+isdn_net_lib_exit(void)
+{
+ fsm_free(&isdn_net_fsm);
+}
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 846b11a11d8f..3c59a373459b 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -23,7 +23,7 @@
/* Prototypes */
static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
static int isdn_ppp_closewait(int slot);
-static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
+static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb, int proto);
static int isdn_ppp_if_get_unit(char *namebuf);
static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *);
@@ -59,10 +59,10 @@ static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
static ippp_bundle * isdn_ppp_bundle_arr = NULL;
static int isdn_ppp_mp_bundle_array_init(void);
-static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to );
-static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
- struct sk_buff *skb);
-static void isdn_ppp_mp_cleanup( isdn_net_local * lp );
+static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to);
+static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *idev,
+ struct sk_buff *skb);
+static void isdn_ppp_mp_cleanup(isdn_net_local *lp );
static int isdn_ppp_bundle(struct ippp_struct *, int unit);
#endif /* CONFIG_ISDN_MPP */
@@ -100,9 +100,8 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot
* in this case we bind another lp to the master device
*/
static void
-isdn_ppp_free(isdn_net_local * lp)
+isdn_ppp_free(isdn_net_dev *idev)
{
- isdn_net_dev *idev = lp->netdev;
unsigned long flags;
struct ippp_struct *is;
@@ -116,9 +115,9 @@ isdn_ppp_free(isdn_net_local * lp)
cli();
#ifdef CONFIG_ISDN_MPP
- spin_lock(&lp->netdev->pb->lock);
+ spin_lock(&idev->pb->lock);
#endif
- isdn_net_rm_from_bundle(lp);
+ isdn_net_rm_from_bundle(idev);
#ifdef CONFIG_ISDN_MPP
if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
isdn_ppp_mp_cleanup(lp);
@@ -139,7 +138,7 @@ isdn_ppp_free(isdn_net_local * lp)
is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */
if (is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_free %d %p %p\n", idev->ppp_slot, lp, is->idev);
+ printk(KERN_DEBUG "isdn_ppp_free %d %p\n", idev->ppp_slot, is->idev);
is->idev = NULL; /* link is down .. set lp to NULL */
idev->ppp_slot = -1; /* is this OK ?? */
@@ -152,9 +151,8 @@ isdn_ppp_free(isdn_net_local * lp)
* bind isdn_net_local <=> ippp-device
*/
int
-isdn_ppp_bind(isdn_net_local * lp)
+isdn_ppp_bind(isdn_net_dev *idev)
{
- isdn_net_dev *idev = lp->netdev;
int i;
int unit = 0;
long flags;
@@ -226,10 +224,8 @@ isdn_ppp_bind(isdn_net_local * lp)
*/
static void
-isdn_ppp_wakeup_daemon(isdn_net_local *lp)
+isdn_ppp_wakeup_daemon(isdn_net_dev *idev)
{
- isdn_net_dev *idev = lp->netdev;
-
if (idev->ppp_slot < 0 || idev->ppp_slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
__FUNCTION__, idev->ppp_slot);
@@ -314,8 +310,6 @@ isdn_ppp_open(struct inode *ino, struct file *file)
is->maxcid = 16; /* VJ: maxcid */
is->tk = current;
init_waitqueue_head(&is->wq);
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
- is->last = is->rq;
is->minor = minor;
#ifdef CONFIG_ISDN_PPP_VJ
/*
@@ -337,7 +331,6 @@ static int
isdn_ppp_release(struct inode *ino, struct file *file)
{
uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
- int i;
struct ippp_struct *is;
lock_kernel();
@@ -356,14 +349,7 @@ isdn_ppp_release(struct inode *ino, struct file *file)
is->state &= ~IPPP_CONNECT;
isdn_net_hangup(is->idev);
}
- for (i = 0; i < NUM_RCV_BUFFS; i++) {
- if (is->rq[i].buf) {
- kfree(is->rq[i].buf);
- is->rq[i].buf = NULL;
- }
- }
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
- is->last = is->rq;
+ skb_queue_purge(&is->rq);
#ifdef CONFIG_ISDN_PPP_VJ
/* TODO: if this was the previous master: link the slcomp to the new master */
@@ -487,7 +473,7 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
if (idev) {
/* OK .. we are ready to send buffers */
- netif_wake_queue(&idev->dev);
+ isdn_net_dev_wake_queue(idev);
}
}
is->pppcfg = val;
@@ -562,14 +548,16 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
return isdn_ppp_set_compressor(is, &data);
case PPPIOCGCALLINFO:
{
+ isdn_net_local *mlp;
struct isdn_net_phone *phone;
struct pppcallinfo pci;
int i;
memset((char *) &pci,0,sizeof(struct pppcallinfo));
if(idev) {
- strncpy(pci.local_num,idev->local.msn,63);
+ mlp = idev->mlp;
+ strncpy(pci.local_num, mlp->msn, 63);
i = 0;
- list_for_each_entry(phone, &idev->local.phone[1], list) {
+ list_for_each_entry(phone, &mlp->phone[1], list) {
if (i++ == idev->dial) {
strncpy(pci.remote_num,phone->num,63);
break;
@@ -580,7 +568,7 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
pci.calltype = CALLTYPE_OUTGOING;
else
pci.calltype = CALLTYPE_INCOMING;
- if(idev->local.flags & ISDN_NET_CALLBACK)
+ if(mlp->flags & ISDN_NET_CALLBACK)
pci.calltype |= CALLTYPE_CALLBACK;
}
return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo));
@@ -595,12 +583,8 @@ static unsigned int
isdn_ppp_poll(struct file *file, poll_table * wait)
{
unsigned int mask;
- struct ippp_buf_queue *bf;
- struct ippp_buf_queue *bl;
- unsigned long flags;
struct ippp_struct *is;
- lock_kernel();
is = file->private_data;
if (is->debug & 0x2)
@@ -622,21 +606,15 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
/* we're always ready to send .. */
mask = POLLOUT | POLLWRNORM;
- save_flags(flags);
- cli();
- bl = is->last;
- bf = is->first;
/*
* if IPPP_NOBLOCK is set we return even if we have nothing to read
*/
- if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
+ if (!skb_queue_empty(&is->rq) || is->state & IPPP_NOBLOCK) {
is->state &= ~IPPP_NOBLOCK;
mask |= POLLIN | POLLRDNORM;
}
- restore_flags(flags);
out:
- unlock_kernel();
return mask;
}
@@ -647,10 +625,8 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
static int
isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
{
- struct ippp_buf_queue *bf,
- *bl;
- unsigned long flags;
- unsigned char *nbuf;
+ struct sk_buff *skb;
+ unsigned char *p;
struct ippp_struct *is;
if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
@@ -663,36 +639,23 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
printk(KERN_DEBUG "ippp: device not activated.\n");
return 0;
}
- nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC);
- if (!nbuf) {
- printk(KERN_WARNING "ippp: Can't alloc buf\n");
+ if (skb_queue_len(&is->rq) > IPPP_MAX_RQ_LEN) {
+ printk(KERN_WARNING "ippp: Queue is full\n");
return 0;
}
- nbuf[0] = PPP_ALLSTATIONS;
- nbuf[1] = PPP_UI;
- nbuf[2] = proto >> 8;
- nbuf[3] = proto & 0xff;
- memcpy(nbuf + 4, buf, len);
-
- save_flags(flags);
- cli();
-
- bf = is->first;
- bl = is->last;
-
- if (bf == bl) {
- printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
- bf = bf->next;
- kfree(bf->buf);
- is->first = bf;
+ skb = dev_alloc_skb(len + 4);
+ if (!skb) {
+ printk(KERN_WARNING "ippp: Can't alloc buf\n");
+ return 0;
}
- bl->buf = (char *) nbuf;
- bl->len = len + 4;
+ p = skb_put(skb, 4);
+ p += put_u8(p, PPP_ALLSTATIONS);
+ p += put_u8(p, PPP_UI);
+ p += put_u16(p, proto);
+ memcpy(skb_put(skb, len), buf, len);
- is->last = bl->next;
- restore_flags(flags);
-
- wake_up_interruptible(&is->wq);
+ skb_queue_tail(&is->rq, skb);
+ wake_up_interruptible(&is->wq);
return len;
}
@@ -706,54 +669,36 @@ static ssize_t
isdn_ppp_read(struct file *file, char *buf, size_t count, loff_t *off)
{
struct ippp_struct *is;
- struct ippp_buf_queue *b;
- unsigned long flags;
- unsigned char *save_buf;
+ struct sk_buff *skb;
int retval;
if (off != &file->f_pos)
return -ESPIPE;
- lock_kernel();
-
is = file->private_data;
if (!(is->state & IPPP_OPEN)) {
retval = 0;
goto out;
}
- retval = verify_area(VERIFY_WRITE, (void *) buf, count);
- if (retval)
- goto out;
-
- save_flags(flags);
- cli();
-
- b = is->first->next;
- save_buf = b->buf;
- if (!save_buf) {
- restore_flags(flags);
+ skb = skb_dequeue(&is->rq);
+ if (!skb) {
retval = -EAGAIN;
goto out;
}
- if (b->len < count)
- count = b->len;
- b->buf = NULL;
- is->first = b;
-
- restore_flags(flags);
-
- if (copy_to_user(buf, save_buf, count)) {
- kfree(save_buf);
+ if (skb->len > count) {
+ retval = -EMSGSIZE;
+ goto out_free;
+ }
+ if (copy_to_user(buf, skb->data, skb->len)) {
retval = -EFAULT;
- goto out;
+ goto out_free;
}
- kfree(save_buf);
-
- retval = count;
+ retval = skb->len;
+ out_free:
+ dev_kfree_skb(skb);
out:
- unlock_kernel();
return retval;
}
@@ -832,9 +777,9 @@ isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,idev->ppp_slot);
}
- isdn_ppp_send_ccp(idev,&idev->local,skb); /* keeps CCP/compression states in sync */
+ isdn_ppp_send_ccp(idev,idev->mlp,skb); /* keeps CCP/compression states in sync */
- isdn_net_write_super(&idev->local, skb);
+ isdn_net_write_super(idev, skb);
}
}
retval = count;
@@ -881,15 +826,7 @@ isdn_ppp_init(void)
}
memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
ippp_table[i]->state = 0;
- ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
- ippp_table[i]->last = ippp_table[i]->rq;
-
- for (j = 0; j < NUM_RCV_BUFFS; j++) {
- ippp_table[i]->rq[j].buf = NULL;
- ippp_table[i]->rq[j].last = ippp_table[i]->rq +
- (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
- ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
- }
+ skb_queue_head_init(&ippp_table[i]->rq);
}
return 0;
}
@@ -963,10 +900,9 @@ static int isdn_ppp_strip_proto(struct sk_buff *skb)
/*
* handler for incoming packets on a syncPPP interface
*/
-static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
+static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
- isdn_net_dev *idev = lp->netdev;
struct ippp_struct *is;
int slot;
int proto;
@@ -976,7 +912,7 @@ static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
* huptimer on LCP packets.
*/
if (PPP_PROTOCOL(skb->data) != PPP_LCP)
- isdn_net_reset_huptimer(net_dev,lp->netdev);
+ idev->huptimer = 0;
slot = idev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
@@ -1012,12 +948,12 @@ static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
if (proto == PPP_MP) {
- isdn_ppp_mp_receive(net_dev, lp, skb);
+ isdn_ppp_mp_receive(lp, idev, skb);
return;
}
}
#endif
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
+ isdn_ppp_push_higher(lp, idev, skb, proto);
}
/*
@@ -1026,10 +962,10 @@ static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
* note: net_dev has to be master net_dev
*/
static void
-isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
+isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
+ struct sk_buff *skb, int proto)
{
- isdn_net_dev *idev = lp->netdev;
- struct net_device *dev = &net_dev->dev;
+ struct net_device *dev = &lp->dev;
struct ippp_struct *is, *mis;
int slot;
@@ -1041,14 +977,6 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
}
is = ippp_table[slot];
- if (lp->master) { // FIXME?
- slot = ((isdn_net_local *) (lp->master->priv))->netdev->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
- slot);
- goto drop_packet;
- }
- }
mis = ippp_table[slot];
if (is->debug & 0x10) {
@@ -1079,12 +1007,12 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
case PPP_VJC_UNCOMP:
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
- if (net_dev->ppp_slot < 0) {
+ if (idev->ppp_slot < 0) {
printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n",
- __FUNCTION__ , net_dev->ppp_slot);
+ __FUNCTION__ , idev->ppp_slot);
goto drop_packet;
}
- if (slhc_remember(ippp_table[net_dev->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
+ if (slhc_remember(ippp_table[idev->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
goto drop_packet;
}
@@ -1105,12 +1033,12 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
}
skb_put(skb, skb_old->len + 128);
memcpy(skb->data, skb_old->data, skb_old->len);
- if (net_dev->ppp_slot < 0) {
+ if (idev->ppp_slot < 0) {
printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n",
- __FUNCTION__ , net_dev->ppp_slot);
+ __FUNCTION__ , idev->ppp_slot);
goto drop_packet;
}
- pkt_len = slhc_uncompress(ippp_table[net_dev->ppp_slot]->slcomp,
+ pkt_len = slhc_uncompress(ippp_table[idev->ppp_slot]->slcomp,
skb->data, skb_old->len);
kfree_skb(skb_old);
if (pkt_len < 0)
@@ -1123,7 +1051,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
#endif
case PPP_CCP:
case PPP_CCPFRAG:
- isdn_ppp_receive_ccp(net_dev,lp,skb,proto);
+ isdn_ppp_receive_ccp(idev,lp,skb,proto);
/* Dont pop up ResetReq/Ack stuff to the daemon any
longer - the job is done already */
if(skb->data[0] == CCP_RESETREQ ||
@@ -1146,7 +1074,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
return;
drop_packet:
- net_dev->local.stats.rx_dropped++;
+ lp->stats.rx_dropped++;
kfree_skb(skb);
}
@@ -1184,20 +1112,21 @@ static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
* skb isn't allowed!!
*/
-int
-isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
+static int
+isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
- isdn_net_local *lp,*mlp;
- isdn_net_dev *idev;
- isdn_net_dev *nd;
+ isdn_net_local *mlp = ndev->priv;
+ isdn_net_dev *idev = list_entry(mlp->online.next, isdn_net_dev, online);
unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
int slot;
- mlp = (isdn_net_local *) (netdev->priv);
- nd = mlp->netdev; /* get master lp */
+ ndev->trans_start = jiffies;
- slot = nd->ppp_slot;
+ if (list_empty(&mlp->online))
+ return isdn_net_autodial(skb, ndev);
+
+ slot = idev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
slot);
@@ -1208,7 +1137,8 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
if (ipts->debug & 0x1)
- printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
+ printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name);
+ netif_stop_queue(ndev);
return 1;
}
@@ -1226,13 +1156,13 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
return 0;
}
- lp = isdn_net_get_locked_lp(nd);
- if (!lp) {
- printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
+ idev = isdn_net_get_locked_dev(mlp);
+ if (!idev) {
+ printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
+ netif_stop_queue(ndev);
return 1;
}
/* we have our lp locked from now on */
- idev = lp->netdev;
slot = idev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
@@ -1385,10 +1315,10 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,idev->ppp_slot);
}
- isdn_net_writebuf_skb(lp, skb);
+ isdn_net_writebuf_skb(idev, skb);
unlock:
- spin_unlock_bh(&lp->xmit_lock);
+ spin_unlock_bh(&idev->xmit_lock);
return 0;
}
@@ -1459,7 +1389,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
is->mp_seqno = 0;
if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
return -ENOMEM;
- lp->next = lp->last = lp; /* nobody else in a queue */
+
lp->netdev->pb->frags = NULL;
lp->netdev->pb->frames = 0;
lp->netdev->pb->seq = LONG_MAX;
@@ -1479,12 +1409,12 @@ static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
-static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
- struct sk_buff *skb)
+static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev,
+ struct sk_buff *skb)
{
isdn_net_dev *idev = lp->netdev;
struct ippp_struct *is;
- isdn_net_local * lpq;
+ isdn_net_dev *qdev;
ippp_bundle * mp;
isdn_mppp_stats * stats;
struct sk_buff * newfrag, * frag, * start, *nextf;
@@ -1492,8 +1422,8 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
unsigned long flags;
int slot;
- spin_lock_irqsave(&net_dev->pb->lock, flags);
- mp = net_dev->pb;
+ spin_lock_irqsave(&lp->netdev->pb->lock, flags);
+ mp = lp->netdev->pb;
stats = &mp->stats;
slot = idev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
@@ -1531,8 +1461,8 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
/* find the minimum received sequence number over all links */
is->last_link_seqno = minseq = newseq;
- for (lpq = net_dev->queue;;) {
- slot = lpq->netdev->ppp_slot;
+ list_for_each_entry(qdev, &lp->online, online) {
+ slot = qdev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
__FUNCTION__ ,slot);
@@ -1541,8 +1471,6 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
if (MP_LT(lls, minseq))
minseq = lls;
}
- if ((lpq = lpq->next) == net_dev->queue)
- break;
}
if (MP_LT(minseq, mp->seq))
minseq = mp->seq; /* can't go beyond already processed
@@ -1631,7 +1559,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
/* Reassemble the packet then dispatch it */
- isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
+ isdn_ppp_mp_reassembly(lp->netdev, lp, start, nextf);
start = NULL;
frag = NULL;
@@ -1808,7 +1736,7 @@ void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
}
}
proto = isdn_ppp_strip_proto(skb);
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
+ isdn_ppp_push_higher(lp, idev, skb, proto);
}
static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb)
@@ -1844,7 +1772,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
spin_lock_irqsave(&p->pb->lock, flags);
nidev = is->idev;
- idev = p->queue->netdev;
+ idev = list_entry(p->mlp->online.next, isdn_net_dev, online);
if( nidev->ppp_slot < 0 || nidev->ppp_slot >= ISDN_MAX_CHANNELS ||
idev ->ppp_slot < 0 || idev ->ppp_slot >= ISDN_MAX_CHANNELS ) {
printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
@@ -1854,7 +1782,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
goto out;
}
- isdn_net_add_to_bundle(p, &nidev->local);
+ isdn_net_add_to_bundle(p->mlp, nidev);
ippp_table[nidev->ppp_slot]->unit = ippp_table[idev->ppp_slot]->unit;
@@ -1863,7 +1791,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
(SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
ippp_table[nidev->ppp_slot]->mpppcfg |= ippp_table[idev->ppp_slot]->mpppcfg &
(SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
- rc = isdn_ppp_mp_init(&nidev->local, p->pb);
+ rc = isdn_ppp_mp_init(nidev->mlp, p->pb);
out:
spin_unlock_irqrestore(&p->pb->lock, flags);
return rc;
@@ -1936,7 +1864,7 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if(copy_to_user(r, PPP_VERSION, len)) error = -EFAULT;
break;
case SIOCGPPPSTATS:
- error = isdn_ppp_dev_ioctl_stats(lp->netdev->ppp_slot, ifr, dev);
+ error = isdn_ppp_dev_ioctl_stats(0, ifr, dev);
break;
default:
error = -EINVAL;
@@ -1977,28 +1905,25 @@ isdn_ppp_dial_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
isdn_net_dev *idev;
- isdn_net_local *lp;
- struct net_device *sdev;
+ isdn_net_dev *sdev;
idev = isdn_net_findif(name);
if (!idev)
return 1;
- lp = &idev->local;
if (!isdn_net_bound(idev))
return 5;
- sdev = lp->slave;
+ sdev = idev->slave;
while (sdev) {
- isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
- if (!isdn_net_bound(mlp->netdev))
+ if (!isdn_net_bound(sdev))
break;
- sdev = mlp->slave;
+ sdev = sdev->slave;
}
if (!sdev)
return 2;
- isdn_net_dial_req((isdn_net_local *) sdev->priv);
+ isdn_net_dial_req(sdev);
return 0;
#else
return -1;
@@ -2009,35 +1934,20 @@ int
isdn_ppp_hangup_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *idev;
- isdn_net_local *lp, *mlp = NULL;
- struct net_device *sdev;
+ isdn_net_dev *idev, *sdev;
idev = isdn_net_findif(name);
if (!idev)
return 1;
- lp = &idev->local;
+
if (!isdn_net_bound(idev))
return 5;
- sdev = lp->slave;
- while (sdev) {
- mlp = (isdn_net_local *) sdev->priv;
-
- if (mlp->slave) { /* find last connected link in chain */
- isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv;
-
- if (!isdn_net_bound(nlp->netdev))
- break;
- } else if (isdn_net_bound(mlp->netdev))
- break;
-
- sdev = mlp->slave;
- }
- if (!sdev)
+ sdev = idev->slave;
+ if (!sdev || !isdn_net_bound(sdev))
return 2;
- isdn_net_hangup(mlp->netdev);
+ isdn_net_hangup(sdev);
return 0;
#else
return -1;
@@ -2139,7 +2049,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
printk(KERN_DEBUG "Sending CCP Frame:\n");
isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,idev->ppp_slot);
- isdn_net_write_super(&idev->local, skb);
+ isdn_net_write_super(idev, skb);
}
/* Allocate the reset state vector */
@@ -2537,10 +2447,9 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
* we received a CCP frame ..
* not a clean solution, but we MUST handle a few cases in the kernel
*/
-static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp,
struct sk_buff *skb,int proto)
{
- isdn_net_dev *idev = lp->netdev;
struct ippp_struct *is;
struct ippp_struct *mis;
int len;
@@ -2557,16 +2466,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
is = ippp_table[idev->ppp_slot];
isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,idev->ppp_slot);
- if(lp->master) {
- int slot = ((isdn_net_local *) (lp->master->priv))->netdev->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __FUNCTION__ , slot);
- return;
- }
- mis = ippp_table[slot];
- } else
- mis = is;
+ mis = is;
switch(skb->data[0]) {
case CCP_CONFREQ:
@@ -2715,9 +2615,8 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
* and I tried to modify this file according to that. --abp
*/
-static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
+static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb)
{
- isdn_net_dev *idev = lp->netdev;
struct ippp_struct *mis,*is;
int proto, slot = idev->ppp_slot;
unsigned char *data;
@@ -2745,16 +2644,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct
printk(KERN_DEBUG "Received CCP frame from daemon:\n");
isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,idev->ppp_slot);
- if (lp->master) {
- slot = ((isdn_net_local *) (lp->master->priv))->netdev->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: slot(%d) out of range\n",
- __FUNCTION__ , slot);
- return;
- }
- mis = ippp_table[slot];
- } else
- mis = is;
+ mis = is;
if (mis != is)
printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
@@ -2926,6 +2816,7 @@ isdn_ppp_header(struct sk_buff *skb, struct net_device *dev,
}
struct isdn_netif_ops isdn_ppp_ops = {
+ .hard_start_xmit = isdn_ppp_start_xmit,
.hard_header = isdn_ppp_header,
.do_ioctl = isdn_ppp_dev_ioctl,
.flags = IFF_NOARP | IFF_POINTOPOINT,
diff --git a/drivers/isdn/i4l/isdn_ppp.h b/drivers/isdn/i4l/isdn_ppp.h
index 81743ea38e9b..af6f50fd11db 100644
--- a/drivers/isdn/i4l/isdn_ppp.h
+++ b/drivers/isdn/i4l/isdn_ppp.h
@@ -20,20 +20,6 @@ extern void isdn_ppp_cleanup(void);
extern int isdn_ppp_dial_slave(char *);
extern int isdn_ppp_hangup_slave(char *);
-#ifdef CONFIG_ISDN_PPP
-
-int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
-
-#else
-
-static inline int
-isdn_ppp_xmit(struct sk_buff *, struct net_device *)
-{
- return 0;
-}
-
-#endif
-
#define IPPP_OPEN 0x01
#define IPPP_CONNECT 0x02
#define IPPP_CLOSEWAIT 0x04
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index 7de3324606ee..d8c7b6e2eea3 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -16,6 +16,9 @@
#include <linux/ioctl.h>
+// FIXME!!!
+#include <../drivers/isdn/i4l/isdn_fsm.h>
+
#ifdef CONFIG_COBALT_MICRO_SERVER
/* Save memory */
#define ISDN_MAX_DRIVERS 2
@@ -282,6 +285,8 @@ struct isdn_net_dev_s;
struct isdn_net_local_s;
struct isdn_netif_ops {
+ int (*hard_start_xmit) (struct sk_buff *skb,
+ struct net_device *dev);
int (*hard_header) (struct sk_buff *skb,
struct net_device *dev,
unsigned short type,
@@ -294,26 +299,24 @@ struct isdn_netif_ops {
unsigned short flags; /* interface flags (a la BSD) */
unsigned short type; /* interface hardware type */
unsigned char addr_len;/* hardware address length */
- void (*receive)(struct isdn_net_dev_s *p,
- struct isdn_net_local_s *olp,
- struct sk_buff *skb);
- void (*connected)(struct isdn_net_local_s *lp);
- void (*disconnected)(struct isdn_net_local_s *lp);
- int (*bind)(struct isdn_net_local_s *lp);
- void (*unbind)(struct isdn_net_local_s *lp);
- int (*init)(struct isdn_net_local_s *lp);
- void (*cleanup)(struct isdn_net_local_s *lp);
- int (*open)(struct isdn_net_local_s *lp);
- void (*close)(struct isdn_net_local_s *lp);
+ void (*receive)(struct isdn_net_local_s *,
+ struct isdn_net_dev_s *,
+ struct sk_buff *);
+ void (*connected)(struct isdn_net_dev_s *);
+ void (*disconnected)(struct isdn_net_dev_s *);
+ int (*bind)(struct isdn_net_dev_s *);
+ void (*unbind)(struct isdn_net_dev_s *);
+ int (*init)(struct isdn_net_local_s *);
+ void (*cleanup)(struct isdn_net_local_s *);
+ int (*open)(struct isdn_net_local_s *);
+ void (*close)(struct isdn_net_local_s *);
};
/* Local interface-data */
typedef struct isdn_net_local_s {
ulong magic;
- spinlock_t lock;
struct net_device_stats stats; /* Ethernet Statistics */
int flags; /* Connection-flags */
- int dialretry; /* Counter for Dialout-retries */
int dialmax; /* Max. Number of Dial-retries */
int dialtimeout; /* How long shall we try on dialing */
int dialwait; /* wait after failed attempt */
@@ -329,26 +332,17 @@ typedef struct isdn_net_local_s {
u_char l2_proto; /* Layer-2-protocol */
u_char l3_proto; /* Layer-3-protocol */
- int sqfull; /* Flag: netdev-queue overloaded */
- ulong sqfull_stamp; /* Start-Time of overload */
ulong slavedelay; /* Dynamic bundling delaytime */
int triggercps; /* BogoCPS needed for trigger slave */
struct list_head phone[2]; /* List of remote-phonenumbers */
/* phone[0] = Incoming Numbers */
/* phone[1] = Outgoing Numbers */
- struct net_device *master; /* Ptr to Master device for slaves */
- struct net_device *slave; /* Ptr to Slave device for masters */
- struct isdn_net_local_s *next; /* Ptr to next link in bundle */
- struct isdn_net_local_s *last; /* Ptr to last link in bundle */
- struct isdn_net_dev_s *netdev; /* Ptr to netdev */
- struct sk_buff_head super_tx_queue; /* List of supervisory frames to */
- /* be transmitted asap */
- atomic_t frame_cnt; /* number of frames currently */
- /* queued in HL driver */
- /* Ptr to orig. hard_header_cache */
- spinlock_t xmit_lock; /* used to protect the xmit path of */
- /* a particular channel (including */
- /* the frame_cnt */
+
+ struct list_head slaves; /* list of all bundled channels */
+ struct list_head online; /* circular list of all bundled
+ channels, which are currently
+ online */
+ spinlock_t online_lock; /* lock to protect queue */
#ifdef CONFIG_ISDN_X25
struct concap_device_ops *dops; /* callbacks used by encapsulator */
@@ -361,33 +355,34 @@ typedef struct isdn_net_local_s {
ulong cisco_last_slarp_in; /* jiffie of last keepalive packet we received */
char cisco_line_state; /* state of line according to keepalive packets */
char cisco_debserint; /* debugging flag of cisco hdlc with slarp */
- struct timer_list cisco_timer;
- struct work_struct tqueue;
- struct isdn_netif_ops *ops;
+
+ struct timer_list cisco_timer;
+
+ struct isdn_netif_ops *ops;
+
+ struct net_device dev; /* interface to upper levels */
} isdn_net_local;
/* the interface itself */
typedef struct isdn_net_dev_s {
- isdn_net_local local;
-
int isdn_slot; /* Index to isdn device/channel */
int pre_device; /* Preselected isdn-device */
int pre_channel; /* Preselected isdn-channel */
int exclusive; /* -1 if non excl./idx to excl chan */
struct timer_list dial_timer; /* dial events timer */
+ struct fsm_inst fi; /* call control state machine */
int dial_event; /* event in case of timer expiry */
- int dialstate; /* State for dialing */
int dial; /* # of phone number just dialed */
int outgoing; /* Flag: outgoing call */
- unsigned long dialstarted; /* first dialing-attempt */
- unsigned long dialwait_timer;/* earliest next dialing-attempt */
+ int dialretry; /* Counter for Dialout-retries */
int cps; /* current speed of this interface */
int transcount; /* byte-counter for cps-calculation */
int last_jiffies; /* when transcount was reset */
+ int sqfull; /* Flag: netdev-queue overloaded */
+ ulong sqfull_stamp; /* Start-Time of overload */
- struct timer_list hup_timer; /* auto hangup timer */
int huptimer; /* Timeout-counter for auto-hangup */
int charge; /* Counter for charging units */
int charge_state; /* ChargeInfo state machine */
@@ -397,13 +392,22 @@ typedef struct isdn_net_dev_s {
int pppbind; /* ippp device for bindings */
int ppp_slot; /* PPPD device slot number */
- isdn_net_local *queue; /* circular list of all bundled
- channels, which are currently
- online */
- spinlock_t queue_lock; /* lock to protect queue */
+ spinlock_t xmit_lock; /* used to protect the xmit path of */
+ /* a particular channel (including */
+ /* the frame_cnt */
+ struct sk_buff_head super_tx_queue; /* List of supervisory frames to */
+ /* be transmitted asap */
+ atomic_t frame_cnt; /* number of frames currently */
+ /* queued in HL driver */
+ struct tasklet_struct tlet;
+
+ isdn_net_local *mlp; /* Ptr to master device for all devs*/
+
+ struct list_head slaves; /* Members of local->slaves */
+ struct list_head online; /* Members of local->online */
+
char name[10]; /* Name of device */
- struct list_head global_list; /* global list of all isdn_net_devs */
- struct net_device dev; /* interface to upper levels */
+ struct list_head global_list; /* global list of all isdn_net_devs */
#ifdef CONFIG_ISDN_PPP
ippp_bundle * pb; /* pointer to the common bundle structure
* with the per-bundle data */
diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h
index dcd0ad4aa68b..68353a39b98c 100644
--- a/include/linux/isdn_ppp.h
+++ b/include/linux/isdn_ppp.h
@@ -159,14 +159,7 @@ typedef struct {
isdn_mppp_stats stats;
} ippp_bundle;
-#define NUM_RCV_BUFFS 64
-
-struct ippp_buf_queue {
- struct ippp_buf_queue *next;
- struct ippp_buf_queue *last;
- char *buf; /* NULL here indicates end of queue */
- int len;
-};
+#define IPPP_MAX_RQ_LEN 8
/* The data structure for one CCP reset transaction */
enum ippp_ccp_reset_states {
@@ -201,9 +194,7 @@ struct ippp_ccp_reset {
struct ippp_struct {
struct ippp_struct *next_link;
int state;
- struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */
- struct ippp_buf_queue *first; /* pointer to (current) first packet */
- struct ippp_buf_queue *last; /* pointer to (current) last used packet in queue */
+ struct sk_buff_head rq;
wait_queue_head_t wq;
struct task_struct *tk;
unsigned int mpppcfg;