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

Next file: linux/drivers/isdn/isdn_ppp.h
Previous file: linux/drivers/isdn/isdn_net.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.91/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.27 1997/03/30 16:51:17 calle Exp $
+/* $Id: isdn_ppp.c,v 1.33 1998/02/20 17:11:54 fritz Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,37 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.33  1998/02/20 17:11:54  fritz
+ * Changes for recent kernels.
+ *
+ * Revision 1.32  1998/01/31 19:29:55  calle
+ * Merged changes from and for 2.1.82, not tested only compiled ...
+ *
+ * Revision 1.31  1997/10/09 21:29:01  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *   New L1 error status (not yet in use).
+ *   Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.30  1997/10/01 09:20:38  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.29  1997/08/21 23:11:44  fritz
+ * Added changes for kernels >= 2.1.45
+ *
+ * Revision 1.28  1997/06/17 13:05:57  hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ * more compression changes (but disabled at the moment)
+ * changed one copy_to_user() to run with enabled IRQs
+ * a few MP changes
+ * changed 'proto' handling in the isdn_ppp receive code
+ *
  * Revision 1.27  1997/03/30 16:51:17  calle
  * changed calls to copy_from_user/copy_to_user and removed verify_area
  * were possible.
@@ -128,9 +159,7 @@
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/isdn.h>
-#if (LINUX_VERSION_CODE >= 0x020117)
 #include <linux/poll.h>
-#endif
 #include "isdn_common.h"
 #include "isdn_ppp.h"
 #include "isdn_net.h"
@@ -148,6 +177,12 @@
 				 struct sk_buff *skb, int proto);
 static int isdn_ppp_if_get_unit(char *namebuf);
 static int isdn_ppp_set_compressor(struct ippp_struct *is,int num);
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
+				struct ippp_struct *,struct ippp_struct *);
+static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
+				struct sk_buff *skb);
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+	struct ippp_struct *is,struct ippp_struct *master,int type);
 
 #ifdef CONFIG_ISDN_MPP
 static int isdn_ppp_bundle(struct ippp_struct *, int unit);
@@ -160,7 +195,7 @@
 static void isdn_ppp_free_mpqueue(isdn_net_dev *);
 #endif
 
-char *isdn_ppp_revision = "$Revision: 1.27 $";
+char *isdn_ppp_revision = "$Revision: 1.33 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 static struct isdn_ppp_compressor *ipc_head = NULL;
@@ -267,7 +302,7 @@
 		char exclusive[ISDN_MAX_CHANNELS];	/* exclusive flags */
 		memset(exclusive, 0, ISDN_MAX_CHANNELS);
 		while (net_dev) {	/* step through net devices to find exclusive minors */
-			isdn_net_local *lp = &net_dev->local;
+			isdn_net_local *lp = net_dev->local;
 			if (lp->pppbind >= 0)
 				exclusive[lp->pppbind] = 1;
 			net_dev = net_dev->next;
@@ -382,7 +417,12 @@
 	if (is->debug & 0x1)
 		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
 
+	/* compression stuff */
 	is->compressor = NULL;
+	is->decomp_stat = is->comp_stat = NULL;
+	is->link_compressor = NULL;
+	is->link_decomp_stat = is->link_comp_stat = NULL;
+
 	is->lp = NULL;
 	is->mp_seqno = 0;       /* MP sequence number */
 	is->pppcfg = 0;         /* ppp configuration */
@@ -644,50 +684,6 @@
 	return 0;
 }
 
