patch-2.3.46 linux/drivers/isdn/isdn_net.c
Next file: linux/drivers/isdn/isdn_ppp.c
Previous file: linux/drivers/isdn/isdn_common.h
Back to the patch index
Back to the overall index
- Lines: 622
- Date:
Tue Feb 15 11:40:43 2000
- Orig file:
v2.3.45/linux/drivers/isdn/isdn_net.c
- Orig date:
Thu Nov 11 20:11:38 1999
diff -u --recursive --new-file v2.3.45/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.95 1999/10/27 21:21:17 detabc Exp $
+/* $Id: isdn_net.c,v 1.107 2000/02/13 09:52:05 kai Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -21,6 +21,66 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.107 2000/02/13 09:52:05 kai
+ * increased TX_TIMEOUT to 20sec
+ *
+ * Revision 1.106 2000/02/12 19:26:55 kai
+ * adopted to latest 2.3 softnet changes.
+ *
+ * tested with PPP and MPPP, it works here.
+ * can somebody check raw-ip?
+ *
+ * also changed std2kern, stddiff for bash-1 compatibility,
+ * hope this doesn't break anything.
+ *
+ * Revision 1.105 2000/02/12 11:43:26 he
+ * SOFTNET related changes, first try. Compatible with linux 2.2.x, but
+ * not tested for kernels with softnet (>= 2.3.43) yet.
+ *
+ * Revision 1.104 2000/02/06 21:49:59 detabc
+ * add rewriting of socket's and frame's saddr for udp-ipv4 dynip-connections.
+ * Include checksum-recompute of ip- and udp-header's.
+ *
+ * Revision 1.103 2000/01/23 18:45:37 keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
+ * Revision 1.102 2000/01/09 20:43:14 detabc
+ * exand logical bind-group's for both call's (in and out).
+ * add first part of kernel-config-help for abc-extension.
+ *
+ * Revision 1.101 1999/12/05 16:06:08 detabc
+ * add resethandling for rawip-compression.
+ * at now all B2-Protocols are usable with rawip-compression
+ *
+ * Revision 1.100 1999/12/04 15:05:25 detabc
+ * bugfix abc-rawip-bsdcompress with channel-bundeling
+ *
+ * Revision 1.99 1999/11/30 11:29:06 detabc
+ * add a on the fly frame-counter and limit
+ *
+ * Revision 1.98 1999/11/28 14:49:07 detabc
+ * In case of rawip-compress adjust dev[x]->ibytes/obytes to reflect the
+ * uncompressed size.
+ *
+ * Revision 1.97 1999/11/26 15:54:59 detabc
+ * added compression (isdn_bsdcompress) for rawip interfaces with x75i B2-protocol.
+ *
+ * Revision 1.96 1999/11/20 22:14:13 detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * to many connection's in short time.
+ * config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * or remote side.
+ * wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
* Revision 1.95 1999/10/27 21:21:17 detabc
* Added support for building logically-bind-group's per interface.
* usefull for outgoing call's with more then one isdn-card.
@@ -393,10 +453,6 @@
#endif
-#ifndef ISDN_NEW_TBUSY
-#define ISDN_NEW_TBUSY
-#endif
-#ifdef ISDN_NEW_TBUSY
/*
* Outline of new tbusy handling:
*
@@ -413,29 +469,60 @@
*/
/*
- * Tell upper layers that the network device is ready to xmit more frames.
- */
-static void __inline__ isdn_net_dev_xon(struct net_device * dev)
-{
- dev->tbusy = 0;
- mark_bh(NET_BH);
-}
-
-static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
-{
- lp->netdev->dev.tbusy = 0;
- if(lp->master) lp->master->tbusy = 0;
- mark_bh(NET_BH);
+ * 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 is 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.
+ *
+ * The old code abused the slaves dev->start to remember the corresponding
+ * master's interface state (ifup'ed or not). This does not work with SOFTNET
+ * any more, because there's now dev->start anymore.
+ * Instead I chose to add isdn_net_started() which gives the state of the
+ * master in case of slaves.
+ * I'm still not sure if this is how it's supposed to be done this way
+ * because it uses test_bit(LINK_STATE_START, &dev->state) which might be
+ * considered private to the network layer. However, it works for now.
+ * Alternative: set a flag in _open() and clear it in _close()
+ *
+ * I left some dead code around in #if 0 which I'm not absolutely sure about.
+ * If no problems turn up, it should be removed later
+ *
+ * --KG
+ */
+
+/*
+ * Find out if the netdevice has been ifup-ed yet.
+ * For slaves, look at the corresponding master.
+ */
+static int __inline__ isdn_net_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 test_bit(LINK_STATE_START, &dev->state);
}
/*
- * Ask upper layers to temporarily cease passing us more xmit frames.
+ * wake up the network -> net_device queue.
+ * For slaves, wake the corresponding master interface.
*/
-static void __inline__ isdn_net_dev_xoff(struct net_device * dev)
+static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
{
- dev->tbusy = 1;
+ if (lp->master)
+ netif_wake_queue(lp->master);
+ else
+ netif_wake_queue(&lp->netdev->dev);
}
-#endif
+
+
+#define ISDN_NET_TX_TIMEOUT (20*HZ)
/* Prototypes */
@@ -443,7 +530,7 @@
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *);
-char *isdn_net_revision = "$Revision: 1.95 $";
+char *isdn_net_revision = "$Revision: 1.107 $";
/*
* Code for raw-networking over ISDN
@@ -482,14 +569,9 @@
#endif
ulong flags;
+ /* not sure if the cli() is needed at all --KG */
save_flags(flags);
cli(); /* Avoid glitch on writes to CMD regs */
- dev->interrupt = 0;
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xon(dev);
-#else
- dev->tbusy = 0;
-#endif
#ifdef CONFIG_ISDN_X25
if( cprot && cprot -> pops && dops )
cprot -> pops -> restart ( cprot, dev, dops );
@@ -505,8 +587,12 @@
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);
- dev->start = 1;
/* 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;
@@ -524,7 +610,6 @@
if ((p = (((isdn_net_local *) dev->priv)->slave))) {
while (p) {
isdn_net_reset(p);
- p->start = 1;
p = (((isdn_net_local *) p->priv)->slave);
}
}
@@ -703,19 +788,11 @@
mdev = &lp->netdev->dev;
if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
lp->sav_skb = NULL;
-#ifndef ISDN_NEW_TBUSY
- mark_bh(NET_BH);
-#endif
} else {
return 1;
}
}
-#ifdef ISDN_NEW_TBUSY
isdn_net_lp_xon(lp);
-#else
- if (test_and_clear_bit(0, (void *) &(p->dev.tbusy)))
- mark_bh(NET_BH);
-#endif
}
return 1;
case ISDN_STAT_DCONN:
@@ -814,18 +891,7 @@
if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
lp->first_skb = NULL;
}
-#ifdef ISDN_NEW_TBUSY
if(! lp->first_skb) isdn_net_lp_xon(lp);
-#else
- else {
- /*
- * dev.tbusy is usually cleared implicitly by isdn_net_xmit(,,lp->first_skb).
- * With an empty lp->first_skb, we need to do this ourselves
- */
- lp->netdev->dev.tbusy = 0;
- mark_bh(NET_BH);
- }
-#endif /* ISDN_NEW_TBUSY */
return 1;
}
break;
@@ -1259,14 +1325,16 @@
strcpy(addinfo, " IDP");
break;
}
- printk(KERN_INFO "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
+ printk(KERN_INFO
+ "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
p[12], p[13], p[14], p[15],
p[16], p[17], p[18], p[19],
addinfo);
break;
case ETH_P_ARP:
- printk(KERN_INFO "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
+ printk(KERN_INFO
+ "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
p[14], p[15], p[16], p[17],
p[24], p[25], p[26], p[27]);
break;
@@ -1280,14 +1348,8 @@
*
* Return: 0 on success, !0 on failure.
*/
-#ifndef ISDN_NEW_TBUSY
-/*
- * Side-effects: ndev->tbusy is cleared on success.
- */
-#endif
-int
-isdn_net_send_skb(struct net_device *ndev, isdn_net_local * lp,
- struct sk_buff *skb)
+int isdn_net_send_skb
+ (struct net_device *ndev, isdn_net_local * lp,struct sk_buff *skb)
{
int ret;
int len = skb->len; /* save len */
@@ -1295,17 +1357,11 @@
ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
if (ret == len) {
lp->transcount += len;
-#ifndef ISDN_NEW_TBUSY
- clear_bit(0, (void *) &(ndev->tbusy));
-#endif
return 0;
}
if (ret < 0) {
dev_kfree_skb(skb);
lp->stats.tx_errors++;
-#ifndef ISDN_NEW_TBUSY
- clear_bit(0, (void *) &(ndev->tbusy));
-#endif
return 0;
}
return 1;
@@ -1351,11 +1407,7 @@
if (lp->srobin == ndev)
ret = isdn_net_send_skb(ndev, lp, skb);
else
-#ifdef ISDN_NEW_TBUSY
ret = isdn_net_start_xmit(skb, lp->srobin);
-#else
- ret = ndev->tbusy = isdn_net_start_xmit(skb, lp->srobin);
-#endif
lp->srobin = (slp->slave) ? slp->slave : ndev;
slp = (isdn_net_local *) (lp->srobin->priv);
if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0)))
@@ -1397,6 +1449,35 @@
}
}
+
+void isdn_net_tx_timeout(struct net_device * ndev)
+{
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+
+ printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
+ if (!lp->dialstate){
+ lp->stats.tx_errors++;
+ /*
+ * There is a certain probability that this currently
+ * works at all because if we always wake up the interface,
+ * then upper layer will try to send the next packet
+ * immediately. And then, the old clean_up logic in the
+ * driver will hopefully continue to work as it used to do.
+ *
+ * This is rather primitive right know, we better should
+ * clean internal queues here, in particular for multilink and
+ * ppp, and reset HL driver's channel, too. --HE
+ *
+ * actually, this may not matter at all, because ISDN hardware
+ * should not see transmitter hangs at all IMO
+ * changed KERN_DEBUG to KERN_WARNING to find out if this is
+ * ever called
+ */
+ }
+ ndev->trans_start = jiffies;
+ netif_wake_queue(ndev);
+}
+
/*
* Try sending a packet.
* If this interface isn't connected to a ISDN-Channel, find a free channel,
@@ -1409,19 +1490,6 @@
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = lp -> netdev -> cprot;
#endif
- if (ndev->tbusy) {
- if (jiffies - ndev->trans_start < (2 * HZ))
- return 1;
- if (!lp->dialstate)
- lp->stats.tx_errors++;
- ndev->trans_start = jiffies;
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xon(ndev);
-#endif
- }
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */
-#endif
#ifdef CONFIG_ISDN_X25
/* At this point hard_start_xmit() passes control to the encapsulation
protocol (if present).
@@ -1436,9 +1504,7 @@
*/
if( cprot ) {
int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
-#ifdef ISDN_NEW_TBUSY
- if(ret) isdn_net_dev_xoff(ndev);
-#endif
+ if(ret) netif_stop_queue(ndev);
return ret;
} else
#endif
@@ -1458,9 +1524,6 @@
if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
return 0;
}
if (lp->phone[1]) {
@@ -1476,15 +1539,11 @@
if(jiffies < lp->dialwait_timer) {
isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
restore_flags(flags);
return 0;
} else
lp->dialwait_timer = 0;
}
-
/* Grab a free ISDN-Channel */
if (((chi =
isdn_get_free_channel(
@@ -1492,7 +1551,8 @@
lp->l2_proto,
lp->l3_proto,
lp->pre_device,
- lp->pre_channel)
+ lp->pre_channel,
+ lp->msn)
) < 0) &&
((chi =
isdn_get_free_channel(
@@ -1500,15 +1560,13 @@
lp->l2_proto,
lp->l3_proto,
lp->pre_device,
- lp->pre_channel^1)
+ lp->pre_channel^1,
+ lp->msn)
) < 0)) {
restore_flags(flags);
isdn_net_unreachable(ndev, skb,
"No channel");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
return 0;
}
/* Log packet, which triggered dialing */
@@ -1528,9 +1586,7 @@
}
restore_flags(flags);
isdn_net_dial(); /* Initiate dialing */
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xoff(ndev);
-#endif
+ netif_stop_queue(ndev);
return 1; /* let upper layer requeue skb packet */
}
#endif
@@ -1544,9 +1600,6 @@
}
lp->first_skb = skb;
/* Initiate dialing */
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
restore_flags(flags);
isdn_net_dial();
return 0;
@@ -1554,9 +1607,6 @@
isdn_net_unreachable(ndev, skb,
"No phone number");
dev_kfree_skb(skb);
-#ifndef ISDN_NEW_TBUSY
- ndev->tbusy = 0;
-#endif
return 0;
}
} else {
@@ -1567,24 +1617,16 @@
int ret;
if (lp->first_skb) {
if (isdn_net_xmit(ndev, lp, lp->first_skb)){
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xoff(ndev);
-#endif
+ netif_stop_queue(ndev);
return 1;
}
lp->first_skb = NULL;
}
ret = (isdn_net_xmit(ndev, lp, skb));
-#ifdef ISDN_NEW_TBUSY
- if(ret) isdn_net_dev_xoff(ndev);
-#endif
+ if(ret) netif_stop_queue(ndev);
return ret;
} else
-#ifdef ISDN_NEW_TBUSY
- isdn_net_dev_xoff(ndev);
-#else
- ndev->tbusy = 1;
-#endif
+ netif_stop_queue(ndev);
}
}
return 1;
@@ -1606,8 +1648,7 @@
#ifdef CONFIG_ISDN_X25
if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
#endif
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
if ((p = (((isdn_net_local *) dev->priv)->slave))) {
/* If this interface has slaves, stop them also */
while (p) {
@@ -1618,8 +1659,6 @@
cprot -> pops -> close( cprot );
#endif
isdn_net_hangup(p);
- p->tbusy = 1;
- p->start = 0;
p = (((isdn_net_local *) p->priv)->slave);
}
}
@@ -2360,7 +2399,7 @@
* Is the interface up?
* If not, reject the call actively.
*/
- if (!p->dev.start) {
+ if (!isdn_net_started(p)) {
restore_flags(flags);
printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
lp->name);
@@ -2389,7 +2428,7 @@
p = (isdn_net_dev *) p->next;
continue;
}
- }
+ }
if (lp->flags & ISDN_NET_CALLBACK) {
int chi;
/*
@@ -2411,9 +2450,10 @@
isdn_get_free_channel(
ISDN_USAGE_NET,
lp->l2_proto,
- lp->l3_proto,
+ lp->l3_proto,
lp->pre_device,
- lp->pre_channel)
+ lp->pre_channel,
+ lp->msn)
) < 0) {
printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
@@ -2528,7 +2568,8 @@
lp->l2_proto,
lp->l3_proto,
lp->pre_device,
- lp->pre_channel)
+ lp->pre_channel,
+ lp->msn)
) < 0) {
printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
restore_flags(flags);
@@ -2626,11 +2667,13 @@
p = (((isdn_net_local *) p->priv)->slave);
}
((isdn_net_local *) q->priv)->slave = &(netdev->dev);
- q->interrupt = 0;
- q->tbusy = 0;
- q->start = master->start;
} else {
/* Device shall be a master */
+ /*
+ * Watchdog timer (currently) for master only.
+ */
+ netdev->dev.tx_timeout = isdn_net_tx_timeout;
+ netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
if (register_netdev(&netdev->dev) != 0) {
printk(KERN_WARNING "isdn_net: Could not register net-device\n");
kfree(netdev->local);
@@ -2701,7 +2744,7 @@
if (n->local->master)
return NULL;
/* Master must not be started yet */
- if (n->dev.start)
+ if (isdn_net_started(n))
return NULL;
return (isdn_net_new(newname, &(n->dev)));
}
@@ -2744,9 +2787,8 @@
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = p -> cprot;
#endif
- if (p->dev.start) {
- printk(KERN_WARNING
- "%s: cannot change encap when if is up\n",
+ if (isdn_net_started(p)) {
+ printk(KERN_WARNING "%s: cannot change encap when if is up\n",
lp->name);
return -EBUSY;
}
@@ -2837,10 +2879,9 @@
/* If binding is exclusive, try to grab the channel */
save_flags(flags);
- if ((i = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
- lp->l3_proto,
- drvidx,
- chidx)) < 0) {
+ if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
+ lp->l2_proto, lp->l3_proto, drvidx,
+ chidx, lp->msn)) < 0) {
/* Grab failed, because desired channel is in use */
lp->exclusive = -1;
restore_flags(flags);
@@ -3181,14 +3222,7 @@
save_flags(flags);
cli();
- if (p->local->master) {
- /* If it's a slave, it may be removed even if it is busy. However
- * it has to be hung up first.
- */
- isdn_net_hangup(&p->dev);
- p->dev.start = 0;
- }
- if (p->dev.start) {
+ if (isdn_net_started(p)) {
restore_flags(flags);
return -EBUSY;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)