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

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)