Dynamic Timeout-Rule-Handling vs. 971110 included

This commit is contained in:
Christian A. Lademann 1998-03-07 18:21:34 +00:00
parent 9d9814cd49
commit 0c64f33f52
11 changed files with 1623 additions and 13 deletions

View File

@ -7,6 +7,11 @@ if [ "$CONFIG_INET" != "n" ]; then
bool 'Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
bool 'Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
fi
bool 'Support dynamic timeout-rules' CONFIG_ISDN_TIMEOUT_RULES
if [ "$CONFIG_ISDN_TIMEOUT_RULES" != "n" ]; then
bool 'Use masqueraded addresses for rule-matching' CONFIG_ISDN_TIMRU_USE_MASQ
fi
bool 'Support budget-accounting' CONFIG_ISDN_BUDGET
fi
bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
if [ "$CONFIG_X25" != "n" ]; then

View File

@ -25,6 +25,12 @@ ifeq ($(CONFIG_ISDN),y)
ifdef CONFIG_ISDN_AUDIO
L_OBJS += isdn_audio.o
endif
ifdef CONFIG_ISDN_TIMEOUT_RULES
L_OBJS += isdn_timru.o
endif
ifdef CONFIG_ISDN_BUDGET
L_OBJS += isdn_budget.o
endif
else
ifeq ($(CONFIG_ISDN),m)
M_OBJS += isdn.o
@ -41,6 +47,12 @@ else
ifdef CONFIG_ISDN_AUDIO
O_OBJS += isdn_audio.o
endif
ifdef CONFIG_ISDN_TIMEOUT_RULES
O_OBJS += isdn_timru.o
endif
ifdef CONFIG_ISDN_BUDGET
O_OBJS += isdn_budget.o
endif
endif
endif

197
drivers/isdn/isdn_budget.c Normal file
View File

@ -0,0 +1,197 @@
/* isdn_budget.c
*
* Linux ISDN subsystem, budget-accounting for network interfaces.
*
* Copyright 1997 by Christian Lademann <cal@zls.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
30.06.97:cal:angelegt
04.11.97:cal:budget.period: int --> time_t
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/isdn.h>
#include "isdn_common.h"
#include "isdn_net.h"
#ifdef CONFIG_ISDN_BUDGET
#define VERBOSE_PRINTK(v, l, p...) { \
if(dev->net_verbose >= (v)) { \
printk(l ## p); \
} else { ; } \
}
int
isdn_net_budget(int type, struct device *ndev) {
isdn_net_local *lp = (isdn_net_local *)ndev->priv;
int i, ret = 0;
switch(type) {
case ISDN_BUDGET_INIT:
for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) {
lp->budget [i] .amount = -1;
lp->budget [i] .used = 0;
lp->budget [i] .period = (time_t)0;
lp->budget [i] .period_started = (time_t)0;
lp->budget [i] .last_check = CURRENT_TIME;
lp->budget [i] .notified = 0;
}
return(0);
break;
case ISDN_BUDGET_CHECK_DIAL:
case ISDN_BUDGET_CHECK_CHARGE:
case ISDN_BUDGET_CHECK_ONLINE:
ret = 0;
for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) {
if(lp->budget [i] .amount < 0)
continue;
if(lp->budget [i] .period_started + lp->budget [i] .period < CURRENT_TIME) {
lp->budget [i] .used = 0;
lp->budget [i] .period_started = CURRENT_TIME;
lp->budget [i] .notified = 0;
}
if(lp->budget [i] .used >= lp->budget [i] .amount)
ret |= (1 << i);
}
switch(type) {
case ISDN_BUDGET_CHECK_DIAL:
if(! ret) {
lp->budget [ISDN_BUDGET_DIAL] .used++;
lp->budget [ISDN_BUDGET_DIAL] .last_check = CURRENT_TIME;
}
break;
case ISDN_BUDGET_CHECK_CHARGE:
lp->budget [ISDN_BUDGET_CHARGE] .used++;
lp->budget [ISDN_BUDGET_CHARGE] .last_check = CURRENT_TIME;
break;
case ISDN_BUDGET_CHECK_ONLINE:
if(lp->budget [ISDN_BUDGET_ONLINE] .last_check) {
lp->budget [ISDN_BUDGET_ONLINE] .used += (CURRENT_TIME - lp->budget [ISDN_BUDGET_ONLINE] .last_check);
}
lp->budget [ISDN_BUDGET_ONLINE] .last_check = CURRENT_TIME;
break;
}
/*
if(ret)
lp->flags |= ISDN_NET_STOPPED;
*/
for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) {
if(ret & (1 << i) && ! lp->budget [i] .notified) {
switch(i) {
case ISDN_BUDGET_DIAL:
printk(KERN_WARNING "isdn_budget: dial budget used up.\n");
break;
case ISDN_BUDGET_CHARGE:
printk(KERN_WARNING "isdn_budget: charge budget used up.\n");
break;
case ISDN_BUDGET_ONLINE:
printk(KERN_WARNING "isdn_budget: online budget used up.\n");
break;
default:
printk(KERN_WARNING "isdn_budget: budget #%d used up.\n", i);
break;
}
lp->budget [i] .notified = 1;
}
}
return(ret);
break;
case ISDN_BUDGET_START_ONLINE:
lp->budget [ISDN_BUDGET_ONLINE] .last_check = CURRENT_TIME;
return(0);
break;
}
return(-1);
}
int
isdn_budget_ioctl(isdn_ioctl_budget *iocmd) {
isdn_net_dev *p = isdn_net_findif(iocmd->name);
if(p) {
switch(iocmd->command) {
case ISDN_BUDGET_SET_BUDGET:
if(! suser())
return(-EPERM);
if(iocmd->budget < 0 || iocmd->budget > ISDN_BUDGET_NUM_BUDGET)
return(-EINVAL);
if(iocmd->amount < 0)
iocmd->amount = -1;
p->local->budget [iocmd->budget] .amount = iocmd->amount;
p->local->budget [iocmd->budget] .period = iocmd->period;
if(iocmd->used <= 0)
p->local->budget [iocmd->budget] .used = 0;
else
p->local->budget [iocmd->budget] .used = iocmd->used;
if(iocmd->period_started == (time_t)0)
p->local->budget [iocmd->budget] .period_started = CURRENT_TIME;
else
p->local->budget [iocmd->budget] .period_started = iocmd->period_started;
return(0);
break;
case ISDN_BUDGET_GET_BUDGET:
if(iocmd->budget < 0 || iocmd->budget > ISDN_BUDGET_NUM_BUDGET)
return(-EINVAL);
iocmd->amount = p->local->budget [iocmd->budget] .amount;
iocmd->used = p->local->budget [iocmd->budget] .used;
iocmd->period = p->local->budget [iocmd->budget] .period;
iocmd->period_started = p->local->budget [iocmd->budget] .period_started;
return(0);
break;
default:
return(-EINVAL);
break;
}
}
return(-ENODEV);
}
#endif

View File

@ -21,6 +21,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.56 1998/02/25 17:49:38 he
* Changed return codes caused be failing copy_{to,from}_user to -EFAULT
*
* Revision 1.55 1998/02/23 23:35:32 fritz
* Eliminated some compiler warnings.
*
@ -295,7 +298,7 @@ isdn_MOD_DEC_USE_COUNT(void)
MOD_DEC_USE_COUNT;
}
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) || defined(CONFIG_ISDN_TIMEOUT_RULES)
void
isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
{
@ -1273,6 +1276,12 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
isdn_ioctl_struct iocts;
isdn_net_ioctl_phone phone;
isdn_net_ioctl_cfg cfg;
#ifdef CONFIG_ISDN_TIMEOUT_RULES
isdn_ioctl_timeout_rule timru;
#endif /* CONFIG_ISDN_TIMEOUT_RULES */
#ifdef CONFIG_ISDN_BUDGET
isdn_ioctl_budget budget;
#endif /* CONFIG_ISDN_BUDGET */
} iocpar;
#define name iocpar.name
@ -1280,6 +1289,13 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
#define iocts iocpar.iocts
#define phone iocpar.phone
#define cfg iocpar.cfg
#ifdef CONFIG_ISDN_TIMEOUT_RULES
# define timru iocpar.timru
#endif /* CONFIG_ISDN_TIMEOUT_RULES */
#ifdef CONFIG_ISDN_BUDGET
# define budget iocpar.budget
#endif /* CONFIG_ISDN_BUDGET */
if (minor == ISDN_MINOR_STATUS) {
switch (cmd) {
@ -1429,6 +1445,57 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
return -EFAULT;
return isdn_net_force_hangup(name);
break;
#ifdef CONFIG_ISDN_TIMEOUT_RULES
case IIOCNETARU:
/* Add a rule to a network-interface */
if (arg) {
if((ret = copy_from_user((char *) &timru, (char *) arg, sizeof(timru))))
return(ret);
return(isdn_timru_ioctl_add_rule(&timru));
} else
return(-EINVAL);
case IIOCNETDRU:
/* Delete a rule from a network-interface */
if (arg) {
if((ret = copy_from_user((char *) &timru, (char *) arg, sizeof(timru))))
return(ret);
return(isdn_timru_ioctl_del_rule(&timru));
} else
return(-EINVAL);
case IIOCNETGRU:
/* Get a rule of a network-interface */
if (arg) {
if((ret = copy_from_user((char *)&timru, (char *)arg, sizeof(timru))))
return(ret);
if((ret = isdn_timru_ioctl_get_rule(&timru)))
return(ret);
if((ret = copy_to_user((char *)arg, (char *)&timru, sizeof(timru))))
return(ret);
return(0);
} else
return(-EINVAL);
#endif /* CONFIG_ISDN_TIMEOUT_RULES */
#ifdef CONFIG_ISDN_BUDGET
case IIOCNETBUD:
/* handle budget-accounting of a network-interface */
if (arg) {
if((ret = copy_from_user((char *)&budget, (char *)arg, sizeof(budget))))
return(ret);
if((ret = isdn_budget_ioctl(&budget)))
return(ret);
if((ret = copy_to_user((char *)arg, (char *)&budget, sizeof(budget))))
return(ret);
return(0);
} else
return(-EINVAL);
#endif /* CONFIG_ISDN_BUDGET */
#endif /* CONFIG_NETDEVICES */
case IIOCSETVER:
dev->net_verbose = arg;

View File

@ -21,6 +21,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.9 1998/02/20 17:19:01 fritz
* Added common stub for sending commands to lowlevel.
*
* Revision 1.8 1997/10/09 21:28:49 fritz
* New HL<->LL interface:
* New BSENT callback with nr. of bytes included.
@ -87,6 +90,6 @@ extern int isdn_readbchan(int, int, u_char *, u_char *, int, int);
extern int isdn_get_free_channel(int, int, int, int, int);
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
extern int register_isdn(isdn_if * i);
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) || defined(CONFIG_ISDN_TIMEOUT_RULES)
extern void isdn_dumppkt(char *, u_char *, int, int);
#endif

View File

@ -21,6 +21,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.57 1998/02/25 18:31:13 fritz
* Added debugging output in adjust_header.
*
* Revision 1.56 1998/02/25 17:49:42 he
* Changed return codes caused be failing copy_{to,from}_user to -EFAULT
*
@ -280,9 +283,24 @@ char *isdn_net_revision = "$Revision$";
static void
isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason)
{
int i;
printk(KERN_DEBUG "isdn_net: %s: %s, send ICMP\n",
dev->name, reason);
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
if(skb)
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
#if 0
for(i = 0; i < DEV_NUMBUFFS; i++) {
struct sk_buff *skb;
while((skb = skb_dequeue(&dev->buffs[i]))) {
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
dev_kfree_skb(skb);
}
}
#endif
}
static void
@ -434,7 +452,11 @@ isdn_net_autohup()
if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
anymore = 1;
l->huptimer++;
if ((l->onhtime) && (l->huptimer > l->onhtime))
#ifdef CONFIG_ISDN_TIMEOUT_RULES
if ((l->timeout_rules || l->huptimeout) && l->huptimer > l->huptimeout)
#else
if ((l->onhtime) && (l->huptimer > l->onhtime))
#endif
if (l->hupflags & ISDN_MANCHARGE &&
l->hupflags & ISDN_CHARGEHUP) {
while (jiffies - l->chargetime > l->chargeint)
@ -458,6 +480,17 @@ isdn_net_autohup()
isdn_net_hangup(&p->dev);
} else if (l->hupflags & ISDN_INHUP)
isdn_net_hangup(&p->dev);
#ifdef CONFIG_ISDN_BUDGET
if(isdn_net_budget(ISDN_BUDGET_CHECK_ONLINE, &p->dev)) {
isdn_net_hangup(&p->dev);
}
#endif
if(dev->global_flags & ISDN_GLOBAL_STOPPED || l->flags & ISDN_NET_STOPPED) {
isdn_net_hangup(&p->dev);
break;
}
}
p = (isdn_net_dev *) p->next;
}
@ -596,6 +629,16 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
lp->chargetime = jiffies;
printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n",
lp->name, lp->chargetime);
/* reset dial-timeout */
lp->dialstarted = 0;
lp->dialwait_timer = 0;
#ifdef CONFIG_ISDN_BUDGET
(void)isdn_net_budget(ISDN_BUDGET_START_ONLINE, &p->dev);
(void)isdn_net_budget(ISDN_BUDGET_CHECK_CHARGE, &p->dev);
#endif
/* Immediately send first skb to speed up arp */
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
@ -613,6 +656,13 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
lp->first_skb = NULL;
}
#ifdef CONFIG_ISDN_TIMEOUT_RULES
else {
/* recalc initial huptimeout,
there is no packet to match the rules. */
isdn_net_recalc_timeout(ISDN_TIMRU_BRINGUP, ISDN_TIMRU_PACKET_NONE, &p->dev, NULL, 0);
}
#endif
return 1;
}
break;
@ -638,6 +688,11 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
lp->chargetime = jiffies;
printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %d\n",
lp->name, lp->chargetime);
#ifdef CONFIG_ISDN_BUDGET
if(isdn_net_budget(ISDN_BUDGET_CHECK_CHARGE, &p->dev)) {
isdn_net_hangup(&p->dev);
}
#endif
return 1;
}
}
@ -703,6 +758,13 @@ isdn_net_dial(void)
break;
}
anymore = 1;
if(lp->dialtimeout > 0)
if(lp->dialstarted == 0 || jiffies > (lp->dialstarted + lp->dialtimeout + lp->dialwait)) {
lp->dialstarted = jiffies;
lp->dialwait_timer = 0;
}
lp->dialstate++;
/* Fall through */
case 2:
@ -723,6 +785,12 @@ isdn_net_dial(void)
* If list of phone-numbers is exhausted, increment
* retry-counter.
*/
if(dev->global_flags & ISDN_GLOBAL_STOPPED || lp->flags & ISDN_NET_STOPPED) {
isdn_net_unreachable(&p->dev, lp->first_skb, "dial suppressed: isdn stopped");
isdn_net_hangup(&p->dev);
break;
}
cmd.driver = lp->isdn_device;
cmd.command = ISDN_CMD_SETL2;
cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
@ -747,6 +815,24 @@ isdn_net_dial(void)
lp->dialstate = 4;
printk(KERN_INFO "%s: Open leased line ...\n", lp->name);
} else {
#ifdef CONFIG_ISDN_BUDGET
if(isdn_net_budget(ISDN_BUDGET_CHECK_DIAL, &p->dev)) {
restore_flags(flags);
isdn_net_unreachable(&p->dev, lp->first_skb, "dial: budget(s) used up");
isdn_net_hangup(&p->dev);
break;
}
#endif
if(lp->dialtimeout > 0)
if(jiffies > (lp->dialstarted + lp->dialtimeout)) {
restore_flags(flags);
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
isdn_net_unreachable(&p->dev, lp->first_skb, "dial: timed out");
isdn_net_hangup(&p->dev);
break;
}
sprintf(cmd.parm.setup.phone, "%s", lp->dial->num);
/*
* Switch to next number or back to start if at end of list.
@ -754,6 +840,17 @@ isdn_net_dial(void)
if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) {
lp->dial = lp->phone[1];
lp->dialretry++;
if (lp->dialretry > lp->dialmax) {
restore_flags(flags);
if (lp->dialtimeout == 0) {
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
isdn_net_unreachable(&p->dev, lp->first_skb, "dial: tried all numbers dialmax times");
}
isdn_net_hangup(&p->dev);
break;
}
}
restore_flags(flags);
cmd.driver = lp->isdn_device;
@ -768,7 +865,7 @@ isdn_net_dial(void)
isdn_info_update();
}
printk(KERN_INFO "%s: dialing %d %s...\n", lp->name,
lp->dialretry - 1, cmd.parm.setup.phone);
lp->dialretry, cmd.parm.setup.phone);
lp->dtimer = 0;
#ifdef ISDN_DEBUG_NET_DIAL
printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
@ -792,14 +889,11 @@ isdn_net_dial(void)
break;
case 4:
/* Wait for D-Channel-connect.
* If timeout and max retries not
* reached, switch back to state 3.
* If timeout, switch back to state 3.
* Dialmax-handling moved to state 3.
*/
if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
if (lp->dialretry < lp->dialmax) {
lp->dialstate = 3;
} else
isdn_net_hangup(&p->dev);
lp->dialstate = 3;
anymore = 1;
break;
case 5:
@ -1071,14 +1165,21 @@ isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
{
int ret;
#if CONFIG_ISDN_TIMEOUT_RULES
(void)isdn_net_recalc_timeout(ISDN_TIMRU_KEEPUP_OUT,
ISDN_TIMRU_PACKET_SKB, ndev, skb, 0);
#endif
/* For the other encaps the header has already been built */
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
return isdn_ppp_xmit(skb, ndev);
}
#endif
#ifndef CONFIG_ISDN_TIMEOUT_RULES
/* Reset hangup-timeout */
lp->huptimer = 0;
#endif
if (lp->cps > lp->triggercps) {
/* Device overloaded */
@ -1190,6 +1291,32 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
ulong flags;
save_flags(flags);
cli();
#ifdef CONFIG_ISDN_TIMEOUT_RULES
if(isdn_net_recalc_timeout(ISDN_TIMRU_BRINGUP,
ISDN_TIMRU_PACKET_SKB, ndev, skb, 0) <= 0) {
isdn_net_unreachable(ndev, skb, "dial rejected: packet may not bring up connection");
dev_kfree_skb(skb);
ndev->tbusy = 0;
restore_flags(flags);
return 0;
}
#endif
if(lp->dialwait_timer <= 0)
if(lp->dialstarted > 0 && lp->dialtimeout > 0 && jiffies < lp->dialstarted + lp->dialtimeout + lp->dialwait)
lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait;
if(lp->dialwait_timer > 0) {
if(jiffies < lp->dialwait_timer) {
isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
dev_kfree_skb(skb);
ndev->tbusy = 0;
restore_flags(flags);
return 0;
} else
lp->dialwait_timer = 0;
}
/* Grab a free ISDN-Channel */
if ((chi =
isdn_get_free_channel(ISDN_USAGE_NET,
@ -1464,8 +1591,10 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
isdn_net_local *olp = lp; /* original 'lp' */
#ifdef CONFIG_ISDN_PPP
#ifndef CONFIG_ISDN_TIMEOUT_RULES
int proto = PPP_PROTOCOL(skb->data);
#endif
#endif
#ifdef CONFIG_ISDN_X25
struct concap_proto *cprot = lp -> netdev -> cprot;
#endif
@ -1494,20 +1623,26 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
switch (lp->p_encap) {
case ISDN_NET_ENCAP_ETHER:
/* Ethernet over ISDN */
#ifndef CONFIG_ISDN_TIMEOUT_RULES
olp->huptimer = 0;
lp->huptimer = 0;
#endif
skb->protocol = isdn_net_type_trans(skb, ndev);
break;
case ISDN_NET_ENCAP_UIHDLC:
/* HDLC with UI-frame (for ispa with -h1 option) */
#ifndef CONFIG_ISDN_TIMEOUT_RULES
olp->huptimer = 0;
lp->huptimer = 0;
#endif
skb_pull(skb, 2);
/* Fall through */
case ISDN_NET_ENCAP_RAWIP:
/* RAW-IP without MAC-Header */
#ifndef CONFIG_ISDN_TIMEOUT_RULES
olp->huptimer = 0;
lp->huptimer = 0;
#endif
skb->protocol = htons(ETH_P_IP);
break;
case ISDN_NET_ENCAP_CISCOHDLCK:
@ -1547,8 +1682,10 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
/* Fall through */
case ISDN_NET_ENCAP_IPTYP:
/* IP with type field */
#ifndef CONFIG_ISDN_TIMEOUT_RULES
olp->huptimer = 0;
lp->huptimer = 0;
#endif
skb->protocol = *(unsigned short *) &(skb->data[0]);
skb_pull(skb, 2);
if (*(unsigned short *) skb->data == 0xFFFF)
@ -1556,6 +1693,7 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
break;
#ifdef CONFIG_ISDN_PPP
case ISDN_NET_ENCAP_SYNCPPP:
#ifndef CONFIG_ISDN_TIMEOUT_RULES
/*
* If encapsulation is syncppp, don't reset
* huptimer on LCP packets.
@ -1564,6 +1702,7 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
olp->huptimer = 0;
lp->huptimer = 0;
}
#endif
isdn_ppp_receive(lp->netdev, olp, skb);
return;
#endif
@ -1581,6 +1720,13 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
kfree_skb(skb);
return;
}
#ifdef CONFIG_ISDN_TIMEOUT_RULES
isdn_net_recalc_timeout(ISDN_TIMRU_KEEPUP_IN,
ISDN_TIMRU_PACKET_SKB, ndev, skb, 0);
/* FIXME: olp->huptimer = lp->huptimer ? */
#endif
netif_rx(skb);
return;
}
@ -2232,6 +2378,7 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
ulong flags;
save_flags(flags);
cli();
/* Grab a free ISDN-Channel */
if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
lp->l3_proto,
@ -2364,6 +2511,19 @@ isdn_net_new(char *name, struct device *master)
netdev->local->dialmax = 1;
netdev->local->flags = ISDN_NET_CBHUP; /* Hangup before Callback */
netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */
netdev->local->dialtimeout = -1; /* Infinite Dial-Timeout */
netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
netdev->local->dialstarted = 0; /* Jiffies of last dial-start */
netdev->local->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
#ifdef CONFIG_ISDN_TIMEOUT_RULES
netdev->local->timeout_rules = NULL;
#endif
#ifdef CONFIG_ISDN_BUDGET
(void)isdn_net_budget(ISDN_BUDGET_INIT, &netdev->dev);
#endif
/* Put into to netdev-chain */
netdev->next = (void *) dev->netdev;
dev->netdev = netdev;
@ -2562,6 +2722,8 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
lp->triggercps = cfg->triggercps;
lp->slavedelay = cfg->slavedelay * HZ;
lp->pppbind = cfg->pppbind;
lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
lp->dialwait = cfg->dialwait * HZ;
if (cfg->secure)
lp->flags |= ISDN_NET_SECURE;
else
@ -2583,6 +2745,10 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
lp->flags &= ~ISDN_NET_CALLBACK;
break;
}
if (cfg->stopped)
lp->flags |= ISDN_NET_STOPPED;
else
lp->flags &= ~ISDN_NET_STOPPED;
if (cfg->chargehup)
lp->hupflags |= ISDN_CHARGEHUP;
else
@ -2650,6 +2816,7 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
if (lp->flags & ISDN_NET_CBOUT)
cfg->callback = 2;
cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
cfg->stopped = (lp->flags & ISDN_NET_STOPPED) ? 1 : 0;
cfg->chargehup = (lp->hupflags & 4) ? 1 : 0;
cfg->ihup = (lp->hupflags & 8) ? 1 : 0;
cfg->cbdelay = lp->cbdelay;
@ -2659,6 +2826,8 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
(lp->chargeint / HZ) : 0;
cfg->pppbind = lp->pppbind;
cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
cfg->dialwait = lp->dialwait / HZ;
if (lp->slave)
strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
else

View File

@ -19,6 +19,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.34 1998/02/25 17:49:48 he
* Changed return codes caused be failing copy_{to,from}_user to -EFAULT
*
* Revision 1.33 1998/02/20 17:11:54 fritz
* Changes for recent kernels.
*
@ -832,8 +835,10 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
{
isdn_net_local *lp;
struct ippp_struct *is;
#ifndef CONFIG_ISDN_TIMEOUT_RULES
int proto;
unsigned char protobuf[4];
#endif
is = file->private_data;
@ -847,6 +852,7 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
if (!lp)
printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
else {
#ifndef CONFIG_ISDN_TIMEOUT_RULES
/*
* Don't reset huptimer for
* LCP packets. (Echo requests).
@ -856,6 +862,7 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
proto = PPP_PROTOCOL(protobuf);
if (proto != PPP_LCP)
lp->huptimer = 0;
#endif
if (lp->isdn_device < 0 || lp->isdn_channel < 0)
return 0;
@ -875,6 +882,12 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
}
#ifdef CONFIG_ISDN_TIMEOUT_RULES
(void)isdn_net_recalc_timeout(ISDN_TIMRU_KEEPUP_OUT,
ISDN_TIMRU_PACKET_PPP, &lp->netdev->dev, skb->data, 0);
#endif
if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) {
if (lp->sav_skb) {
dev_kfree_skb(lp->sav_skb);
@ -1225,15 +1238,24 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
isdn_ppp_receive_ccp(net_dev,lp,skb);
/* fall through */
default:
#ifdef CONFIG_ISDN_TIMEOUT_RULES
(void)isdn_net_recalc_timeout(ISDN_TIMRU_KEEPUP_IN,
ISDN_TIMRU_PACKET_PPP_NO_HEADER, dev, skb->data, proto);
#endif
isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
dev_kfree_skb(skb);
return;
}
#ifdef CONFIG_ISDN_TIMEOUT_RULES
(void)isdn_net_recalc_timeout(ISDN_TIMRU_KEEPUP_IN,
ISDN_TIMRU_PACKET_SKB, dev, skb, 0);
#else
/* Reset hangup-timer */
lp->huptimer = 0;
#endif
netif_rx(skb);
/* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */
/* Reset hangup-timer */
lp->huptimer = 0;
return;
}
@ -1335,7 +1357,9 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
}
ipt = ippp_table[lp->ppp_slot];
#ifndef CONFIG_ISDN_TIMEOUT_RULES
lp->huptimer = 0;
#endif
/*
* after this line .. requeueing in the device queue is no longer allowed!!!

905
drivers/isdn/isdn_timru.c Normal file
View File

@ -0,0 +1,905 @@
/* isdn_timru.c
*
* Linux ISDN subsystem, timeout-rules for network interfaces.
*
* Copyright 1997 by Christian Lademann <cal@zls.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
02.06.97:cal:
- ISDN_TIMRU_PACKET_NONE = 0 definiert, die anderen ISDN_TIMRU_PACKET_* -
Definitionen jeweils inkrementiert
- isdn_net_recalc_timeout():
- In der Schleife zum Finden einer passenden Regel wurde in jedem Fall
die Wildcard-Kette durchsucht. Jetzt nicht mehr.
- beim Testen einer Bringup-Regel wird der anfaengliche Timeout auf den
Hangup-Timeout des Devices gesetzt (lp->onhtime).
10.06.97:cal:
- isdn_net_recalc_timeout(): rule->neg-Handling gesaeubert: eine Regel passt
genau dann, wenn match(rule) XOR rule->neg und das bei allen Regeltypen.
- isdn_net_add_rule(): rule->timeout bei BRINGUP immer 1, sonst > 0.
- alle return(-1), die zu ioctl-Calls zurueckgehen --> return(-EINVAL).
- div. Leerzeilen geloescht / eingefuegt; alle return's "geklammert".
12.06.97:cal:
- isdn_net_recalc_timeout(): Falls IP-Masquerading verwendet wird, kann mit
der neuen Option CONFIG_TIMRU_USE_MASQ der Regel-Match auf die ursprueng-
lichen Adressen und nicht auf die der Firewall angewendet werden. Dazu ist
ein Patch in net/ipv4/ip_masq.c notwendig: ip_masq_in_get_2 muss
exportiert werden.
26.06.97:cal:
- isdn_net_add_rule(): rule->timeout darf bei BRINGUP >= 0 sein. Damit
laesst sich folgende Systax erreichen: "Falls Paket passt, starte die
Verbindung NICHT", wie es im Stand 970602 moeglich war.
- isdn_net_recalc_timeout(): BRINGUP: initial timeout wird auf den in der
passenden Regel gefundenen Timeout gesetzt. Ist dieser 0, so wird die
Verbindung nicht aufgebaut.
16.10.97:cal:
- isdn_net_recalc_timeout(): beachte Fake-Header, der bei ausgehenden
SyncPPP-Paketen eingesetzt wird;
TimRu's "recalc timeout:" - Meldungen in einer Zeile
04.11.97:cal:
- isdn_net.c, isdn_net_new(): Timeout-Rules nicht mehr automatisch
alloziieren;
- isdn_net.c, isdn_net_autohup(): AutoHup auch durchfuehren, wenn keine
Timeout-Rules alloziiert sind.
*/
/*
TODO:
- Masq-Adressen statt Paketadresse ausgeben, falls die Masq-Adressen verwendet
werden.
- Masq-Adressen-Verwendung als Option in den Regeln vorsehen
- TCP-Flags als Regel-Optionen
- weitere Verfeinerungen fuer Nicht-TCP/IP-Pakete
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/isdn.h>
#include <linux/if_arp.h>
#include <linux/in.h>
#include <net/icmp.h>
#include <net/tcp.h>
#include <net/udp.h>
#ifdef CONFIG_ISDN_TIMRU_USE_MASQ
#ifdef CONFIG_IP_MASQUERADE
#include <net/ip_masq.h>
#endif
#endif
#include "isdn_common.h"
#include "isdn_net.h"
#ifdef CONFIG_ISDN_PPP
#include "isdn_ppp.h"
#endif
#ifdef CONFIG_ISDN_TIMEOUT_RULES
static int
isdn_timru_match(isdn_timeout_rule *this, isdn_timeout_rule *rule);
#define printk_ip(a) printk("%ld.%ld.%ld.%ld",(ntohl(a)>>24)&0xFF,\
(ntohl(a)>>16)&0xFF,\
(ntohl(a)>>8)&0xFF,\
(ntohl(a))&0xFF)
#define printk_port(a) printk("%d",ntohs(a))
#define VERBOSE_PRINTK(v, l, p...) { \
if(dev->net_verbose >= (v)) { \
printk(l ## p); \
} else { ; } \
}
int
isdn_net_recalc_timeout(int type, int prot, struct device *ndev, void *buf, ulong arg) {
isdn_net_local *lp = (isdn_net_local *)ndev->priv;
struct sk_buff *skb;
struct iphdr *ip;
struct icmphdr *icmp;
struct tcphdr *tcp;
struct udphdr *udp;
#ifdef CONFIG_ISDN_TIMRU_USE_MASQ
#ifdef CONFIG_IP_MASQUERADE
struct ip_masq *masq;
int m_prot;
__u32 m_saddr, m_daddr;
__u16 m_sport, m_dport;
int check_for_masq;
#endif
#endif
isdn_timeout_rule match_rule;
/*
char *cbuf;
*/
int ppp_proto, ppp_hdrlen = 0, new_timeout;
match_rule.type = type;
match_rule.protfam = ISDN_TIMRU_PROTFAM_WILDCARD;
if(dev->net_verbose > 4) {
printk(KERN_DEBUG "recalc_timeout:");
switch(type) {
case ISDN_TIMRU_BRINGUP: printk("BRINGUP, "); break;
case ISDN_TIMRU_KEEPUP_IN: printk("KEEPUP_IN, "); break;
case ISDN_TIMRU_KEEPUP_OUT: printk("KEEPUP_OUT, "); break;
default:
printk("ERROR\n");
return(-1);
break;
}
}
switch(prot) {
case ISDN_TIMRU_PACKET_PPP:
case ISDN_TIMRU_PACKET_PPP_NO_HEADER:
if(prot == ISDN_TIMRU_PACKET_PPP) {
ppp_proto = PPP_PROTOCOL((char *)buf);
/*
cbuf = (char *)(buf + PPP_HDRLEN);
*/
} else {
ppp_proto = (int)arg;
/*
cbuf = (char *)buf;
*/
}
match_rule.protfam = ISDN_TIMRU_PROTFAM_PPP;
match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_WILDCARD;
switch(ppp_proto) {
case PPP_IPCP:
match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_IPCP;
VERBOSE_PRINTK(5, "", "PPP/IPCP\n");
break;
case PPP_IPXCP:
match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_IPXCP;
VERBOSE_PRINTK(5, "", "PPP/IPXCP\n");
break;
case PPP_CCP:
match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_CCP;
VERBOSE_PRINTK(5, "", "PPP/CCP\n");
break;
case PPP_LCP:
match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_LCP;
VERBOSE_PRINTK(5, "", "PPP/LCP\n");
break;
case PPP_PAP:
match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_PAP;
VERBOSE_PRINTK(5, "", "PPP/PAP\n");
break;
case PPP_LQR:
match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_LQR;
VERBOSE_PRINTK(5, "", "PPP/LQR\n");
break;
case PPP_CHAP:
match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_CHAP;
VERBOSE_PRINTK(5, "", "PPP/CHAP\n");
break;
default:
match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_WILDCARD;
if(dev->net_verbose >= 5) {
printk("PPP/? (%x)\n", ppp_proto);
isdn_dumppkt("R:", (u_char *)buf, 40, 40);
}
break;
}
break;
case ISDN_TIMRU_PACKET_SKB:
skb = (struct sk_buff *)buf;
#ifdef CONFIG_ISDN_PPP
if((type == ISDN_TIMRU_BRINGUP ||
type == ISDN_TIMRU_KEEPUP_OUT) &&
lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
/* jump over fake header. */
ppp_hdrlen = IPPP_MAX_HEADER;
}
#endif
switch(ntohs(skb->protocol)) {
case ETH_P_IP:
/*
if(!(ip = skb->ip_hdr))
*/
ip = (struct iphdr *)(skb->data + ppp_hdrlen);
match_rule.protfam = ISDN_TIMRU_PROTFAM_IP;
match_rule.rule.ip.saddr.s_addr = ip->saddr;
match_rule.rule.ip.daddr.s_addr = ip->daddr;
match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
switch(ip->protocol) {
case IPPROTO_ICMP:
if(!(icmp = (struct icmphdr *)((unsigned long *)ip+ip->ihl))) {
VERBOSE_PRINTK(5, "", "IP/ICMP HDR-ERR\n");
} else {
match_rule.rule.ip.protocol = ISDN_TIMRU_IP_ICMP;
match_rule.rule.ip.pt.type.from = icmp->type;
if(dev->net_verbose >= 5) {
printk("IP/ICMP ");
printk_ip(ip->saddr);
printk(" --> ");
printk_ip(ip->daddr);
printk("/");
printk_port(icmp->type);
printk("\n");
}
}
break;
case IPPROTO_IGMP:
match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
VERBOSE_PRINTK(5, "", "IP/IGMP\n");
break;
case IPPROTO_IPIP:
match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
VERBOSE_PRINTK(5, "", "IP/IPIP\n");
break;
case IPPROTO_TCP:
if(!(tcp = (struct tcphdr *)((unsigned long *)ip+ip->ihl))) {
VERBOSE_PRINTK(5, "", "IP/TCP HDR-ERR\n");
} else {
match_rule.rule.ip.protocol = ISDN_TIMRU_IP_TCP;
match_rule.rule.ip.pt.port.s_from = tcp->source;
match_rule.rule.ip.pt.port.d_from = tcp->dest;
if(dev->net_verbose >= 5) {
printk("IP/TCP ");
printk_ip(ip->saddr);
printk("/");
printk_port(tcp->source);
printk(" --> ");
printk_ip(ip->daddr);
printk("/");
printk_port(tcp->dest);
printk("\n");
}
}
break;
case IPPROTO_EGP:
match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
VERBOSE_PRINTK(5, "", "IP/EGP\n");
break;
case IPPROTO_PUP:
match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
VERBOSE_PRINTK(5, "" "IP/PUP\n");
break;
case IPPROTO_UDP:
if(!(udp=(struct udphdr *)((unsigned long *)ip+ip->ihl))) {
VERBOSE_PRINTK(5, "", "IP/UDP HDR-ERR\n");
} else {
match_rule.rule.ip.protocol = ISDN_TIMRU_IP_UDP;
match_rule.rule.ip.pt.port.s_from = udp->source;
match_rule.rule.ip.pt.port.d_from = udp->dest;
if(dev->net_verbose >= 5) {
printk("IP/UDP ");
printk_ip(ip->saddr);
printk("/");
printk_port(udp->source);
printk(" --> ");
printk_ip(ip->daddr);
printk("/");
printk_port(udp->dest);
printk("\n");
}
}
break;
case IPPROTO_IDP:
match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
VERBOSE_PRINTK(5, "", "IP/IDP\n");
break;
default:
match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
if(dev->net_verbose >= 5) {
printk("IP/? (%x)\n", ip->protocol);
isdn_dumppkt("R:", (u_char *)skb, skb->len, 180);
}
break;
}
break;
case ETH_P_ARP:
VERBOSE_PRINTK(5, "", "ARP/?\n");
break;
case ETH_P_IPX:
VERBOSE_PRINTK(5, "", "IPX/?\n");
break;
case ETH_P_802_2:
VERBOSE_PRINTK(5, "", "802.2/?\n");
break;
case ETH_P_802_3:
VERBOSE_PRINTK(5, "", "802.3/?\n");
break;
default:
if(dev->net_verbose >= 5) {
printk("?/? (%x)\n", ntohs(skb->protocol));
isdn_dumppkt("R:", (u_char *)skb, skb->len, 1800);
}
break;
}
#ifdef CONFIG_ISDN_TIMRU_USE_MASQ
#ifdef CONFIG_IP_MASQUERADE
check_for_masq = 0;
m_saddr = m_daddr = (__u32)0;
m_sport = m_dport = (__u16)0;
m_prot = 0;
switch(match_rule.protfam) {
case ISDN_TIMRU_PROTFAM_IP:
m_saddr = match_rule.rule.ip.saddr.s_addr;
m_daddr = match_rule.rule.ip.daddr.s_addr;
switch(match_rule.rule.ip.protocol) {
case ISDN_TIMRU_IP_TCP:
m_prot = IPPROTO_TCP;
m_sport = match_rule.rule.ip.pt.port.s_from;
m_dport = match_rule.rule.ip.pt.port.d_from;
check_for_masq = 1;
break;
case ISDN_TIMRU_IP_UDP:
m_prot = IPPROTO_UDP;
m_sport = match_rule.rule.ip.pt.port.s_from;
m_dport = match_rule.rule.ip.pt.port.d_from;
check_for_masq = 1;
break;
#if 0
#ifdef CONFIG_IP_MASQUERADE_ICMP
case ISDN_TIMRU_IP_ICMP:
m_sport = match_rule.rule.ip.pt.type.from;
m_dport = 0;
check_for_masq = 1;
break;
#endif
#endif
}
break;
}
if(check_for_masq) {
masq = NULL;
switch(type) {
case ISDN_TIMRU_BRINGUP:
case ISDN_TIMRU_KEEPUP_OUT:
if((masq = ip_masq_in_get_2(m_prot, m_daddr, m_dport, m_saddr, m_sport))) {
match_rule.rule.ip.saddr.s_addr = m_saddr;
match_rule.rule.ip.daddr.s_addr = m_daddr;
switch(m_prot) {
case IPPROTO_TCP:
case IPPROTO_UDP:
match_rule.rule.ip.pt.port.s_from = m_sport;
match_rule.rule.ip.pt.port.d_from = m_dport;
break;
}
}
break;
case ISDN_TIMRU_KEEPUP_IN:
if((masq = ip_masq_in_get_2(m_prot, m_saddr, m_sport, m_daddr, m_dport))) {
match_rule.rule.ip.saddr.s_addr = m_daddr;
match_rule.rule.ip.daddr.s_addr = m_saddr;
switch(m_prot) {
case IPPROTO_TCP:
case IPPROTO_UDP:
match_rule.rule.ip.pt.port.s_from = m_sport;
match_rule.rule.ip.pt.port.d_from = m_dport;
break;
}
}
break;
}
if(masq && dev->net_verbose >= 5) {
printk(KERN_DEBUG "MASQ-TIMRU: ");
printk_ip(masq->maddr);
printk("/");
printk_port(masq->mport);
printk(": ");
printk_ip(masq->saddr);
printk("/");
printk_port(masq->sport);
printk(" --> ");
printk_ip(masq->daddr);
printk("/");
printk_port(masq->dport);
printk("\n");
}
}
#endif
#endif
break;
}
new_timeout = lp->onhtime;
if(prot && lp->timeout_rules) {
isdn_timeout_rule *head, *tor;
int pf, found_match, i;
pf = match_rule.protfam;
found_match = 0;
while(1) {
head = tor = lp->timeout_rules->timru[type][pf];
i = 0;
while(tor) {
if((isdn_timru_match(&match_rule, tor) > 0) ^ (tor->neg > 0)) {
found_match = 1;
new_timeout = tor->timeout;
}
if(found_match) {
#ifdef DEBUG_RULES
printk(KERN_DEBUG "Rule %d-%d-%d matches\n", type, pf, i);
#endif
break;
}
if(tor->next == head)
tor = NULL;
else {
tor = tor->next;
i++;
}
}
if(! found_match && pf != ISDN_TIMRU_PROTFAM_WILDCARD)
pf = ISDN_TIMRU_PROTFAM_WILDCARD;
else
break;
}
if(! found_match) {
new_timeout = lp->timeout_rules->defaults[type];
#ifdef DEBUG_RULES
printk("No rule matches: using default\n");
#endif
}
}
if(type == ISDN_TIMRU_BRINGUP) {
if(new_timeout > 0) {
lp->huptimeout = new_timeout;
lp->huptimer = 0;
}
} else {
if(new_timeout > lp->huptimeout
|| lp->huptimeout - lp->huptimer < new_timeout) {
lp->huptimeout = new_timeout;
lp->huptimer = 0;
}
}
return(new_timeout);
}
static int
isdn_timru_match(isdn_timeout_rule *this, isdn_timeout_rule *rule) {
if(this->protfam != rule->protfam)
return(0);
switch(rule->protfam) {
case ISDN_TIMRU_PROTFAM_WILDCARD:
return(1);
break;
case ISDN_TIMRU_PROTFAM_PPP:
if(rule->rule.ppp.protocol == ISDN_TIMRU_PPP_WILDCARD
|| rule->rule.ppp.protocol == this->rule.ppp.protocol)
return(1);
break;
case ISDN_TIMRU_PROTFAM_IP:
if((this->rule.ip.saddr.s_addr & rule->rule.ip.smask.s_addr) != rule->rule.ip.saddr.s_addr
|| (this->rule.ip.daddr.s_addr & rule->rule.ip.dmask.s_addr) != rule->rule.ip.daddr.s_addr)
return(0);
if(rule->rule.ip.protocol == ISDN_TIMRU_IP_WILDCARD)
return(1);
if(rule->rule.ip.protocol != this->rule.ip.protocol)
return(0);
switch(rule->rule.ip.protocol) {
case ISDN_TIMRU_IP_ICMP:
if(this->rule.ip.pt.type.from < rule->rule.ip.pt.type.from
|| this->rule.ip.pt.type.from > rule->rule.ip.pt.type.to)
return(0);
break;
case ISDN_TIMRU_IP_TCP:
case ISDN_TIMRU_IP_UDP:
if(this->rule.ip.pt.port.s_from < rule->rule.ip.pt.port.s_from
|| this->rule.ip.pt.port.s_from > rule->rule.ip.pt.port.s_to)
return(0);
if(this->rule.ip.pt.port.d_from < rule->rule.ip.pt.port.d_from
|| this->rule.ip.pt.port.d_from > rule->rule.ip.pt.port.d_to)
return(0);
break;
}
break;
}
return(1);
}
static int
isdn_timru_rule_equals(isdn_timeout_rule *this, isdn_timeout_rule *rule) {
if(this->neg != rule->neg
|| this->protfam != rule->protfam)
return(0);
switch(rule->protfam) {
case ISDN_TIMRU_PROTFAM_PPP:
if(this->rule.ppp.protocol != rule->rule.ppp.protocol)
return(0);
break;
case ISDN_TIMRU_PROTFAM_IP:
if(this->rule.ip.protocol != rule->rule.ip.protocol
|| this->rule.ip.saddr.s_addr != rule->rule.ip.saddr.s_addr
|| this->rule.ip.smask.s_addr != rule->rule.ip.smask.s_addr
|| this->rule.ip.daddr.s_addr != rule->rule.ip.daddr.s_addr
|| this->rule.ip.dmask.s_addr != rule->rule.ip.dmask.s_addr)
return(0);
switch(rule->rule.ip.protocol) {
case ISDN_TIMRU_IP_ICMP:
if(this->rule.ip.pt.type.from != rule->rule.ip.pt.type.from
|| this->rule.ip.pt.type.to != rule->rule.ip.pt.type.to)
return(0);
break;
case ISDN_TIMRU_IP_TCP:
case ISDN_TIMRU_IP_UDP:
if(this->rule.ip.pt.port.s_from != rule->rule.ip.pt.port.s_from
|| this->rule.ip.pt.port.s_to != rule->rule.ip.pt.port.s_to
|| this->rule.ip.pt.port.d_from != rule->rule.ip.pt.port.d_from
|| this->rule.ip.pt.port.d_to != rule->rule.ip.pt.port.d_to)
return(0);
break;
}
break;
}
return(1);
}
int
isdn_timru_alloc_timeout_rules(struct device *ndev) {
isdn_net_local *lp = (isdn_net_local *)ndev->priv;
int i, j;
ulong flags;
save_flags(flags);
cli();
if(!(lp->timeout_rules = (struct isdn_timeout_rules *)kmalloc(sizeof(struct isdn_timeout_rules), GFP_KERNEL))) {
restore_flags(flags);
printk(KERN_WARNING "isdn_timru: failed to allocate memory.\n");
return(-ENOMEM);
}
memset((char *)lp->timeout_rules, 0, sizeof(struct isdn_timeout_rules));
for(i = 0; i < ISDN_TIMRU_NUM_CHECK; i++) {
lp->timeout_rules->defaults[i] = lp->onhtime;
for(j = 0; j < ISDN_TIMRU_NUM_PROTFAM; j++)
lp->timeout_rules->timru[i][j] = NULL;
}
restore_flags(flags);
return(0);
}
int
isdn_timru_free_timeout_rules(struct device *ndev) {
isdn_net_local *lp = (isdn_net_local *)ndev->priv;
isdn_timeout_rule *head, *this, *next;
int i, j;
ulong flags;
if(!lp->timeout_rules)
return(-1);
save_flags(flags);
cli();
for(i = 0; i < ISDN_TIMRU_NUM_CHECK; i++)
for(j = 0; j < ISDN_TIMRU_NUM_CHECK; j++)
if((head = lp->timeout_rules->timru[i][j])) {
this = head;
do {
next = this->next;
kfree(this);
} while(next == head);
}
kfree(lp->timeout_rules);
lp->timeout_rules = NULL;
restore_flags(flags);
return(0);
}
int
isdn_timru_add_rule(int where, struct device *ndev, isdn_timeout_rule *rule) {
isdn_net_local *lp = (isdn_net_local *)ndev->priv;
isdn_timeout_rule **head;
ulong flags;
int ret;
if(!lp->timeout_rules)
if((ret = isdn_timru_alloc_timeout_rules(ndev)))
return(ret);
if(rule->timeout < 0)
return(-EINVAL);
save_flags(flags);
cli();
head = &(lp->timeout_rules->timru[rule->type][rule->protfam]);
if(! *head)
rule->next = rule->prev = *head = rule;
else {
rule->next = *head;
rule->prev = (*head)->prev;
(*head)->prev->next = rule;
(*head)->prev = rule;
if(where == 0) /* add to head of chain */
*head = rule;
}
restore_flags(flags);
return(0);
}
int
isdn_timru_del_rule(struct device *ndev, isdn_timeout_rule *rule) {
isdn_net_local *lp = (isdn_net_local *)ndev->priv;
isdn_timeout_rule **head, *this;
ulong flags;
if(!lp->timeout_rules)
return(-EINVAL);
save_flags(flags);
cli();
head = &(lp->timeout_rules->timru[rule->type][rule->protfam]);
if(! *head) {
restore_flags(flags);
return(-EINVAL);
}
this = *head;
do {
if(isdn_timru_rule_equals(this, rule)) {
if(this->next != this) { /* more than one rule */
this->prev->next = this->next;
this->next->prev = this->prev;
if(this == *head)
*head = this->next;
} else
*head = NULL;
kfree(this);
restore_flags(flags);
return(0);
} else
this = this->next;
} while(this == *head);
restore_flags(flags);
return(-EINVAL);
}
int
isdn_timru_set_default(int type, struct device *ndev, int def) {
isdn_net_local *lp = (isdn_net_local *)ndev->priv;
ulong flags;
int ret;
if(!lp->timeout_rules)
if((ret = isdn_timru_alloc_timeout_rules(ndev)))
return(ret);
if(def < 0)
return(-EINVAL);
save_flags(flags);
cli();
lp->timeout_rules->defaults[type] = def;
restore_flags(flags);
return(0);
}
int
isdn_timru_get_rule(struct device *ndev, isdn_timeout_rule **rule, int i, int j, int k) {
isdn_net_local *lp = (isdn_net_local *)ndev->priv;
isdn_timeout_rule *head, *this;
int l;
ulong flags;
if(!lp->timeout_rules
|| i < 0 || i > ISDN_TIMRU_NUM_CHECK
|| j < 0 || j > ISDN_TIMRU_NUM_PROTFAM
|| k < 0)
return(-EINVAL);
save_flags(flags);
cli();
if(!(this = head = lp->timeout_rules->timru[i][j])) {
restore_flags(flags);
return(-EINVAL);
}
for(l = 0; l < k; l++) {
if(this->next == head) {
restore_flags(flags);
return(-EINVAL);
}
this = this->next;
}
*rule = this;
restore_flags(flags);
return(0);
}
int
isdn_timru_get_default(int type, struct device *ndev, int *ret) {
isdn_net_local *lp = (isdn_net_local *)ndev->priv;
ulong flags;
if(!lp->timeout_rules)
return(-EINVAL);
save_flags(flags);
cli();
*ret = lp->timeout_rules->defaults[type];
restore_flags(flags);
return(0);
}
int
isdn_timru_ioctl_add_rule(isdn_ioctl_timeout_rule *iorule)
{
isdn_net_dev *p = isdn_net_findif(iorule->name);
isdn_timeout_rule *r;
if(p) {
if(iorule->where < 0) { /* set default */
return(isdn_timru_set_default(iorule->type, &p->dev, iorule->defval));
} else {
if(!(r = (isdn_timeout_rule *) kmalloc(sizeof(isdn_timeout_rule), GFP_KERNEL)))
return(-ENOMEM);
memcpy((char *)r, (char *)&iorule->rule, sizeof(isdn_timeout_rule));
return(isdn_timru_add_rule(iorule->where, &p->dev, r));
}
}
return(-ENODEV);
}
int
isdn_timru_ioctl_del_rule(isdn_ioctl_timeout_rule *iorule)
{
isdn_net_dev *p = isdn_net_findif(iorule->name);
isdn_timeout_rule *r;
if(p) {
if(!(r = (isdn_timeout_rule *) kmalloc(sizeof(isdn_timeout_rule), GFP_KERNEL)))
return(-ENOMEM);
memcpy((char *)r, (char *)&iorule->rule, sizeof(isdn_timeout_rule));
return(isdn_timru_del_rule(&p->dev, r));
}
return(-ENODEV);
}
int
isdn_timru_ioctl_get_rule(isdn_ioctl_timeout_rule *iorule)
{
int ret, def;
isdn_net_dev *p = isdn_net_findif(iorule->name);
isdn_timeout_rule *r;
if(p) {
if(iorule->where < 0) { /* get default */
if((ret = isdn_timru_get_default(iorule->type, &p->dev, &def)) < 0)
return(ret);
iorule->protfam = p->local->huptimer;
iorule->index = p->local->huptimeout;
iorule->defval = def;
} else {
if(isdn_timru_get_rule(&p->dev, &r, iorule->type, iorule->protfam, iorule->index))
return(-ENOMEM);
memcpy((char *)&iorule->rule, (char *)r, sizeof(isdn_timeout_rule));
}
return(0);
}
return(-ENODEV);
}
#endif

View File

@ -27,6 +27,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.37 1998/02/22 19:45:24 fritz
* Some changes regarding V.110
*
* Revision 1.36 1998/02/20 17:35:55 fritz
* Added V.110 stuff.
*
@ -206,6 +209,11 @@
#define IIOCNETDIL _IO('I',20)
#define IIOCGETCPS _IO('I',21)
#define IIOCGETDVR _IO('I',22)
#define IIOCNETARU _IO('I',23)
#define IIOCNETDRU _IO('I',24)
#define IIOCNETGRU _IO('I',25)
#define IIOCNETBUD _IO('I',26)
#define IIOCNETALN _IO('I',32)
#define IIOCNETDLN _IO('I',33)
@ -281,6 +289,9 @@ typedef struct {
int pppbind; /* ippp device for bindings */
int chargeint; /* Use fixed charge interval length */
int triggercps; /* BogoCPS needed for triggering slave */
int dialtimeout; /* Dial-Timeout */
int dialwait; /* Time to wait after failed dial */
int stopped; /* Flag: Stopped */
} isdn_net_ioctl_cfg;
#ifdef __KERNEL__
@ -397,6 +408,9 @@ typedef struct {
#define ISDN_NET_TMP 0x10 /* tmp interface until getting an IP */
#define ISDN_NET_DYNAMIC 0x20 /* this link is dynamically allocated */
#endif
#define ISDN_NET_STOPPED 0x40 /* this interface is stopped */
#define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */
/* Phone-list-element */
@ -405,6 +419,28 @@ typedef struct {
char num[ISDN_MSNLEN];
} isdn_net_phone;
#ifdef CONFIG_ISDN_TIMEOUT_RULES
#include <linux/isdn_timru.h>
struct isdn_timeout_rules {
isdn_timeout_rule *timru[ISDN_TIMRU_NUM_CHECK][ISDN_TIMRU_NUM_PROTFAM];
int defaults[ISDN_TIMRU_NUM_CHECK];
};
#endif
#ifdef CONFIG_ISDN_BUDGET
#include <linux/isdn_budget.h>
typedef struct {
int amount, /* usable amount */
used, /* used so far */
period, /* length of period */
notified; /* flag: notified user about low budget */
time_t period_started, /* when did the current period start? */
last_check; /* last time checked */
} isdn_budget;
#endif
/*
Principles when extending structures for generic encapsulation protocol
("concap") support:
@ -487,6 +523,17 @@ typedef struct isdn_net_local_s {
struct device *,
unsigned char *);
int pppbind; /* ippp device for bindings */
int dialtimeout; /* How long shall we try on dialing? (jiffies) */
int dialwait; /* How long shall we wait after failed attempt? (jiffies) */
ulong dialstarted; /* jiffies of first dialing-attempt */
ulong dialwait_timer; /* jiffies of earliest next dialing-attempt */
int huptimeout; /* How long will the connection be up? (seconds) */
#ifdef CONFIG_ISDN_TIMEOUT_RULES
struct isdn_timeout_rules *timeout_rules;
#endif
#ifdef CONFIG_ISDN_BUDGET
isdn_budget budget [ISDN_BUDGET_NUM_BUDGET];
#endif
#ifdef CONFIG_ISDN_X25
struct concap_device_ops *dops; /* callbacks used by encapsulator */
#endif

View File

@ -0,0 +1,62 @@
/* isdn_budget.h
*
* Linux ISDN subsystem, budget-accounting for network interfaces.
*
* Copyright 1997 by Christian Lademann <cal@zls.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
30.06.97:cal:angelegt
04.11.97:cal:budget.period: int --> time_t
*/
#ifndef __isdn_budget_h__
#define __isdn_budget_h__
#include <linux/types.h>
#define ISDN_BUDGET_DIAL 0
#define ISDN_BUDGET_CHARGE 1
#define ISDN_BUDGET_ONLINE 2
#define ISDN_BUDGET_NUM_BUDGET 3
#define ISDN_BUDGET_INIT 0
#define ISDN_BUDGET_CHECK_DIAL 1
#define ISDN_BUDGET_CHECK_CHARGE 2
#define ISDN_BUDGET_CHECK_ONLINE 3
#define ISDN_BUDGET_START_ONLINE 10
#define ISDN_BUDGET_SET_BUDGET 0
#define ISDN_BUDGET_GET_BUDGET 1
typedef struct {
char name [9]; /* Interface */
int command, /* subcommand */
budget, /* budget-nr. */
amount, /* set/get budget-amount */
used; /* set/get used amount */
time_t period, /* set/get length of period */
period_started; /* set/get startpoint of period */
} isdn_ioctl_budget;
#ifdef __KERNEL__
extern int isdn_net_budget(int, struct device *);
extern int isdn_budget_ioctl(isdn_ioctl_budget *);
#endif /* __KERNEL__ */
#endif /* __isdn_budget_h__ */

119
include/linux/isdn_timru.h Normal file
View File

@ -0,0 +1,119 @@
/* isdn_timru.h
*
* Linux ISDN subsystem, timeout-rules for network interfaces.
*
* Copyright 1997 by Christian Lademann <cal@zls.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
02.06.97:cal:ISDN_TIMRU_PACKET_NONE def., ISDN_TIMRU_PACKET_* inkr.
*/
#ifndef __isdn_timru_h__
#define __isdn_timru_h__
#define ISDN_TIMRU_PACKET_NONE 0
#define ISDN_TIMRU_PACKET_SKB 1
#define ISDN_TIMRU_PACKET_PPP 2
#define ISDN_TIMRU_PACKET_PPP_NO_HEADER 3
#define ISDN_TIMRU_BRINGUP 0
#define ISDN_TIMRU_KEEPUP_IN 1
#define ISDN_TIMRU_KEEPUP_OUT 2
#define ISDN_TIMRU_BRINGDOWN 3
#define ISDN_TIMRU_NUM_CHECK 4
#define ISDN_TIMRU_PROTFAM_WILDCARD 0
#define ISDN_TIMRU_PROTFAM_IP 1
#define ISDN_TIMRU_PROTFAM_PPP 2
#define ISDN_TIMRU_PROTFAM_IPX 3
#define ISDN_TIMRU_NUM_PROTFAM 4
#define ISDN_TIMRU_IP_WILDCARD 0
#define ISDN_TIMRU_IP_ICMP 1
#define ISDN_TIMRU_IP_TCP 2
#define ISDN_TIMRU_IP_UDP 3
#define ISDN_TIMRU_PPP_WILDCARD 0
#define ISDN_TIMRU_PPP_IPCP 1
#define ISDN_TIMRU_PPP_IPXCP 2
#define ISDN_TIMRU_PPP_CCP 3
#define ISDN_TIMRU_PPP_LCP 4
#define ISDN_TIMRU_PPP_PAP 5
#define ISDN_TIMRU_PPP_LQR 6
#define ISDN_TIMRU_PPP_CHAP 7
typedef struct {
struct in_addr saddr, /* Source Address */
smask, /* Source Subnetmask */
daddr, /* Dest. Address */
dmask; /* Dest. Subnetmask */
ushort protocol; /* TCP, UDP, ... */
union {
struct {
__u16 s_from, /* Source Port */
s_to,
d_from,
d_to;
} port;
struct {
__u8 from, /* ICMP-Type */
to;
} type;
} pt;
} isdn_timeout_rule_ip;
typedef struct {
ushort protocol; /* IPCP, LCP, ... */
} isdn_timeout_rule_ppp;
typedef struct isdn_timeout_rule_s {
struct isdn_timeout_rule_s *next, /* Pointer to next rule */
*prev; /* Pointer to previous rule */
ushort type, /* BRINGUP, KEEPUP_*, ... */
neg;
int timeout; /* Timeout value */
ushort protfam; /* IP, IPX, PPP, ... */
union {
isdn_timeout_rule_ip ip; /* IP-Rule */
isdn_timeout_rule_ppp ppp; /* PPP-Rule */
} rule; /* Prot.-specific rule */
} isdn_timeout_rule;
typedef struct {
char name [9]; /* Interface */
int where, /* 0/1: add to start/end of list, -1: handle default */
type,
protfam,
index,
defval;
isdn_timeout_rule rule; /* Rule */
} isdn_ioctl_timeout_rule;
#ifdef __KERNEL__
extern int isdn_net_recalc_timeout(int, int, struct device *, void *, ulong);
extern int isdn_timru_alloc_timeout_rules(struct device *);
extern int isdn_timru_ioctl_add_rule(isdn_ioctl_timeout_rule *);
extern int isdn_timru_ioctl_del_rule(isdn_ioctl_timeout_rule *);
extern int isdn_timru_ioctl_get_rule(isdn_ioctl_timeout_rule *);
#endif /* __KERNEL__ */
#endif /* __isdn_timru_h__ */