patch-2.2.7 linux/drivers/net/ppp.c

Next file: linux/drivers/net/rrunner.c
Previous file: linux/drivers/net/pcnet32.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.6/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
@@ -4,7 +4,7 @@
  *  Al Longyear <longyear@netcom.com>
  *  Extensively rewritten by Paul Mackerras <paulus@cs.anu.edu.au>
  *
- *  ==FILEVERSION 990114==
+ *  ==FILEVERSION 990331==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
@@ -45,9 +45,8 @@
 
 #define PPP_MAX_RCV_QLEN	32	/* max # frames we queue up for pppd */
 
-/* $Id: ppp.c,v 1.19 1998/07/07 04:27:37 paulus Exp $ */
+/* $Id: ppp.c,v 1.24 1999/03/31 06:07:57 paulus Exp $ */
 
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -61,6 +60,7 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
+#include <linux/sched.h>	/* to get the struct task_struct */
 #include <linux/string.h>	/* used in new tty drivers */
 #include <linux/signal.h>	/* used in new tty drivers */
 #include <asm/system.h>
@@ -90,6 +90,9 @@
 #include <linux/kmod.h>
 #endif
 
+typedef ssize_t		rw_ret_t;
+typedef size_t		rw_count_t;
+
 /*
  * Local functions
  */
@@ -101,9 +104,11 @@
 
 static void ppp_async_init(struct ppp *ppp);
 static void ppp_async_release(struct ppp *ppp);
+static int ppp_tty_sync_push(struct ppp *ppp);
 static int ppp_tty_push(struct ppp *ppp);
 static int ppp_async_encode(struct ppp *ppp);
 static int ppp_async_send(struct ppp *, struct sk_buff *);
+static int ppp_sync_send(struct ppp *, struct sk_buff *);
 
 static int ppp_ioctl(struct ppp *, unsigned int, unsigned long);
 static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp);
@@ -186,10 +191,10 @@
  * TTY callbacks
  */
 
-static ssize_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *,
-			    size_t);
-static ssize_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *,
-			     size_t);
+static rw_ret_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *,
+			     rw_count_t);
+static rw_ret_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *,
+			      rw_count_t);
 static int ppp_tty_ioctl(struct tty_struct *, struct file *, unsigned int,
 			 unsigned long);
 static unsigned int ppp_tty_poll(struct tty_struct *tty, struct file *filp,
@@ -236,7 +241,6 @@
 	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
 	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
 };
-EXPORT_SYMBOL(ppp_crc16_table);
 
 #ifdef CHECK_CHARACTERS
 static __u32 paritytab[8] =
@@ -458,13 +462,13 @@
  * Read a PPP frame from the rcv_q list,
  * waiting if necessary
  */