-#if (LINUX_VERSION_CODE < 0x020117)
-int
-isdn_ppp_select(int min, struct file *file, int type, select_table * st)
-{
-	struct ippp_buf_queue *bf,
-	*bl;
-	unsigned long flags;
-	struct ippp_struct *is;
-
-	is = file->private_data;
-
-	if (is->debug & 0x2)
-		printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n", min, type);
-
-	if (!(is->state & IPPP_OPEN))
-		return -EINVAL;
-
-	switch (type) {
-		case SEL_IN:
-			save_flags(flags);
-			cli();
-			bl = is->last;
-			bf = is->first;
-			/*
-			 * if IPPP_NOBLOCK is set we return even if we have nothing to read
-			 */
-			if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) {
-				select_wait(&is->wq, st);
-				restore_flags(flags);
-				return 0;
-			}
-			is->state &= ~IPPP_NOBLOCK;
-			restore_flags(flags);
-			return 1;
-		case SEL_OUT:
-			/* we're always ready to send .. */
-			return 1;
-		case SEL_EX:
-			select_wait(&is->wq1, st);
-			return 0;
-	}
-	return 1;
-}
-#else
 unsigned int
 isdn_ppp_poll(struct file *file, poll_table * wait)
 {
@@ -700,7 +696,8 @@
 	is = file->private_data;
 
 	if (is->debug & 0x2)
-		printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_dentry->d_inode->i_rdev));
+		printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
+				MINOR(file->f_dentry->d_inode->i_rdev));
 
 	poll_wait(file, &is->wq, wait);
 
@@ -725,8 +722,6 @@
 	restore_flags(flags);
 	return mask;
 }
-#endif
-
 
 /*
  *  fill up isdn_ppp_read() queue ..
@@ -798,31 +793,35 @@
 	struct ippp_buf_queue *b;
 	int r;
 	unsigned long flags;
+	unsigned char *save_buf;
 
 	is = file->private_data;
 
 	if (!(is->state & IPPP_OPEN))
 		return 0;
 
+	if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
+		return r;
+
 	save_flags(flags);
 	cli();
 
 	b = is->first->next;
-	if (!b->buf) {
+	save_buf = b->buf;
+	if (!save_buf) {
 		restore_flags(flags);
 		return -EAGAIN;
 	}
 	if (b->len < count)
 		count = b->len;
-	if ((r = copy_to_user(buf, b->buf, count))) {
-		restore_flags(flags);
-		return r;
-	}
-	kfree(b->buf);
 	b->buf = NULL;
 	is->first = b;
+
 	restore_flags(flags);
 
+	copy_to_user(buf, save_buf, count);
+	kfree(save_buf);
+
 	return count;
 }
 
@@ -872,14 +871,13 @@
 				printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
 				return count;
 			}
-			SET_SKB_FREE(skb);
 			if (copy_from_user(skb_put(skb, count), buf, count))
 				return -EFAULT;
 			if (is->debug & 0x40) {
 				printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
 				isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
 			}
-			if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb)) != count) {
+			if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) {
 				if (lp->sav_skb) {
 					dev_kfree_skb(lp->sav_skb);
 					printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count);
@@ -935,45 +933,65 @@
 }
 
 /*
+ * get the PPP protocol header and pull skb
+ */
+static int isdn_ppp_strip_proto(struct sk_buff *skb) 
+{
+	int proto;
+	if (skb->data[0] & 0x1) {
+		proto = skb->data[0];
+		skb_pull(skb, 1);   /* protocol ID is only 8 bit */
+	} else {
+		proto = ((int) skb->data[0] << 8) + skb->data[1];
+		skb_pull(skb, 2);
+	}
+	return proto;
+}
+
+
+/*
  * handler for incoming packets on a syncPPP interface
  */
