patch-1.3.93 linux/drivers/isdn/isdn_net.c
Next file: linux/drivers/isdn/isdn_net.h
Previous file: linux/drivers/isdn/isdn_common.h
Back to the patch index
Back to the overall index
- Lines: 567
- Date:
Sun Apr 21 11:56:14 1996
- Orig file:
v1.3.92/linux/drivers/isdn/isdn_net.c
- Orig date:
Fri Apr 12 15:51:53 1996
diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.4 1996/02/19 15:23:38 fritz Exp fritz $
+/* $Id: isdn_net.c,v 1.5 1996/04/20 16:28:38 fritz Exp $
*
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -21,6 +21,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.5 1996/04/20 16:28:38 fritz
+ * Made more parameters of the dial statemachine user-configurable and
+ * added hangup after dial for more reliability using callback.
+ * Changed all io going through generic routines in isdn_common.c
+ * Added missing call to dev_free_skb on failed dialing.
+ * Added uihdlc encapsulation.
+ * Fixed isdn_net_setcfg not to destroy interface-flags anymore.
+ * Misc. typos.
+ *
* Revision 1.4 1996/02/19 15:23:38 fritz
* Bugfix: Sync-PPP packets got compressed twice, when resent due to
* send-queue-full reject.
@@ -70,7 +79,7 @@
static int isdn_net_start_xmit(struct sk_buff *, struct device *);
static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
-char *isdn_net_revision = "$Revision: 1.4 $";
+char *isdn_net_revision = "$Revision: 1.5 $";
/*
* Code for raw-networking over ISDN
@@ -208,10 +217,15 @@
return 1;
case ISDN_STAT_DCONN:
/* D-Channel is up */
- if (lp->dialstate == 4 || lp->dialstate == 7
- || lp->dialstate == 8) {
- lp->dialstate++;
- return 1;
+ 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:
@@ -236,25 +250,32 @@
break;
case ISDN_STAT_BCONN:
/* B-Channel is up */
- if (lp->dialstate >= 5 && lp->dialstate <= 10) {
- 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);
- printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
- /* If first Chargeinfo comes before B-Channel connect,
- * we correct the timestamp here.
- */
- lp->chargetime = jiffies;
- /* Immediately send first skb to speed up arp */
- if (lp->first_skb) {
- if (!(isdn_net_xmit(&p->dev,lp,lp->first_skb)))
- lp->first_skb = NULL;
- }
- return 1;
+ 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);
+ printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
+ /* If first Chargeinfo comes before B-Channel connect,
+ * we correct the timestamp here.
+ */
+ lp->chargetime = jiffies;
+ /* Immediately send first skb to speed up arp */
+ if (lp->first_skb) {
+ if (!(isdn_net_xmit(&p->dev,lp,lp->first_skb)))
+ lp->first_skb = NULL;
+ }
+ return 1;
}
break;
case ISDN_STAT_NODCH:
@@ -316,6 +337,10 @@
isdn_ctrl cmd;
while (p) {
+#ifdef ISDN_DEBUG_NET_DIAL
+ if (p->local.dialstate)
+ printk(KERN_DEBUG "%s: dialstate=%d\n", p->local.name,p->local.dialstate);
+#endif
switch (p->local.dialstate) {
case 0:
/* Nothing to do for this interface */
@@ -359,6 +384,7 @@
p->local.huptimer = 0;
p->local.outgoing = 1;
p->local.hupflags |= 1;
+ p->local.hupflags &= ~2;
if (!strcmp(p->local.dial->num, "LEASED")) {
p->local.dialstate = 4;
printk(KERN_INFO "%s: Open leased line ...\n", p->local.name);
@@ -388,18 +414,20 @@
dev->drv[p->local.isdn_device]->interface->command(&cmd);
}
anymore = 1;
- p->local.dialstate++;
+ p->local.dialstate =
+ (p->local.cbdelay &&
+ (p->local.flags & ISDN_NET_CBOUT))?12:4;
break;
case 4:
- /* Wait for D-Channel-connect or incoming call, if passive
- * callback configured. If timeout and max retries not
+ /* Wait for D-Channel-connect.
+ * If timeout and max retries not
* reached, switch back to state 3.
*/
if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
if (p->local.dialretry < p->local.dialmax) {
p->local.dialstate = 3;
} else
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(&p->dev);
anymore = 1;
break;
case 5:
@@ -456,7 +484,7 @@
p->local.dialstate++;
break;
case 8:
- case 10:
+ case 10:
/* Wait for B- or D-channel-connect */
#ifdef ISDN_DEBUG_NET_DIAL
printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
@@ -466,6 +494,28 @@
else
anymore = 1;
break;
+ case 11:
+ /* Callback Delay */
+ if (p->local.dtimer++ > p->local.cbdelay)
+ p->local.dialstate = 1;
+ anymore = 1;
+ break;
+ case 12:
+ /* Remote does callback. Hangup after cbdelay, then wait for incoming
+ * call (in state 4).
+ */
+ if (p->local.dtimer++ > p->local.cbdelay) {
+ printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->local.name);
+ p->local.dtimer = 0;
+ p->local.dialstate = 4;
+ cmd.driver = p->local.isdn_device;
+ cmd.command = ISDN_CMD_HANGUP;
+ cmd.arg = p->local.isdn_channel;
+ (void) dev->drv[cmd.driver]->interface->command(&cmd);
+ isdn_all_eaz(p->local.isdn_device, p->local.isdn_channel);
+ }
+ anymore = 1;
+ break;
default:
printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
p->local.dialstate, p->local.name);
@@ -476,24 +526,6 @@
}
/*
- * Send-data-helpfunction for net-interfaces
- */
-int
-isdn_net_send(u_char * buf, int di, int ch, int len)
-{
- int l;
-
- if ((l = dev->drv[di]->interface->writebuf(di, ch, buf, len, 0)) == len)
- return 1;
- /* Device driver queue full (or packet > 4000 bytes, should never
- * happen)
- */
- if (l == -EINVAL)
- printk(KERN_ERR "isdn_net: Huh, sending pkt too big!\n");
- return 0;
-}
-
-/*
* Perform hangup for a net-interface.
*/
void
@@ -505,6 +537,10 @@
save_flags(flags);
cli();
+ if (lp->first_skb) {
+ dev_kfree_skb(lp->first_skb,FREE_WRITE);
+ lp->first_skb = NULL;
+ }
if (lp->flags & ISDN_NET_CONNECTED) {
printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
lp->dialstate = 0;
@@ -560,9 +596,9 @@
len = 4;
#ifdef CONFIG_ISDN_MPP
if (lp->ppp_minor!=-1) {
- if (ippp_table[lp->ppp_minor].mpppcfg &
+ if (ippp_table[lp->ppp_minor]->mpppcfg &
SC_MP_PROT) {
- if (ippp_table[lp->ppp_minor].mpppcfg &
+ if (ippp_table[lp->ppp_minor]->mpppcfg &
SC_OUT_SHORT_SEQ)
len = 7;
else
@@ -634,16 +670,8 @@
int ret;
lp->transcount += skb->len;
- if (dev->drv[lp->isdn_device]->interface->writebuf_skb)
- ret = dev->drv[lp->isdn_device]->interface->
- writebuf_skb(lp->isdn_device, lp->isdn_channel, skb);
- else {
- if ((ret = isdn_net_send(skb->data, lp->isdn_device,
- lp->isdn_channel, skb->len)))
- dev_kfree_skb(skb, FREE_WRITE);
- }
-
- if (ret)
+ ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb);
+ if (ret == skb->len)
clear_bit(0, (void *)&(ndev->tbusy));
return (!ret);
}
@@ -790,6 +818,11 @@
/* remember first skb to speed up arp
* when using encap ETHER
*/
+ if (lp->first_skb) {
+ printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n");
+ dev_kfree_skb(lp->first_skb,FREE_WRITE);
+ lp->first_skb = NULL;
+ }
lp->first_skb = skb;
/* Initiate dialing */
isdn_net_dial();
@@ -951,35 +984,39 @@
isdn_dumppkt("R:", skb->data, skb->len, 40);
#endif
switch (lp->p_encap) {
- case ISDN_NET_ENCAP_ETHER:
- /* Ethernet over ISDN */
- skb->protocol = isdn_net_type_trans(skb,ndev);
- break;
- case ISDN_NET_ENCAP_RAWIP:
- /* RAW-IP without MAC-Header */
- skb->protocol = htons(ETH_P_IP);
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- /* CISCO-HDLC IP with type field and fake I-frame-header */
- skb_pull(skb, 2);
- /* Fall through */
- case ISDN_NET_ENCAP_IPTYP:
- /* IP with type field */
- skb->protocol = *(unsigned short *)&(skb->data[0]);
- skb_pull(skb, 2);
- if (*(unsigned short *)skb->data == 0xFFFF)
- skb->protocol = htons(ETH_P_802_3);
- break;
+ case ISDN_NET_ENCAP_ETHER:
+ /* Ethernet over ISDN */
+ skb->protocol = isdn_net_type_trans(skb,ndev);
+ break;
+ case ISDN_NET_ENCAP_UIHDLC:
+ /* HDLC with UI-frame (for ispa with -h1 option) */
+ skb_pull(skb,2);
+ /* Fall through */
+ case ISDN_NET_ENCAP_RAWIP:
+ /* RAW-IP without MAC-Header */
+ skb->protocol = htons(ETH_P_IP);
+ break;
+ case ISDN_NET_ENCAP_CISCOHDLC:
+ /* CISCO-HDLC IP with type field and fake I-frame-header */
+ skb_pull(skb, 2);
+ /* Fall through */
+ case ISDN_NET_ENCAP_IPTYP:
+ /* IP with type field */
+ skb->protocol = *(unsigned short *)&(skb->data[0]);
+ skb_pull(skb, 2);
+ if (*(unsigned short *)skb->data == 0xFFFF)
+ skb->protocol = htons(ETH_P_802_3);
+ break;
#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- isdn_ppp_receive(lp->netdev, olp, skb);
- return;
-#endif
- default:
- printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
- lp->name);
- kfree_skb(skb,FREE_READ);
- return;
+ case ISDN_NET_ENCAP_SYNCPPP:
+ isdn_ppp_receive(lp->netdev, olp, skb);
+ return;
+#endif
+ default:
+ printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
+ lp->name);
+ kfree_skb(skb,FREE_READ);
+ return;
}
netif_rx(skb);
return;
@@ -1100,6 +1137,11 @@
*((ushort*) skb_push(skb, 2)) = htons(type);
len = 2;
break;
+ case ISDN_NET_ENCAP_UIHDLC:
+ /* HDLC with UI-Frames (for ispa with -h1 option) */
+ *((ushort*) skb_push(skb, 2)) = htons(0x0103);
+ len = 2;
+ break;
case ISDN_NET_ENCAP_CISCOHDLC:
skb_push(skb, 4);
skb->data[0] = 0x0f;
@@ -1113,9 +1155,9 @@
len = 4;
#ifdef CONFIG_ISDN_MPP
if (lp->ppp_minor!=-1) {
- if (ippp_table[lp->ppp_minor].mpppcfg &
+ if (ippp_table[lp->ppp_minor]->mpppcfg &
SC_MP_PROT) {
- if (ippp_table[lp->ppp_minor].mpppcfg &
+ if (ippp_table[lp->ppp_minor]->mpppcfg &
SC_OUT_SHORT_SEQ)
len = 7;
else
@@ -1355,7 +1397,9 @@
*
* Return-Value: 0 = No appropriate interface for this call.
* 1 = Call accepted
- * 2 = Do callback
+ * 2 = Reject call, wait cbdelay, then call back
+ * 3 = Reject call
+ * 4 = Wait cbdelay, then call back
*/
int
isdn_net_find_icall(int di, int ch, int idx, char *num)
@@ -1436,11 +1480,11 @@
printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
p->local.name, p->local.msn, p->local.flags, p->local.dialstate);
#endif
- if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) && /* EAZ is matching */
- (((!(p->local.flags & ISDN_NET_CONNECTED)) && /* but not connected */
- (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
- (((p->local.dialstate == 4) && /* if dialing */
- (!(p->local.flags & ISDN_NET_CALLBACK))) /* but no callback */
+ if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) && /* EAZ is matching */
+ (((!(p->local.flags & ISDN_NET_CONNECTED)) && /* but not connected */
+ (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
+ ((((p->local.dialstate == 4) || (p->local.dialstate == 12)) && /* if dialing */
+ (!(p->local.flags & ISDN_NET_CALLBACK))) /* but no callback */
))) {
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
@@ -1513,7 +1557,7 @@
continue;
}
}
- }
+ } /* if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) */
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: match2\n");
#endif
@@ -1578,7 +1622,8 @@
return 0;
}
/* Setup dialstate. */
- lp->dialstate = 1;
+ lp->dtimer = 0;
+ lp->dialstate = 11;
lp->flags |= ISDN_NET_CONNECTED;
/* Connect interface with channel */
isdn_net_bind_channel(lp, chi);
@@ -1592,9 +1637,9 @@
return 0;
}
#endif
- /* Initiate dialing by returning 2 */
+ /* Initiate dialing by returning 2 or 4 */
restore_flags(flags);
- return 2;
+ return (lp->flags & ISDN_NET_CBHUP)?2:4;
} else
printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name);
restore_flags(flags);
@@ -1613,7 +1658,7 @@
#endif
/* if this interface is dialing, it does it probably on a different
device, so free this device */
- if (p->local.dialstate == 4)
+ if ((p->local.dialstate == 4) || (p->local.dialstate == 12))
isdn_free_channel(p->local.isdn_device, p->local.isdn_channel,
ISDN_USAGE_NET);
dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
@@ -1630,6 +1675,7 @@
p->local.outgoing = 0;
p->local.huptimer = 0;
p->local.hupflags |= 1;
+ p->local.hupflags &= ~2;
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
if (isdn_ppp_bind(lp) < 0) {
@@ -1732,7 +1778,7 @@
* Allocate a new network-interface and initialize it's data structures.
*/
char *
- isdn_net_new(char *name, struct device *master)
+isdn_net_new(char *name, struct device *master)
{
isdn_net_dev *netdev;
@@ -1802,8 +1848,9 @@
netdev->local.hupflags = 8; /* Do hangup even on incoming calls */
netdev->local.onhtime = 10; /* Default hangup-time for saving costs
of those who forget configuring this */
- /* The following should be configurable via ioctl */
netdev->local.dialmax = 1;
+ netdev->local.flags = ISDN_NET_CBHUP; /* Hangup before Callback */
+ netdev->local.cbdelay = 25; /* Wait 5 secs before Callback */
/* Put into to netdev-chain */
netdev->next = (void *) dev->netdev;
dev->netdev = netdev;
@@ -1811,7 +1858,7 @@
}
char *
- isdn_net_newslave(char *parm)
+isdn_net_newslave(char *parm)
{
char *p = strchr(parm, ',');
isdn_net_dev *n;
@@ -1860,9 +1907,7 @@
printk(KERN_WARNING "isdn_net: No driver with selected features\n");
return -ENODEV;
}
- if ((p->local.p_encap != cfg->p_encap) &&
- ((p->local.p_encap == ISDN_NET_ENCAP_RAWIP) ||
- (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) ))
+ if (p->local.p_encap != cfg->p_encap)
if (p->dev.start) {
printk(KERN_WARNING
"%s: cannot change encap when if is up\n",
@@ -1939,16 +1984,30 @@
p->local.charge = cfg->charge;
p->local.l2_proto = cfg->l2_proto;
p->local.l3_proto = cfg->l3_proto;
+ p->local.cbdelay = cfg->cbdelay;
+ p->local.dialmax = cfg->dialmax;
p->local.slavedelay = cfg->slavedelay * HZ;
- p->local.p_encap = cfg->p_encap;
if (cfg->secure)
p->local.flags |= ISDN_NET_SECURE;
else
p->local.flags &= ~ISDN_NET_SECURE;
- if (cfg->callback)
- p->local.flags |= ISDN_NET_CALLBACK;
+ if (cfg->cbhup)
+ p->local.flags |= ISDN_NET_CBHUP;
else
- p->local.flags &= ~ISDN_NET_CALLBACK;
+ p->local.flags &= ~ISDN_NET_CBHUP;
+ switch (cfg->callback) {
+ case 0:
+ p->local.flags &= ~(ISDN_NET_CALLBACK&ISDN_NET_CBOUT);
+ break;
+ case 1:
+ p->local.flags |= ISDN_NET_CALLBACK;
+ p->local.flags &= ~ISDN_NET_CBOUT;
+ break;
+ case 2:
+ p->local.flags |= ISDN_NET_CBOUT;
+ p->local.flags &= ~ISDN_NET_CALLBACK;
+ break;
+ }
if (cfg->chargehup)
p->local.hupflags |= 4;
else
@@ -1957,23 +2016,26 @@
p->local.hupflags |= 8;
else
p->local.hupflags &= ~8;
- if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
- p->dev.hard_header = NULL;
- p->dev.header_cache_bind = NULL;
- p->dev.header_cache_update = NULL;
- p->dev.flags = IFF_NOARP;
- } else {
- p->dev.hard_header = isdn_net_header;
- if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
- p->dev.header_cache_bind = p->local.org_hcb;
- p->dev.header_cache_update = p->local.org_hcu;
- p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
- } else {
+ if (cfg->p_encap != p->local.p_encap) {
+ if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
+ p->dev.hard_header = NULL;
p->dev.header_cache_bind = NULL;
p->dev.header_cache_update = NULL;
p->dev.flags = IFF_NOARP;
+ } else {
+ p->dev.hard_header = isdn_net_header;
+ if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
+ p->dev.header_cache_bind = p->local.org_hcb;
+ p->dev.header_cache_update = p->local.org_hcu;
+ p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
+ } else {
+ p->dev.header_cache_bind = NULL;
+ p->dev.header_cache_update = NULL;
+ p->dev.flags = IFF_NOARP;
+ }
}
}
+ p->local.p_encap = cfg->p_encap;
return 0;
}
return -ENODEV;
@@ -2001,8 +2063,12 @@
cfg->p_encap = p->local.p_encap;
cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
cfg->callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0;
+ cfg->callback = (p->local.flags & ISDN_NET_CBOUT) ? 2 : 0;
+ cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0;
cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0;
cfg->ihup = (p->local.hupflags & 8) ? 1 : 0;
+ cfg->cbdelay = p->local.cbdelay;
+ cfg->dialmax = p->local.dialmax;
cfg->slavedelay = p->local.slavedelay / HZ;
if (p->local.slave)
strcpy(cfg->slave, ((isdn_net_local *) p->local.slave->priv)->name);
@@ -2074,6 +2140,7 @@
n = n->next;
more = 1;
}
+ put_fs_byte(0,phones);
restore_flags(flags);
return count;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this