-static ssize_t
+static rw_ret_t
 ppp_tty_read(struct tty_struct *tty, struct file *file, __u8 * buf,
-	     size_t nr)
+	     rw_count_t nr)
 {
 	struct ppp *ppp = tty2ppp (tty);
 	struct sk_buff *skb;
-	ssize_t len, err;
+	rw_ret_t len, err;
 
 	/*
 	 * Validate the pointers
@@ -546,9 +550,9 @@
  * Writing to a tty in ppp line discipline sends a PPP frame.
  * Used by pppd to send control packets (LCP, etc.).
  */
-static ssize_t
+static rw_ret_t
 ppp_tty_write(struct tty_struct *tty, struct file *file, const __u8 * data,
-	      size_t count)
+	      rw_count_t count)
 {
 	struct ppp *ppp = tty2ppp (tty);
 	__u8 *new_data;
@@ -600,7 +604,7 @@
 	 */
 	ppp_send_ctrl(ppp, skb);
 
-	return (ssize_t) count;
+	return (rw_ret_t) count;
 }
 
 /*
@@ -799,6 +803,135 @@
 }
 
 /*
+ * Send a packet to the peer over a synchronous tty line.
+ * All encoding and FCS are handled by hardware.
+ * Addr/Ctrl and Protocol field compression implemented.
+ * Returns -1 iff the packet could not be accepted at present,
+ * 0 if the packet was accepted but we can't accept another yet, or
+ * 1 if we can accept another packet immediately.
+ * If this procedure returns 0, ppp_output_wakeup will be called
+ * exactly once.
+ */
+static int
+ppp_sync_send(struct ppp *ppp, struct sk_buff *skb)
+{
+	unsigned char *data;
+	int islcp;
+	
+	CHECK_PPP(0);
+
+	if (ppp->tpkt != NULL)
+		return -1;
+	ppp->tpkt = skb;
+
+	data = ppp->tpkt->data;
+	
+	/*
+	 * LCP packets with code values between 1 (configure-reqest)
+	 * and 7 (code-reject) must be sent as though no options
+	 * had been negotiated.
+	 */
+	islcp = PPP_PROTOCOL(data) == PPP_LCP
+		&& 1 <= data[PPP_HDRLEN] && data[PPP_HDRLEN] <= 7;
+
+	/* only reset idle time for data packets */
+	if (PPP_PROTOCOL(data) < 0x8000)
+		ppp->last_xmit = jiffies;
+	++ppp->stats.ppp_opackets;
+	ppp->stats.ppp_ooctects += ppp->tpkt->len;
+
+	if ( !(data[2]) && (ppp->flags & SC_COMP_PROT) ) {
+		/* compress protocol field */
+		data[2] = data[1];
+		data[1] = data[0];
+		skb_pull(ppp->tpkt,1);
+		data = ppp->tpkt->data;
+	}
+	
+	/*
+	 * Do address/control compression
+	 */
+	if ((ppp->flags & SC_COMP_AC) && !islcp
+	    && PPP_ADDRESS(data) == PPP_ALLSTATIONS
+	    && PPP_CONTROL(data) == PPP_UI) {
+		/* strip addr and control field */
+		skb_pull(ppp->tpkt,2);
+	}
+
+	return ppp_tty_sync_push(ppp);
+}
+
+/*
+ * Push a synchronous frame out to the tty.
+ * Returns 1 if frame accepted (or discarded), 0 otherwise.
+ */
+static int
+ppp_tty_sync_push(struct ppp *ppp)
+{
+	int sent;
+	struct tty_struct *tty = ppp2tty(ppp);
+	unsigned long flags;
+		
+	CHECK_PPP(0);
+
+	if (ppp->tpkt == NULL)
+		return 0;
+		
+	/* prevent reentrancy with tty_pushing flag */		
+	save_flags(flags);
+	cli();
+	if (ppp->tty_pushing) {
+		/* record wakeup attempt so we don't loose */
+		/* a wakeup call while doing push processing */
+		ppp->woke_up=1;
+		restore_flags(flags);
+		return 0;
+	}
+	ppp->tty_pushing = 1;
+	restore_flags(flags);
+	
+	if (tty == NULL || tty->disc_data != (void *) ppp)
+		goto flush;
+		
+	for(;;){
+		ppp->woke_up=0;
+		
+		/* Note: Sync driver accepts complete frame or nothing */
+		tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+		sent = tty->driver.write(tty, 0, ppp->tpkt->data, ppp->tpkt->len);
+		if (sent < 0) {
+			/* write error (possible loss of CD) */
+			/* record error and discard current packet */
+			ppp->stats.ppp_oerrors++;
+			break;
+		}
+		ppp->stats.ppp_obytes += sent;
+		if (sent < ppp->tpkt->len) {
+			/* driver unable to accept frame just yet */
+			save_flags(flags);
+			cli();
+			if (ppp->woke_up) {
+				/* wake up called while processing */
+				/* try to send the frame again */
+				restore_flags(flags);
+				continue;
+			}
+			/* wait for wakeup callback to try send again */
+			ppp->tty_pushing = 0;
+			restore_flags(flags);
+			return 0;
+		}
+		break;
+	}
+flush:	
+	/* done with current packet (sent or discarded) */
+	kfree_skb(ppp->tpkt);
+	ppp->tpkt = 0;
+	ppp->tty_pushing = 0;
+	return 1;
+}
+
+/*
  * Send a packet to the peer over an async tty line.
  * Returns -1 iff the packet could not be accepted at present,
  * 0 if the packet was accepted but we can't accept another yet, or
@@ -830,6 +963,9 @@
 {
 	int avail, sent, done = 0;
 	struct tty_struct *tty = ppp2tty(ppp);
+	
+	if ( ppp->flags & SC_SYNC ) 
+		return ppp_tty_sync_push(ppp);
 
 	CHECK_PPP(0);
 	if (ppp->tty_pushing)
@@ -1028,6 +1164,73 @@
 
 	ppp->stats.ppp_ibytes += count;
 	skb = ppp->rpkt;
+	
+	if ( ppp->flags & SC_SYNC ) {
+		/* synchronous mode */
+		
+		if (ppp->toss==0xE0) {
+			/* this is the 1st frame, reset vj comp */
+			ppp_receive_error(ppp);
+			ppp->toss = 0;
+		}
+		
+		/*
+		 * Allocate an skbuff for frame.
+		 * The 128 is room for VJ header expansion.
+		 */
+		
+		if (skb == NULL)
+			skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN);
+			
+		if (skb == NULL) {
+			if (ppp->flags & SC_DEBUG)
+				printk(KERN_DEBUG "couldn't "
+				       "alloc skb for recv\n");
+		} else {
+			/*
+			 * Decompress A/C and protocol compression here.
+			 */
+			p = skb_put(skb, 2);
+			p[0] = PPP_ALLSTATIONS;
+			p[1] = PPP_UI;
+			if (*data == PPP_ALLSTATIONS) {
+				data += 2;
+				count -= 2;
+			}
+			if ((*data & 1) != 0) {
+				p = skb_put(skb, 1);
+				p[0] = 0;
+			}
+
+			/* copy frame to socket buffer */
+			p = skb_put(skb, count);
+			memcpy(p,data,count);
+			
+			/*
+			 * Check if we've overflowed the MRU
+			 */
+			if (skb->len >= ppp->mru + PPP_HDRLEN + 2
+			    || skb_tailroom(skb) <= 0) {
+				++ppp->estats.rx_length_errors;
+				if (ppp->flags & SC_DEBUG)
+					printk(KERN_DEBUG "rcv frame too long: "
+					       "len=%d mru=%d hroom=%d troom=%d\n",
+					       skb->len, ppp->mru, skb_headroom(skb),
+					       skb_tailroom(skb));
+			} else {
+				if (!ppp_receive_frame(ppp, skb)) {
+					kfree_skb(skb);
+					ppp_receive_error(ppp);
+				}
+			}
+		
+			/* Reset for the next frame */
+			skb = NULL;
+		}
+		ppp->rpkt = skb;
+		return;
+	}
+	
 	while (count-- > 0) {
 		/*
 		 * Collect the character and error condition for the character.
@@ -1291,9 +1494,6 @@
 
 	CHECK_PPP_MAGIC(ppp);
 
-	/* ppp_dev_close may be called with tbusy==1 so we must set it to 0 */
-	dev->tbusy=0;
-
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -1850,23 +2050,25 @@
 		return 0;
 	}
 