-void
-isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
+void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
 {
 	struct ippp_struct *is;
+	int proto;
+
 	is = ippp_table[lp->ppp_slot];
 
 	if (is->debug & 0x4) {
 		printk(KERN_DEBUG "ippp_receive: len: %d\n", (int) skb->len);
 		isdn_ppp_frame_log("receive", skb->data, skb->len, 32);
 	}
-	if (net_dev->local.master) {
+	if (net_dev->local->master) {
 		printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n");
-		net_dev = ((isdn_net_local *) net_dev->local.master->priv)->netdev;
+		net_dev = ((isdn_net_local *) net_dev->local->master->priv)->netdev;
 	}
 	if (skb->data[0] == 0xff && skb->data[1] == 0x03)
 		skb_pull(skb, 2);
 	else if (is->pppcfg & SC_REJ_COMP_AC) {
-		SET_SKB_FREE(skb);
 		dev_kfree_skb(skb);
 		return;         /* discard it silently */
 	}
+
+	proto = isdn_ppp_strip_proto(skb);
+
 #ifdef CONFIG_ISDN_MPP
 	if (!(is->mpppcfg & SC_REJ_MP_PROT)) {
-		int proto;
 		int sqno_end;
-		if (skb->data[0] & 0x1) {
-			proto = skb->data[0];
-			skb_pull(skb, 1);	/* protocol ID is only 8 bit */
-		} else {
-			proto = ((int) skb->data[0] << 8) + skb->data[1];
-			skb_pull(skb, 2);
+		
+		if(proto == PPP_LINK_COMP) {
+			printk(KERN_DEBUG "received single link compressed frame\n");
+			skb = isdn_ppp_decompress(skb,is,NULL);
+			if(!skb)
+				return;
+			proto = isdn_ppp_strip_proto(skb);
 		}
+
 		if (proto == PPP_MP) {
 			isdn_net_local *lpq;
-			long sqno,
-			 min_sqno,
-			 tseq;
+			long sqno, min_sqno, tseq;
+
 			u_char BEbyte = skb->data[0];
 			if (is->debug & 0x8)
 				printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto,
@@ -987,6 +1005,10 @@
 				skb_pull(skb, 2);
 			}
 
+			/*
+			 * new sequence number lower than last number? (this is only allowed
+			 * for overflow case)
+			 */
 			if ((tseq = is->last_link_seqno) >= sqno) {
 				int range = is->range;
 				if (tseq + 1024 < range + sqno)	/* redundancy check .. not MP conform */
@@ -995,9 +1017,14 @@
 					sqno += range;
 					is->last_link_seqno = sqno;
 				}
-			} else
+			} else {
+				/* here, we should also add an redundancy check */
 				is->last_link_seqno = sqno;
+			}
 
+			/* 
+			 * step over all links to find lowest link number
+			 */
 			for (min_sqno = LONG_MAX, lpq = net_dev->queue;;) {
 				long lls = ippp_table[lpq->ppp_slot]->last_link_seqno;
 				if (lls >= 0 && lls < min_sqno)
@@ -1006,11 +1033,14 @@
 				if (lpq == net_dev->queue)
 					break;
 			}
-			if (min_sqno >= ippp_table[lpq->ppp_slot]->range) {	/* OK, every link overflowed */
-				int mask = ippp_table[lpq->ppp_slot]->range - 1;	/* range is a power of 2 */
-#if 0
-				isdn_ppp_cleanup_queue(net_dev, min_sqno);
-#endif
+
+			/*
+			 * for the case, that the last frame numbers of all 
+			 * links are overflowed: mask/reduce the sequenece number to
+			 * 'normal' numbering.
+			 */
+			if (min_sqno >= ippp_table[lpq->ppp_slot]->range) {
+				int mask = ippp_table[lpq->ppp_slot]->range-1;	/* range is power of two, so a mask will do the job */
 				isdn_ppp_mask_queue(net_dev, mask);
 				net_dev->ib.next_num &= mask;
 				{
@@ -1064,7 +1094,6 @@
 				if (!q) {
 					net_dev->ib.modify = 0;
 					printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n");
-					SET_SKB_FREE(skb);
 					dev_kfree_skb(skb);
 					return;	/* discard */
 				}
@@ -1093,7 +1122,8 @@
 				 * packet was 'in order' .. push it higher
 				 */
 				net_dev->ib.next_num = sqno_end + 1;
-				isdn_ppp_push_higher(net_dev, lp, skb, -1);
+				proto = isdn_ppp_strip_proto(skb);
+				isdn_ppp_push_higher(net_dev, lp, skb, proto);
 			}
 			isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno);
 			net_dev->ib.modify = 0;
@@ -1102,7 +1132,7 @@
 			isdn_ppp_push_higher(net_dev, lp, skb, proto);
 	} else
 #endif
-		isdn_ppp_push_higher(net_dev, lp, skb, -1);
+		isdn_ppp_push_higher(net_dev, lp, skb, proto);
 }
 
 /*
@@ -1115,19 +1145,21 @@
 	struct device *dev = &net_dev->dev;
 	struct ippp_struct *is = ippp_table[lp->ppp_slot];
 
-	if (proto < 0) {        /* MP, oder normales Paket bei REJ_MP, MP Pakete gehen bei REJ zum pppd */
-		if (skb->data[0] & 0x01) {	/* is it odd? */
-			proto = (unsigned char) skb->data[0];
-			skb_pull(skb, 1);	/* protocol ID is only 8 bit */
-		} else {
-			proto = ((int) (unsigned char) skb->data[0] << 8) + (unsigned char) skb->data[1];
-			skb_pull(skb, 2);
-		}
-	}
 	if (is->debug & 0x10) {
 		printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
 		isdn_ppp_frame_log("rpush", skb->data, skb->len, 32);
 	}
+
+	if(proto == PPP_COMP) {
+		if(!lp->master)
+			skb = isdn_ppp_decompress(skb,is,is);
+		else
+			skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]);
+		if(!skb)
+			return;
+		proto = isdn_ppp_strip_proto(skb);
+	}
+
 	switch (proto) {
 		case PPP_IPX:  /* untested */
 			if (is->debug & 0x20)
@@ -1140,10 +1172,9 @@
 		case PPP_VJC_UNCOMP:
 			if (is->debug & 0x20)
 				printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
-			if (slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
+			if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
 				printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
-				net_dev->local.stats.rx_dropped++;
-				SET_SKB_FREE(skb);
+				net_dev->local->stats.rx_dropped++;
 				dev_kfree_skb(skb);
 				return;
 			}
@@ -1164,11 +1195,9 @@
 				int pkt_len;
 				skb = dev_alloc_skb(skb_old->len + 40);
 
-				SET_SKB_FREE(skb_old);
-
 				if (!skb) {
 					printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
-					net_dev->local.stats.rx_dropped++;
+					net_dev->local->stats.rx_dropped++;
 					dev_kfree_skb(skb_old);
 					return;
 				}
@@ -1176,11 +1205,10 @@
 				skb_put(skb, skb_old->len + 40);
 				memcpy(skb->data, skb_old->data, skb_old->len);
 				skb->mac.raw = skb->data;
-				pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
+				pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
 						skb->data, skb_old->len);
 				dev_kfree_skb(skb_old);
 				if (pkt_len < 0) {
-					SET_SKB_FREE(skb);
 					dev_kfree_skb(skb);
 					lp->stats.rx_dropped++;
 					return;
@@ -1191,20 +1219,21 @@
 #else
 			printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
 			lp->stats.rx_dropped++;
-			SET_SKB_FREE(skb);
 			dev_kfree_skb(skb);
 			return;
 #endif
 			break;
+		case PPP_CCP:
+			isdn_ppp_receive_ccp(net_dev,lp,skb);
+			/* fall through */
 		default:
 			isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot);	/* push data to pppd device */
-			SET_SKB_FREE(skb);
 			dev_kfree_skb(skb);
 			return;
 	}
 
 	netif_rx(skb);
-	/* net_dev->local.stats.rx_packets++; *//* done in isdn_net.c */
+	/* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */
 	/* Reset hangup-timer */
 	lp->huptimer = 0;
 
@@ -1212,6 +1241,24 @@
 }
 
 /*
+ * isdn_ppp_skb_push ..
+ * checks whether we have enough space at the beginning of the SKB
+ * and allocs a new SKB if necessary
+ */
+static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
+{
+	struct sk_buff *skb = *skb_p;
+
+	if(skb_headroom(skb) < len) {
+		printk(KERN_ERR "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len);
+		dev_kfree_skb(skb);
+		return NULL;
+	}
+	return skb_push(skb,len);
+}
+
+
+/*
  * send ppp frame .. we expect a PIDCOMPressable proto --
  *  (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
  *
@@ -1223,12 +1270,10 @@
 isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct device *mdev = ((isdn_net_local *) (dev->priv))->master;	/* get master (for redundancy) */
-	isdn_net_local *lp,
-	*mlp;
+	isdn_net_local *lp,*mlp;
 	isdn_net_dev *nd;
 	unsigned int proto = PPP_IP;     /* 0x21 */
-	struct ippp_struct *ipt,
-	*ipts;
+	struct ippp_struct *ipt,*ipts;
 
 	if (mdev)
 		mlp = (isdn_net_local *) (mdev->priv);
@@ -1250,6 +1295,7 @@
 			printk(KERN_INFO "%s: IP frame delayed.\n", dev->name);
 		return 1;
 	}
+
 	switch (ntohs(skb->protocol)) {
 		case ETH_P_IP:
 			proto = PPP_IP;
@@ -1297,11 +1343,18 @@
 	 * after this line .. requeueing in the device queue is no longer allowed!!!
 	 */
 
+	/* Pull off the fake header we stuck on earlier to keep
+     * the fragemntation code happy.
+     * this will break the ISDN_SYNCPPP_READDRESS hack a few lines
+     * above. So, enabling this is no longer allowed
+     */
+	skb_pull(skb,IPPP_MAX_HEADER);
+
 	if (ipt->debug & 0x4)
 		printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
 
 #ifdef CONFIG_ISDN_PPP_VJ
-	if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes .. but this check again */
+	if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes, but check this again */
 		struct sk_buff *new_skb;
 
 		new_skb = dev_alloc_skb(skb->len);
@@ -1310,14 +1363,13 @@
 			int pktlen;
 
 			new_skb->dev = skb->dev;
-			SET_SKB_FREE(new_skb);
 			skb_put(new_skb, skb->len);
 			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 (buf != skb->data) {	
 				if (new_skb->data != buf)
 					printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
 				dev_kfree_skb(skb);
@@ -1339,6 +1391,11 @@
 	}
 #endif
 
+    /*
+     * normal or bundle compression
+     */
+	skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0);
+
 	if (ipt->debug & 0x24)
 		printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
 
@@ -1349,13 +1406,17 @@
 		ipts->mp_seqno++;
 		nd->queue = nd->queue->next;
 		if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
-			unsigned char *data = skb_push(skb, 3);
+			unsigned char *data = isdn_ppp_skb_push(&skb, 3);
+			if(!data)
+				return 0;
 			mp_seqno &= 0xfff;
-			data[0] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8);	/* (B)egin & (E)ndbit .. */
+			data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf);	/* (B)egin & (E)ndbit .. */
 			data[1] = mp_seqno & 0xff;
 			data[2] = proto;	/* PID compression */
 		} else {
-			unsigned char *data = skb_push(skb, 5);
+			unsigned char *data = isdn_ppp_skb_push(&skb, 5);
+			if(!data)
+				return 0;
 			data[0] = MP_BEGIN_FRAG | MP_END_FRAG;	/* (B)egin & (E)ndbit .. */
 			data[1] = (mp_seqno >> 16) & 0xff;	/* sequence number: 24bit */
 			data[2] = (mp_seqno >> 8) & 0xff;
@@ -1365,17 +1426,29 @@
 		proto = PPP_MP; /* MP Protocol, 0x003d */
 	}
 #endif
+
+	/*
+	 * 'link' compression 
+	 */
+	skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
+
 	if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
-		unsigned char *data = skb_push(skb,1);
+		unsigned char *data = isdn_ppp_skb_push(&skb,1);
+		if(!data)
+			return 0;
 		data[0] = proto & 0xff;
 	}
 	else {
-		unsigned char *data = skb_push(skb,2);
+		unsigned char *data = isdn_ppp_skb_push(&skb,2);
+		if(!data)
+			return 0;
 		data[0] = (proto >> 8) & 0xff;
 		data[1] = proto & 0xff;
 	}
 	if(!(ipt->pppcfg & SC_COMP_AC)) {
-		unsigned char *data = skb_push(skb,2);
+		unsigned char *data = isdn_ppp_skb_push(&skb,2);
+		if(!data)
+			return 0;
 		data[0] = 0xff;    /* All Stations */
 		data[1] = 0x03;    /* Unnumbered information */
 	}
@@ -1406,10 +1479,8 @@
 	p->ib.sq = NULL;
 	while (q) {
 		struct sqqueue *qn = q->next;
-		if (q->skb) {
-			SET_SKB_FREE(q->skb);
+		if (q->skb)
 			dev_kfree_skb(q->skb);
-		}
 		kfree(q);
 		q = qn;
 	}
