patch-2.0.8 linux/drivers/isdn/isdn_ppp.c

Next file: linux/drivers/net/3c59x.c
Previous file: linux/drivers/isdn/isdn_net.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.7/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.12 1996/06/24 17:42:03 fritz Exp $
+/* $Id: isdn_ppp.c,v 1.13 1996/07/01 19:47:24 hipp Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.13  1996/07/01 19:47:24  hipp
+ * Fixed memory leak in VJ handling and more VJ changes
+ *
  * Revision 1.12  1996/06/24 17:42:03  fritz
  * Minor bugfixes.
  *
@@ -93,7 +96,7 @@
 		int BEbyte, int *sqno, int min_sqno);
 #endif
 
-char *isdn_ppp_revision              = "$Revision: 1.12 $";
+char *isdn_ppp_revision              = "$Revision: 1.13 $";
 struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
 extern int isdn_net_force_dial_lp(isdn_net_local *);
@@ -137,6 +140,7 @@
 	ippp_table[lp->ppp_minor]->lp = NULL;	/* link is down .. set lp to NULL */
 	lp->ppp_minor = -1;			/* is this OK ?? */
 	restore_flags(flags);
+
 	return 0;
 }
 
@@ -254,12 +258,6 @@
         /*
          * VJ header compression init
          */
-	ippp_table[minor]->cbuf = kmalloc(ippp_table[minor]->mru + PPP_HARD_HDR_LEN + 2, GFP_KERNEL);
-
-	if (ippp_table[minor]->cbuf == NULL) {
-		printk(KERN_DEBUG "ippp: Can't allocate memory buffer for VJ compression.\n");
-		return -ENOMEM;
-	}
 	ippp_table[minor]->slcomp = slhc_init(16, 16);	/* not necessary for 2. link in bundle */
 #endif
 
@@ -300,7 +298,6 @@
 #ifdef CONFIG_ISDN_PPP_VJ
 	slhc_free(ippp_table[minor]->slcomp);
 	ippp_table[minor]->slcomp = NULL;
-	kfree(ippp_table[minor]->cbuf);
 #endif
 
 	ippp_table[minor]->state = 0;
@@ -673,7 +670,8 @@
 	if(skb->data[0] == 0xff && skb->data[1] == 0x03)
 		skb_pull(skb,2);
 	else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC) {
-		dev_kfree_skb(skb,FREE_WRITE);
+		skb->free = 1;
+		dev_kfree_skb(skb,0 /* FREE_READ */ );
 		return;		/* discard it silently */
 	}
 
@@ -767,7 +765,8 @@
 				if (!q) {
 					net_dev->ib.modify = 0;
 					printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n");
-					dev_kfree_skb(skb,FREE_WRITE);
+					skb->free = 1;
+					dev_kfree_skb(skb, 0 /* FREE_READ */ );
 					return;		/* discard */
 				}
 				q->skb = skb;