-	/*
-	 * Verify the FCS of the frame and discard the FCS characters
-	 * from the end of the buffer.
-	 */
-	if (ppp->rfcs != PPP_GOODFCS) {
-		if (ppp->flags & SC_DEBUG) {
-			printk(KERN_DEBUG
-			       "ppp: frame with bad fcs, length = %d\n",
-			       count);
-			ppp_print_buffer("bad frame", data, count);
+	if ( !(ppp->flags & SC_SYNC) ) { 
+		/*
+		 * Verify the FCS of the frame and discard the FCS characters
+		 * from the end of the buffer.
+		 */
+		if (ppp->rfcs != PPP_GOODFCS) {
+			if (ppp->flags & SC_DEBUG) {
+				printk(KERN_DEBUG
+				       "ppp: frame with bad fcs, length = %d\n",
+				       count);
+				ppp_print_buffer("bad frame", data, count);
+			}
+			++ppp->estats.rx_crc_errors;
+			return 0;
 		}
-		++ppp->estats.rx_crc_errors;
-		return 0;
+		count -= 2;		/* ignore the fcs characters */
+		skb_trim(skb, count);
 	}
-	count -= 2;		/* ignore the fcs characters */
-	skb_trim(skb, count);
-
+	
 	/*
 	 * Process the active decompressor.
 	 */
@@ -2055,7 +2257,7 @@
 		return 0;
 	new_count = slhc_uncompress(ppp->slcomp, skb->data + PPP_HDRLEN,
 				    skb->len - PPP_HDRLEN);
-	if (new_count<=0) {
+	if (new_count <= 0) {
 		if (ppp->flags & SC_DEBUG)
 			printk(KERN_NOTICE
 			       "ppp: error in VJ decompression\n");
@@ -2234,7 +2436,10 @@
 	/*
 	 * Send the frame
 	 */
-	ret = ppp_async_send(ppp, skb);
+	if ( ppp->flags & SC_SYNC ) 
+		ret = ppp_sync_send(ppp, skb);
+	else
+		ret = ppp_async_send(ppp, skb);
 	if (ret > 0) {
 		/* we can release the lock */
 		ppp->xmit_busy = 0;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)