cregit-Linux how code gets into the kernel

Release 4.14 drivers/isdn/i4l/isdn_net.c

Directory: drivers/isdn/i4l
/* $Id: isdn_net.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
 *
 * Linux ISDN subsystem, network interfaces and related functions (linklevel).
 *
 * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
 * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
 * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
 *
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02
 *                                       guy@traverse.com.au
 * Outgoing calls - looks for a 'V' in first char of dialed number
 * Incoming calls - checks first character of eaz as follows:
 *   Numeric - accept DATA only - original functionality
 *   'V'     - accept VOICE (DOV) only
 *   'B'     - accept BOTH DATA and DOV types
 *
 * Jan 2001: fix CISCO HDLC      Bjoern A. Zeeb <i4l@zabbadoz.net>
 *           for info on the protocol, see
 *           http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
 */

#include <linux/isdn.h>
#include <linux/slab.h>
#include <net/arp.h>
#include <net/dst.h>
#include <net/pkt_sched.h>
#include <linux/inetdevice.h>
#include "isdn_common.h"
#include "isdn_net.h"
#ifdef CONFIG_ISDN_PPP
#include "isdn_ppp.h"
#endif
#ifdef CONFIG_ISDN_X25
#include <linux/concap.h>
#include "isdn_concap.h"
#endif


/*
 * Outline of new tbusy handling:
 *
 * Old method, roughly spoken, consisted of setting tbusy when entering
 * isdn_net_start_xmit() and at several other locations and clearing
 * it from isdn_net_start_xmit() thread when sending was successful.
 *
 * With 2.3.x multithreaded network core, to prevent problems, tbusy should
 * only be set by the isdn_net_start_xmit() thread and only when a tx-busy
 * condition is detected. Other threads (in particular isdn_net_stat_callb())
 * are only allowed to clear tbusy.
 *
 * -HE
 */

/*
 * About SOFTNET:
 * Most of the changes were pretty obvious and basically done by HE already.
 *
 * One problem of the isdn net device code is that it uses struct net_device
 * for masters and slaves. However, only master interface are registered to
 * the network layer, and therefore, it only makes sense to call netif_*
 * functions on them.
 *
 * --KG
 */

/*
 * Find out if the netdevice has been ifup-ed yet.
 * For slaves, look at the corresponding master.
 */