@@ -840,30 +839,46 @@
 
 	switch (proto) {
 	case PPP_IPX: /* untested */
+		if(ippp_table[lp->ppp_minor]->debug & 0x20)
+			printk(KERN_DEBUG "isdn_ppp: _IPX\n");
 		skb->dev = dev;
 		skb->mac.raw = skb->data;
 		skb->protocol = htons(ETH_P_IPX);
 		break;
 #ifdef CONFIG_ISDN_PPP_VJ
 	case PPP_VJC_UNCOMP:
-		slhc_remember(ippp_table[net_dev->local.ppp_minor]->slcomp, skb->data, skb->len);
+		if(ippp_table[lp->ppp_minor]->debug & 0x20)
+			printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
+		if(slhc_remember(ippp_table[net_dev->local.ppp_minor]->slcomp, skb->data, skb->len) <= 0) {
+			printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
+			net_dev->local.stats.rx_dropped++;
+			skb->free = 1;
+			dev_kfree_skb(skb,0 /* FREE_READ */ );
+			return;
+		}
 #endif
 	case PPP_IP:
+		if(ippp_table[lp->ppp_minor]->debug & 0x20)
+			printk(KERN_DEBUG "isdn_ppp: IP\n");
 		skb->dev = dev;
 		skb->mac.raw = skb->data;
 		skb->protocol = htons(ETH_P_IP);
 		break;
 	case PPP_VJC_COMP:
+                if(ippp_table[lp->ppp_minor]->debug & 0x20)
+                        printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
 #ifdef CONFIG_ISDN_PPP_VJ
 		{
 			struct sk_buff *skb_old = skb;
 			int pkt_len;
 			skb = dev_alloc_skb(skb_old->len + 40);
 
+			skb_old->free = 1;
+
 			if (!skb) {
 				printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
 				net_dev->local.stats.rx_dropped++;
-				dev_kfree_skb(skb_old,FREE_WRITE);
+				dev_kfree_skb(skb_old,0 /* FREE_READ */ );
 				return;
 			}
 			skb->dev = dev;
@@ -872,9 +887,10 @@
 			skb->mac.raw = skb->data;
 			pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_minor]->slcomp,
 						  skb->data, skb_old->len);
-			dev_kfree_skb(skb_old,FREE_WRITE);
+			dev_kfree_skb(skb_old,0 /* FREE_READ */ );
 			if(pkt_len < 0) {
-				dev_kfree_skb(skb,FREE_WRITE);
+				skb->free = 1;
+				dev_kfree_skb(skb, 0 /* FREE_READ */ );
 				lp->stats.rx_dropped++;
 				return;
 			}
@@ -884,13 +900,15 @@
 #else
 		printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
 		lp->stats.rx_dropped++;
-		dev_kfree_skb(skb,FREE_WRITE);
+		skb->free = 1;
+		dev_kfree_skb(skb,0 /* FREE_READ */ );
 		return;
 #endif
 		break;
 	default:
 		isdn_ppp_fill_rq(skb->data, skb->len,proto, lp->ppp_minor);	/* push data to pppd device */
-		dev_kfree_skb(skb,FREE_WRITE);
+		skb->free = 1;
+		dev_kfree_skb(skb,0 /* FREE_READ */ );
 		return;
 	}
 
@@ -905,6 +923,9 @@
 /*
  * send ppp frame .. we expect a PIDCOMPressable proto -- 
  *  (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
+ *
+ * VJ compression may change skb pointer!!! .. requeue with old
+ * skb isn't allowed!! 
  */
 
 int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
@@ -957,8 +978,7 @@
 
 #ifdef CONFIG_ISDN_PPP_VJ
 	if (ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes .. but check again */
-		u_char *buf = skb->data;
-		int pktlen;
+		struct sk_buff *new_skb;
 		int len = 4;
 #ifdef CONFIG_ISDN_MPP
 		if (ipt->mpppcfg & SC_MP_PROT) /* sigh */ 	/* ipt or ipts ?? */
@@ -967,20 +987,41 @@
 			else
 				len += 5;
 #endif
-		buf += len;
-		pktlen = slhc_compress(ipts->slcomp, buf, skb->len-len, ipts->cbuf,
-				&buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
-		skb_trim(skb,pktlen+len);
-		if(buf != skb->data+len) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*)  */
-			memcpy(skb->data+len,buf,pktlen);
-		}
-		if (skb->data[len] & SL_TYPE_COMPRESSED_TCP) {	/* cslip? style -> PPP */
-			proto = PPP_VJC_COMP;
-			skb->data[len] ^= SL_TYPE_COMPRESSED_TCP;
-		} else {
-			if (skb->data[len] >= SL_TYPE_UNCOMPRESSED_TCP)
-				proto = PPP_VJC_UNCOMP;
-			skb->data[len] = (skb->data[len] & 0x0f) | 0x40;
+		new_skb = dev_alloc_skb(skb->len);
+		if(new_skb) {
+			u_char *buf;
+			int pktlen;
+
+			new_skb->dev = skb->dev;
+			new_skb->free = 1;
+			skb_put(new_skb,skb->len);
+			skb_pull(skb,len);	/* pull PPP header */
+			skb_pull(new_skb,len);	/* pull PPP header */
+			buf = skb->data;
+
+			pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
+					&buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
+
+			if(buf != skb->data) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*)  */
+				if(new_skb->data != buf)
+					printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
+				dev_kfree_skb(skb,FREE_WRITE);
+				skb = new_skb;
+			}
+			else {
+				dev_kfree_skb(new_skb,0 /* FREE_WRITE */ );
+			}
+
+			skb_trim(skb,pktlen);
+			if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) {	/* cslip? style -> PPP */
+				proto = PPP_VJC_COMP;
+				skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
+			} else {
+				if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
+					proto = PPP_VJC_UNCOMP;
+				skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
+			}
+			skb_push(skb,len);
 		}
 	}
 #endif