@@ -1424,7 +1495,6 @@
 
 	while (q) {
 		struct mpqueue *ql = q->next;
-		SET_SKB_FREE(q->skb);
 		dev_kfree_skb(q->skb);
 		kfree(q);
 		q = ql;
@@ -1599,7 +1669,6 @@
 	if (!(*skb)) {
 		while (q) {
 			struct mpqueue *ql = q->next;
-			SET_SKB_FREE(q->skb);
 			dev_kfree_skb(q->skb);
 			kfree(q);
 			q = ql;
@@ -1612,7 +1681,6 @@
 		struct mpqueue *ql = q->next;
 		memcpy((*skb)->data + cnt, q->skb->data, q->skb->len);
 		cnt += q->skb->len;
-		SET_SKB_FREE(q->skb);
 		dev_kfree_skb(q->skb);
 		kfree(q);
 		q = ql;
@@ -1632,13 +1700,15 @@
 	struct sqqueue *q;
 
 	while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno)) {
+		int proto;
 		if (q->sqno_start != net_dev->ib.next_num) {
 			printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n", net_dev->ib.next_num);
 #ifdef CONFIG_ISDN_PPP_VJ
-			slhc_toss(ippp_table[net_dev->local.ppp_slot]->slcomp);
+			slhc_toss(ippp_table[net_dev->local->ppp_slot]->slcomp);
 #endif
 		}
-		isdn_ppp_push_higher(net_dev, lp, q->skb, -1);
+		proto = isdn_ppp_strip_proto(q->skb);
+		isdn_ppp_push_higher(net_dev, lp, q->skb, proto);
 		net_dev->ib.sq = q->next;
 		net_dev->ib.next_num = q->sqno_end + 1;
 		kfree(q);
@@ -1663,32 +1733,30 @@
 
 	struct mpqueue *ql,
 	*q = dev->mp_last;
-	while (q) {
-		if (q->sqno < min_sqno) {
-			if (q->BEbyte & MP_END_FRAG) {
-				printk(KERN_DEBUG "ippp: freeing stale packet!\n");
-				if ((dev->mp_last = q->next))
-					q->next->last = NULL;
-				while (q) {
-					ql = q->last;
-					SET_SKB_FREE(q->skb);
-					dev_kfree_skb(q->skb);
-					kfree(q);
+	while(q && (q->sqno < min_sqno) ) {
+		if ( (q->BEbyte & MP_END_FRAG) || 
+			 (q->next && (q->next->sqno <= min_sqno) && (q->next->BEbyte & MP_BEGIN_FRAG)) ) {
+			printk(KERN_DEBUG "ippp: freeing stale packet(s), min_sq: %ld!\n",min_sqno);
+			if ((dev->mp_last = q->next))
+				q->next->last = NULL;
+			while (q) {
+				ql = q->last;
+				printk(KERN_DEBUG "ippp, freeing packet with sqno: %ld\n",q->sqno);
+				dev_kfree_skb(q->skb);
+				kfree(q);
 #ifdef CONFIG_ISDN_PPP_VJ
-					toss = 1;
+				toss = 1;
 #endif
-					q = ql;
-				}
-				q = dev->mp_last;
-			} else
-				q = q->next;
+				q = ql;
+			}
+			q = dev->mp_last;
 		} else
-			break;
+			q = q->next;
 	}
 #ifdef CONFIG_ISDN_PPP_VJ
 	/* did we free a stale frame ? */
 	if (toss)
-		slhc_toss(ippp_table[dev->local.ppp_slot]->slcomp);
+		slhc_toss(ippp_table[dev->local->ppp_slot]->slcomp);
 #endif
 }
 
@@ -1708,7 +1776,7 @@
 	*qn;
 
 	while (net_dev) {
-		isdn_net_local *lp = &net_dev->local;
+		isdn_net_local *lp = net_dev->local;
 		if (net_dev->ib.modify || lp->master) {	/* interface locked or slave? */
 			net_dev = net_dev->next;
 			continue;
@@ -1728,7 +1796,8 @@
 				net_dev->ib.next_num = q->sqno_end + 1;
 				q->next = NULL;
 				for (; ql;) {
-					isdn_ppp_push_higher(net_dev, lp, ql->skb, -1);
+					int proto = isdn_ppp_strip_proto(ql->skb);
+					isdn_ppp_push_higher(net_dev, lp, ql->skb, proto);
 					qn = ql->next;
 					kfree(ql);
 					ql = qn;
@@ -1804,7 +1873,7 @@
 		case SIOCGPPPVER:
 			r = (char *) ifr->ifr_ifru.ifru_data;
 			len = strlen(PPP_VERSION) + 1;
-		        error = copy_to_user(r, PPP_VERSION, len);
+			error = copy_to_user(r, PPP_VERSION, len);
 			break;
 		case SIOCGPPPSTATS:
 			error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
@@ -1853,7 +1922,7 @@
 
 	if (!(ndev = isdn_net_findif(name)))
 		return 1;
-	lp = &ndev->local;
+	lp = ndev->local;
 	if (!(lp->flags & ISDN_NET_CONNECTED))
 		return 5;
 
@@ -1884,7 +1953,7 @@
 
 	if (!(ndev = isdn_net_findif(name)))
 		return 1;
-	lp = &ndev->local;
+	lp = ndev->local;
 	if (!(lp->flags & ISDN_NET_CONNECTED))
 		return 5;
 
@@ -1905,6 +1974,128 @@
 #endif
 }
 
+/*
+ * PPP compression stuff
+ */
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master)
+{
+#if 1
+	printk(KERN_ERR "compression not included!\n");
+	dev_kfree_skb(skb);
+	return NULL;
+#else
+	if(!master) {
+		/* 
+		 * single link compression 
+		 */
+		if(!is->link_compressor) {
+			printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+			dev_kfree_skb(skb);
+			return NULL;
+		}
+		if(!is->link_decomp_stat) {
+			printk(KERN_DEBUG "ippp: initialize link compressor\n");
+		}
+/*
+		-> decompress link
+*/
+    }
+	else {
+		/*
+		 * 'normal' or bundle-compression 
+		 */
+		if(!master->compressor) {
+			printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+			dev_kfree_skb(skb);
+			return NULL;
+		}
+		if(!master->decomp_stat) {
+#if 0
+			master->decomp_stat = (master->compressor->decomp_alloc)( .. );
+#endif
+			printk(KERN_DEBUG "ippp: initialize compressor\n");
+		}
+	}
+	
+	return skb;
+#endif
+}
+
+/*
+ * compress a frame 
+ *   type=0: normal/bundle compression
+ *       =1: link compression
+ * returns original skb if we haven't compressed the frame
+ * and a new skb pointer if we've done it
+ */
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+	struct ippp_struct *is,struct ippp_struct *master,int type)
+{
+#if 1	
+	return skb_in;
+#else
+    int ret;
+    int new_proto;
+    struct isdn_ppp_compressor *compressor;
+    void *stat;
+    struct sk_buff *skb_out;
+
+	if(type) { /* type=1 => Link compression */
+		compressor = is->link_compressor;
+		stat = is->link_comp_stat;
+		new_proto = PPP_LINK_COMP;
+	}
+	else {
+		if(!master) {
+			compressor = is->compressor;
+			stat = is->comp_stat;
+		}
+		else {
+			compressor = master->compressor;
+			stat = master->comp_stat;
+		}
+		new_proto = PPP_COMP;
+	}
+
+	if(!compressor) {
+		printk(KERN_ERR "No compressor set!\n");
+		return skb_in;
+	}
+	if(!stat) {
+		/* init here ? */
+		return skb_in;
+	}
+
+	skb_out = dev_alloc_skb(skb_in->len);
+	if(!skb_out)
+		return skb_in;
+
+	ret = (compressor->compress)(stat,skb_in,skb_out,*proto);
+	if(!ret) {
+		dev_kfree_skb(skb_out);
+		return skb_in;
+	}
+	
+	dev_kfree_skb(skb_in);
+	*proto = new_proto;
+	return skb_out;
+#endif
+
+}
+
+/*
+ * we received a CCP frame .. 
+ * not a clean solution, but we SHOULD handle a few cased in the kernel
+ */
+static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+	 struct sk_buff *skb)
+{
+#if 0
+	printk(KERN_DEBUG "isdn_ppp_receive_cpp: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		skb->data[0],skb->data[1],skb->data[2],skb->data[3],
+		skb->data[4],skb->data[5],skb->data[6],skb->data[7] );
+#endif
+}
 
 int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
 {
@@ -1937,6 +2128,7 @@
 		if(ipc->num == num) {
 			return 0;	
 			is->compressor = ipc;
+			is->link_compressor = ipc;
 		}
 		ipc = ipc->next;
 	}

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