static __inline__ int isdn_net_device_started(isdn_net_dev *n) { isdn_net_local *lp = n->local; struct net_device *dev; if (lp->master) dev = lp->master; else dev = n->dev; return netif_running(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton3775.51%150.00%
Kai Germaschewski1224.49%150.00%
Total49100.00%2100.00%

/* * wake up the network -> net_device queue. * For slaves, wake the corresponding master interface. */
static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp) { if (lp->master) netif_wake_queue(lp->master); else netif_wake_queue(lp->netdev->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton1852.94%133.33%
Kai Germaschewski1647.06%266.67%
Total34100.00%3100.00%

/* * stop the network -> net_device queue. * For slaves, stop the corresponding master interface. */
static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp) { if (lp->master) netif_stop_queue(lp->master); else netif_stop_queue(lp->netdev->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton2470.59%133.33%
Kai Germaschewski1029.41%266.67%
Total34100.00%3100.00%

/* * find out if the net_device which this lp belongs to (lp can be * master or slave) is busy. It's busy iff all (master and slave) * queues are busy */
static __inline__ int isdn_net_device_busy(isdn_net_local *lp) { isdn_net_local *nlp; isdn_net_dev *nd; unsigned long flags; if (!isdn_net_lp_busy(lp)) return 0; if (lp->master) nd = ISDN_MASTER_PRIV(lp)->netdev; else nd = lp->netdev; spin_lock_irqsave(&nd->queue_lock, flags); nlp = lp->next; while (nlp != lp) { if (!isdn_net_lp_busy(nlp)) { spin_unlock_irqrestore(&nd->queue_lock, flags); return 0; } nlp = nlp->next; } spin_unlock_irqrestore(&nd->queue_lock, flags); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton10182.79%114.29%
Kai Germaschewski1814.75%571.43%
Wang Chen32.46%114.29%
Total122100.00%7100.00%


static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp) { atomic_inc(&lp->frame_cnt); if (isdn_net_device_busy(lp)) isdn_net_device_stop_queue(lp); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton2580.65%125.00%
Kai Germaschewski619.35%375.00%
Total31100.00%4100.00%


static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp) { atomic_dec(&lp->frame_cnt); if (!(isdn_net_device_busy(lp))) { if (!skb_queue_empty(&lp->super_tx_queue)) { schedule_work(&lp->tqueue); } else { isdn_net_device_wake_queue(lp); } } }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton4778.33%133.33%
Kai Germaschewski1321.67%266.67%
Total60100.00%3100.00%


static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) { atomic_set(&lp->frame_cnt, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton2095.24%150.00%
Kai Germaschewski14.76%150.00%
Total21100.00%2100.00%

/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just * to be safe. * For 2.3.x we push it up to 20 secs, because call establishment * (in particular callback) may take such a long time, and we * don't want confusing messages in the log. However, there is a slight * possibility that this large timeout will break other things like MPPP, * which might rely on the tx timeout. If so, we'll find out this way... */ #define ISDN_NET_TX_TIMEOUT (20 * HZ) /* Prototypes */ static int isdn_net_force_dial_lp(isdn_net_local *); static netdev_tx_t isdn_net_start_xmit(struct sk_buff *, struct net_device *); static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); char *isdn_net_revision = "$Revision: 1.1.2.2 $"; /* * Code for raw-networking over ISDN */
static void isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason) { if (skb) { u_short proto = ntohs(skb->protocol); printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n", dev->name, (reason != NULL) ? reason : "unknown", (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : ""); dst_link_failure(skb); } else { /* dial not triggered by rawIP packet */ printk(KERN_DEBUG "isdn_net: %s: %s\n", dev->name, (reason != NULL) ? reason : "reason unknown"); } }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton95100.00%1100.00%
Total95100.00%1100.00%


static void isdn_net_reset(struct net_device *dev) { #ifdef CONFIG_ISDN_X25 struct concap_device_ops *dops = ((isdn_net_local *)netdev_priv(dev))->dops; struct concap_proto *cprot = ((isdn_net_local *)netdev_priv(dev))->netdev->cprot; #endif #ifdef CONFIG_ISDN_X25 if (cprot && cprot->pops && dops) cprot->pops->restart(cprot, dev, dops); #endif }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton7692.68%150.00%
Wang Chen67.32%150.00%
Total82100.00%2100.00%

/* Open/initialize the board. */
static int isdn_net_open(struct net_device *dev) { int i; struct net_device *p; struct in_device *in_dev; /* moved here from isdn_net_reset, because only the master has an interface associated which is supposed to be started. BTW: we need to call netif_start_queue, not netif_wake_queue here */ netif_start_queue(dev); isdn_net_reset(dev); /* Fill in the MAC-level header (not needed, but for compatibility... */ for (i = 0; i < ETH_ALEN - sizeof(u32); i++) dev->dev_addr[i] = 0xfc; if ((in_dev = dev->ip_ptr) != NULL) { /* * Any address will do - we take the first */ struct in_ifaddr *ifa = in_dev->ifa_list; if (ifa != NULL) memcpy(dev->dev_addr + 2, &ifa->ifa_local, 4); } /* If this interface has slaves, start them also */ p = MASTER_TO_SLAVE(dev); if (p) { while (p) { isdn_net_reset(p); p = MASTER_TO_SLAVE(p); } } isdn_lock_drivers(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton13793.20%150.00%
Wang Chen106.80%150.00%
Total147100.00%2100.00%

/* * Assign an ISDN-channel to a net-interface */
static void isdn_net_bind_channel(isdn_net_local *lp, int idx) { lp->flags |= ISDN_NET_CONNECTED; lp->isdn_device = dev->drvmap[idx]; lp->isdn_channel = dev->chanmap[idx]; dev->rx_netdev[idx] = lp->netdev; dev->st_netdev[idx] = lp->netdev; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton63100.00%1100.00%
Total63100.00%1100.00%

/* * unbind a net-interface (resets interface after an error) */
static void isdn_net_unbind_channel(isdn_net_local *lp) { skb_queue_purge(&lp->super_tx_queue); if (!lp->master) { /* reset only master device */ /* Moral equivalent of dev_purge_queues(): BEWARE! This chunk of code cannot be called from hardware interrupt handler. I hope it is true. --ANK */ qdisc_reset_all_tx(lp->netdev->dev); } lp->dialstate = 0; dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; if (lp->isdn_device != -1 && lp->isdn_channel != -1) isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); lp->flags &= ~ISDN_NET_CONNECTED; lp->isdn_device = -1; lp->isdn_channel = -1; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton11286.15%125.00%
Paul Bolle1612.31%125.00%
David S. Miller10.77%125.00%
Joe Perches10.77%125.00%
Total130100.00%4100.00%

/* * Perform auto-hangup and cps-calculation for net-interfaces. * * auto-hangup: * Increment idle-counter (this counter is reset on any incoming or * outgoing packet), if counter exceeds configured limit either do a * hangup immediately or - if configured - wait until just before the next * charge-info. * * cps-calculation (needed for dynamic channel-bundling): * Since this function is called every second, simply reset the * byte-counter of the interface after copying it to the cps-variable. */ static unsigned long last_jiffies = -HZ;
void isdn_net_autohup(void) { isdn_net_dev *p = dev->netdev; int anymore; anymore = 0; while (p) { isdn_net_local *l = p->local; if (jiffies == last_jiffies) l->cps = l->transcount; else l->cps = (l->transcount * HZ) / (jiffies - last_jiffies); l->transcount = 0; if (dev->net_verbose > 3) printk(KERN_DEBUG "%s: %d bogocps\n", p->dev->name, l->cps); if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) { anymore = 1; l->huptimer++; /* * if there is some dialmode where timeout-hangup * should _not_ be done, check for that here */ if ((l->onhtime) && (l->huptimer > l->onhtime)) { if (l->hupflags & ISDN_MANCHARGE && l->hupflags & ISDN_CHARGEHUP) { while (time_after(jiffies, l->chargetime + l->chargeint)) l->chargetime += l->chargeint; if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ)) if (l->outgoing || l->hupflags & ISDN_INHUP) isdn_net_hangup(p->dev); } else if (l->outgoing) { if (l->hupflags & ISDN_CHARGEHUP) { if (l->hupflags & ISDN_WAITCHARGE) { printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n", p->dev->name, l->hupflags); isdn_net_hangup(p->dev); } else if (time_after(jiffies, l->chargetime + l->chargeint)) { printk(KERN_DEBUG "isdn_net: %s: chtime = %lu, chint = %d\n", p->dev->name, l->chargetime, l->chargeint); isdn_net_hangup(p->dev); } } else isdn_net_hangup(p->dev); } else if (l->hupflags & ISDN_INHUP) isdn_net_hangup(p->dev); } if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) { isdn_net_hangup(p->dev); break; } } p = (isdn_net_dev *) p->next; } last_jiffies = jiffies; isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton38396.96%133.33%
Karsten Keil92.28%133.33%
Al Viro30.76%133.33%
Total395100.00%3100.00%


static void isdn_net_lp_disconnected(isdn_net_local *lp) { isdn_net_rm_from_bundle(lp); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton15100.00%1100.00%
Total15100.00%1100.00%

/* * Handle status-messages from ISDN-interfacecard. * This function is called from within the main-status-dispatcher * isdn_status_callback, which itself is called from the low-level driver. * Return: 1 = Event handled, 0 = not for us or unknown Event. */
int isdn_net_stat_callback(int idx, isdn_ctrl *c) { isdn_net_dev *p = dev->st_netdev[idx]; int cmd = c->command; if (p) { isdn_net_local *lp = p->local; #ifdef CONFIG_ISDN_X25 struct concap_proto *cprot = lp->netdev->cprot; struct concap_proto_ops *pops = cprot ? cprot->pops : NULL; #endif switch (cmd) { case ISDN_STAT_BSENT: /* A packet has successfully been sent out */ if ((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate)) { isdn_net_dec_frame_cnt(lp); lp->stats.tx_packets++; lp->stats.tx_bytes += c->parm.length; } return 1; case ISDN_STAT_DCONN: /* D-Channel is up */ switch (lp->dialstate) { case 4: case 7: case 8: lp->dialstate++; return 1; case 12: lp->dialstate = 5; return 1; } break; case ISDN_STAT_DHUP: /* Either D-Channel-hangup or error during dialout */ #ifdef CONFIG_ISDN_X25 /* If we are not connencted then dialing had failed. If there are generic encap protocol receiver routines signal the closure of the link*/ if (!(lp->flags & ISDN_NET_CONNECTED) && pops && pops->disconn_ind) pops->disconn_ind(cprot); #endif /* CONFIG_ISDN_X25 */ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) isdn_net_ciscohdlck_disconnected(lp); #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) isdn_ppp_free(lp); #endif isdn_net_lp_disconnected(lp); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); printk(KERN_INFO "%s: remote hangup\n", p->dev->name); printk(KERN_INFO "%s: Chargesum is %d\n", p->dev->name, lp->charge); isdn_net_unbind_channel(lp); return 1; } break; #ifdef CONFIG_ISDN_X25 case ISDN_STAT_BHUP: /* B-Channel-hangup */ /* try if there are generic encap protocol receiver routines and signal the closure of the link */ if (pops && pops->disconn_ind) { pops->disconn_ind(cprot); return 1; } break; #endif /* CONFIG_ISDN_X25 */ case ISDN_STAT_BCONN: /* B-Channel is up */ isdn_net_zero_frame_cnt(lp); switch (lp->dialstate) { case 5: case 6: case 7: case 8: case 9: case 10: case 12: if (lp->dialstate <= 6) { dev->usage[idx] |= ISDN_USAGE_OUTGOING; isdn_info_update(); } else dev->rx_netdev[idx] = p; lp->dialstate = 0; isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1); if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) isdn_net_ciscohdlck_connected(lp); if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { if (lp->master) { /* is lp a slave? */ isdn_net_dev *nd = ISDN_MASTER_PRIV(lp)->netdev; isdn_net_add_to_bundle(nd, lp); } } printk(KERN_INFO "isdn_net: %s connected\n", p->dev->name); /* If first Chargeinfo comes before B-Channel connect, * we correct the timestamp here. */ lp->chargetime = jiffies; /* reset dial-timeout */ lp->dialstarted = 0; lp->dialwait_timer = 0; #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) isdn_ppp_wakeup_daemon(lp); #endif #ifdef CONFIG_ISDN_X25 /* try if there are generic concap receiver routines */ if (pops) if (pops->connect_ind) pops->connect_ind(cprot); #endif /* CONFIG_ISDN_X25 */ /* ppp needs to do negotiations first */ if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) isdn_net_device_wake_queue(lp); return 1; } break; case ISDN_STAT_NODCH: /* No D-Channel avail. */ if (lp->dialstate == 4) { lp->dialstate--; return 1; } break; case ISDN_STAT_CINF: /* Charge-info from TelCo. Calculate interval between * charge-infos and set timestamp for last info for * usage by isdn_net_autohup() */ lp->charge++; if (lp->hupflags & ISDN_HAVECHARGE) { lp->hupflags &= ~ISDN_WAITCHARGE; lp->chargeint = jiffies - lp->chargetime - (2 * HZ); } if (lp->hupflags & ISDN_WAITCHARGE) lp->hupflags |= ISDN_HAVECHARGE; lp->chargetime = jiffies; printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n", p->dev->name, lp->chargetime); return 1; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton65397.03%120.00%
Karsten Keil121.78%120.00%
Joe Perches40.59%120.00%
Wang Chen30.45%120.00%
Al Viro10.15%120.00%
Total673100.00%5100.00%

/* * Perform dialout for net-interfaces and timeout-handling for * D-Channel-up and B-Channel-up Messages. * This function is initially called from within isdn_net_start_xmit() or * or isdn_net_find_icall() after initializing the dialstate for an * interface. If further calls are needed, the function schedules itself * for a timer-callback via isdn_timer_function(). * The dialstate is also affected by incoming status-messages from * the ISDN-Channel which are handled in isdn_net_stat_callback() above. */
void isdn_net_dial(void) { isdn_net_dev *p = dev->netdev; int anymore = 0; int i; isdn_ctrl cmd; u_char *phone_number; while (p) { isdn_net_local *lp = p->local; #ifdef ISDN_DEBUG_NET_DIAL if (lp->dialstate) printk(KERN_DEBUG "%s: dialstate=%d\n", p->dev->name, lp->dialstate); #endif switch (lp->dialstate) { case 0: /* Nothing to do for this interface */ break; case 1: /* Initiate dialout. Set phone-number-pointer to first number * of interface. */ lp->dial = lp->phone[1]; if (!lp->dial) { printk(KERN_WARNING "%s: phone number deleted?\n", p->dev->name); isdn_net_hangup(p->dev); break; } anymore = 1; if (lp->dialtimeout > 0) if (lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) { lp->dialstarted = jiffies; lp->dialwait_timer = 0; } lp->dialstate++; /* Fall through */ case 2: /* Prepare dialing. Clear EAZ, then set EAZ. */ cmd.driver = lp->isdn_device; cmd.arg = lp->isdn_channel; cmd.command = ISDN_CMD_CLREAZ; isdn_command(&cmd); sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver)); cmd.command = ISDN_CMD_SETEAZ; isdn_command(&cmd); lp->dialretry = 0; anymore = 1; lp->dialstate++; /* Fall through */ case 3: /* Setup interface, dial current phone-number, switch to next number. * If list of phone-numbers is exhausted, increment * retry-counter. */ if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) { char *s; if (dev->global_flags & ISDN_GLOBAL_STOPPED) s = "dial suppressed: isdn system stopped"; else s = "dial suppressed: dialmode `off'"; isdn_net_unreachable(p->dev, NULL, s); 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); isdn_command(&cmd); cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_SETL3; cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); isdn_command(&cmd); cmd.driver = lp->isdn_device; cmd.arg = lp->isdn_channel; if (!lp->dial) { printk(KERN_WARNING "%s: phone number deleted?\n", p->dev->name); isdn_net_hangup(p->dev); break; } if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) { lp->dialstate = 4; printk(KERN_INFO "%s: Open leased line ...\n", p->dev->name); } else { if (lp->dialtimeout > 0) if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; isdn_net_unreachable(p->dev, NULL, "dial: timed out"); isdn_net_hangup(p->dev); break; } cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_DIAL; cmd.parm.setup.si2 = 0; /* check for DOV */ phone_number = lp->dial->num; if ((*phone_number == 'v') || (*phone_number == 'V')) { /* DOV call */ cmd.parm.setup.si1 = 1; } else { /* DATA call */ cmd.parm.setup.si1 = 7; } strcpy(cmd.parm.setup.phone, phone_number); /* * Switch to next number or back to start if at end of list. */ if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) { lp->dial = lp->phone[1]; lp->dialretry++; if (lp->dialretry > lp->dialmax) { if (lp->dialtimeout == 0) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times"); } isdn_net_hangup(p->dev); break; } } sprintf(cmd.parm.setup.eazmsn, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver)); i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel); if (i >= 0) { strcpy(dev->num[i], cmd.parm.setup.phone); dev->usage[i] |= ISDN_USAGE_OUTGOING; isdn_info_update(); } printk(KERN_INFO "%s: dialing %d %s... %s\n", p->dev->name, lp->dialretry, cmd.parm.setup.phone, (cmd.parm.setup.si1 == 1) ? "DOV" : ""); lp->dtimer = 0; #ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device, lp->isdn_channel); #endif isdn_command(&cmd); } lp->huptimer = 0; lp->outgoing = 1; if (lp->chargeint) { lp->hupflags |= ISDN_HAVECHARGE; lp->hupflags &= ~ISDN_WAITCHARGE; } else { lp->hupflags |= ISDN_WAITCHARGE; lp->hupflags &= ~ISDN_HAVECHARGE; } anymore = 1; lp->dialstate = (lp->cbdelay && (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4; break; case 4: /* Wait for D-Channel-connect. * If timeout, switch back to state 3. * Dialmax-handling moved to state 3. */ if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) lp->dialstate = 3; anymore = 1; break; case 5: /* Got D-Channel-Connect, send B-Channel-request */ cmd.driver = lp->isdn_device; cmd.arg = lp->isdn_channel; cmd.command = ISDN_CMD_ACCEPTB; anymore = 1; lp->dtimer = 0; lp->dialstate++; isdn_command(&cmd); break; case 6: /* Wait for B- or D-Channel-connect. If timeout, * switch back to state 3. */ #ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer); #endif if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) lp->dialstate = 3; anymore = 1; break; case 7: /* Got incoming Call, setup L2 and L3 protocols, * then wait for D-Channel-connect */ #ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer); #endif cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_SETL2; cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); isdn_command(&cmd); cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_SETL3; cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); isdn_command(&cmd); if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)