@@ -1019,7 +1060,7 @@
         /* tx-stats are now updated via BSENT-callback */
 	if(isdn_net_send_skb(dev , lp , skb)) {	
 		if(lp->sav_skb) {	/* whole sav_skb processing with disabled IRQs ?? */
-			printk(KERN_ERR "%s: whoops .. there is another stored skb!\n!",dev->name);
+			printk(KERN_ERR "%s: whoops .. there is another stored skb!\n",dev->name);
 			dev_kfree_skb(skb,FREE_WRITE);
 		}
 		else
@@ -1035,8 +1076,10 @@
 	p->ib.sq = NULL;
 	while(q) {
 		struct sqqueue *qn = q->next;
-		if(q->skb)
-			dev_kfree_skb(q->skb,FREE_WRITE);
+		if(q->skb) {
+			q->skb->free = 1;
+			dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+		}
 		kfree(q);
 		q = qn;
 	}
@@ -1048,7 +1091,8 @@
 	struct mpqueue *ql, *q = p->mp_last;
 	while (q) {
 		ql = q->next;
- 		dev_kfree_skb(q->skb,FREE_WRITE);
+		q->skb->free = 1;
+ 		dev_kfree_skb(q->skb,0 /* FREE_READ */ );
 		kfree(q);
 		q = ql;
 	}
@@ -1217,7 +1261,8 @@
 	if (!(*skb)) {
 		while (q) {
 			struct mpqueue *ql = q->next;
-			dev_kfree_skb(q->skb,FREE_WRITE);
+			q->skb->free = 1;
+			dev_kfree_skb(q->skb,0 /* FREE_READ */ );
 			kfree(q);
 			q = ql;
 		}
@@ -1229,7 +1274,8 @@
 		struct mpqueue *ql = q->next;
 		memcpy((*skb)->data + cnt, q->skb->data, q->skb->len);
 		cnt += q->skb->len;
-		dev_kfree_skb(q->skb,FREE_WRITE);
+		q->skb->free = 1;
+		dev_kfree_skb(q->skb,0 /* FREE_READ */ );
 		kfree(q);
 		q = ql;
 	}
@@ -1262,7 +1308,8 @@
 					q->next->last = NULL;
 				while (q) {
 					ql = q->last;
-					dev_kfree_skb(q->skb,FREE_WRITE);
+					q->skb->free = 1;
+					dev_kfree_skb(q->skb,0 /* FREE_READ */ );
 					kfree(q);
 #ifdef CONFIG_ISDN_PPP_VJ
 					toss = 1;
@@ -1380,7 +1427,7 @@
 	int len;
 	isdn_net_local *lp = (isdn_net_local *) dev->priv;
 
-#if 1
+#if 0
 	printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n",cmd,lp->ppp_minor);
 #endif
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov