From 0c64f33f52bf2114b73a9336c934995d70779b1e Mon Sep 17 00:00:00 2001 From: "Christian A. Lademann" Date: Sat, 7 Mar 1998 18:21:34 +0000 Subject: [PATCH] Dynamic Timeout-Rule-Handling vs. 971110 included --- drivers/isdn/Config.in | 5 + drivers/isdn/Makefile | 12 + drivers/isdn/isdn_budget.c | 197 ++++++++ drivers/isdn/isdn_common.c | 69 ++- drivers/isdn/isdn_common.h | 5 +- drivers/isdn/isdn_net.c | 187 +++++++- drivers/isdn/isdn_ppp.c | 28 +- drivers/isdn/isdn_timru.c | 905 ++++++++++++++++++++++++++++++++++++ include/linux/isdn.h | 47 ++ include/linux/isdn_budget.h | 62 +++ include/linux/isdn_timru.h | 119 +++++ 11 files changed, 1623 insertions(+), 13 deletions(-) create mode 100644 drivers/isdn/isdn_budget.c create mode 100644 drivers/isdn/isdn_timru.c create mode 100644 include/linux/isdn_budget.h create mode 100644 include/linux/isdn_timru.h diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index 3787c735..d8cdf62f 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -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 diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 35d56d14..25468e91 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -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 diff --git a/drivers/isdn/isdn_budget.c b/drivers/isdn/isdn_budget.c new file mode 100644 index 00000000..d86238c3 --- /dev/null +++ b/drivers/isdn/isdn_budget.c @@ -0,0 +1,197 @@ +/* isdn_budget.c + * + * Linux ISDN subsystem, budget-accounting for network interfaces. + * + * Copyright 1997 by Christian Lademann + * + * 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 +#define __NO_VERSION__ +#include +#include +#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 diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 508281ea..729e10d3 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -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; diff --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h index 8a8cfa3b..1600c96f 100644 --- a/drivers/isdn/isdn_common.h +++ b/drivers/isdn/isdn_common.h @@ -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 diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 2aef6f1c..8845a366 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -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 diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index 74953611..bf2189e0 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -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!!! diff --git a/drivers/isdn/isdn_timru.c b/drivers/isdn/isdn_timru.c new file mode 100644 index 00000000..ecd314eb --- /dev/null +++ b/drivers/isdn/isdn_timru.c @@ -0,0 +1,905 @@ +/* isdn_timru.c + * + * Linux ISDN subsystem, timeout-rules for network interfaces. + * + * Copyright 1997 by Christian Lademann + * + * 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 +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_ISDN_TIMRU_USE_MASQ +#ifdef CONFIG_IP_MASQUERADE +#include +#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 diff --git a/include/linux/isdn.h b/include/linux/isdn.h index fb3a402e..58a9db46 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -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 + +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 + +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 diff --git a/include/linux/isdn_budget.h b/include/linux/isdn_budget.h new file mode 100644 index 00000000..2eacceac --- /dev/null +++ b/include/linux/isdn_budget.h @@ -0,0 +1,62 @@ +/* isdn_budget.h + * + * Linux ISDN subsystem, budget-accounting for network interfaces. + * + * Copyright 1997 by Christian Lademann + * + * 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 + +#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__ */ diff --git a/include/linux/isdn_timru.h b/include/linux/isdn_timru.h new file mode 100644 index 00000000..361dbbea --- /dev/null +++ b/include/linux/isdn_timru.h @@ -0,0 +1,119 @@ +/* isdn_timru.h + * + * Linux ISDN subsystem, timeout-rules for network interfaces. + * + * Copyright 1997 by Christian Lademann + * + * 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__ */