]> git.ozlabs.org Git - ppp.git/commitdiff
Updates from Al's ppp-2.2.0d release
authorPaul Mackerras <paulus@samba.org>
Mon, 18 Dec 1995 03:38:17 +0000 (03:38 +0000)
committerPaul Mackerras <paulus@samba.org>
Mon, 18 Dec 1995 03:38:17 +0000 (03:38 +0000)
23 files changed:
chat/Makefile.linux
chat/chat.8
chat/chat.c
include/linux/if_ppp.h
include/linux/if_pppvar.h
include/linux/ppp-comp.h [new file with mode: 0644]
include/linux/ppp_defs.h [new file with mode: 0644]
linux/Changes [new file with mode: 0644]
linux/bsd_comp.c [new file with mode: 0644]
linux/if.h [new file with mode: 0644]
linux/if_arp.h [new file with mode: 0644]
linux/if_ppp.h
linux/if_pppvar.h
linux/kinstall.sh [new file with mode: 0755]
linux/patch-1.2 [new file with mode: 0644]
linux/patch-1.3 [new file with mode: 0644]
linux/ppp-comp.h [new file with mode: 0644]
linux/ppp.c
linux/ppp_defs.h [new file with mode: 0644]
linux/route.h [new file with mode: 0644]
pppd/Makefile.linux
pppd/ipxcp.c [new file with mode: 0644]
pppd/ipxcp.h [new file with mode: 0644]

index 1531410fa8c7874cfac1dc18fe3f45597ef6ae17..7f9cbb3d415ca06fe72ad255acc7d77bcaba1cae 100644 (file)
@@ -1,4 +1,4 @@
-#      $Id: Makefile.linux,v 1.4 1995/12/11 02:55:14 paulus Exp $
+#      $Id: Makefile.linux,v 1.5 1995/12/18 03:32:43 paulus Exp $
 
 CDEF1= -DTERMIOS                       # Use the termios structure
 CDEF2= -DPIDSTRING                     # I like ascii pid values
 
 CDEF1= -DTERMIOS                       # Use the termios structure
 CDEF2= -DPIDSTRING                     # I like ascii pid values
@@ -7,12 +7,12 @@ CDEF4=        -UNO_SLEEP                      # Use the usleep function
 CDEF5= -DFNDELAY=O_NDELAY              # Old name value
 CDEFS= $(CDEF1) $(CDEF2) $(CDEF3) $(CDEF4) $(CDEF5)
 
 CDEF5= -DFNDELAY=O_NDELAY              # Old name value
 CDEFS= $(CDEF1) $(CDEF2) $(CDEF3) $(CDEF4) $(CDEF5)
 
-CFLAGS=        -O2 -N $(CDEFS)
+CFLAGS=        -O2 $(CDEFS)
 
 all:   chat
 
 chat:  chat.o
 
 all:   chat
 
 chat:  chat.o
-       $(CC) -o chat chat.o
+       $(CC) -O2 -o chat chat.o
 
 chat.o:        chat.c
        $(CC) -c $(CFLAGS) -o chat.o chat.c
 
 chat.o:        chat.c
        $(CC) -c $(CFLAGS) -o chat.o chat.c
index c70eb70cff16aaf0ff81d52631c6ec77345cd154..c227e79bd2eaab9d8b879ddf54177fe2232ab3a8 100644 (file)
@@ -1,6 +1,6 @@
 .\" -*- nroff -*-
 .\" manual page [] for chat 1.8
 .\" -*- nroff -*-
 .\" manual page [] for chat 1.8
-.\" $Id: chat.8,v 1.2 1995/06/12 11:24:14 paulus Exp $
+.\" $Id: chat.8,v 1.3 1995/12/18 03:32:45 paulus Exp $
 .\" SH section heading
 .\" SS subsection heading
 .\" LP paragraph
 .\" SH section heading
 .\" SS subsection heading
 .\" LP paragraph
@@ -48,6 +48,16 @@ Request that the \fIchat\fR script be executed in a verbose mode. The
 \fIchat\fR program will then log all text received from the modem and
 the output strings which it sends to the SYSLOG.
 .TP
 \fIchat\fR program will then log all text received from the modem and
 the output strings which it sends to the SYSLOG.
 .TP
+.B -V
+Request that the \fIchat\fR script be executed in a stderr verbose
+mode. The \fIchat\fR program will then log all text received from the
+modem and the output strings which it sends to the stderr device. This
+device is usually the local console at the station running the chat or
+pppd program. This option will not work properly if the stderr is
+redirected to the /dev/null locaiton as is the case should pppd be run
+in the 'detached' mode. In that case, use the '-v' option to record
+the session on the SYSLOG device.
+.TP
 .B script
 If the script is not specified in a file with the \fI-f\fR option then
 the script is included as parameters to the \fIchat\fR program.
 .B script
 If the script is not specified in a file with the \fI-f\fR option then
 the script is included as parameters to the \fIchat\fR program.
index f7aaabf1a30050d66130078c018a6d469b0b265c..7b805ad9ac1ad17d98b5deb0090ff2b147d05f56 100644 (file)
@@ -31,7 +31,7 @@
  *
  */
 
  *
  */
 
-static char rcsid[] = "$Id: chat.c,v 1.9 1995/06/12 11:24:15 paulus Exp $";
+static char rcsid[] = "$Id: chat.c,v 1.10 1995/12/18 03:32:46 paulus Exp $";
 
 #include <stdio.h>
 #include <time.h>
 
 #include <stdio.h>
 #include <time.h>
@@ -93,6 +93,7 @@ char *program_name;
 #define        DEFAULT_CHAT_TIMEOUT    45
 
 int verbose       = 0;
 #define        DEFAULT_CHAT_TIMEOUT    45
 
 int verbose       = 0;
+int Verbose       = 0;
 int quiet         = 0;
 int report        = 0;
 int exit_code     = 0;
 int quiet         = 0;
 int report        = 0;
 int exit_code     = 0;
@@ -199,6 +200,10 @@ char **argv;
                ++verbose;
                break;
 
                ++verbose;
                break;
 
+           case 'V':
+               ++Verbose;
+               break;
+
            case 'f':
                if (arg = OPTARG(argc, argv))
                    {
            case 'f':
                if (arg = OPTARG(argc, argv))
                    {
@@ -580,7 +585,7 @@ int status;
            fprintf (report_fp, "Closing \"%s\".\n", report_file);
            }
        fclose (report_fp);
            fprintf (report_fp, "Closing \"%s\".\n", report_file);
            }
        fclose (report_fp);
-       report_fp = (FILE*) NULL;
+       report_fp = (FILE *) NULL;
         }
 
 #if defined(get_term_param)
         }
 
 #if defined(get_term_param)
@@ -752,12 +757,71 @@ int sending;
     return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
     }
 
     return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
     }
 
+/*
+ * A modified version of 'strtok'. This version skips \ sequences.
+ */
+
+char *expect_strtok (s, term)
+char *s, *term;
+    {
+    static char *str        = "";
+    static int escape_flag = 0;
+    char   *result;
+/*
+ * If a string was specified then do initial processing.
+ */
+    if (s)
+       {
+       str         = s;
+       escape_flag = 0;
+       }
+
+    result = (char *) 0;
+    while (*str)
+       {
+/*
+ * Look for the terminator sequence.
+ * If the escape flag is set then this character is not the terminator.
+ * We assume that term does not contain the backslash character.
+ */
+       if (escape_flag || strchr (term, *str) == (char *) 0)
+           {
+           if (result == (char *) 0)
+               {
+               result = str;
+               }
+
+           if (escape_flag || *str == '\\')
+               {
+               escape_flag = !escape_flag;
+               }
+
+           ++str;
+           continue;
+           }
+/*
+ * This is the terminator. If we have a string then this is the end of the
+ * scan operation.
+ */
+       *str++ = '\0';
+       if (result)
+           {
+           break;
+           }
+       }
+    return (result);
+    }
+
 /*
  * Process the expect string
  */
 /*
  * Process the expect string
  */
-void chat_expect(s)
-register char *s;
+
+void chat_expect (s)
+char *s;
     {
     {
+    char *expect;
+    char *reply;
+
     if (strcmp(s, "ABORT") == 0)
        {
        ++abort_next;
     if (strcmp(s, "ABORT") == 0)
        {
        ++abort_next;
@@ -775,82 +839,57 @@ register char *s;
        ++timeout_next;
        return;
        }
        ++timeout_next;
        return;
        }
-
-    while (*s)
+/*
+ * Fetch the expect and reply string.
+ */
+    for (;;)
        {
        {
-       register char *hyphen;
+       expect = expect_strtok (s, "-");
+       s      = (char *) 0;
 
 
-       for (hyphen = s; *hyphen; ++hyphen)
+       if (expect == (char *) 0)
            {
            {
-           if (*hyphen == '-')
-               {
-               if (hyphen == s || hyphen[-1] != '\\')
-                   {
-                   break;
-                   }
-               }
+           return;
            }
            }
-       
-       if (*hyphen == '-')
-           {
-           *hyphen = '\0';
 
 
-           if (get_string(s))
-               {
-               return;
-               }
-           else
-               {
-               s = hyphen + 1;
-
-               for (hyphen = s; *hyphen; ++hyphen)
-                   {
-                   if (*hyphen == '-')
-                       {
-                       if (hyphen == s || hyphen[-1] != '\\')
-                           {
-                           break;
-                           }
-                       }
-                   }
-
-               if (*hyphen == '-')
-                   {
-                   *hyphen = '\0';
-
-                   chat_send(s);
-                   s = hyphen + 1;
-                   }
-               else
-                   {
-                   chat_send(s);
-                   return;
-                   }
-               }
+       reply = expect_strtok (s, "-");
+/*
+ * Handle the expect string. If successful then exit.
+ */
+       if (get_string (expect))
+           {
+           return;
            }
            }
-       else
+/*
+ * If there is a sub-reply string then send it. Otherwise any condition
+ * is terminal.
+ */
+       if (reply == (char *) 0 || exit_code != 3)
            {
            {
-           if (get_string(s))
-               {
-               return;
-               }
-           else
-               {
-               if (fail_reason)
-                   {
-                   syslog(LOG_INFO, "Failed (%s)", fail_reason);
-                   }
-               else
-                   {
-                   syslog(LOG_INFO, "Failed");
-                   }
-
-               terminate(exit_code);
-               }
+           break;
            }
            }
+
+       chat_send (reply);
+       }
+/*
+ * The expectation did not occur. This is terminal.
+ */
+    if (fail_reason)
+       {
+       syslog(LOG_INFO, "Failed (%s)", fail_reason);
+       }
+    else
+       {
+       syslog(LOG_INFO, "Failed");
        }
        }
+    terminate(exit_code);
     }
 
     }
 
+/*
+ * Translate the input character to the appropriate string for printing
+ * the data.
+ */
+
 char *character(c)
 int c;
     {
 char *character(c)
 int c;
     {
@@ -1219,6 +1258,11 @@ register char *string;
                }
            }
 
                }
            }
 
+       if (Verbose) {
+          if (c == '\n')      fputc( '\n', stderr );
+          else if (c != '\r') fprintf( stderr, "%s", character(c) );
+       }
+
        *s++ = c;
 
        if (s - temp >= len &&
        *s++ = c;
 
        if (s - temp >= len &&
index ebf3ea36d732c307e67f8d380625bf87ddf06329..5f21d9447d886749c069caa9423a3ddb184c1cca 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: if_ppp.h,v 1.3 1995/06/12 11:36:50 paulus Exp $    */
+/*     $Id: if_ppp.h,v 1.4 1995/12/18 03:38:01 paulus Exp $    */
 
 /*
  * if_ppp.h - Point-to-Point Protocol definitions.
 
 /*
  * if_ppp.h - Point-to-Point Protocol definitions.
  */
 
 /*
  */
 
 /*
- *  ==PPPVERSION 2.1.3==
+ *  ==FILEVERSION 6==
  *
  *  NOTE TO MAINTAINERS:
  *
  *  NOTE TO MAINTAINERS:
- *     If you modify this file at all, increment the last number above.
- *     ppp.c is shipped with a PPP distribution as well as with the kernel;
- *     if everyone increases the PPPVERSION number above, then scripts
- *     can do the right thing when deciding whether to install a new ppp.c
+ *     If you modify this file at all, increment the number above.
+ *     if_ppp.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new if_ppp.h
  *     file.  Don't change the format of that line otherwise, so the
  *     installation script can recognize it.
  */
  *     file.  Don't change the format of that line otherwise, so the
  *     installation script can recognize it.
  */
 #ifndef _IF_PPP_H_
 #define _IF_PPP_H_
 
 #ifndef _IF_PPP_H_
 #define _IF_PPP_H_
 
+#if defined(__linux__)
+#include <linux/if.h>
+#include <linux/ioctl.h>
+#include <linux/ppp_defs.h>
+#endif
+
 /*
  * Packet sizes
  */
 /*
  * Packet sizes
  */
@@ -44,6 +50,8 @@
 #define PPP_VERSION    "2.2.0"
 #define PPP_MAGIC      0x5002  /* Magic value for the ppp structure */
 #define PROTO_IPX      0x002b  /* protocol numbers */
 #define PPP_VERSION    "2.2.0"
 #define PPP_MAGIC      0x5002  /* Magic value for the ppp structure */
 #define PROTO_IPX      0x002b  /* protocol numbers */
+#define PROTO_DNA_RT    0x0027  /* DNA Routing */
+
 
 /*
  * Bit definitions for flags.
 
 /*
  * Bit definitions for flags.
@@ -96,11 +104,18 @@ struct ppp_option_data {
 };
 
 struct ifpppstatsreq {
 };
 
 struct ifpppstatsreq {
-    char ifr__name[IFNAMSIZ];          /* Name of the device */
-    struct ppp_stats *stats_ptr;       /* Pointer to stats buffer */
-    struct ppp_stats stats;            /* statistic information */
+  struct ifreq    b;
+  struct ppp_stats stats;                      /* statistic information */
 };
 
 };
 
+struct ifpppcstatsreq {
+  struct ifreq         b;
+  struct ppp_comp_stats stats;
+};
+
+#define ifr__name       b.ifr_ifrn.ifrn_name
+#define stats_ptr       b.ifr_ifru.ifru_data
+
 /*
  * Ioctl definitions.
  */
 /*
  * Ioctl definitions.
  */
@@ -121,13 +136,13 @@ struct ifpppstatsreq {
 #define PPPIOCSCOMPRESS        _IOW('t', 77, struct ppp_option_data)
 #define PPPIOCGNPMODE  _IOWR('t', 76, struct npioctl) /* get NP mode */
 #define PPPIOCSNPMODE  _IOW('t', 75, struct npioctl)  /* set NP mode */
 #define PPPIOCSCOMPRESS        _IOW('t', 77, struct ppp_option_data)
 #define PPPIOCGNPMODE  _IOWR('t', 76, struct npioctl) /* get NP mode */
 #define PPPIOCSNPMODE  _IOW('t', 75, struct npioctl)  /* set NP mode */
-
 #define PPPIOCGDEBUG   _IOR('t', 65, int)      /* Read debug level */
 #define PPPIOCSDEBUG   _IOW('t', 64, int)      /* Set debug level */
 #define PPPIOCGDEBUG   _IOR('t', 65, int)      /* Read debug level */
 #define PPPIOCSDEBUG   _IOW('t', 64, int)      /* Set debug level */
-#define PPPIOCGTIME    _IOR('t', 63, struct ppp_ddinfo) /* Read time info */
+#define PPPIOCGIDLE    _IOR('t', 63, struct ppp_idle) /* get idle time */
 
 #define SIOCGPPPSTATS   (SIOCDEVPRIVATE + 0)
 
 #define SIOCGPPPSTATS   (SIOCDEVPRIVATE + 0)
-#define SIOCGPPPVER     (SIOCDEVPRIVATE + 1)
+#define SIOCGPPPVER     (SIOCDEVPRIVATE + 1)  /* NEVER change this!! */
+#define SIOCGPPPCSTATS  (SIOCDEVPRIVATE + 2)
 
 #if !defined(ifr_mtu)
 #define ifr_mtu        ifr_ifru.ifru_metric
 
 #if !defined(ifr_mtu)
 #define ifr_mtu        ifr_ifru.ifru_metric
index 89be343e4f41e18b7da2967be3743c579e163c81..8d3dfc355d315a0b234e5907eb3c4f1692c39981 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp $ */
+/*     $Id: if_pppvar.h,v 1.3 1995/12/18 03:38:02 paulus Exp $ */
 /*
  * if_pppvar.h - private structures and declarations for PPP.
  *
 /*
  * if_pppvar.h - private structures and declarations for PPP.
  *
  */
 
 /*
  */
 
 /*
- *  ==PPPVERSION 2.1.3==
+ *  ==FILEVERSION 4==
  *
  *  NOTE TO MAINTAINERS:
  *
  *  NOTE TO MAINTAINERS:
- *     If you modify this file at all, increment the last number above.
- *     ppp.c is shipped with a PPP distribution as well as with the kernel;
- *     if everyone increases the PPPVERSION number above, then scripts
- *     can do the right thing when deciding whether to install a new ppp.c
+ *     If you modify this file at all, increment the number above.
+ *     if_pppvar.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new if_pppvar.h
  *     file.  Don't change the format of that line otherwise, so the
  *     installation script can recognize it.
  */
  *     file.  Don't change the format of that line otherwise, so the
  *     installation script can recognize it.
  */
  * Buffers for the PPP process have the following structure
  */
 
  * Buffers for the PPP process have the following structure
  */
 
-#define RBUFSIZE 2048   /* MUST be a power of 2 and be <= 4095 */
+#define RBUFSIZE  2048           /* MUST be a power of 2 and be <= 4095 */
+
 struct ppp_buffer {
   int                  size;           /* Size of the buffer area      */
   int                  count;          /* Count of characters in bufr  */
   int                  head;           /* index to head of list        */
   int                  tail;           /* index to tail of list        */
 struct ppp_buffer {
   int                  size;           /* Size of the buffer area      */
   int                  count;          /* Count of characters in bufr  */
   int                  head;           /* index to head of list        */
   int                  tail;           /* index to tail of list        */
-  int                  locked;         /* Buffer is being sent         */
+  unsigned long                locked;         /* Buffer is being sent         */
   int                  type;           /* Type of the buffer           */
                                        /* =0, device read buffer       */
                                        /* =1, device write buffer      */
                                        /* =2, daemon write buffer      */
                                        /* =3, daemon read buffer       */
   unsigned short       fcs;            /* Frame Check Sequence (CRC)   */
   int                  type;           /* Type of the buffer           */
                                        /* =0, device read buffer       */
                                        /* =1, device write buffer      */
                                        /* =2, daemon write buffer      */
                                        /* =3, daemon read buffer       */
   unsigned short       fcs;            /* Frame Check Sequence (CRC)   */
+  unsigned char         filler[4];      /* Extra space if needed        */
 };
 
 /* Given a pointer to the ppp_buffer then return base address of buffer */
 };
 
 /* Given a pointer to the ppp_buffer then return base address of buffer */
@@ -100,7 +102,7 @@ struct ppp {
        ext_accm        xmit_async_map; /* 1 bit means that given control 
                                           character is quoted on output*/
 
        ext_accm        xmit_async_map; /* 1 bit means that given control 
                                           character is quoted on output*/
 
-       unsigned long   recv_async_map; /* 1 bit means that given control 
+       __u32           recv_async_map; /* 1 bit means that given control 
                                           character is ignored on input*/
        int                     mtu;    /* maximum xmit frame size      */
        int                     mru;    /* maximum receive frame size   */
                                           character is ignored on input*/
        int                     mtu;    /* maximum xmit frame size      */
        int                     mru;    /* maximum receive frame size   */
@@ -122,7 +124,7 @@ struct ppp {
        struct ppp_buffer *s1buf;       /* Pointer to daemon buffer     */
        struct ppp_buffer *s2buf;       /* Pointer to device buffer     */
 
        struct ppp_buffer *s1buf;       /* Pointer to daemon buffer     */
        struct ppp_buffer *s2buf;       /* Pointer to device buffer     */
 
-       unsigned long     last_xmit;    /* time of last transmission    */
+       __u32             last_xmit;    /* time of last transmission    */
 
   /* These are pointers to the malloc()ed frame buffers.
      These buffers are used while processing a packet. If a packet
 
   /* These are pointers to the malloc()ed frame buffers.
      These buffers are used while processing a packet. If a packet
@@ -140,8 +142,8 @@ struct ppp {
        struct wait_queue *read_wait;   /* queue for writing processes  */
 
   /* Statistic information */
        struct wait_queue *read_wait;   /* queue for writing processes  */
 
   /* Statistic information */
-       struct pppstat    stats;        /* statistic information        */
-       struct ppp_ddinfo ddinfo;       /* demand dial information      */
+       struct pppstat        stats;    /* statistic information        */
+       struct ppp_idle       ddinfo;   /* demand dial information      */
 
   /* PPP compression protocol information */
        u_int   sc_bytessent;             /* count of octets sent */
 
   /* PPP compression protocol information */
        u_int   sc_bytessent;             /* count of octets sent */
diff --git a/include/linux/ppp-comp.h b/include/linux/ppp-comp.h
new file mode 100644 (file)
index 0000000..b72da19
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * ppp-comp.h - Definitions for doing PPP packet compression.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp-comp.h,v 1.1 1995/12/18 03:38:10 paulus Exp $
+ */
+
+/*
+ *  ==FILEVERSION 4==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     ppp-comp.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new ppp-comp.h
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
+
+#ifndef _NET_PPP_COMP_H
+#define _NET_PPP_COMP_H
+
+/*
+ * The following symbols control whether we include code for
+ * various compression methods.
+ */
+
+#ifndef DO_BSD_COMPRESS
+#define DO_BSD_COMPRESS        1       /* by default, include BSD-Compress */
+#endif
+
+#define DO_PREDICTOR_1 0
+#define DO_PREDICTOR_2 0
+#define DO_DEFLATE     0
+
+/*
+ * Structure giving methods for compression/decompression.
+ */
+
+#ifdef PACKETPTR
+struct compressor {
+       int     compress_proto; /* CCP compression protocol number */
+
+       /* Allocate space for a compressor (transmit side) */
+       void    *(*comp_alloc) (unsigned char *options, int opt_len);
+
+       /* Free space used by a compressor */
+       void    (*comp_free) (void *state);
+
+       /* Initialize a compressor */
+       int     (*comp_init) (void *state, unsigned char *options,
+                             int opt_len, int unit, int opthdr, int debug);
+
+       /* Reset a compressor */
+       void    (*comp_reset) (void *state);
+
+       /* Compress a packet */
+       int     (*compress) (void *state, unsigned char *rptr,
+                             unsigned char *obuf, int isize, int osize);
+
+       /* Return compression statistics */
+       void    (*comp_stat) (void *state, struct compstat *stats);
+
+       /* Allocate space for a decompressor (receive side) */
+       void    *(*decomp_alloc) (unsigned char *options, int opt_len);
+
+       /* Free space used by a decompressor */
+       void    (*decomp_free) (void *state);
+
+       /* Initialize a decompressor */
+       int     (*decomp_init) (void *state, unsigned char *options,
+                               int opt_len, int unit, int opthdr, int mru,
+                               int debug);
+
+       /* Reset a decompressor */
+       void    (*decomp_reset) (void *state);
+
+       /* Decompress a packet. */
+       int     (*decompress) (void *state, unsigned char *ibuf, int isize,
+                               unsigned char *obuf, int osize);
+
+       /* Update state for an incompressible packet received */
+       void    (*incomp) (void *state, unsigned char *ibuf, int icnt);
+
+       /* Return decompression statistics */
+       void    (*decomp_stat) (void *state, struct compstat *stats);
+};
+#endif /* PACKETPTR */
+
+/*
+ * Return values for decompress routine.
+ * We need to make these distinctions so that we can disable certain
+ * useful functionality, namely sending a CCP reset-request as a result
+ * of an error detected after decompression.  This is to avoid infringing
+ * a patent held by Motorola.
+ * Don't you just lurve software patents.
+ */
+
+#define DECOMP_OK              0       /* everything went OK */
+#define DECOMP_ERROR           1       /* error detected before decomp. */
+#define DECOMP_FATALERROR      2       /* error detected after decomp. */
+
+/*
+ * CCP codes.
+ */
+
+#define CCP_CONFREQ    1
+#define CCP_CONFACK    2
+#define CCP_TERMREQ    5
+#define CCP_TERMACK    6
+#define CCP_RESETREQ   14
+#define CCP_RESETACK   15
+
+/*
+ * Max # bytes for a CCP option
+ */
+
+#define CCP_MAX_OPTION_LENGTH  32
+
+/*
+ * Parts of a CCP packet.
+ */
+
+#define CCP_CODE(dp)           ((dp)[0])
+#define CCP_ID(dp)             ((dp)[1])
+#define CCP_LENGTH(dp)         (((dp)[2] << 8) + (dp)[3])
+#define CCP_HDRLEN             4
+
+#define CCP_OPT_CODE(dp)       ((dp)[0])
+#define CCP_OPT_LENGTH(dp)     ((dp)[1])
+#define CCP_OPT_MINLEN         2
+
+/*
+ * Definitions for BSD-Compress.
+ */
+
+#define CI_BSD_COMPRESS                21      /* config. option for BSD-Compress */
+#define CILEN_BSD_COMPRESS     3       /* length of config. option */
+
+/* Macros for handling the 3rd byte of the BSD-Compress config option. */
+#define BSD_NBITS(x)           ((x) & 0x1F)    /* number of bits requested */
+#define BSD_VERSION(x)         ((x) >> 5)      /* version of option format */
+#define BSD_CURRENT_VERSION    1               /* current version number */
+#define BSD_MAKE_OPT(v, n)     (((v) << 5) | (n))
+
+#define BSD_MIN_BITS           9       /* smallest code size supported */
+#define BSD_MAX_BITS           15      /* largest code size supported */
+
+/*
+ * Definitions for other, as yet unsupported, compression methods.
+ */
+
+#define CI_PREDICTOR_1         1       /* config option for Predictor-1 */
+#define CILEN_PREDICTOR_1      2       /* length of its config option */
+#define CI_PREDICTOR_2         2       /* config option for Predictor-2 */
+#define CILEN_PREDICTOR_2      2       /* length of its config option */
+
+#define CI_DEFLATE             24      /* config option for Deflate */
+#define CILEN_DEFLATE          4       /* length of its config option */
+
+#define DEFLATE_MIN_SIZE       8
+#define DEFLATE_MAX_SIZE       15
+#define DEFLATE_METHOD_VAL     8
+#define DEFLATE_SIZE(x)                (((x) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x)      ((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w)    ((((w) - DEFLATE_MIN_SIZE) << 4) \
+                                + DEFLATE_METHOD_VAL)
+#define DEFLATE_CHK_SEQUENCE   0
+
+#endif /* _NET_PPP_COMP_H */
diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h
new file mode 100644 (file)
index 0000000..8913ae7
--- /dev/null
@@ -0,0 +1,177 @@
+/*     $Id: ppp_defs.h,v 1.1 1995/12/18 03:38:15 paulus Exp $  */
+
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+/*
+ *  ==FILEVERSION 6==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     ppp_defs.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new ppp_defs.h
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
+
+#ifndef _PPP_DEFS_H_
+#define _PPP_DEFS_H_
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_HDRLEN     4       /* octets for standard ppp header */
+#define PPP_FCSLEN     2       /* octets for FCS */
+#define PPP_MRU                1500    /* default MRU = max length of info field */
+
+#define PPP_ADDRESS(p) (((u_char *)(p))[0])
+#define PPP_CONTROL(p) (((u_char *)(p))[1])
+#define PPP_PROTOCOL(p)        ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
+
+/*
+ * Significant octet values.
+ */
+#define        PPP_ALLSTATIONS 0xff    /* All-Stations broadcast address */
+#define        PPP_UI          0x03    /* Unnumbered Information */
+#define        PPP_FLAG        0x7e    /* Flag Sequence */
+#define        PPP_ESCAPE      0x7d    /* Asynchronous Control Escape */
+#define        PPP_TRANS       0x20    /* Asynchronous transparency modifier */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP         0x21    /* Internet Protocol */
+#define PPP_IPX                0x2b    /* IPX protocol */
+#define        PPP_VJC_COMP    0x2d    /* VJ compressed TCP */
+#define        PPP_VJC_UNCOMP  0x2f    /* VJ uncompressed TCP */
+#define PPP_COMP       0xfd    /* compressed packet */
+#define PPP_IPCP       0x8021  /* IP Control Protocol */
+#define PPP_IPXCP      0x802b  /* IPX Control Protocol */
+#define PPP_CCP                0x80fd  /* Compression Control Protocol */
+#define PPP_LCP                0xc021  /* Link Control Protocol */
+#define PPP_PAP                0xc023  /* Password Authentication Protocol */
+#define PPP_LQR                0xc025  /* Link Quality Report protocol */
+#define PPP_CHAP       0xc223  /* Cryptographic Handshake Auth. Protocol */
+
+/*
+ * A 32-bit unsigned integral type.
+ */
+#ifndef __BIT_TYPES_DEFINED__
+#ifdef UINT32_T
+typedef UINT32_T       u_int32_t;
+#else
+typedef unsigned int   u_int32_t;
+#endif
+#endif
+
+/*
+ * Extended asyncmap - allows any character to be escaped.
+ */
+typedef u_int32_t      ext_accm[8];
+
+/*
+ * What to do with network protocol (NP) packets.
+ */
+enum NPmode {
+    NPMODE_PASS,               /* pass the packet through */
+    NPMODE_DROP,               /* silently drop the packet */
+    NPMODE_ERROR,              /* return an error */
+    NPMODE_QUEUE               /* save it up for later. */
+};
+
+/*
+ * Statistics for LQRP and pppstats
+ */
+struct pppstat {
+    u_int      ppp_discards;   /* # frames discarded */
+
+    u_int      ppp_ibytes;     /* bytes received */
+    u_int      ppp_ioctects;   /* bytes received not in error */
+    u_int      ppp_ipackets;   /* packets received */
+    u_int      ppp_ierrors;    /* receive errors */
+    u_int      ppp_ilqrs;      /* # LQR frames received */
+
+    u_int      ppp_obytes;     /* raw bytes sent */
+    u_int      ppp_ooctects;   /* frame bytes sent */
+    u_int      ppp_opackets;   /* packets sent */
+    u_int      ppp_oerrors;    /* transmit errors */ 
+    u_int      ppp_olqrs;      /* # LQR frames sent */
+};
+
+struct vjstat {
+    u_int      vjs_packets;    /* outbound packets */
+    u_int      vjs_compressed; /* outbound compressed packets */
+    u_int      vjs_searches;   /* searches for connection state */
+    u_int      vjs_misses;     /* times couldn't find conn. state */
+    u_int      vjs_uncompressedin; /* inbound uncompressed packets */
+    u_int      vjs_compressedin;   /* inbound compressed packets */
+    u_int      vjs_errorin;    /* inbound unknown type packets */
+    u_int      vjs_tossed;     /* inbound packets tossed because of error */
+};
+
+struct compstat {
+    u_int      unc_bytes;      /* total uncompressed bytes */
+    u_int      unc_packets;    /* total uncompressed packets */
+    u_int      comp_bytes;     /* compressed bytes */
+    u_int      comp_packets;   /* compressed packets */
+    u_int      inc_bytes;      /* incompressible bytes */
+    u_int      inc_packets;    /* incompressible packets */
+    /* the compression ratio is defined as in_count / bytes_out */
+    u_int       in_count;      /* Bytes received */
+    u_int       bytes_out;     /* Bytes transmitted */
+    double     ratio;          /* not computed in kernel. */
+};
+
+struct ppp_stats {
+    struct pppstat     p;      /* basic PPP statistics */
+    struct vjstat      vj;     /* VJ header compression statistics */
+};
+
+struct ppp_comp_stats {
+    struct compstat    c;      /* packet compression statistics */
+    struct compstat    d;      /* packet decompression statistics */
+};
+
+/*
+ * The following structure records the time in seconds since
+ * the last NP packet was sent or received.
+ */
+struct ppp_idle {
+    time_t xmit_idle;          /* time since last NP packet sent */
+    time_t recv_idle;          /* time since last NP packet received */
+};
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+#endif
+
+#endif /* _PPP_DEFS_H_ */
diff --git a/linux/Changes b/linux/Changes
new file mode 100644 (file)
index 0000000..7eafaab
--- /dev/null
@@ -0,0 +1,130 @@
+     This archive represents the file called 'ppp-2.2.0d.tar.gz' for
+     Linux only.
+
+The changes from 2.2.0c to 2.2.0d are:
+
+1. Change chat to recognize the ABORT strings if you specify a sub-string.
+
+2. Change the ppp.c file to prevent the symbol table compilation problems.
+
+3. Augment the IP list in the authentication to include a netmask option
+   and to permit a reject as well as the default accept entries.
+
+4. Flushed the tty input buffer prior to starting the connect program.
+   This prevents old modem responses from a previous session to be fed to
+   the current one.
+
+5. Integrated Paul Mackerras' fix for a bug in the CCP which causes
+   the bsd compression to constantly re-negotiate a smaller and smaller
+   code size.
+
+6. Added options to set the Predictor-1 compressor if so desired. Predictor-1
+   is used by Morningstar's PPP package.
+
+7. Add support for Microsoft DNS parameters by Christoper Lameter.
+
+8. Support for the IPX protocol. It originated, and substantially resembles
+   since it started with, the work by G.Cambell@irl.cri.nz. Many thanks to
+   him for starting and getting the initial code to work. The IPX support
+   requires at least the 1.3.43 kernel.
+
+The changes from 2.2.0b to 2.2.0c are:
+
+1. Correct the reference in the ppp.c file for the definition of the
+   symbol table. This is used if you not using modules.
+
+There is still a compile/link problem with the a.out format. The problem
+is not with ppp, but in the module.h header file. If you are using a.out
+and have problems linking with an unresolved 'mod_use_count_' then use
+the following patch on the /usr/include/linux/module.h header file.
+
+ELF does not have this problem. Only a.out will complain.
+
+--- module.h.orig      Thu Oct 19 05:32:32 1995
++++ module.h   Thu Oct 19 05:33:44 1995
+@@ -90,12 +90,12 @@
+  * define the count variable, and usage macros.
+  */
+-extern long mod_use_count_;
+ #if defined(CONFIG_MODVERSIONS) && defined(MODULE) && !defined(__GENKSYMS__)
+ int Using_Versions; /* gcc will handle this global (used as a flag) correctly */
+ #endif
+ #ifdef MODULE
++extern long mod_use_count_;
+ #define MOD_INC_USE_COUNT      mod_use_count_++
+ #define MOD_DEC_USE_COUNT      mod_use_count_--
+ #define MOD_IN_USE           (mod_use_count_ != 0)
+
+
+The changes from 2.2.0a to 2.2.0b are:
+
+1. Correct a problem with the 1.3.33+ kernels in that they would cause
+   a SIGSEGV should you run the pppd program with the 'defaultroute'
+   option.
+
+2. Corrections in the ppp.c driver for non-module builds regarding the
+   symbol version informaiton.
+
+3. Removed bad definitions of the MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT
+   from ppp.c.
+
+4. Corrected the cleanup logic for the device. The test for ppp_alive
+   was the wrong sense.
+
+5. Corrected the references in chat scripts for "/usr/lib/ppp" to be
+   "/usr/sbin".
+
+The changes from 2.2.0 and 2.2.0a are:
+
+1. The code files have been moved to the /usr/sbin directory. This should
+   have been done in the 2.2.0 package but something happened and an old
+   Makefile was shipped in its place.
+
+2. The BSD compressor module, bsd_comp, will ONLY compile as a loadable
+   module. This was performed for a few technical reasons and one legal
+   reason. (The legal reason is in the README file here.)
+
+3. The test for the presence of ppp support has been moved to after the
+   decode of the options. It means that the test will no longer use /dev/tty
+   which may not be appropriate at that time.
+
+4. The pppstats program has been changed to work with the driver since the
+   driver will no longer attempt to do a floating point operation. This
+   previously would cause a kernel panic.
+
+                       ADDITIONAL INFORMATION
+
+1. This distribution requires either a kernel from the 1.2 series
+which is at or later than 1.2.11 or a kernel from the 1.3 series which
+is at or later 1.3.34. In short, you should use the latest version
+from either release. The difficulties in supporting earlier versions
+as they were being developed were too great. This means that the code
+may or may not work. If it does not then when you ask the answer will
+be the same; UPGRADE to the latest revision of the 1.2 or 1.3 kernels!!
+
+2. Please, please, read the README file in this directory __and__ the
+README.linux file. Pay attention to the fact that you _must_ do the
+command:
+
+make kernel
+
+This does not mean that you need to build the kernel, although you
+will need to do this also, but you must do the command from the ppp
+directory to make any appropriate patches.
+
+3. Do not be concerned should the 'make kernel' say that a file is
+current and not need to be replaced. It only means that the kernel
+already has the proper files. To be honest, it is the reason that
+there is a 'make kernel' -- to cover this condition. I had too many
+people put older drivers into the kernel because they followed the
+wrong set of instructions. Now, for all versions, there is only one
+set of instructions -- "do make kernel".
+
+[Ed.: After I wrote this, I received email from someone who had problems
+which could not be addressed by the standard 'make kernel'. It will not
+be able to make the proper changes if you have not applied the sequence
+against an original then there is a version specific instruction in the
+README.linux file.]
+
diff --git a/linux/bsd_comp.c b/linux/bsd_comp.c
new file mode 100644 (file)
index 0000000..508db4f
--- /dev/null
@@ -0,0 +1,1201 @@
+/* Because this code is derived from the 4.3BSD compress source:
+ *
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods, derived from original work by Spencer Thomas
+ * and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This version is for use with contigious buffers on Linux-derived systems.
+ *
+ *  ==FILEVERSION 5==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     bsd_comp.c is shipped with a PPP distribution as well as with
+ *     the kernel; if everyone increases the FILEVERSION number above,
+ *     then scripts can do the right thing when deciding whether to
+ *     install a new bsd_comp.c file. Don't change the format of that
+ *     line otherwise, so the installation script can recognize it.
+ *
+ * $Id: bsd_comp.c,v 1.2 1995/12/18 03:37:05 paulus Exp $
+ */
+
+#ifndef MODULE
+#error This file must be compiled as a module.
+#endif
+
+#include <linux/module.h>
+
+#include <endian.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#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>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+
+#include <net/if.h>
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inet.h>
+#include <linux/ioctl.h>
+
+#include <linux/ppp_defs.h>
+
+#ifdef NEW_SKBUFF
+#include <linux/netprotocol.h>
+#endif
+
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <net/if_arp.h>
+
+#undef   PACKETPTR
+#define  PACKETPTR 1
+#include <linux/ppp-comp.h>
+#undef   PACKETPTR
+
+/*
+ * PPP "BSD compress" compression
+ *  The differences between this compression and the classic BSD LZW
+ *  source are obvious from the requirement that the classic code worked
+ *  with files while this handles arbitrarily long streams that
+ *  are broken into packets.  They are:
+ *
+ *     When the code size expands, a block of junk is not emitted by
+ *         the compressor and not expected by the decompressor.
+ *
+ *     New codes are not necessarily assigned every time an old
+ *         code is output by the compressor.  This is because a packet
+ *         end forces a code to be emitted, but does not imply that a
+ *         new sequence has been seen.
+ *
+ *     The compression ratio is checked at the first end of a packet
+ *         after the appropriate gap.  Besides simplifying and speeding
+ *         things up, this makes it more likely that the transmitter
+ *         and receiver will agree when the dictionary is cleared when
+ *         compression is not going well.
+ */
+
+/*
+ * Macros to extract protocol version and number of bits
+ * from the third byte of the BSD Compress CCP configuration option.
+ */
+
+#define BSD_VERSION(x) ((x) >> 5)
+#define BSD_NBITS(x)   ((x) & 0x1F)
+
+#define BSD_CURRENT_VERSION    1
+
+/*
+ * A dictionary for doing BSD compress.
+ */
+
+struct bsd_dict {
+    union {                            /* hash value */
+       unsigned long   fcode;
+       struct {
+#ifndef BIG_ENDIAN_BITFIELD /* Little endian order */
+           unsigned short      prefix; /* preceding code */
+           unsigned char       suffix; /* last character of new code */
+           unsigned char       pad;
+#else /* Big endian order */
+           unsigned char       pad;
+           unsigned char       suffix; /* last character of new code */
+           unsigned short      prefix; /* preceding code */
+#endif
+       } hs;
+    } f;
+    unsigned short codem1;             /* output of hash table -1 */
+    unsigned short cptr;               /* map code to hash table entry */
+};
+
+struct bsd_db {
+    int            totlen;                     /* length of this structure */
+    unsigned int   hsize;              /* size of the hash table */
+    unsigned char  hshift;             /* used in hash function */
+    unsigned char  n_bits;             /* current bits/code */
+    unsigned char  maxbits;            /* maximum bits/code */
+    unsigned char  debug;              /* non-zero if debug desired */
+    unsigned char  unit;               /* ppp unit number */
+    unsigned short seqno;              /* sequence # of next packet */
+    unsigned int   mru;                        /* size of receive (decompress) bufr */
+    unsigned int   maxmaxcode;         /* largest valid code */
+    unsigned int   max_ent;            /* largest code in use */
+    unsigned int   in_count;           /* uncompressed bytes, aged */
+    unsigned int   bytes_out;          /* compressed bytes, aged */
+    unsigned int   ratio;              /* recent compression ratio */
+    unsigned int   checkpoint;         /* when to next check the ratio */
+    unsigned int   clear_count;                /* times dictionary cleared */
+    unsigned int   incomp_count;       /* incompressible packets */
+    unsigned int   incomp_bytes;       /* incompressible bytes */
+    unsigned int   uncomp_count;       /* uncompressed packets */
+    unsigned int   uncomp_bytes;       /* uncompressed bytes */
+    unsigned int   comp_count;         /* compressed packets */
+    unsigned int   comp_bytes;         /* compressed bytes */
+    unsigned short  *lens;             /* array of lengths of codes */
+    struct bsd_dict *dict;             /* dictionary */
+};
+
+#define BSD_OVHD       2               /* BSD compress overhead/packet */
+#define MIN_BSD_BITS   9
+#define BSD_INIT_BITS  MIN_BSD_BITS
+#define MAX_BSD_BITS   15
+
+static void    bsd_free (void *state);
+static void    *bsd_alloc(unsigned char *options, int opt_len, int decomp);
+static void    *bsd_comp_alloc (unsigned char *options, int opt_len);
+static void    *bsd_decomp_alloc (unsigned char *options, int opt_len);
+
+static int     bsd_init        (void *db, unsigned char *options,
+                                int opt_len, int unit, int debug, int decomp);
+static int     bsd_comp_init   (void *state, unsigned char *options,
+                                int opt_len, int unit, int opthdr, int debug);
+static int     bsd_decomp_init (void *state, unsigned char *options,
+                                int opt_len, int unit, int opthdr, int mru,
+                                int debug);
+
+static void    bsd_reset (void *state);
+static void    bsd_comp_stats (void *state, struct compstat *stats);
+
+static int     bsd_compress (void *state, unsigned char *rptr,
+                             unsigned char *obuf, int isize, int osize);
+static void    bsd_incomp (void *state, unsigned char *ibuf, int icnt);
+
+static int     bsd_decompress (void *state, unsigned char *ibuf, int isize,
+                               unsigned char *obuf, int osize);
+
+/* These are in ppp.c */
+extern int  ppp_register_compressor   (struct compressor *cp);
+extern void ppp_unregister_compressor (struct compressor *cp);
+
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define CLEAR  256                     /* table clear output code */
+#define FIRST  257                     /* first free entry */
+#define LAST   255
+
+#define MAXCODE(b)     ((1 << (b)) - 1)
+#define BADCODEM1      MAXCODE(MAX_BSD_BITS);
+
+#define BSD_HASH(prefix,suffix,hshift) ((((unsigned long)(suffix))<<(hshift)) \
+                                        ^ (unsigned long)(prefix))
+#define BSD_KEY(prefix,suffix)         ((((unsigned long)(suffix)) << 16) \
+                                        + (unsigned long)(prefix))
+
+#define CHECK_GAP      10000           /* Ratio check interval */
+
+#define RATIO_SCALE_LOG        8
+#define RATIO_SCALE    (1<<RATIO_SCALE_LOG)
+#define RATIO_MAX      (0x7fffffff>>RATIO_SCALE_LOG)
+
+/*
+ * clear the dictionary
+ */
+
+static void
+bsd_clear(struct bsd_db *db)
+{
+    db->clear_count++;
+    db->max_ent      = FIRST-1;
+    db->n_bits       = BSD_INIT_BITS;
+    db->bytes_out    = 0;
+    db->in_count     = 0;
+    db->incomp_count = 0;
+    db->ratio       = 0;
+    db->checkpoint   = CHECK_GAP;
+}
+
+/*
+ * If the dictionary is full, then see if it is time to reset it.
+ *
+ * Compute the compression ratio using fixed-point arithmetic
+ * with 8 fractional bits.
+ *
+ * Since we have an infinite stream instead of a single file,
+ * watch only the local compression ratio.
+ *
+ * Since both peers must reset the dictionary at the same time even in
+ * the absence of CLEAR codes (while packets are incompressible), they
+ * must compute the same ratio.
+ */
+
+static int bsd_check (struct bsd_db *db)       /* 1=output CLEAR */
+  {
+    unsigned int new_ratio;
+
+    if (db->in_count >= db->checkpoint)
+      {
+       /* age the ratio by limiting the size of the counts */
+       if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX)
+         {
+           db->in_count  -= (db->in_count  >> 2);
+           db->bytes_out -= (db->bytes_out >> 2);
+         }
+       
+       db->checkpoint = db->in_count + CHECK_GAP;
+       
+       if (db->max_ent >= db->maxmaxcode)
+         {
+           /* Reset the dictionary only if the ratio is worse,
+            * or if it looks as if it has been poisoned
+            * by incompressible data.
+            *
+            * This does not overflow, because
+            *  db->in_count <= RATIO_MAX.
+            */
+
+           new_ratio = db->in_count << RATIO_SCALE_LOG;
+           if (db->bytes_out != 0)
+             {
+               new_ratio /= db->bytes_out;
+             }
+           
+           if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
+             {
+               bsd_clear (db);
+               return 1;
+             }
+           db->ratio = new_ratio;
+         }
+      }
+    return 0;
+  }
+
+/*
+ * Return statistics.
+ */
+
+static void bsd_comp_stats (void *state, struct compstat *stats)
+  {
+    struct bsd_db *db = (struct bsd_db *) state;
+    
+    stats->unc_bytes    = db->uncomp_bytes;
+    stats->unc_packets  = db->uncomp_count;
+    stats->comp_bytes   = db->comp_bytes;
+    stats->comp_packets = db->comp_count;
+    stats->inc_bytes    = db->incomp_bytes;
+    stats->inc_packets  = db->incomp_count;
+    stats->in_count     = db->in_count;
+    stats->bytes_out    = db->bytes_out;
+  }
+
+/*
+ * Reset state, as on a CCP ResetReq.
+ */
+
+static void bsd_reset (void *state)
+  {
+    struct bsd_db *db = (struct bsd_db *) state;
+
+    bsd_clear(db);
+
+    db->seqno       = 0;
+    db->clear_count = 0;
+  }
+
+/*
+ * Release the compression structure
+ */
+
+static void bsd_free (void *state)
+  {
+    struct bsd_db *db = (struct bsd_db *) state;
+    
+    if (db)
+      {
+/*
+ * Release the dictionary
+ */
+       if (db->dict)
+         {
+           vfree (db->dict);
+           db->dict = NULL;
+         }
+/*
+ * Release the string buffer
+ */
+       if (db->lens)
+         {
+           vfree (db->lens);
+           db->lens = NULL;
+         }
+/*
+ * Finally release the structure itself.
+ */
+       kfree (db);
+       MOD_DEC_USE_COUNT;
+      }
+  }
+
+/*
+ * Allocate space for a (de) compressor.
+ */
+
+static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
+  {
+    int bits;
+    unsigned int hsize, hshift, maxmaxcode;
+    struct bsd_db *db;
+
+    if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3
+       || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
+      {
+       return NULL;
+      }
+
+    bits = BSD_NBITS(options[2]);
+
+    switch (bits)
+      {
+    case 9:                    /* needs 82152 for both directions */
+    case 10:                   /* needs 84144 */
+    case 11:                   /* needs 88240 */
+    case 12:                   /* needs 96432 */
+       hsize = 5003;
+       hshift = 4;
+       break;
+    case 13:                   /* needs 176784 */
+       hsize = 9001;
+       hshift = 5;
+       break;
+    case 14:                   /* needs 353744 */
+       hsize = 18013;
+       hshift = 6;
+       break;
+    case 15:                   /* needs 691440 */
+       hsize = 35023;
+       hshift = 7;
+       break;
+    case 16:                   /* needs 1366160--far too much, */
+       /* hsize = 69001; */    /* and 69001 is too big for cptr */
+       /* hshift = 8; */       /* in struct bsd_db */
+       /* break; */
+    default:
+       return NULL;
+      }
+/*
+ * Allocate the main control structure for this instance.
+ */
+    maxmaxcode = MAXCODE(bits);
+    db         = (struct bsd_db *) kmalloc (sizeof (struct bsd_db),
+                                           GFP_KERNEL);
+    if (!db)
+      {
+       return NULL;
+      }
+
+    memset (db, 0, sizeof(struct bsd_db));
+/*
+ * Allocate space for the dictionary. This may be more than one page in
+ * length.
+ */
+    db->dict = (struct bsd_dict *) vmalloc (hsize *
+                                           sizeof (struct bsd_dict));
+    if (!db->dict)
+      {
+       bsd_free (db);
+       return NULL;
+      }
+
+    MOD_INC_USE_COUNT;
+/*
+ * If this is the compression buffer then there is no length data.
+ */
+    if (!decomp)
+      {
+       db->lens = NULL;
+      }
+/*
+ * For decompression, the length information is needed as well.
+ */
+    else
+      {
+        db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
+                                              sizeof (db->lens[0]));
+       if (!db->lens)
+         {
+           bsd_free (db);
+           return (NULL);
+         }
+      }
+/*
+ * Initialize the data information for the compression code
+ */
+    db->totlen     = sizeof (struct bsd_db)   +
+                   (sizeof (struct bsd_dict) * hsize);
+
+    db->hsize      = hsize;
+    db->hshift     = hshift;
+    db->maxmaxcode = maxmaxcode;
+    db->maxbits    = bits;
+
+    return (void *) db;
+  }
+
+static void *bsd_comp_alloc (unsigned char *options, int opt_len)
+  {
+    return bsd_alloc (options, opt_len, 0);
+  }
+
+static void *bsd_decomp_alloc (unsigned char *options, int opt_len)
+  {
+    return bsd_alloc (options, opt_len, 1);
+  }
+
+/*
+ * Initialize the database.
+ */
+
+static int bsd_init (void *state, unsigned char *options,
+                    int opt_len, int unit, int debug, int decomp)
+  {
+    struct bsd_db *db = state;
+    int indx;
+    
+    if ((opt_len != 3) || (options[0] != CI_BSD_COMPRESS) || (options[1] != 3)
+       || (BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
+       || (BSD_NBITS(options[2]) != db->maxbits)
+       || (decomp && db->lens == NULL))
+      {
+       return 0;
+      }
+
+    if (decomp)
+      {
+       indx = LAST;
+       do
+         {
+           db->lens[indx] = 1;
+         }
+       while (indx-- > 0);
+      }
+
+    indx = db->hsize;
+    while (indx-- != 0)
+      {
+       db->dict[indx].codem1 = BADCODEM1;
+       db->dict[indx].cptr   = 0;
+      }
+
+    db->unit = unit;
+    db->mru  = 0;
+#ifndef DEBUG
+    if (debug)
+#endif
+      db->debug = 1;
+    
+    bsd_reset(db);
+    
+    return 1;
+  }
+
+static int bsd_comp_init (void *state, unsigned char *options,
+                         int opt_len, int unit, int opthdr, int debug)
+  {
+    return bsd_init (state, options, opt_len, unit, debug, 0);
+  }
+
+static int bsd_decomp_init (void *state, unsigned char *options,
+                           int opt_len, int unit, int opthdr, int mru,
+                           int debug)
+  {
+    return bsd_init (state, options, opt_len, unit, debug, 1);
+  }
+
+/*
+ * Obtain pointers to the various structures in the compression tables
+ */
+
+#define dict_ptrx(p,idx) &(p->dict[idx])
+#define lens_ptrx(p,idx) &(p->lens[idx])
+
+#ifdef DEBUG
+static unsigned short *lens_ptr(struct bsd_db *db, int idx)
+  {
+    if ((unsigned int) idx > (unsigned int) db->maxmaxcode)
+      {
+       printk ("<9>ppp: lens_ptr(%d) > max\n", idx);
+       idx = 0;
+      }
+    return lens_ptrx (db, idx);
+  }
+
+static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx)
+  {
+    if ((unsigned int) idx >= (unsigned int) db->hsize)
+      {
+       printk ("<9>ppp: dict_ptr(%d) > max\n", idx);
+       idx = 0;
+      }
+    return dict_ptrx (db, idx);
+  }
+
+#else
+#define lens_ptr(db,idx) lens_ptrx(db,idx)
+#define dict_ptr(db,idx) dict_ptrx(db,idx)
+#endif
+
+/*
+ * compress a packet
+ *
+ *     The result of this function is the size of the compressed
+ *     packet. A zero is returned if the packet was not compressed
+ *     for some reason, such as the size being larger than uncompressed.
+ *
+ *     One change from the BSD compress command is that when the
+ *     code size expands, we do not output a bunch of padding.
+ */
+
+static int bsd_compress (void *state, unsigned char *rptr, unsigned char *obuf,
+                        int isize, int osize)
+  {
+    struct bsd_db *db;
+    int hshift;
+    unsigned int max_ent;
+    unsigned int n_bits;
+    unsigned int bitno;
+    unsigned long accm;
+    int ent;
+    unsigned long fcode;
+    struct bsd_dict *dictp;
+    unsigned char c;
+    int hval;
+    int disp;
+    int ilen;
+    int mxcode;
+    unsigned char *wptr;
+    int olen;
+
+#define PUTBYTE(v)                     \
+  {                                    \
+    ++olen;                            \
+    if (wptr)                          \
+      {                                        \
+       *wptr++ = (unsigned char) (v);  \
+       if (olen >= osize)              \
+         {                             \
+           wptr = NULL;                \
+         }                             \
+      }                                        \
+  }
+
+#define OUTPUT(ent)                    \
+  {                                    \
+    bitno -= n_bits;                   \
+    accm |= ((ent) << bitno);          \
+    do                                 \
+      {                                        \
+       PUTBYTE(accm >> 24);            \
+       accm <<= 8;                     \
+       bitno += 8;                     \
+      }                                        \
+    while (bitno <= 24);               \
+  }
+
+  /*
+   * If the protocol is not in the range we're interested in,
+   * just return without compressing the packet.  If it is,
+   * the protocol becomes the first byte to compress.
+   */
+
+    ent = PPP_PROTOCOL(rptr);
+    if (ent < 0x21 || ent > 0xf9)
+      {
+       return 0;
+      }
+
+    db      = (struct bsd_db *) state;
+    hshift  = db->hshift;
+    max_ent = db->max_ent;
+    n_bits  = db->n_bits;
+    bitno   = 32;
+    accm    = 0;
+    mxcode  = MAXCODE (n_bits);
+
+    /* Initialize the output pointers */
+    wptr  = obuf;
+    olen  = PPP_HDRLEN + BSD_OVHD;
+
+    if (osize > isize)
+      {
+       osize = isize;
+      }
+
+    /* This is the PPP header information */
+    if (wptr)
+      {
+       *wptr++ = PPP_ADDRESS(rptr);
+       *wptr++ = PPP_CONTROL(rptr);
+       *wptr++ = 0;
+       *wptr++ = PPP_COMP;
+       *wptr++ = db->seqno >> 8;
+       *wptr++ = db->seqno;
+      }
+
+    /* Skip the input header */
+    rptr  += PPP_HDRLEN;
+    isize -= PPP_HDRLEN;
+    ilen   = ++isize; /* This is off by one, but that is what is in draft! */
+
+    while (--ilen > 0)
+      {
+       c     = *rptr++;
+       fcode = BSD_KEY  (ent, c);
+       hval  = BSD_HASH (ent, c, hshift);
+       dictp = dict_ptr (db, hval);
+       
+       /* Validate and then check the entry. */
+       if (dictp->codem1 >= max_ent)
+         {
+           goto nomatch;
+         }
+
+       if (dictp->f.fcode == fcode)
+         {
+           ent = dictp->codem1 + 1;
+           continue;   /* found (prefix,suffix) */
+         }
+       
+       /* continue probing until a match or invalid entry */
+       disp = (hval == 0) ? 1 : hval;
+
+       do
+         {
+           hval += disp;
+           if (hval >= db->hsize)
+             {
+               hval -= db->hsize;
+             }
+           dictp = dict_ptr (db, hval);
+           if (dictp->codem1 >= max_ent)
+             {
+               goto nomatch;
+             }
+         }
+       while (dictp->f.fcode != fcode);
+
+       ent = dictp->codem1 + 1;        /* finally found (prefix,suffix) */
+       continue;
+       
+nomatch:
+       OUTPUT(ent);            /* output the prefix */
+       
+       /* code -> hashtable */
+       if (max_ent < db->maxmaxcode)
+         {
+           struct bsd_dict *dictp2;
+           struct bsd_dict *dictp3;
+           int    indx;
+
+           /* expand code size if needed */
+           if (max_ent >= mxcode)
+             {
+               db->n_bits = ++n_bits;
+               mxcode     = MAXCODE (n_bits);
+             }
+           
+           /* Invalidate old hash table entry using
+            * this code, and then take it over.
+            */
+
+           dictp2 = dict_ptr (db, max_ent + 1);
+           indx   = dictp2->cptr;
+           dictp3 = dict_ptr (db, indx);
+
+           if (dictp3->codem1 == max_ent)
+             {
+               dictp3->codem1 = BADCODEM1;
+             }
+
+           dictp2->cptr   = hval;
+           dictp->codem1  = max_ent;
+           dictp->f.fcode = fcode;
+           db->max_ent    = ++max_ent;
+
+           if (db->lens)
+             {
+               unsigned short *len1 = lens_ptr (db, max_ent);
+               unsigned short *len2 = lens_ptr (db, ent);
+               *len1 = *len2 + 1;
+             }
+         }
+       ent = c;
+      }
+    
+    OUTPUT(ent);               /* output the last code */
+
+    db->bytes_out    += olen;  /* Do not count bytes from here */
+    db->uncomp_bytes += isize;
+    db->in_count     += isize;
+    ++db->uncomp_count;
+    ++db->seqno;
+
+    if (bitno < 32)
+      {
+       ++db->bytes_out; /* must be set before calling bsd_check */
+      }
+
+    /*
+     * Generate the clear command if needed
+     */
+
+    if (bsd_check(db))
+      {
+       OUTPUT (CLEAR);
+      }
+    
+    /*
+     * Pad dribble bits of last code with ones.
+     * Do not emit a completely useless byte of ones.
+     */
+
+    if (bitno != 32)
+      {
+       PUTBYTE((accm | (0xff << (bitno-8))) >> 24);
+      }
+    
+    /*
+     * Increase code size if we would have without the packet
+     * boundary because the decompressor will do so.
+     */
+
+    if (max_ent >= mxcode && max_ent < db->maxmaxcode)
+      {
+       db->n_bits++;
+      }
+
+    /* If output length is too large then this is an incomplete frame. */
+    if (wptr == NULL)
+      {
+       ++db->incomp_count;
+       db->incomp_bytes += isize;
+       olen              = 0;
+      }
+    else /* Count the number of compressed frames */
+      {
+       ++db->comp_count;
+       db->comp_bytes += olen;
+      }
+
+    /* Return the resulting output length */
+    return olen;
+#undef OUTPUT
+#undef PUTBYTE
+  }
+
+/*
+ * Update the "BSD Compress" dictionary on the receiver for
+ * incompressible data by pretending to compress the incoming data.
+ */
+
+static void bsd_incomp (void *state, unsigned char *ibuf, int icnt)
+  {
+    (void) bsd_compress (state, ibuf, (char *) 0, icnt, 0);
+  }
+
+/*
+ * Decompress "BSD Compress".
+ *
+ * Because of patent problems, we return DECOMP_ERROR for errors
+ * found by inspecting the input data and for system problems, but
+ * DECOMP_FATALERROR for any errors which could possibly be said to
+ * be being detected "after" decompression.  For DECOMP_ERROR,
+ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
+ * infringing a patent of Motorola's if we do, so we take CCP down
+ * instead.
+ *
+ * Given that the frame has the correct sequence number and a good FCS,
+ * errors such as invalid codes in the input most likely indicate a
+ * bug, so we return DECOMP_FATALERROR for them in order to turn off
+ * compression, even though they are detected by inspecting the input.
+ */
+
+static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
+                          unsigned char *obuf, int osize)
+  {
+    struct bsd_db *db;
+    unsigned int max_ent;
+    unsigned long accm;
+    unsigned int bitno;                /* 1st valid bit in accm */
+    unsigned int n_bits;
+    unsigned int tgtbitno;     /* bitno when we have a code */
+    struct bsd_dict *dictp;
+    int explen;
+    int seq;
+    unsigned int incode;
+    unsigned int oldcode;
+    unsigned int finchar;
+    unsigned char *p;
+    unsigned char *wptr;
+    int adrs;
+    int ctrl;
+    int ilen;
+    int codelen;
+    int extra;
+
+    db       = (struct bsd_db *) state;
+    max_ent  = db->max_ent;
+    accm     = 0;
+    bitno    = 32;             /* 1st valid bit in accm */
+    n_bits   = db->n_bits;
+    tgtbitno = 32 - n_bits;    /* bitno when we have a code */
+    
+    /*
+     * Save the address/control from the PPP header
+     * and then get the sequence number.
+     */
+
+    adrs  = PPP_ADDRESS (ibuf);
+    ctrl  = PPP_CONTROL (ibuf);
+
+    seq   = (ibuf[4] << 8) + ibuf[5];
+
+    ibuf += (PPP_HDRLEN + 2);
+    ilen  = isize - (PPP_HDRLEN + 2);
+    
+    /*
+     * Check the sequence number and give up if it differs from
+     * the value we're expecting.
+     */
+
+    if (seq != db->seqno)
+      {
+       if (db->debug)
+         {
+           printk("bsd_decomp%d: bad sequence # %d, expected %d\n",
+                  db->unit, seq, db->seqno - 1);
+         }
+       return DECOMP_ERROR;
+      }
+
+    ++db->seqno;
+    db->bytes_out += ilen;
+
+    /*
+     * Fill in the ppp header, but not the last byte of the protocol
+     * (that comes from the decompressed data).
+     */
+
+    wptr    = obuf;
+    *wptr++ = adrs;
+    *wptr++ = ctrl;
+    *wptr++ = 0;
+    
+    oldcode = CLEAR;
+    explen  = 3;
+
+    /*
+     * Keep the checkpoint correctly so that incompressible packets
+     * clear the dictionary at the proper times.
+     */
+
+    for (;;)
+      {
+       if (ilen-- <= 0)
+         {
+           db->in_count += (explen - 3); /* don't count the header */
+           break;
+         }
+
+       /*
+        * Accumulate bytes until we have a complete code.
+        * Then get the next code, relying on the 32-bit,
+        * unsigned accm to mask the result.
+        */
+
+       bitno -= 8;
+       accm  |= *ibuf++ << bitno;
+       if (tgtbitno < bitno)
+         {
+           continue;
+         }
+
+       incode = accm >> tgtbitno;
+       accm <<= n_bits;
+       bitno += n_bits;
+
+       /*
+        * The dictionary must only be cleared at the end of a packet.
+        */
+       
+       if (incode == CLEAR)
+         {
+           if (ilen > 0)
+             {
+               if (db->debug)
+                 {
+                   printk("bsd_decomp%d: bad CLEAR\n", db->unit);
+                 }
+               return DECOMP_FATALERROR;       /* probably a bug */
+             }
+           
+           bsd_clear(db);
+           break;
+         }
+
+       if ((incode > max_ent + 2) || (incode > db->maxmaxcode)
+           || (incode > max_ent && oldcode == CLEAR))
+         {
+           if (db->debug)
+             {
+               printk("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
+                      db->unit, incode, oldcode);
+               printk("max_ent=0x%x explen=%d seqno=%d\n",
+                      max_ent, explen, db->seqno);
+             }
+           return DECOMP_FATALERROR;   /* probably a bug */
+         }
+       
+       /* Special case for KwKwK string. */
+       if (incode > max_ent)
+         {
+           finchar = oldcode;
+           extra   = 1;
+         }
+       else
+         {
+           finchar = incode;
+           extra   = 0;
+         }
+       
+       codelen = *(lens_ptr (db, finchar));
+       explen += codelen + extra;
+       if (explen > osize)
+         {
+           if (db->debug)
+             {
+               printk("bsd_decomp%d: ran out of mru\n", db->unit);
+#ifdef DEBUG
+               printk("  len=%d, finchar=0x%x, codelen=%d, explen=%d\n",
+                      ilen, finchar, codelen, explen);
+#endif
+             }
+           return DECOMP_FATALERROR;
+         }
+       
+       /*
+        * Decode this code and install it in the decompressed buffer.
+        */
+
+       wptr += codelen;
+       p     = wptr;
+       while (finchar > LAST)
+         {
+           struct bsd_dict *dictp2 = dict_ptr (db, finchar);
+           
+           dictp = dict_ptr (db, dictp2->cptr);
+#ifdef DEBUG
+           if (--codelen <= 0 || dictp->codem1 != finchar-1)
+             {
+               if (codelen <= 0)
+                 {
+                   printk("bsd_decomp%d: fell off end of chain ", db->unit);
+                   printk("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
+                          incode, finchar, dictp2->cptr, max_ent);
+                 }
+               else
+                 {
+                   if (dictp->codem1 != finchar-1)
+                     {
+                       printk("bsd_decomp%d: bad code chain 0x%x "
+                              "finchar=0x%x ",
+                              db->unit, incode, finchar);
+
+                       printk("oldcode=0x%x cptr=0x%x codem1=0x%x\n",
+                              oldcode, dictp2->cptr, dictp->codem1);
+                     }
+                 }
+               return DECOMP_FATALERROR;
+             }
+#endif
+           *--p    = dictp->f.hs.suffix;
+           finchar = dictp->f.hs.prefix;
+         }
+       *--p = finchar;
+       
+#ifdef DEBUG
+       if (--codelen != 0)
+         {
+           printk("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
+                  db->unit, codelen, incode, max_ent);
+         }
+#endif
+       
+       if (extra)              /* the KwKwK case again */
+         {
+           *wptr++ = finchar;
+         }
+       
+       /*
+        * If not first code in a packet, and
+        * if not out of code space, then allocate a new code.
+        *
+        * Keep the hash table correct so it can be used
+        * with uncompressed packets.
+        */
+
+       if (oldcode != CLEAR && max_ent < db->maxmaxcode)
+         {
+           struct bsd_dict *dictp2, *dictp3;
+           unsigned short  *lens1,  *lens2;
+           unsigned long fcode;
+           int hval, disp, indx;
+           
+           fcode = BSD_KEY(oldcode,finchar);
+           hval  = BSD_HASH(oldcode,finchar,db->hshift);
+           dictp = dict_ptr (db, hval);
+           
+           /* look for a free hash table entry */
+           if (dictp->codem1 < max_ent)
+             {
+               disp = (hval == 0) ? 1 : hval;
+               do
+                 {
+                   hval += disp;
+                   if (hval >= db->hsize)
+                     {
+                       hval -= db->hsize;
+                     }
+                   dictp = dict_ptr (db, hval);
+                 }
+               while (dictp->codem1 < max_ent);
+             }
+           
+           /*
+            * Invalidate previous hash table entry
+            * assigned this code, and then take it over
+            */
+
+           dictp2 = dict_ptr (db, max_ent + 1);
+           indx   = dictp2->cptr;
+           dictp3 = dict_ptr (db, indx);
+
+           if (dictp3->codem1 == max_ent)
+             {
+               dictp3->codem1 = BADCODEM1;
+             }
+
+           dictp2->cptr   = hval;
+           dictp->codem1  = max_ent;
+           dictp->f.fcode = fcode;
+           db->max_ent    = ++max_ent;
+
+           /* Update the length of this string. */
+           lens1  = lens_ptr (db, max_ent);
+           lens2  = lens_ptr (db, oldcode);
+           *lens1 = *lens2 + 1;
+           
+           /* Expand code size if needed. */
+           if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+             {
+               db->n_bits = ++n_bits;
+               tgtbitno   = 32-n_bits;
+             }
+         }
+       oldcode = incode;
+      }
+
+    ++db->comp_count;
+    ++db->uncomp_count;
+    db->comp_bytes   += isize - BSD_OVHD - PPP_HDRLEN;
+    db->uncomp_bytes += explen;
+
+    if (bsd_check(db))
+      {
+       if (db->debug)
+         {
+           printk("bsd_decomp%d: peer should have cleared dictionary on %d\n",
+                  db->unit, db->seqno - 1);
+         }
+      }
+    return explen;
+  }
+     
+/*************************************************************
+ * Table of addresses for the BSD compression module
+ *************************************************************/
+
+static struct compressor ppp_bsd_compress = {
+    CI_BSD_COMPRESS,           /* compress_proto */
+    bsd_comp_alloc,            /* comp_alloc */
+    bsd_free,                  /* comp_free */
+    bsd_comp_init,             /* comp_init */
+    bsd_reset,                 /* comp_reset */
+    bsd_compress,              /* compress */
+    bsd_comp_stats,            /* comp_stat */
+    bsd_decomp_alloc,          /* decomp_alloc */
+    bsd_free,                  /* decomp_free */
+    bsd_decomp_init,           /* decomp_init */
+    bsd_reset,                 /* decomp_reset */
+    bsd_decompress,            /* decompress */
+    bsd_incomp,                        /* incomp */
+    bsd_comp_stats             /* decomp_stat */
+};
+
+/*************************************************************
+ * Module support routines
+ *************************************************************/
+
+int
+init_module(void)
+{
+       int answer = ppp_register_compressor (&ppp_bsd_compress);
+       if (answer == 0)
+               printk (KERN_INFO "PPP BSD Compression module registered\n");
+       return answer;
+}
+
+void
+cleanup_module(void)
+{
+       ppp_unregister_compressor (&ppp_bsd_compress);
+}
diff --git a/linux/if.h b/linux/if.h
new file mode 100644 (file)
index 0000000..222d93f
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Global definitions for the INET interface module.
+ *
+ * Version:    @(#)if.h        1.0.2   04/18/93
+ *
+ * Authors:    Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988
+ *             Ross Biro, <bir7@leland.Stanford.Edu>
+ *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_H
+#define _LINUX_IF_H
+
+#include <linux/types.h>               /* for "caddr_t" et al          */
+#include <linux/socket.h>              /* for "struct sockaddr" et al  */
+
+/* Standard interface flags. */
+#define        IFF_UP          0x1             /* interface is up              */
+#define        IFF_BROADCAST   0x2             /* broadcast address valid      */
+#define        IFF_DEBUG       0x4             /* turn on debugging            */
+#define        IFF_LOOPBACK    0x8             /* is a loopback net            */
+#define        IFF_POINTOPOINT 0x10            /* interface is has p-p link    */
+#define        IFF_NOTRAILERS  0x20            /* avoid use of trailers        */
+#define        IFF_RUNNING     0x40            /* resources allocated          */
+#define        IFF_NOARP       0x80            /* no ARP protocol              */
+#define        IFF_PROMISC     0x100           /* receive all packets          */
+/* Not supported */
+#define        IFF_ALLMULTI    0x200           /* receive all multicast packets*/
+
+#define IFF_MASTER     0x400           /* master of a load balancer    */
+#define IFF_SLAVE      0x800           /* slave of a load balancer     */
+
+#define IFF_MULTICAST  0x1000          /* Supports multicast           */
+
+/*
+ * The ifaddr structure contains information about one address
+ * of an interface.  They are maintained by the different address
+ * families, are allocated and attached when an address is set,
+ * and are linked together so all addresses for an interface can
+ * be located.
+ */
+struct ifaddr 
+{
+       struct sockaddr ifa_addr;       /* address of interface         */
+       union {
+               struct sockaddr ifu_broadaddr;
+               struct sockaddr ifu_dstaddr;
+       } ifa_ifu;
+       struct iface            *ifa_ifp;       /* back-pointer to interface    */
+       struct ifaddr           *ifa_next;      /* next address for interface   */
+};
+
+#define        ifa_broadaddr   ifa_ifu.ifu_broadaddr   /* broadcast address    */
+#define        ifa_dstaddr     ifa_ifu.ifu_dstaddr     /* other end of link    */
+
+/*
+ *     Device mapping structure. I'd just gone off and designed a 
+ *     beautiful scheme using only loadable modules with arguments
+ *     for driver options and along come the PCMCIA people 8)
+ *
+ *     Ah well. The get() side of this is good for WDSETUP, and it'll
+ *     be handy for debugging things. The set side is fine for now and
+ *     being very small might be worth keeping for clean configuration.
+ */
+
+struct ifmap 
+{
+       unsigned long mem_start;
+       unsigned long mem_end;
+       unsigned short base_addr; 
+       unsigned char irq;
+       unsigned char dma;
+       unsigned char port;
+       /* 3 bytes spare */
+};
+
+/*
+ * Interface request structure used for socket
+ * ioctl's.  All interface ioctl's must have parameter
+ * definitions which begin with ifr_name.  The
+ * remainder may be interface specific.
+ */
+
+struct ifreq 
+{
+#define IFHWADDRLEN    6
+#define        IFNAMSIZ        16
+       union
+       {
+               char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
+               char    ifrn_hwaddr[IFHWADDRLEN];       /* Obsolete */
+       } ifr_ifrn;
+       
+       union {
+               struct  sockaddr ifru_addr;
+               struct  sockaddr ifru_dstaddr;
+               struct  sockaddr ifru_broadaddr;
+               struct  sockaddr ifru_netmask;
+               struct  sockaddr ifru_hwaddr;
+               short   ifru_flags;
+               int     ifru_metric;
+               int     ifru_mtu;
+               struct  ifmap ifru_map;
+               char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
+               caddr_t ifru_data;
+       } ifr_ifru;
+};
+
+#define ifr_name       ifr_ifrn.ifrn_name      /* interface name       */
+#define old_ifr_hwaddr ifr_ifrn.ifrn_hwaddr    /* interface hardware   */
+#define ifr_hwaddr     ifr_ifru.ifru_hwaddr    /* MAC address          */
+#define        ifr_addr        ifr_ifru.ifru_addr      /* address              */
+#define        ifr_dstaddr     ifr_ifru.ifru_dstaddr   /* other end of p-p lnk */
+#define        ifr_broadaddr   ifr_ifru.ifru_broadaddr /* broadcast address    */
+#define        ifr_netmask     ifr_ifru.ifru_netmask   /* interface net mask   */
+#define        ifr_flags       ifr_ifru.ifru_flags     /* flags                */
+#define        ifr_metric      ifr_ifru.ifru_metric    /* metric               */
+#define        ifr_mtu         ifr_ifru.ifru_mtu       /* mtu                  */
+#define ifr_map                ifr_ifru.ifru_map       /* device map           */
+#define ifr_slave      ifr_ifru.ifru_slave     /* slave device         */
+#define        ifr_data        ifr_ifru.ifru_data      /* for use by interface */
+
+/*
+ * Structure used in SIOCGIFCONF request.
+ * Used to retrieve interface configuration
+ * for machine (useful for programs which
+ * must know all networks accessible).
+ */
+
+struct ifconf 
+{
+       int     ifc_len;                        /* size of buffer       */
+       union 
+       {
+               caddr_t ifcu_buf;
+               struct  ifreq *ifcu_req;
+       } ifc_ifcu;
+};
+#define        ifc_buf ifc_ifcu.ifcu_buf               /* buffer address       */
+#define        ifc_req ifc_ifcu.ifcu_req               /* array of structures  */
+
+#endif /* _LINUX_IF_H */
diff --git a/linux/if_arp.h b/linux/if_arp.h
new file mode 100644 (file)
index 0000000..34e4c78
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Global definitions for the ARP (RFC 826) protocol.
+ *
+ * Version:    @(#)if_arp.h    1.0.1   04/16/93
+ *
+ * Authors:    Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
+ *             Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source.
+ *             Ross Biro, <bir7@leland.Stanford.Edu>
+ *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *             Florian La Roche.
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_ARP_H
+#define _LINUX_IF_ARP_H
+
+/* ARP protocol HARDWARE identifiers. */
+#define ARPHRD_NETROM  0               /* from KA9Q: NET/ROM pseudo    */
+#define ARPHRD_ETHER   1               /* Ethernet 10Mbps              */
+#define        ARPHRD_EETHER   2               /* Experimental Ethernet        */
+#define        ARPHRD_AX25     3               /* AX.25 Level 2                */
+#define        ARPHRD_PRONET   4               /* PROnet token ring            */
+#define        ARPHRD_CHAOS    5               /* Chaosnet                     */
+#define        ARPHRD_IEEE802  6               /* IEEE 802.2 Ethernet/TR/TB    */
+#define        ARPHRD_ARCNET   7               /* ARCnet                       */
+#define        ARPHRD_APPLETLK 8               /* APPLEtalk                    */
+/* Dummy types for non ARP hardware */
+#define ARPHRD_SLIP    256
+#define ARPHRD_CSLIP   257
+#define ARPHRD_SLIP6   258
+#define ARPHRD_CSLIP6  259
+#define ARPHRD_RSRVD   260             /* Notional KISS type           */
+#define ARPHRD_ADAPT   264
+#define ARPHRD_PPP     512
+#define ARPHRD_TUNNEL  768             /* IPIP tunnel                  */
+#define ARPHRD_TUNNEL6 769             /* IPIP6 tunnel                 */
+#define ARPHRD_FRAD    770             /* Frame Relay                  */
+#define ARPHRD_SKIP    771             /* SKIP vif                     */
+
+/* ARP protocol opcodes. */
+#define        ARPOP_REQUEST   1               /* ARP request                  */
+#define        ARPOP_REPLY     2               /* ARP reply                    */
+#define        ARPOP_RREQUEST  3               /* RARP request                 */
+#define        ARPOP_RREPLY    4               /* RARP reply                   */
+
+
+/* ARP ioctl request. */
+struct arpreq {
+  struct sockaddr      arp_pa;         /* protocol address             */
+  struct sockaddr      arp_ha;         /* hardware address             */
+  int                  arp_flags;      /* flags                        */
+  struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */
+  char                 arp_dev[16];
+};
+
+struct arpreq_old {
+  struct sockaddr      arp_pa;         /* protocol address             */
+  struct sockaddr      arp_ha;         /* hardware address             */
+  int                  arp_flags;      /* flags                        */
+  struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */
+};
+
+/* ARP Flag values. */
+#define ATF_COM                0x02            /* completed entry (ha valid)   */
+#define        ATF_PERM        0x04            /* permanent entry              */
+#define        ATF_PUBL        0x08            /* publish entry                */
+#define        ATF_USETRAILERS 0x10            /* has requested trailers       */
+#define ATF_NETMASK     0x20            /* want to use a netmask (only
+                                          for proxy entries) */
+
+/*
+ *     This structure defines an ethernet arp header.
+ */
+
+struct arphdr
+{
+       unsigned short  ar_hrd;         /* format of hardware address   */
+       unsigned short  ar_pro;         /* format of protocol address   */
+       unsigned char   ar_hln;         /* length of hardware address   */
+       unsigned char   ar_pln;         /* length of protocol address   */
+       unsigned short  ar_op;          /* ARP opcode (command)         */
+
+#if 0
+        /*
+         *      Ethernet looks like this : This bit is variable sized however...
+         */
+       unsigned char           ar_sha[ETH_ALEN];       /* sender hardware address      */
+       unsigned char           ar_sip[4];              /* sender IP address            */
+       unsigned char           ar_tha[ETH_ALEN];       /* target hardware address      */
+       unsigned char           ar_tip[4];              /* target IP address            */
+#endif
+
+};
+
+#endif /* _LINUX_IF_ARP_H */
index ebf3ea36d732c307e67f8d380625bf87ddf06329..5f21d9447d886749c069caa9423a3ddb184c1cca 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: if_ppp.h,v 1.3 1995/06/12 11:36:50 paulus Exp $    */
+/*     $Id: if_ppp.h,v 1.4 1995/12/18 03:38:01 paulus Exp $    */
 
 /*
  * if_ppp.h - Point-to-Point Protocol definitions.
 
 /*
  * if_ppp.h - Point-to-Point Protocol definitions.
  */
 
 /*
  */
 
 /*
- *  ==PPPVERSION 2.1.3==
+ *  ==FILEVERSION 6==
  *
  *  NOTE TO MAINTAINERS:
  *
  *  NOTE TO MAINTAINERS:
- *     If you modify this file at all, increment the last number above.
- *     ppp.c is shipped with a PPP distribution as well as with the kernel;
- *     if everyone increases the PPPVERSION number above, then scripts
- *     can do the right thing when deciding whether to install a new ppp.c
+ *     If you modify this file at all, increment the number above.
+ *     if_ppp.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new if_ppp.h
  *     file.  Don't change the format of that line otherwise, so the
  *     installation script can recognize it.
  */
  *     file.  Don't change the format of that line otherwise, so the
  *     installation script can recognize it.
  */
 #ifndef _IF_PPP_H_
 #define _IF_PPP_H_
 
 #ifndef _IF_PPP_H_
 #define _IF_PPP_H_
 
+#if defined(__linux__)
+#include <linux/if.h>
+#include <linux/ioctl.h>
+#include <linux/ppp_defs.h>
+#endif
+
 /*
  * Packet sizes
  */
 /*
  * Packet sizes
  */
@@ -44,6 +50,8 @@
 #define PPP_VERSION    "2.2.0"
 #define PPP_MAGIC      0x5002  /* Magic value for the ppp structure */
 #define PROTO_IPX      0x002b  /* protocol numbers */
 #define PPP_VERSION    "2.2.0"
 #define PPP_MAGIC      0x5002  /* Magic value for the ppp structure */
 #define PROTO_IPX      0x002b  /* protocol numbers */
+#define PROTO_DNA_RT    0x0027  /* DNA Routing */
+
 
 /*
  * Bit definitions for flags.
 
 /*
  * Bit definitions for flags.
@@ -96,11 +104,18 @@ struct ppp_option_data {
 };
 
 struct ifpppstatsreq {
 };
 
 struct ifpppstatsreq {
-    char ifr__name[IFNAMSIZ];          /* Name of the device */
-    struct ppp_stats *stats_ptr;       /* Pointer to stats buffer */
-    struct ppp_stats stats;            /* statistic information */
+  struct ifreq    b;
+  struct ppp_stats stats;                      /* statistic information */
 };
 
 };
 
+struct ifpppcstatsreq {
+  struct ifreq         b;
+  struct ppp_comp_stats stats;
+};
+
+#define ifr__name       b.ifr_ifrn.ifrn_name
+#define stats_ptr       b.ifr_ifru.ifru_data
+
 /*
  * Ioctl definitions.
  */
 /*
  * Ioctl definitions.
  */
@@ -121,13 +136,13 @@ struct ifpppstatsreq {
 #define PPPIOCSCOMPRESS        _IOW('t', 77, struct ppp_option_data)
 #define PPPIOCGNPMODE  _IOWR('t', 76, struct npioctl) /* get NP mode */
 #define PPPIOCSNPMODE  _IOW('t', 75, struct npioctl)  /* set NP mode */
 #define PPPIOCSCOMPRESS        _IOW('t', 77, struct ppp_option_data)
 #define PPPIOCGNPMODE  _IOWR('t', 76, struct npioctl) /* get NP mode */
 #define PPPIOCSNPMODE  _IOW('t', 75, struct npioctl)  /* set NP mode */
-
 #define PPPIOCGDEBUG   _IOR('t', 65, int)      /* Read debug level */
 #define PPPIOCSDEBUG   _IOW('t', 64, int)      /* Set debug level */
 #define PPPIOCGDEBUG   _IOR('t', 65, int)      /* Read debug level */
 #define PPPIOCSDEBUG   _IOW('t', 64, int)      /* Set debug level */
-#define PPPIOCGTIME    _IOR('t', 63, struct ppp_ddinfo) /* Read time info */
+#define PPPIOCGIDLE    _IOR('t', 63, struct ppp_idle) /* get idle time */
 
 #define SIOCGPPPSTATS   (SIOCDEVPRIVATE + 0)
 
 #define SIOCGPPPSTATS   (SIOCDEVPRIVATE + 0)
-#define SIOCGPPPVER     (SIOCDEVPRIVATE + 1)
+#define SIOCGPPPVER     (SIOCDEVPRIVATE + 1)  /* NEVER change this!! */
+#define SIOCGPPPCSTATS  (SIOCDEVPRIVATE + 2)
 
 #if !defined(ifr_mtu)
 #define ifr_mtu        ifr_ifru.ifru_metric
 
 #if !defined(ifr_mtu)
 #define ifr_mtu        ifr_ifru.ifru_metric
index 89be343e4f41e18b7da2967be3743c579e163c81..8d3dfc355d315a0b234e5907eb3c4f1692c39981 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp $ */
+/*     $Id: if_pppvar.h,v 1.3 1995/12/18 03:38:02 paulus Exp $ */
 /*
  * if_pppvar.h - private structures and declarations for PPP.
  *
 /*
  * if_pppvar.h - private structures and declarations for PPP.
  *
  */
 
 /*
  */
 
 /*
- *  ==PPPVERSION 2.1.3==
+ *  ==FILEVERSION 4==
  *
  *  NOTE TO MAINTAINERS:
  *
  *  NOTE TO MAINTAINERS:
- *     If you modify this file at all, increment the last number above.
- *     ppp.c is shipped with a PPP distribution as well as with the kernel;
- *     if everyone increases the PPPVERSION number above, then scripts
- *     can do the right thing when deciding whether to install a new ppp.c
+ *     If you modify this file at all, increment the number above.
+ *     if_pppvar.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new if_pppvar.h
  *     file.  Don't change the format of that line otherwise, so the
  *     installation script can recognize it.
  */
  *     file.  Don't change the format of that line otherwise, so the
  *     installation script can recognize it.
  */
  * Buffers for the PPP process have the following structure
  */
 
  * Buffers for the PPP process have the following structure
  */
 
-#define RBUFSIZE 2048   /* MUST be a power of 2 and be <= 4095 */
+#define RBUFSIZE  2048           /* MUST be a power of 2 and be <= 4095 */
+
 struct ppp_buffer {
   int                  size;           /* Size of the buffer area      */
   int                  count;          /* Count of characters in bufr  */
   int                  head;           /* index to head of list        */
   int                  tail;           /* index to tail of list        */
 struct ppp_buffer {
   int                  size;           /* Size of the buffer area      */
   int                  count;          /* Count of characters in bufr  */
   int                  head;           /* index to head of list        */
   int                  tail;           /* index to tail of list        */
-  int                  locked;         /* Buffer is being sent         */
+  unsigned long                locked;         /* Buffer is being sent         */
   int                  type;           /* Type of the buffer           */
                                        /* =0, device read buffer       */
                                        /* =1, device write buffer      */
                                        /* =2, daemon write buffer      */
                                        /* =3, daemon read buffer       */
   unsigned short       fcs;            /* Frame Check Sequence (CRC)   */
   int                  type;           /* Type of the buffer           */
                                        /* =0, device read buffer       */
                                        /* =1, device write buffer      */
                                        /* =2, daemon write buffer      */
                                        /* =3, daemon read buffer       */
   unsigned short       fcs;            /* Frame Check Sequence (CRC)   */
+  unsigned char         filler[4];      /* Extra space if needed        */
 };
 
 /* Given a pointer to the ppp_buffer then return base address of buffer */
 };
 
 /* Given a pointer to the ppp_buffer then return base address of buffer */
@@ -100,7 +102,7 @@ struct ppp {
        ext_accm        xmit_async_map; /* 1 bit means that given control 
                                           character is quoted on output*/
 
        ext_accm        xmit_async_map; /* 1 bit means that given control 
                                           character is quoted on output*/
 
-       unsigned long   recv_async_map; /* 1 bit means that given control 
+       __u32           recv_async_map; /* 1 bit means that given control 
                                           character is ignored on input*/
        int                     mtu;    /* maximum xmit frame size      */
        int                     mru;    /* maximum receive frame size   */
                                           character is ignored on input*/
        int                     mtu;    /* maximum xmit frame size      */
        int                     mru;    /* maximum receive frame size   */
@@ -122,7 +124,7 @@ struct ppp {
        struct ppp_buffer *s1buf;       /* Pointer to daemon buffer     */
        struct ppp_buffer *s2buf;       /* Pointer to device buffer     */
 
        struct ppp_buffer *s1buf;       /* Pointer to daemon buffer     */
        struct ppp_buffer *s2buf;       /* Pointer to device buffer     */
 
-       unsigned long     last_xmit;    /* time of last transmission    */
+       __u32             last_xmit;    /* time of last transmission    */
 
   /* These are pointers to the malloc()ed frame buffers.
      These buffers are used while processing a packet. If a packet
 
   /* These are pointers to the malloc()ed frame buffers.
      These buffers are used while processing a packet. If a packet
@@ -140,8 +142,8 @@ struct ppp {
        struct wait_queue *read_wait;   /* queue for writing processes  */
 
   /* Statistic information */
        struct wait_queue *read_wait;   /* queue for writing processes  */
 
   /* Statistic information */
-       struct pppstat    stats;        /* statistic information        */
-       struct ppp_ddinfo ddinfo;       /* demand dial information      */
+       struct pppstat        stats;    /* statistic information        */
+       struct ppp_idle       ddinfo;   /* demand dial information      */
 
   /* PPP compression protocol information */
        u_int   sc_bytessent;             /* count of octets sent */
 
   /* PPP compression protocol information */
        u_int   sc_bytessent;             /* count of octets sent */
diff --git a/linux/kinstall.sh b/linux/kinstall.sh
new file mode 100755 (executable)
index 0000000..06ea13b
--- /dev/null
@@ -0,0 +1,270 @@
+#!/bin/sh
+#
+#  kinstall.sh -- install updated kernel PPP driver in Linux kernel source
+#     Michael Callahan callahan@maths.ox.ac.uk 17 May 1995
+#
+#  This script is complicated because we want to avoid installing a driver
+#  in a kernel if it won't work in that kernel.  This means two things:
+#    1) we check the version of the kernel and refuse to install if the
+#       kernel is too old;
+#    2) we check that the files already in the kernel aren't more recent
+#       than the one we're about to install.
+#  If either 1) or 2) occurs then we exit with an error message and don't
+#  touch anything.
+#
+#  In addition, we have to edit the Makefile in the drivers/net
+#  directory to add support for the ppp-comp compression option.
+#
+#  Finally, we have to check that certain include file stubs in
+#  /usr/include/net exist, or else pppd won't compile.  Phew!
+
+LINUXSRC=/usr/src/linux
+
+if [ $# -gt 1 ]; then
+   echo usage: $0 [linux-source-directory]
+   exit 1
+fi
+
+if [ $# -eq 1 ]; then
+   LINUXSRC=$1
+fi
+
+#
+#  Make sure we can find the kernel source
+
+LINUXMK=$LINUXSRC/Makefile
+
+if [ ! -r $LINUXMK -o ! -d $LINUXSRC/drivers ]; then
+  echo There appears to be no kernel source distribution in $LINUXSRC.
+  echo Give the top-level kernel source directory as the argument to
+  echo this script.
+  echo usage: $0 [linux-source-directory]
+  exit 1
+fi
+
+#
+#  Check that the kernel source Makefile includes the 
+#    VERSION, PATCHLEVEL, SUBLEVEL version-numbering scheme
+#    introduced in 1.0.1
+if [ `egrep '^VERSION|^PATCHLEVEL|^SUBLEVEL' $LINUXMK | wc -l` -ne 3 ]; then
+  echo You appear to have a very old kernel. You must upgrade.
+  echo It is recommended that you upgrade to the most recent 1.2.X kernel.
+  exit 1
+fi
+
+#
+#  Set the VERSION, PATCHLEVEL, SUBLEVEL variables
+VERSION=`egrep '^VERSION' $LINUXMK | sed 's/[^0-9]//g'`
+PATCHLEVEL=`egrep '^PATCHLEVEL' $LINUXMK | sed 's/[^0-9]//g'`
+SUBLEVEL=`egrep '^SUBLEVEL' $LINUXMK | sed 's/[^0-9]//g'`
+
+KERNEL=$VERSION.$PATCHLEVEL.$SUBLEVEL
+
+#
+#  Pass judgement on the kernel version
+if [ $VERSION -eq 1 ]; then
+  if [ $PATCHLEVEL -eq 0 -o $PATCHLEVEL -eq 1 -a $SUBLEVEL -lt 14 ]; then
+    echo You appear to be running $KERNEL. There is no support for
+    echo kernels predating 1.1.14.  It is recommended that you upgrade
+    echo to the most recent 1.2.X kernel.
+    exit 1
+  fi
+  if [ $PATCHLEVEL -eq 1 ]; then
+    echo You appear to be running $KERNEL. It is recommended that you
+    echo upgrade to the most recent 1.2.X kernel.
+    echo However, installation will proceed.
+  fi
+fi
+
+echo
+echo Installing into kernel version $KERNEL in $LINUXSRC
+echo
+
+#
+# convenience function to exit if the last command failed
+
+function bombiffailed () {
+  STATUS=$?
+  if [ $STATUS -ne 0 ]; then
+    echo "=== kinstall.sh exiting with failure status $STATUS"
+    exit $STATUS
+  fi
+}
+
+#
+# convenience function to compare two files marked with ==FILEVERSION
+# version numbers; returns success if $1 is newer than $2
+
+function newer () {
+  if [ -r $1 ] && f1rev=`fgrep "==FILEVERSION " $1 | sed 's/[^0-9]//g'`; then
+    if [ -r $2 ] && f2rev=`fgrep "==FILEVERSION " $2 | sed 's/[^0-9]//g'`; then
+      if [ "$f1rev" != "" ]; then
+        # return true if f2rev is empty or f1rev => f2rev
+        [ "$f2rev" = "" ] || [ $f1rev -ge $f2rev ]
+      else
+        # f1rev is empty, so false
+        false
+      fi
+    else
+      true  # no FILEVERSION in $2, so $1 is newer
+    fi
+  else
+    false  # no FILEVERSION in $1, so not newer
+  fi
+}
+
+#
+#  Change the USE_SKB_PROTOCOL for correct operation on 1.3.x
+function update_ppp () {
+  mv $LINUXSRC/drivers/net/ppp.c $LINUXSRC/drivers/net/ppp.c.in
+  if [ "$VERSION.$PATCHLEVEL" = "1.3" ]; then
+    sed 's/#define USE_SKB_PROTOCOL 0/#define USE_SKB_PROTOCOL 1/' <$LINUXSRC/drivers/net/ppp.c.in >$LINUXSRC/drivers/net/ppp.c
+  else
+    sed 's/#define USE_SKB_PROTOCOL 1/#define USE_SKB_PROTOCOL 0/' <$LINUXSRC/drivers/net/ppp.c.in >$LINUXSRC/drivers/net/ppp.c
+  fi
+  rm $LINUXSRC/drivers/net/ppp.c.in
+}
+
+#
+#  Install the files.
+
+function installfile () {
+  BASE=`basename $1`
+  if newer $1 $BASE; then
+    echo $1 is newer than $BASE, skipping
+    return 0
+  fi
+  BACKUP=`echo $1 | sed 's/.c$/.old.c/;s/.h$/.old.h/'`
+  if [ -f $1 -a $BACKUP != $1 ]; then
+    echo Saving old $1 as `basename $BACKUP`
+    mv $1 $BACKUP
+    bombiffailed
+  fi
+  echo Installing new $1
+  cp $BASE $1
+  bombiffailed
+  touch $1
+  bombiffailed
+  if [ "$2" = "yes" ]; then
+    update_ppp
+  fi
+}
+
+if [ -f $LINUXSRC/drivers/net/ppp.h ]; then
+  echo Moving old $LINUXSRC/drivers/net/ppp.h file out of the way
+  mv $LINUXSRC/drivers/net/ppp.h $LINUXSRC/drivers/net/ppp.old.h
+  bombiffailed
+fi
+
+for FILE in $LINUXSRC/drivers/net/bsd_comp.c \
+            $LINUXSRC/include/linux/if_ppp.h \
+            $LINUXSRC/include/linux/if_pppvar.h \
+            $LINUXSRC/include/linux/ppp-comp.h \
+            $LINUXSRC/include/linux/ppp_defs.h
+  do
+  installfile $FILE no
+done
+
+installfile $LINUXSRC/drivers/net/ppp.c yes
+
+for FILE in if.h if_arp.h route.h
+  do
+  if [ ! -f $LINUXSRC/include/linux/$FILE ]; then
+    echo Installing new $1
+    cp $FILE $LINUXSRC/include/linux/$FILE
+    bombiffailed
+    touch $LINUXSRC/include/linux/$FILE
+    bombiffailed
+  fi
+done
+
+echo -n 'Adding BSD compression module to drivers makefile...'
+NETMK=$LINUXSRC/drivers/net/Makefile
+fgrep bsd_comp.o $NETMK >/dev/null
+if [ ! "$?" = "0" ]; then
+   echo -n '.'
+   rm -f $NETMK.orig $NETMK.rej
+   if [ "$VERSION.$PATCHLEVEL" = "1.2" ]; then
+      (cd $LINUXSRC; patch -p1 -f -F30 -s) <patch-1.2
+      if [ ! "$?" = "0" ]; then
+         touch $NETMK.rej
+      fi
+   else
+      if [ "$VERSION.$PATCHLEVEL" = "1.3" ]; then
+         (cd $LINUXSRC; patch -p1 -f -F30 -s) <patch-1.3
+         if [ ! "$?" = "0" ]; then
+            touch $NETMK.rej
+         fi
+      else
+         touch $NETMK.rej
+      fi
+   fi
+#
+   if [ -e $NETMK.rej ]; then
+      rm -f $NETMK.rej
+      if [ -e $NETMK.orig ]; then
+         mv $NETMK.orig $NETMK
+      fi
+      sed 's/ppp.o$/ppp.o bsd_comp.o/g' <$NETMK >$NETMK.temp
+      bombiffailed
+      echo -n '.'
+      mv $NETMK $NETMK.orig
+      bombiffailed
+      echo -n '.'
+      mv $NETMK.temp $NETMK
+      bombiffailed
+   fi
+#
+   if [ -e $NETMK.orig ]; then
+      mv $NETMK.orig $NETMK.old
+   fi
+else
+   echo -n '(already there--skipping)'
+fi
+echo
+
+#
+# install header stub files in /usr/include/net
+
+for FILE in if_ppp.h \
+            if_pppvar.h \
+            ppp-comp.h \
+           if.h \
+            if_arp.h \
+           route.h \
+            ppp_defs.h
+  do
+  if [ ! -f /usr/include/net/$FILE ]; then
+    echo Installing stub include file in /usr/include/net/$FILE
+    echo "#include <linux/$FILE>" > /usr/include/net/$FILE
+    bombiffailed
+    chown 0:0 /usr/include/net/$FILE
+    bombiffailed
+    chmod 444 /usr/include/net/$FILE
+    bombiffailed
+    touch /usr/include/net/$FILE
+    bombiffailed
+  fi
+done
+
+for FILE in ip.h \
+           tcp.h
+  do
+  if [ ! -f /usr/include/netinet/$FILE ]; then
+    echo Installing stub include file in /usr/include/netinet/$FILE
+    if [ ! -f $LINUXSRC/include/linux/$FILE ]; then
+      echo "#include \"$LINUXSRC/net/inet/$FILE\"" >/usr/include/netinet/$FILE
+    else
+      echo "#include <linux/$FILE>" > /usr/include/netinet/$FILE
+    fi
+    chown 0:0 /usr/include/netinet/$FILE
+    bombiffailed
+    chmod 444 /usr/include/netinet/$FILE
+    bombiffailed
+    touch /usr/include/netinet/$FILE
+    bombiffailed
+  fi
+done
+
+echo "Kernel driver files installation done."
+exit 0
diff --git a/linux/patch-1.2 b/linux/patch-1.2
new file mode 100644 (file)
index 0000000..4796a6a
--- /dev/null
@@ -0,0 +1,23 @@
+This file is used by the 'make kernel' function. It will apply the patch
+to the drivers/net/Makefile to install the bsd_comp.c file into the list
+of files needed to build the kernel.
+
+This file is for the 1.2 kernel.
+
+--- linux/drivers/net/Makefile.orig    Sun Oct  8 17:07:23 1995
++++ linux/drivers/net/Makefile Sun Oct  8 17:10:25 1995
+@@ -85,12 +85,14 @@
+ NETDRV_OBJS := $(NETDRV_OBJS) ppp.o
+ CONFIG_SLHC = CONFIG_SLHC
+ else
+ MODULES := $(MODULES) ppp.o
+ endif
++MODULES := $(MODULES) bsd_comp.o
++
+ ifdef CONFIG_SLIP
+ NETDRV_OBJS := $(NETDRV_OBJS) slip.o
+ CONFIG_SLHC = CONFIG_SLHC
+ else
+ MODULES := $(MODULES) slip.o
+ endif
diff --git a/linux/patch-1.3 b/linux/patch-1.3
new file mode 100644 (file)
index 0000000..74d7437
--- /dev/null
@@ -0,0 +1,23 @@
+This file is used by the 'make kernel' function. It will apply the patch
+to the drivers/net/Makefile to install the bsd_comp.c file into the list
+of files needed to build the kernel.
+
+This file is for the 1.3 kernel.
+
+--- linux-1.3.32.ORIG/drivers/net/Makefile     Fri Sep  8 23:37:24 1995
++++ linux-1.3.32/drivers/net/Makefile  Sun Sep 24 19:41:35 1995
+@@ -137,10 +137,14 @@
+   CONFIG_SLHC_MODULE = y
+   M_OBJS += ppp.o
+   endif
+ endif
++ifneq ($(CONFIG_PPP),n)
++  M_OBJS += bsd_comp.o
++endif
++
+ ifeq ($(CONFIG_SLIP),y)
+ L_OBJS += slip.o
+ CONFIG_SLHC_BUILTIN = y
+ else
+   ifeq ($(CONFIG_SLIP),m)
diff --git a/linux/ppp-comp.h b/linux/ppp-comp.h
new file mode 100644 (file)
index 0000000..b72da19
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * ppp-comp.h - Definitions for doing PPP packet compression.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp-comp.h,v 1.1 1995/12/18 03:38:10 paulus Exp $
+ */
+
+/*
+ *  ==FILEVERSION 4==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     ppp-comp.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new ppp-comp.h
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
+
+#ifndef _NET_PPP_COMP_H
+#define _NET_PPP_COMP_H
+
+/*
+ * The following symbols control whether we include code for
+ * various compression methods.
+ */
+
+#ifndef DO_BSD_COMPRESS
+#define DO_BSD_COMPRESS        1       /* by default, include BSD-Compress */
+#endif
+
+#define DO_PREDICTOR_1 0
+#define DO_PREDICTOR_2 0
+#define DO_DEFLATE     0
+
+/*
+ * Structure giving methods for compression/decompression.
+ */
+
+#ifdef PACKETPTR
+struct compressor {
+       int     compress_proto; /* CCP compression protocol number */
+
+       /* Allocate space for a compressor (transmit side) */
+       void    *(*comp_alloc) (unsigned char *options, int opt_len);
+
+       /* Free space used by a compressor */
+       void    (*comp_free) (void *state);
+
+       /* Initialize a compressor */
+       int     (*comp_init) (void *state, unsigned char *options,
+                             int opt_len, int unit, int opthdr, int debug);
+
+       /* Reset a compressor */
+       void    (*comp_reset) (void *state);
+
+       /* Compress a packet */
+       int     (*compress) (void *state, unsigned char *rptr,
+                             unsigned char *obuf, int isize, int osize);
+
+       /* Return compression statistics */
+       void    (*comp_stat) (void *state, struct compstat *stats);
+
+       /* Allocate space for a decompressor (receive side) */
+       void    *(*decomp_alloc) (unsigned char *options, int opt_len);
+
+       /* Free space used by a decompressor */
+       void    (*decomp_free) (void *state);
+
+       /* Initialize a decompressor */
+       int     (*decomp_init) (void *state, unsigned char *options,
+                               int opt_len, int unit, int opthdr, int mru,
+                               int debug);
+
+       /* Reset a decompressor */
+       void    (*decomp_reset) (void *state);
+
+       /* Decompress a packet. */
+       int     (*decompress) (void *state, unsigned char *ibuf, int isize,
+                               unsigned char *obuf, int osize);
+
+       /* Update state for an incompressible packet received */
+       void    (*incomp) (void *state, unsigned char *ibuf, int icnt);
+
+       /* Return decompression statistics */
+       void    (*decomp_stat) (void *state, struct compstat *stats);
+};
+#endif /* PACKETPTR */
+
+/*
+ * Return values for decompress routine.
+ * We need to make these distinctions so that we can disable certain
+ * useful functionality, namely sending a CCP reset-request as a result
+ * of an error detected after decompression.  This is to avoid infringing
+ * a patent held by Motorola.
+ * Don't you just lurve software patents.
+ */
+
+#define DECOMP_OK              0       /* everything went OK */
+#define DECOMP_ERROR           1       /* error detected before decomp. */
+#define DECOMP_FATALERROR      2       /* error detected after decomp. */
+
+/*
+ * CCP codes.
+ */
+
+#define CCP_CONFREQ    1
+#define CCP_CONFACK    2
+#define CCP_TERMREQ    5
+#define CCP_TERMACK    6
+#define CCP_RESETREQ   14
+#define CCP_RESETACK   15
+
+/*
+ * Max # bytes for a CCP option
+ */
+
+#define CCP_MAX_OPTION_LENGTH  32
+
+/*
+ * Parts of a CCP packet.
+ */
+
+#define CCP_CODE(dp)           ((dp)[0])
+#define CCP_ID(dp)             ((dp)[1])
+#define CCP_LENGTH(dp)         (((dp)[2] << 8) + (dp)[3])
+#define CCP_HDRLEN             4
+
+#define CCP_OPT_CODE(dp)       ((dp)[0])
+#define CCP_OPT_LENGTH(dp)     ((dp)[1])
+#define CCP_OPT_MINLEN         2
+
+/*
+ * Definitions for BSD-Compress.
+ */
+
+#define CI_BSD_COMPRESS                21      /* config. option for BSD-Compress */
+#define CILEN_BSD_COMPRESS     3       /* length of config. option */
+
+/* Macros for handling the 3rd byte of the BSD-Compress config option. */
+#define BSD_NBITS(x)           ((x) & 0x1F)    /* number of bits requested */
+#define BSD_VERSION(x)         ((x) >> 5)      /* version of option format */
+#define BSD_CURRENT_VERSION    1               /* current version number */
+#define BSD_MAKE_OPT(v, n)     (((v) << 5) | (n))
+
+#define BSD_MIN_BITS           9       /* smallest code size supported */
+#define BSD_MAX_BITS           15      /* largest code size supported */
+
+/*
+ * Definitions for other, as yet unsupported, compression methods.
+ */
+
+#define CI_PREDICTOR_1         1       /* config option for Predictor-1 */
+#define CILEN_PREDICTOR_1      2       /* length of its config option */
+#define CI_PREDICTOR_2         2       /* config option for Predictor-2 */
+#define CILEN_PREDICTOR_2      2       /* length of its config option */
+
+#define CI_DEFLATE             24      /* config option for Deflate */
+#define CILEN_DEFLATE          4       /* length of its config option */
+
+#define DEFLATE_MIN_SIZE       8
+#define DEFLATE_MAX_SIZE       15
+#define DEFLATE_METHOD_VAL     8
+#define DEFLATE_SIZE(x)                (((x) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x)      ((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w)    ((((w) - DEFLATE_MIN_SIZE) << 4) \
+                                + DEFLATE_METHOD_VAL)
+#define DEFLATE_CHK_SEQUENCE   0
+
+#endif /* _NET_PPP_COMP_H */
index cd7e605ac1bf771bfa91847f3fc3819c99165e71..71b6b4c716bd57cde138e7bafe84306292770ef7 100644 (file)
@@ -1,16 +1,20 @@
-/*
- *  PPP for Linux
+/*  PPP for Linux
+ *
+ *  Michael Callahan <callahan@maths.ox.ac.uk>
+ *  Al Longyear <longyear@netcom.com>
  *
  *
- *  ==PPPVERSION 2.1.3==
+ *  Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
+ *  ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
+ *
+ *  ==FILEVERSION 8==
  *
  *  NOTE TO MAINTAINERS:
  *
  *  NOTE TO MAINTAINERS:
- *     If you modify this file at all, increment the last number above.
+ *     If you modify this file at all, increment the number above.
  *     ppp.c is shipped with a PPP distribution as well as with the kernel;
  *     ppp.c is shipped with a PPP distribution as well as with the kernel;
- *     if everyone increases the PPPVERSION number above, then scripts
+ *     if everyone increases the FILEVERSION number above, then scripts
  *     can do the right thing when deciding whether to install a new ppp.c
  *     file.  Don't change the format of that line otherwise, so the
  *     installation script can recognize it.
  *     can do the right thing when deciding whether to install a new ppp.c
  *     file.  Don't change the format of that line otherwise, so the
  *     installation script can recognize it.
- *
  */
 
 /*
  */
 
 /*
 
    OPTIMIZE_FLAG_TIME - Number of jiffies to force sending of leading flag
                        character. This is normally set to ((HZ * 3) / 2).
 
    OPTIMIZE_FLAG_TIME - Number of jiffies to force sending of leading flag
                        character. This is normally set to ((HZ * 3) / 2).
-                       This is 1.5 seconds. If not defined then the leading
+                       This is 1.5 seconds. If zero then the leading
                        flag is always sent.
 
    CHECK_CHARACTERS   - Enable the checking on all received characters for
                        8 data bits, no parity. This adds a small amount of
                        processing for each received character.
                        flag is always sent.
 
    CHECK_CHARACTERS   - Enable the checking on all received characters for
                        8 data bits, no parity. This adds a small amount of
                        processing for each received character.
-
-   PPP_COMPRESS              - Enable the PPP compression protocol. This protocol
-                       is under contention with Motorolla's patent, so use
-                       with caution.
                        
    NEW_SKBUFF        - Use NET3.020 sk_buff's
                        
    NEW_SKBUFF        - Use NET3.020 sk_buff's
+
+   IPX_CHANGE         - Force the use of IPX support into the driver.
+                       THIS IS **VERY** ALPHA LEVEL CODE!!!!
 */
 
 /* #define NEW_SKBUFF          1 */
 #define OPTIMIZE_FLAG_TIME     ((HZ * 3)/2)
 */
 
 /* #define NEW_SKBUFF          1 */
 #define OPTIMIZE_FLAG_TIME     ((HZ * 3)/2)
+
 #define CHECK_CHARACTERS       1
 #define PPP_COMPRESS           1
 #define CHECK_CHARACTERS       1
 #define PPP_COMPRESS           1
+#define USE_SKB_PROTOCOL 1  /* Set by the installation program! */
 
 
-/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp $
+#ifdef  NEW_SKBUFF
+#undef  USE_SKB_PROTOCOL
+#define USE_SKB_PROTOCOL 2
+#endif
+
+#ifndef PPP_MAX_DEV
+#define PPP_MAX_DEV    256
+#endif
+
+#undef  IPX_CHANGE
+
+#if defined(IPX_CHANGE) || defined(NEW_SKBUFF)
+#define PPP_REQUESTED_HDR_LEN   PPP_HARD_HDR_LEN
+#else
+#define PPP_REQUESTED_HDR_LEN   0
+#endif
+
+/* $Id: ppp.c,v 1.6 1995/12/18 03:38:12 paulus Exp $
  * Added dynamic allocation of channels to eliminate
  *   compiled-in limits on the number of channels.
  *
  * Added dynamic allocation of channels to eliminate
  *   compiled-in limits on the number of channels.
  *
  *   released under the GNU General Public License Version 2.
  */
 
  *   released under the GNU General Public License Version 2.
  */
 
+#if USE_SKB_PROTOCOL == 0
+#include <linux/config.h>  /* still needed for 1.2 */
+#endif
+#include <linux/module.h>
+
+#ifndef MOD_INC_USE_COUNT  /* for those 1.2 kernels still out there */
+#undef  MOD_DEC_USE_COUNT
+#define MOD_DEC_USE_COUNT   do {} while (0)
+#define MOD_INC_USE_COUNT   do {} while (0)
+#endif
+
+#include <endian.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <asm/bitops.h>
 #include <asm/segment.h>
 #include <net/if.h>
 #include <asm/bitops.h>
 #include <asm/segment.h>
 #include <net/if.h>
-#include <net/if_arp.h>
-#include <net/if_route.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #ifdef NEW_SKBUFF
 #include <linux/netprotocol.h>
 #else
 #ifdef NEW_SKBUFF
 #include <linux/netprotocol.h>
 #else
-#define skb_data(skb)  ((unsigned char *) (skb)->data)
-typedef struct sk_buff sk_buff;
+typedef struct sk_buff      sk_buff;
+#define skb_data(skb)       ((unsigned char *) (skb)->data)
 #endif
 
 #endif
 
-#include <ip.h>
-#include <tcp.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
 #include <linux/if_arp.h>
 #include "slhc.h"
 #include <linux/if_arp.h>
 #include "slhc.h"
-#include <net/ppp_defs.h>
+#include <linux/ppp_defs.h>
 #include <linux/socket.h>
 #include <linux/socket.h>
-#include <net/if_ppp.h>
-#include <net/if_pppvar.h>
-
-#ifdef MODULE
-#include <linux/module.h>
-#include <linux/version.h>
-#define STATIC static
-#else
-#define MOD_INC_USE_COUNT while(0) { }
-#define MOD_DEC_USE_COUNT while(0) { }
-#endif /* def MODULE */
+#include <linux/if_ppp.h>
+#include <linux/if_pppvar.h>
 
 
-#ifdef PPP_COMPRESS
 #undef   PACKETPTR
 #define  PACKETPTR 1
 #undef   PACKETPTR
 #define  PACKETPTR 1
-#include <net/ppp-comp.h>
+#include <linux/ppp-comp.h>
 #undef   PACKETPTR
 
 #define bsd_decompress (*ppp->sc_rcomp->decompress)
 #define bsd_compress   (*ppp->sc_xcomp->compress)
 #undef   PACKETPTR
 
 #define bsd_decompress (*ppp->sc_rcomp->decompress)
 #define bsd_compress   (*ppp->sc_xcomp->compress)
-#endif
 
 #ifndef PPP_IPX
 #define PPP_IPX 0x2b  /* IPX protocol over PPP */
 
 #ifndef PPP_IPX
 #define PPP_IPX 0x2b  /* IPX protocol over PPP */
@@ -125,46 +146,53 @@ typedef struct sk_buff    sk_buff;
 #define PPP_LQR 0xc025  /* Link Quality Reporting Protocol */
 #endif
 
 #define PPP_LQR 0xc025  /* Link Quality Reporting Protocol */
 #endif
 
+static int ppp_register_compressor (struct compressor *cp);
+static void ppp_unregister_compressor (struct compressor *cp);
+
 /*
  * Local functions
  */
 
 /*
  * Local functions
  */
 
+static struct compressor *find_compressor (int type);
 static void ppp_init_ctrl_blk (register struct ppp *);
 static void ppp_kick_tty (struct ppp *, struct ppp_buffer *bfr);
 static int ppp_doframe (struct ppp *);
 static struct ppp *ppp_alloc (void);
 static void ppp_init_ctrl_blk (register struct ppp *);
 static void ppp_kick_tty (struct ppp *, struct ppp_buffer *bfr);
 static int ppp_doframe (struct ppp *);
 static struct ppp *ppp_alloc (void);
-static void ppp_print_buffer (const u_char *, u_char *, int);
+static void ppp_print_buffer (const u_char *, const u_char *, int);
 extern inline void ppp_stuff_char (struct ppp *ppp,
                                   register struct ppp_buffer *buf,
                                   register u_char chr);
 extern inline int lock_buffer (register struct ppp_buffer *buf);
 extern inline void ppp_stuff_char (struct ppp *ppp,
                                   register struct ppp_buffer *buf,
                                   register u_char chr);
 extern inline int lock_buffer (register struct ppp_buffer *buf);
-static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd);
 
 static int rcv_proto_ip         (struct ppp *, u_short, u_char *, int);
 static int rcv_proto_ipx        (struct ppp *, u_short, u_char *, int);
 static int rcv_proto_vjc_comp   (struct ppp *, u_short, u_char *, int);
 static int rcv_proto_vjc_uncomp (struct ppp *, u_short, u_char *, int);
 static int rcv_proto_unknown    (struct ppp *, u_short, u_char *, int);
 
 static int rcv_proto_ip         (struct ppp *, u_short, u_char *, int);
 static int rcv_proto_ipx        (struct ppp *, u_short, u_char *, int);
 static int rcv_proto_vjc_comp   (struct ppp *, u_short, u_char *, int);
 static int rcv_proto_vjc_uncomp (struct ppp *, u_short, u_char *, int);
 static int rcv_proto_unknown    (struct ppp *, u_short, u_char *, int);
-static int rcv_proto_ccp        (struct ppp *, u_short, u_char *, int);
 static int rcv_proto_lqr        (struct ppp *, u_short, u_char *, int);
 static void ppp_doframe_lower   (struct ppp *, u_char *, int);
 static int ppp_doframe          (struct ppp *);
 
 static int rcv_proto_lqr        (struct ppp *, u_short, u_char *, int);
 static void ppp_doframe_lower   (struct ppp *, u_char *, int);
 static int ppp_doframe          (struct ppp *);
 
-/*
- * List of compressors we know about.
- * We leave some space so maybe we can modload compressors.
- */
+extern int  ppp_bsd_compressor_init(void);
+static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd);
+static int  rcv_proto_ccp (struct ppp *, u_short, u_char *, int);
+
+#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c))
 
 
-#ifdef PPP_COMPRESS
-extern struct compressor ppp_bsd_compress;
+#ifndef OPTIMIZE_FLAG_TIME
+#define OPTIMIZE_FLAG_TIME     0
+#endif
 
 
-struct compressor *ppp_compressors[8] = {
-    &ppp_bsd_compress,
-    NULL
-};
-#endif /* PPP_COMPRESS */
+#ifndef PPP_MAX_DEV
+#define PPP_MAX_DEV 256
+#endif
 
 
-#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c))
+/*
+ * Parameters which may be changed via insmod.
+ */
+
+static int  flag_time = OPTIMIZE_FLAG_TIME;
+static int  max_dev   = PPP_MAX_DEV;
 
 /*
  * The "main" procedure to the ppp device
 
 /*
  * The "main" procedure to the ppp device
@@ -182,6 +210,29 @@ static int ppp_dev_close (struct device *);
 static int ppp_dev_xmit (sk_buff *, struct device *);
 static struct enet_statistics *ppp_dev_stats (struct device *);
 
 static int ppp_dev_xmit (sk_buff *, struct device *);
 static struct enet_statistics *ppp_dev_stats (struct device *);
 
+#if USE_SKB_PROTOCOL == 0  /* The 1.2.x kernel is here */
+#define dev_alloc_skb(count)        alloc_skb(count, GFP_ATOMIC)
+#define skb_put(skb,count)          skb_data(skb)
+#define get_long_user(addr)        get_user_long((void *) addr)
+#define get_int_user(addr)         ((int) get_user_long((void *) addr))
+#define put_byte_user(val,addr)            put_fs_byte(val,((u_char *) (addr)))
+#define put_long_user(val,addr)            put_fs_long((val),((void *) (addr)))
+
+static unsigned short ppp_dev_type (sk_buff *, struct device *);
+static int ppp_dev_header (unsigned char *buff, struct device *dev,
+                          unsigned short type, void *daddr, void *saddr,
+                          unsigned len, struct sk_buff *skb);
+
+#else /* The 1.3.x kernel is here */
+#define get_long_user(addr)        get_user(((int *) addr))
+#define get_int_user(addr)         ((int) get_user(((int *) addr)))
+#define put_byte_user(val,addr)            put_user((val),((u_char *) (addr)))
+#define put_long_user(val,addr)            put_user((val),((int *) (addr)))
+
+static int ppp_dev_header (sk_buff *, struct device *, unsigned short,
+                          void *, void *, unsigned);
+#endif
+
 #ifdef NEW_SKBUFF
 static int ppp_dev_input (struct protocol *self, struct protocol *lower,
                          sk_buff *skb, void *saddr, void *daddr);
 #ifdef NEW_SKBUFF
 static int ppp_dev_input (struct protocol *self, struct protocol *lower,
                          sk_buff *skb, void *saddr, void *daddr);
@@ -189,11 +240,8 @@ static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type,
                           int subid, void *saddr, void *daddr, void *opt);
 static int ppp_dev_getkey(int protocol, int subid, unsigned char *key);
 #else
                           int subid, void *saddr, void *daddr, void *opt);
 static int ppp_dev_getkey(int protocol, int subid, unsigned char *key);
 #else
-static int ppp_dev_header (u_char *, struct device *, unsigned short,
-                          void *, void *, unsigned, sk_buff *);
 static int ppp_dev_rebuild (void *, struct device *, unsigned long,
                            sk_buff *);
 static int ppp_dev_rebuild (void *, struct device *, unsigned long,
                            sk_buff *);
-static unsigned short ppp_dev_type (sk_buff *, struct device *);
 #endif
 
 /*
 #endif
 
 /*
@@ -202,7 +250,7 @@ static unsigned short ppp_dev_type (sk_buff *, struct device *);
 
 static int ppp_tty_read (struct tty_struct *, struct file *, u_char *,
                         unsigned int);
 
 static int ppp_tty_read (struct tty_struct *, struct file *, u_char *,
                         unsigned int);
-static int ppp_tty_write (struct tty_struct *, struct file *, u_char *,
+static int ppp_tty_write (struct tty_struct *, struct file *, const u_char *,
                          unsigned int);
 static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
                          unsigned long);
                          unsigned int);
 static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
                          unsigned long);
@@ -211,13 +259,12 @@ static int ppp_tty_select (struct tty_struct *tty, struct inode *inode,
 static int ppp_tty_open (struct tty_struct *);
 static void ppp_tty_close (struct tty_struct *);
 static int ppp_tty_room (struct tty_struct *tty);
 static int ppp_tty_open (struct tty_struct *);
 static void ppp_tty_close (struct tty_struct *);
 static int ppp_tty_room (struct tty_struct *tty);
-static void ppp_tty_receive (struct tty_struct *tty, u_char * cp,
+static void ppp_tty_receive (struct tty_struct *tty, const u_char * cp,
                             char *fp, int count);
 static void ppp_tty_wakeup (struct tty_struct *tty);
 
                             char *fp, int count);
 static void ppp_tty_wakeup (struct tty_struct *tty);
 
-#define PRINTK(p) printk p ;
-#define CHECK_PPP(a)  if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return a;}
-#define CHECK_PPP_VOID()  if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return;}
+#define CHECK_PPP(a)  if (!ppp->inuse) { printk (ppp_warning, __LINE__); return a;}
+#define CHECK_PPP_VOID()  if (!ppp->inuse) { printk (ppp_warning, __LINE__); return;}
 
 #define in_xmap(ppp,c) (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
 #define in_rmap(ppp,c) ((((unsigned int) (u_char) (c)) < 0x20) && \
 
 #define in_xmap(ppp,c) (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
 #define in_rmap(ppp,c) ((((unsigned int) (u_char) (c)) < 0x20) && \
@@ -238,7 +285,6 @@ struct ppp_hdr {
 
 #define PPP_HARD_HDR_LEN       (sizeof (struct ppp_hdr))
 
 
 #define PPP_HARD_HDR_LEN       (sizeof (struct ppp_hdr))
 
-#if 1
 typedef struct  ppp_ctrl {
        struct ppp_ctrl *next;          /* Next structure in the list   */
        char            name [8];       /* Name of the device           */
 typedef struct  ppp_ctrl {
        struct ppp_ctrl *next;          /* Next structure in the list   */
        char            name [8];       /* Name of the device           */
@@ -252,14 +298,6 @@ static ppp_ctrl_t *ppp_list = NULL;
 #define ctl2dev(ctl) (struct device *) &ctl->dev
 #undef  PPP_NRUNIT
 
 #define ctl2dev(ctl) (struct device *) &ctl->dev
 #undef  PPP_NRUNIT
 
-#else
-
-#define PPP_NRUNIT 4
-static struct ppp ppp_ctrl[PPP_NRUNIT];
-#undef  dev2ppp
-#define dev2ppp(dev)   ((struct ppp *) &ppp_ctrl[dev->base_addr])
-#endif
-
 /* Buffer types */
 #define BUFFER_TYPE_DEV_RD     0  /* ppp read buffer       */
 #define BUFFER_TYPE_TTY_WR     1  /* tty write buffer      */
 /* Buffer types */
 #define BUFFER_TYPE_DEV_RD     0  /* ppp read buffer       */
 #define BUFFER_TYPE_TTY_WR     1  /* tty write buffer      */
@@ -287,21 +325,26 @@ typedef struct ppp_proto_struct {
        pfn_proto       func;
 } ppp_proto_type;
 
        pfn_proto       func;
 } ppp_proto_type;
 
+static
 ppp_proto_type proto_list[] = {
        { PPP_IP,         rcv_proto_ip         },
        { PPP_IPX,        rcv_proto_ipx        },
        { PPP_VJC_COMP,   rcv_proto_vjc_comp   },
        { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp },
 ppp_proto_type proto_list[] = {
        { PPP_IP,         rcv_proto_ip         },
        { PPP_IPX,        rcv_proto_ipx        },
        { PPP_VJC_COMP,   rcv_proto_vjc_comp   },
        { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp },
-       { PPP_LQR,        rcv_proto_lqr       },
-#ifdef PPP_COMPRESS
+       { PPP_LQR,        rcv_proto_lqr        },
        { PPP_CCP,        rcv_proto_ccp        },
        { PPP_CCP,        rcv_proto_ccp        },
-#endif
        { 0,              rcv_proto_unknown    }  /* !!! MUST BE LAST !!! */
 };
 
        { 0,              rcv_proto_unknown    }  /* !!! MUST BE LAST !!! */
 };
 
-/* FCS table from RFC1331 */
+/*
+ * Values for FCS calculations.
+ */
 
 
-static unsigned short fcstab[256] =
+#define PPP_INITFCS    0xffff  /* Initial FCS value */
+#define PPP_GOODFCS    0xf0b8  /* Good final FCS value */
+#define PPP_FCS(fcs, c)        (((fcs) >> 8) ^ ppp_crc16_table[((fcs) ^ (c)) & 0xff])
+
+unsigned short ppp_crc16_table[256] =
 {
        0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
        0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
 {
        0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
        0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
@@ -369,35 +412,22 @@ ppp_first_time (void)
        static struct tty_ldisc ppp_ldisc;
        int    status;
 
        static struct tty_ldisc ppp_ldisc;
        int    status;
 
-#ifdef PPP_NRUNIT
-#define PPP_UNITS3(x) #x
-#define PPP_UNITS2(x) PPP_UNITS3(x)
-#define PPP_UNITS1(x) PPP_UNITS2(x)
-#define PPP_UNITS   "(" PPP_UNITS1(PPP_NRUNIT) " devices)"
-#else
-#define PPP_UNITS   "(dynamic channel allocation)"
-#endif
        printk (KERN_INFO
        printk (KERN_INFO
-               "PPP: version %s " PPP_UNITS
+               "PPP: version %s (dynamic channel allocation)"
 #ifdef NEW_SKBUFF
                " NEW_SKBUFF"
 #endif
                "\n", szVersion);
 #ifdef NEW_SKBUFF
                " NEW_SKBUFF"
 #endif
                "\n", szVersion);
-#undef PPP_UNITS
-#undef PPP_UNITS1
-#undef PPP_UNITS2
-#undef PPP_UNITS3
 
 
+#ifndef MODULE /* slhc module logic has its own copyright announcment */
        printk (KERN_INFO
                "TCP compression code copyright 1989 Regents of the "
                "University of California\n");
        printk (KERN_INFO
                "TCP compression code copyright 1989 Regents of the "
                "University of California\n");
+#endif
        
        
-#ifndef PPP_NRUNIT
        printk (KERN_INFO
                "PPP Dynamic channel allocation code copyright 1995 "
                "Caldera, Inc.\n");
        printk (KERN_INFO
                "PPP Dynamic channel allocation code copyright 1995 "
                "Caldera, Inc.\n");
-#endif
-
 /*
  * Register the protocol for the device
  */
 /*
  * Register the protocol for the device
  */
@@ -411,7 +441,7 @@ ppp_first_time (void)
        proto_ppp.bh_input      = ppp_dev_input;
        proto_ppp.control_event = default_protocol_control;
        proto_ppp.get_binding   = ppp_dev_getkey;
        proto_ppp.bh_input      = ppp_dev_input;
        proto_ppp.control_event = default_protocol_control;
        proto_ppp.get_binding   = ppp_dev_getkey;
-       proto_ppp.header_space  = 0; /* PPP_HARD_HDR_LEN; */
+       proto_ppp.header_space  = PPP_REQUESTED_HDR_LEN;
 
        protocol_register(&proto_ppp);
 #endif
 
        protocol_register(&proto_ppp);
 #endif
@@ -454,9 +484,11 @@ ppp_init_dev (struct device *dev)
        dev->default_protocol = &proto_ppp;     /* Our protocol layer is PPP */
 #else
        dev->hard_header      = ppp_dev_header;
        dev->default_protocol = &proto_ppp;     /* Our protocol layer is PPP */
 #else
        dev->hard_header      = ppp_dev_header;
+#if USE_SKB_PROTOCOL == 0
        dev->type_trans       = ppp_dev_type;
        dev->type_trans       = ppp_dev_type;
+#endif
        dev->rebuild_header   = ppp_dev_rebuild;
        dev->rebuild_header   = ppp_dev_rebuild;
-       dev->hard_header_len  = 0; /* PPP_HARD_HDR_LEN; */
+       dev->hard_header_len  = PPP_REQUESTED_HDR_LEN;
 #endif
 
        /* device INFO */
 #endif
 
        /* device INFO */
@@ -478,7 +510,7 @@ ppp_init_dev (struct device *dev)
        dev->pa_addr    = 0;
        dev->pa_brdaddr = 0;
        dev->pa_mask    = 0;
        dev->pa_addr    = 0;
        dev->pa_brdaddr = 0;
        dev->pa_mask    = 0;
-       dev->pa_alen    = sizeof (unsigned long);
+       dev->pa_alen    = 4; /* sizeof (unsigned long) */
 
        return 0;
 }
 
        return 0;
 }
@@ -510,28 +542,28 @@ ppp_init_ctrl_blk (register struct ppp *ppp)
        ppp->slcomp     = NULL;
        ppp->read_wait  = NULL;
        ppp->write_wait = NULL;
        ppp->slcomp     = NULL;
        ppp->read_wait  = NULL;
        ppp->write_wait = NULL;
-
-#ifdef OPTIMIZE_FLAG_TIME   /* ensure flag will always be sent first time */
-       ppp->last_xmit = jiffies - OPTIMIZE_FLAG_TIME;
-#else
-       ppp->last_xmit = 0;
-#endif
+       ppp->last_xmit  = jiffies - flag_time;
 
        /* clear statistics */
        memset (&ppp->stats, '\0', sizeof (struct pppstat));
 
        /* Reset the demand dial information */
 
        /* clear statistics */
        memset (&ppp->stats, '\0', sizeof (struct pppstat));
 
        /* Reset the demand dial information */
-       ppp->ddinfo.ip_sjiffies  =
-       ppp->ddinfo.ip_rjiffies  =
-       ppp->ddinfo.nip_sjiffies =
-       ppp->ddinfo.nip_rjiffies = jiffies;
+       ppp->ddinfo.xmit_idle=         /* time since last NP packet sent */
+       ppp->ddinfo.recv_idle=jiffies; /* time since last NP packet received */
 
 
-#ifdef PPP_COMPRESS
+       /* PPP compression data */
        ppp->sc_xc_state =
        ppp->sc_rc_state = NULL;
        ppp->sc_xc_state =
        ppp->sc_rc_state = NULL;
-#endif /* PPP_COMPRESS */
 }
 
 }
 
+static struct symbol_table ppp_syms = {
+#include <linux/symtab_begin.h>
+       X(ppp_register_compressor),
+       X(ppp_unregister_compressor),
+       X(ppp_crc16_table),
+#include <linux/symtab_end.h>
+};
+
 /* called at boot/load time for each ppp device defined in the kernel */
 
 #ifndef MODULE
 /* called at boot/load time for each ppp device defined in the kernel */
 
 #ifndef MODULE
@@ -544,20 +576,11 @@ ppp_init (struct device *dev)
        if (first_time) {
                first_time = 0;
                answer     = ppp_first_time();
        if (first_time) {
                first_time = 0;
                answer     = ppp_first_time();
+               if (answer == 0)
+                       (void) register_symtab (&ppp_syms);
        }
        }
-/*
- * Un-register the devices defined at the start of the system. They will
- * be added when they are needed again. The first device just gets us into
- * this code to register the handlers.
- */
-#if 1
-       unregister_netdev (dev);
-#else
-       ppp_init_dev (dev);
-       ppp_init_ctrl_blk (dev2ppp (dev));
-       dev2ppp (dev) -> inuse = 0;
-       dev2ppp (dev) -> dev   = dev;
-#endif
+       if (answer == 0)
+               answer = -ENODEV;
        return answer;
 }
 #endif
        return answer;
 }
 #endif
@@ -715,7 +738,7 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
        ppp->s2buf  = NULL;
        ppp->xbuf   = NULL;
 
        ppp->s2buf  = NULL;
        ppp->xbuf   = NULL;
 
-       ppp->tty->flags &= ~TTY_DO_WRITE_WAKEUP;
+       ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
        ppp->flags      &= ~SC_XMIT_BUSY;
 
        sti ();
        ppp->flags      &= ~SC_XMIT_BUSY;
 
        sti ();
@@ -733,21 +756,19 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
  * CCP is down; free (de)compressor state if necessary.
  */
 
  * CCP is down; free (de)compressor state if necessary.
  */
 
-#ifdef PPP_COMPRESS
 static void
 ppp_ccp_closed (struct ppp *ppp)
 {
 static void
 ppp_ccp_closed (struct ppp *ppp)
 {
-    if (ppp->sc_xc_state) {
-       (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);
-       ppp->sc_xc_state = NULL;
-    }
+       if (ppp->sc_xc_state) {
+               (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);
+               ppp->sc_xc_state = NULL;
+       }
 
 
-    if (ppp->sc_rc_state) {
-       (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);
-       ppp->sc_rc_state = NULL;
-    }
+       if (ppp->sc_rc_state) {
+               (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);
+               ppp->sc_rc_state = NULL;
+       }
 }
 }
-#endif /* PPP_COMPRESS */
 
 /*
  * Called to release all of the information in the current PPP structure.
 
 /*
  * Called to release all of the information in the current PPP structure.
@@ -765,11 +786,7 @@ ppp_release (struct ppp *ppp)
        tty = ppp2tty (ppp);
        dev = ppp2dev (ppp);
 
        tty = ppp2tty (ppp);
        dev = ppp2dev (ppp);
 
-#ifdef PPP_COMPRESS
        ppp_ccp_closed (ppp);
        ppp_ccp_closed (ppp);
-       ppp->sc_xc_state =
-       ppp->sc_rc_state = NULL;
-#endif /* PPP_COMPRESS */
 
        if (tty != NULL && tty->disc_data == ppp)
                tty->disc_data = NULL;  /* Break the tty->ppp link */
 
        if (tty != NULL && tty->disc_data == ppp)
                tty->disc_data = NULL;  /* Break the tty->ppp link */
@@ -814,17 +831,19 @@ ppp_tty_close (struct tty_struct *tty)
 {
        struct ppp *ppp = tty2ppp (tty);
 
 {
        struct ppp *ppp = tty2ppp (tty);
 
-       if (ppp == NULL || ppp->magic != PPP_MAGIC) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_WARNING
-                               "ppp: trying to close unopened tty!\n");
-       } else {
-               CHECK_PPP_VOID();
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_INFO "ppp: channel %s closing.\n",
-                               ppp2dev(ppp) -> name);
-               ppp_release (ppp);
-               MOD_DEC_USE_COUNT;
+       if (ppp != NULL) {
+               if (ppp->magic != PPP_MAGIC) {
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_WARNING
+                                      "ppp: trying to close unopened tty!\n");
+               } else {
+                       CHECK_PPP_VOID();
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_INFO "ppp: channel %s closing.\n",
+                                       ppp2dev(ppp) -> name);
+                       ppp_release (ppp);
+                       MOD_DEC_USE_COUNT;
+               }
        }
 }
 
        }
 }
 
@@ -852,7 +871,7 @@ ppp_tty_open (struct tty_struct *tty)
 /*
  * Allocate the structure from the system
  */
 /*
  * Allocate the structure from the system
  */
-       ppp = ppp_alloc ();
+       ppp = ppp_alloc();
        if (ppp == NULL) {
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_ERR
        if (ppp == NULL) {
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_ERR
@@ -874,7 +893,7 @@ ppp_tty_open (struct tty_struct *tty)
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer (tty);
 /*
        if (tty->driver.flush_buffer)
                tty->driver.flush_buffer (tty);
 /*
- * Allocate space for the default VJ header compression slots (16)
+ * Allocate space for the default VJ header compression slots
  */
        ppp->slcomp = slhc_init (16, 16);
        if (ppp->slcomp == NULL) {
  */
        ppp->slcomp = slhc_init (16, 16);
        if (ppp->slcomp == NULL) {
@@ -964,7 +983,7 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
  */
                xbuf = ppp->xbuf;
                if (xbuf != NULL) {
  */
                xbuf = ppp->xbuf;
                if (xbuf != NULL) {
-                       tty->flags  &= ~TTY_DO_WRITE_WAKEUP;
+                       tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
                        xbuf->locked = 0;
                        ppp->xbuf    = NULL;
 /*
                        xbuf->locked = 0;
                        ppp->xbuf    = NULL;
 /*
@@ -972,9 +991,9 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
  * transmission block.
  */
                        if (ppp2dev (ppp) -> flags & IFF_UP) {
  * transmission block.
  */
                        if (ppp2dev (ppp) -> flags & IFF_UP) {
-                               ppp2dev (ppp)->tbusy = 0;
+                               if (xbuf->type == BUFFER_TYPE_DEV_WR)
+                                       ppp2dev (ppp)->tbusy = 0;
                                mark_bh (NET_BH);
                                mark_bh (NET_BH);
-                               dev_tint (ppp2dev (ppp));
                        }
 /*
  * Wake up the transmission queue for all completion events.
                        }
 /*
  * Wake up the transmission queue for all completion events.
@@ -983,18 +1002,21 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
 /*
  * Look at the priorities. Choose a daemon write over the device driver.
  */
 /*
  * Look at the priorities. Choose a daemon write over the device driver.
  */
+                       cli();
                        xbuf = ppp->s1buf;
                        ppp->s1buf = NULL;
                        if (xbuf == NULL) {
                                xbuf = ppp->s2buf;
                                ppp->s2buf = NULL;
                        }
                        xbuf = ppp->s1buf;
                        ppp->s1buf = NULL;
                        if (xbuf == NULL) {
                                xbuf = ppp->s2buf;
                                ppp->s2buf = NULL;
                        }
+                       sti();
 /*
  * If there is a pending buffer then transmit it now.
  */
                        if (xbuf != NULL) {
                                ppp->flags &= ~SC_XMIT_BUSY;
                                ppp_kick_tty (ppp, xbuf);
 /*
  * If there is a pending buffer then transmit it now.
  */
                        if (xbuf != NULL) {
                                ppp->flags &= ~SC_XMIT_BUSY;
                                ppp_kick_tty (ppp, xbuf);
+                               return;
                        }
                }
        }
                        }
                }
        }
@@ -1019,12 +1041,11 @@ ppp_tty_wakeup (struct tty_struct *tty)
        struct ppp_buffer *xbuf;
        struct ppp *ppp = tty2ppp (tty);
 
        struct ppp_buffer *xbuf;
        struct ppp *ppp = tty2ppp (tty);
 
-       if (!ppp || ppp->magic != PPP_MAGIC) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_DEBUG "PPP: write_wakeup called but "
-                               "couldn't find PPP struct.\n");
+       if (!ppp)
+               return;
+
+       if (ppp->magic != PPP_MAGIC)
                return;
                return;
-       }
 /*
  * Ensure that there is a transmission pending. Clear the re-entry flag if
  * there is no pending buffer. Otherwise, send the buffer.
 /*
  * Ensure that there is a transmission pending. Clear the re-entry flag if
  * there is no pending buffer. Otherwise, send the buffer.
@@ -1106,16 +1127,25 @@ ppp_tty_room (struct tty_struct *tty)
  */
 
 static void
  */
 
 static void
-ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
+ppp_tty_receive (struct tty_struct *tty, const u_char * data,
+                char *flags, int count)
 {
        register struct ppp *ppp = tty2ppp (tty);
 {
        register struct ppp *ppp = tty2ppp (tty);
-       register struct ppp_buffer *buf = ppp->rbuf;
+       register struct ppp_buffer *buf = NULL;
        u_char chr;
        u_char chr;
+/*
+ * Fetch the pointer to the buffer. Be careful about race conditions.
+ */
+       if (ppp != NULL)
+               buf = ppp->rbuf;
+
+       if (buf == NULL)
+               return;
 /*
  * Verify the table pointer and ensure that the line is
  * still in PPP discipline.
  */
 /*
  * Verify the table pointer and ensure that the line is
  * still in PPP discipline.
  */
-       if (!ppp || ppp->magic != PPP_MAGIC) {
+       if (ppp->magic != PPP_MAGIC) {
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_DEBUG
                                "PPP: handler called but couldn't find "
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_DEBUG
                                "PPP: handler called but couldn't find "
@@ -1173,7 +1203,7 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
  * first FLAG are also tossed by this procedure.
  */
                case PPP_FLAG:  /* PPP_FLAG: end of frame */
  * first FLAG are also tossed by this procedure.
  */
                case PPP_FLAG:  /* PPP_FLAG: end of frame */
-                       ppp->stats.ppp_ibytes = ppp->bytes_rcvd;
+                       ppp->stats.ppp_ibytes += ppp->rbuf->count;
                        if (ppp->escape)
                                ppp->toss |= 0x80;
 /*
                        if (ppp->escape)
                                ppp->toss |= 0x80;
 /*
@@ -1235,7 +1265,7 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
 static int
 ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
 {
 static int
 ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
 {
-       sk_buff *skb = alloc_skb (count, GFP_ATOMIC);
+       sk_buff *skb = dev_alloc_skb (count);
 /*
  * Generate a skb buffer for the new frame.
  */
 /*
  * Generate a skb buffer for the new frame.
  */
@@ -1249,17 +1279,19 @@ ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
 /*
  * Move the received data from the input buffer to the skb buffer.
  */
 /*
  * Move the received data from the input buffer to the skb buffer.
  */
-       skb->len = count;               /* Store the length */
        skb->dev = ppp2dev (ppp);       /* We are the device */
        skb->dev = ppp2dev (ppp);       /* We are the device */
-#ifdef NEW_SKBUF
+#if USE_SKB_PROTOCOL == 0
+       skb->len = count;
+#else
        skb->protocol = proto;
        skb->protocol = proto;
+       skb->mac.raw  = skb_data(skb);
 #endif
 #endif
-       memcpy ((u_char *) skb_data(skb), data, count); /* move data */
+       memcpy (skb_put(skb,count), data, count);       /* move data */
 /*
  * Tag the frame and kick it to the proper receive routine
  */
        skb->free = 1;
 /*
  * Tag the frame and kick it to the proper receive routine
  */
        skb->free = 1;
-       ppp->ddinfo.ip_rjiffies = jiffies;
+       ppp->ddinfo.recv_idle = jiffies;
        netif_rx (skb);
        return 1;
 }
        netif_rx (skb);
        return 1;
 }
@@ -1271,10 +1303,8 @@ ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
 static int
 rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count)
 {
 static int
 rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count)
 {
-       if (ppp2dev (ppp)->flags & IFF_UP) {
-               if (count > 0)
-                       return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count);
-       }
+       if ((ppp2dev (ppp)->flags & IFF_UP) && (count > 0))
+               return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count);
        return 0;
 }
 
        return 0;
 }
 
@@ -1285,11 +1315,9 @@ rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count)
 static int
 rcv_proto_ipx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
 {
 static int
 rcv_proto_ipx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
 {
-#ifdef NEW_SKBUF
-       if (ppp2dev (ppp)->flags & IFF_UP) {
-               if (count > 0)
-                       return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
-       } else
+#if defined(NEW_SKBUFF) || defined(IPX_CHANGE)
+       if (((ppp2dev (ppp)->flags & IFF_UP) != 0) && (count > 0))
+               return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
 #endif
        return 0;
 }
 #endif
        return 0;
 }
@@ -1390,10 +1418,9 @@ rcv_proto_unknown (struct ppp *ppp, unsigned short proto,
 
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_INFO
 
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_INFO
-                               "ppp: successfully queued %d bytes\n",
-                               len + 2);
+                               "ppp: successfully queued %d bytes, flags = %x\n",
+                               len + 2, ppp->flags);
 
 
-               ppp->ddinfo.nip_rjiffies = jiffies;
                return 1;
 /*
  * The buffer is full. Unlock the header
                return 1;
 /*
  * The buffer is full. Unlock the header
@@ -1422,91 +1449,90 @@ failure:
  * immediate or the compressors will become confused on the peer.
  */
 
  * immediate or the compressors will become confused on the peer.
  */
 
-#ifdef PPP_COMPRESS
 static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd)
 {
 static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd)
 {
-       int slen = CCP_LENGTH(dp);
+       int slen    = CCP_LENGTH(dp);
+       u_char *opt = dp   + CCP_HDRLEN;
+       int opt_len = slen - CCP_HDRLEN;
+
+       if (slen > len)
+               return;
 
 
-       if (slen <= len) {
-               switch (CCP_CODE(dp)) {
-               case CCP_CONFREQ:
-               case CCP_TERMREQ:
-               case CCP_TERMACK:
+       switch (CCP_CODE(dp)) {
+       case CCP_CONFREQ:
+       case CCP_TERMREQ:
+       case CCP_TERMACK:
 /*
  * CCP must be going down - disable compression
  */
 /*
  * CCP must be going down - disable compression
  */
-                       if (ppp->flags & SC_CCP_UP) {
-                               ppp->flags &= ~(SC_CCP_UP   |
-                                               SC_COMP_RUN |
-                                               SC_DECOMP_RUN);
-                       }
-                       break;
+               if (ppp->flags & SC_CCP_UP) {
+                       ppp->flags &= ~(SC_CCP_UP   |
+                                       SC_COMP_RUN |
+                                       SC_DECOMP_RUN);
+               }
+               break;
 
 
-               case CCP_CONFACK:
-                       if (ppp->flags & SC_CCP_OPEN == 0)
-                               break;
-                       if (ppp->flags & SC_CCP_UP)
-                               break;
-                       if (slen < CCP_HDRLEN + CCP_OPT_MINLEN)
-                               break;
-                       if (slen < CCP_OPT_LENGTH (dp + CCP_HDRLEN) +
-                                  CCP_HDRLEN)
-                               break;
+       case CCP_CONFACK:
+               if ((ppp->flags & SC_CCP_OPEN) == 0)
+                       break;
+               if (ppp->flags & SC_CCP_UP)
+                       break;
+               if (slen < (CCP_HDRLEN + CCP_OPT_MINLEN))
+                       break;
+               if (slen < (CCP_OPT_LENGTH (opt) + CCP_HDRLEN))
+                       break;
 /*
  * we're agreeing to send compressed packets.
  */
 /*
  * we're agreeing to send compressed packets.
  */
-                       if (!rcvd) {
-                               if (ppp->sc_xc_state == NULL)
-                                       break;
-
-                               if ((*ppp->sc_xcomp->comp_init)
-                                   (ppp->sc_xc_state,
-                                    dp   + CCP_HDRLEN,
-                                    slen - CCP_HDRLEN,
-                                    ppp2dev (ppp)->base_addr,
-                                    ppp->flags & SC_DEBUG))
-                                       ppp->flags |= SC_COMP_RUN;
+               if (!rcvd) {
+                       if (ppp->sc_xc_state == NULL)
                                break;
                                break;
-                       }
+
+                       if ((*ppp->sc_xcomp->comp_init)
+                           (ppp->sc_xc_state,
+                            opt,
+                            opt_len,
+                            ppp2dev (ppp)->base_addr,
+                            0,
+                            ppp->flags))
+                               ppp->flags |= SC_COMP_RUN;
+                       break;
+               }
 /*
  * peer is agreeing to send compressed packets.
  */
 /*
  * peer is agreeing to send compressed packets.
  */
-                       if (ppp->sc_rc_state == NULL)
-                               break;
-
-                       if ((*ppp->sc_rcomp->decomp_init)
-                           (ppp->sc_rc_state,
-                            dp   + CCP_HDRLEN,
-                            slen - CCP_HDRLEN,
-                            ppp2dev (ppp)->base_addr,
-                            ppp->mru,
-                            ppp->flags & SC_DEBUG)) {
-                               ppp->flags |= SC_DECOMP_RUN;
-                               ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
-                       }
+               if (ppp->sc_rc_state == NULL)
                        break;
                        break;
+
+               if ((*ppp->sc_rcomp->decomp_init)
+                   (ppp->sc_rc_state,
+                    opt,
+                    opt_len,
+                    ppp2dev (ppp)->base_addr,
+                    0,
+                    ppp->mru,
+                    ppp->flags)) {
+                       ppp->flags |= SC_DECOMP_RUN;
+                       ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
+               }
+               break;
 /*
  * The protocol sequence is complete at this end
  */
 /*
  * The protocol sequence is complete at this end
  */
-               case CCP_RESETACK:
-                       if (ppp->flags & SC_CCP_UP == 0)
-                               break;
-
-                       if (!rcvd) {
-                               if (ppp->sc_xc_state &&
-                                   (ppp->flags & SC_COMP_RUN))
-                                       (*ppp->sc_xcomp->comp_reset)
-                                               (ppp->sc_xc_state);
-                               break;
-                       }
+       case CCP_RESETACK:
+               if ((ppp->flags & SC_CCP_UP) == 0)
+                       break;
 
 
+               if (!rcvd) {
+                       if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN))
+                               (*ppp->sc_xcomp->comp_reset)(ppp->sc_xc_state);
+               } else {
                        if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) {
                        if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) {
-                               (*ppp->sc_rcomp->decomp_reset)
-                                       (ppp->sc_rc_state);
+                             (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state);
                                ppp->flags &= ~SC_DC_ERROR;
                        }
                                ppp->flags &= ~SC_DC_ERROR;
                        }
-                       break;
                }
                }
+               break;
        }
 }
 
        }
 }
 
@@ -1516,7 +1542,6 @@ rcv_proto_ccp (struct ppp *ppp, unsigned short proto, u_char *dp, int len)
        ppp_proto_ccp (ppp, dp, len, 1);
        return rcv_proto_unknown (ppp, proto, dp, len);
 }
        ppp_proto_ccp (ppp, dp, len, 1);
        return rcv_proto_unknown (ppp, proto, dp, len);
 }
-#endif /* PPP_COMPRESS */
 
 /*
  * Handle a LQR packet.
 
 /*
  * Handle a LQR packet.
@@ -1529,8 +1554,8 @@ rcv_proto_ccp (struct ppp *ppp, unsigned short proto, u_char *dp, int len)
 static int
 rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len)
 {
 static int
 rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len)
 {
+#if 0 /* until support is in the pppd process don't corrupt the reject. */
        register u_char *p;
        register u_char *p;
-
        if (len > 8) {
                if (len < 48)
                        memset (&data [len], '\0', 48 - len);
        if (len > 8) {
                if (len < 48)
                        memset (&data [len], '\0', 48 - len);
@@ -1546,6 +1571,7 @@ rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len)
 
                len = 68;
        }
 
                len = 68;
        }
+#endif
 /*
  * Pass the frame to the pppd daemon.
  */
 /*
  * Pass the frame to the pppd daemon.
  */
@@ -1555,15 +1581,14 @@ rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len)
 /* on entry, a received frame is in ppp->rbuf.bufr
    check it and dispose as appropriate */
 
 /* on entry, a received frame is in ppp->rbuf.bufr
    check it and dispose as appropriate */
 
-static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int len)
+static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int count)
 {
 {
-       u_short         proto;
-       int             count = len;
+       u_short         proto = PPP_PROTOCOL (data);
        ppp_proto_type  *proto_ptr;
 /*
  * Ignore empty frames
  */
        ppp_proto_type  *proto_ptr;
 /*
  * Ignore empty frames
  */
-       if (count <= 0)
+       if (count <= 4)
                return;
 /*
  * Count the frame and print it
                return;
 /*
  * Count the frame and print it
@@ -1571,23 +1596,6 @@ static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int len)
        ++ppp->stats.ppp_ipackets;
        if (ppp->flags & SC_LOG_INPKT)
                ppp_print_buffer ("receive frame", data, count);
        ++ppp->stats.ppp_ipackets;
        if (ppp->flags & SC_LOG_INPKT)
                ppp_print_buffer ("receive frame", data, count);
-/*
- * Ignore the leading ADDRESS and CONTROL fields in the frame.
- */
-       if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
-               data  += 2;
-               count -= 2;
-       }
-/*
- * Obtain the protocol from the frame
- */
-       proto = (u_short) *data++;
-       if (proto & 1)
-               count--;
-       else {
-               proto = (proto << 8) | (u_short) *data++;
-               count -= 2;
-       }
 /*
  * Find the procedure to handle this protocol. The last one is marked
  * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon.
 /*
  * Find the procedure to handle this protocol. The last one is marked
  * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon.
@@ -1598,8 +1606,10 @@ static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int len)
 /*
  * Update the appropriate statistic counter.
  */
 /*
  * Update the appropriate statistic counter.
  */
-       if ((*proto_ptr->func) (ppp, proto, data, count))
-               ppp->stats.ppp_ioctects += len;
+       if ((*proto_ptr->func) (ppp, proto,
+                               &data[PPP_HARD_HDR_LEN],
+                               count - PPP_HARD_HDR_LEN))
+               ppp->stats.ppp_ioctects += count;
        else
                ++ppp->stats.ppp_discards;
 }
        else
                ++ppp->stats.ppp_discards;
 }
@@ -1612,11 +1622,9 @@ ppp_doframe (struct ppp *ppp)
 {
        u_char  *data = buf_base (ppp->rbuf);
        int     count = ppp->rbuf->count;
 {
        u_char  *data = buf_base (ppp->rbuf);
        int     count = ppp->rbuf->count;
-#ifdef PPP_COMPRESS
-       int     proto;
+       int     addr, ctrl, proto;
        int     new_count;
        u_char *new_data;
        int     new_count;
        u_char *new_data;
-#endif
 /*
  * If there is a pending error from the receiver then log it and discard
  * the damaged frame.
 /*
  * If there is a pending error from the receiver then log it and discard
  * the damaged frame.
@@ -1659,19 +1667,44 @@ ppp_doframe (struct ppp *ppp)
                return 0;
        }
        count -= 2;             /* ignore the fcs characters */
                return 0;
        }
        count -= 2;             /* ignore the fcs characters */
+/*
+ * Ignore the leading ADDRESS and CONTROL fields in the frame.
+ */
+       addr   = PPP_ALLSTATIONS;
+       ctrl   = PPP_UI;
 
 
-#ifdef PPP_COMPRESS
-       proto  = PPP_PROTOCOL (data);
+       if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
+               data  += 2;
+               count -= 2;
+       }
+/*
+ * Obtain the protocol from the frame
+ */
+       proto = (u_short) *data++;
+       if ((proto & 1) == 0) {
+               proto = (proto << 8) | (u_short) *data++;
+               --count;
+       }
+/*
+ * Rewrite the header with the full information. This may encroach upon
+ * the 'filler' area in the buffer header. This is the purpose for the
+ * filler.
+ */
+       *(--data) = proto;
+       *(--data) = proto >> 8;
+       *(--data) = ctrl;
+       *(--data) = addr;
+       count    += 3;
 /*
  * Process the active decompressor.
  */
        if ((ppp->sc_rc_state != (void *) 0) &&
 /*
  * Process the active decompressor.
  */
        if ((ppp->sc_rc_state != (void *) 0) &&
-           ((ppp->flags & SC_DECOMP_RUN) == 0)) {
+           (ppp->flags & SC_DECOMP_RUN)     &&
+           ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {
+               if (proto == PPP_COMP) {
 /*
  * If the frame is compressed then decompress it.
  */
 /*
  * If the frame is compressed then decompress it.
  */
-               if (((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0) &&
-                   (proto == PPP_COMP)) {
                        new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC);
                        if (new_data == NULL) {
                                if (ppp->flags & SC_DEBUG)
                        new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC);
                        if (new_data == NULL) {
                                if (ppp->flags & SC_DEBUG)
@@ -1691,7 +1724,6 @@ ppp_doframe (struct ppp *ppp)
                                                    count,
                                                    new_data,
                                                    ppp->mru + 4);
                                                    count,
                                                    new_data,
                                                    ppp->mru + 4);
-
                        switch (new_count) {
                        default:
                                ppp_doframe_lower (ppp, new_data, new_count);
                        switch (new_count) {
                        default:
                                ppp_doframe_lower (ppp, new_data, new_count);
@@ -1721,14 +1753,13 @@ ppp_doframe (struct ppp *ppp)
                        return 1;
                }
 /*
                        return 1;
                }
 /*
- * The frame is not special. Pass it through the decompressor without
- * actually decompressing the data
+ * The frame is not special. Pass it through the compressor without
+ * actually compressing the data
  */
                (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
                                          data,
                                          count);
        }
  */
                (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
                                          data,
                                          count);
        }
-#endif
 /*
  * Process the uncompressed frame.
  */
 /*
  * Process the uncompressed frame.
  */
@@ -1758,43 +1789,53 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
 
 #define GETC(c)                                                \
 {                                                      \
 
 #define GETC(c)                                                \
 {                                                      \
-    c = buf_base (ppp->ubuf) [ppp->ubuf->tail++];      \
-    ppp->ubuf->tail &= ppp->ubuf->size;                        \
+       c = buf_base (ppp->ubuf) [ppp->ubuf->tail++];   \
+       ppp->ubuf->tail &= ppp->ubuf->size;             \
 }
 
 /*
  * Validate the pointer to the PPP structure
  */
 }
 
 /*
  * Validate the pointer to the PPP structure
  */
-       if (!ppp || ppp->magic != PPP_MAGIC) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                               "ppp_tty_read: cannot find ppp channel\n");
+       if (!ppp)
                return -EIO;
                return -EIO;
-       }
+
+       if (ppp->magic != PPP_MAGIC)
+               return -EIO;
+
        CHECK_PPP (-ENXIO);
 
        if (ppp->flags & SC_DEBUG)
                printk (KERN_DEBUG
        CHECK_PPP (-ENXIO);
 
        if (ppp->flags & SC_DEBUG)
                printk (KERN_DEBUG
-                       "ppp_tty_read: called %x num %u\n",
-                       (unsigned int) buf,
-                       nr);
+                       "ppp_tty_read: called buf=%p nr=%u\n",
+                       buf, nr);
 /*
  * Acquire the read lock.
  */
        for (;;) {
 /*
  * Acquire the read lock.
  */
        for (;;) {
+               ppp = tty2ppp (tty);
+               if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
+                       return 0;
+
                if (set_bit (0, &ppp->ubuf->locked) != 0) {
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_DEBUG
                                     "ppp_tty_read: sleeping(ubuf)\n");
 
                        current->timeout = 0;
                if (set_bit (0, &ppp->ubuf->locked) != 0) {
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_DEBUG
                                     "ppp_tty_read: sleeping(ubuf)\n");
 
                        current->timeout = 0;
-                       current->state = TASK_INTERRUPTIBLE;
+                       current->state   = TASK_INTERRUPTIBLE;
                        schedule ();
 
                        if (current->signal & ~current->blocked)
                                return -EINTR;
                        continue;
                }
                        schedule ();
 
                        if (current->signal & ~current->blocked)
                                return -EINTR;
                        continue;
                }
+/*
+ * Before we attempt to write the frame to the user, ensure that the
+ * user has access to the pages for the total buffer length.
+ */
+               indx = verify_area (VERIFY_WRITE, buf, nr);
+               if (indx != 0)
+                       return (indx);
 /*
  * Fetch the length of the buffer from the first two bytes.
  */
 /*
  * Fetch the length of the buffer from the first two bytes.
  */
@@ -1833,7 +1874,6 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
 /*
  * Reset the time of the last read operation.
  */
 /*
  * Reset the time of the last read operation.
  */
-               ppp->ddinfo.nip_rjiffies = jiffies;
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len);
 /*
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len);
 /*
@@ -1853,12 +1893,23 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
                        ppp->stats.ppp_ierrors++;
                        return -EOVERFLOW;
                }
                        ppp->stats.ppp_ierrors++;
                        return -EOVERFLOW;
                }
+/*
+ * Before we attempt to write the frame to the user, ensure that the
+ * page tables are proper.
+ */
+               indx = verify_area (VERIFY_WRITE, buf, len + 2);
+               if (indx != 0) {
+                       ppp->ubuf->tail += len;
+                       ppp->ubuf->tail &= ppp->ubuf->size;
+                       clear_bit (0, &ppp->ubuf->locked);
+                       return (indx);
+               }
 /*
  * Fake the insertion of the ADDRESS and CONTROL information because these
  * were not saved in the buffer.
  */
 /*
  * Fake the insertion of the ADDRESS and CONTROL information because these
  * were not saved in the buffer.
  */
-               put_fs_byte (PPP_ALLSTATIONS, buf++);
-               put_fs_byte (PPP_UI,          buf++);
+               put_byte_user (PPP_ALLSTATIONS, buf++);
+               put_byte_user (PPP_UI,          buf++);
 
                indx = len;
 /*
 
                indx = len;
 /*
@@ -1866,7 +1917,8 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
  */
                while (indx-- > 0) {
                        GETC (c);
  */
                while (indx-- > 0) {
                        GETC (c);
-                       put_fs_byte (c, buf++);
+                       put_byte_user (c, buf);
+                       ++buf;
                }
 /*
  * Release the lock and return the character count in the buffer area.
                }
 /*
  * Release the lock and return the character count in the buffer area.
@@ -1896,7 +1948,7 @@ ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
                if ((buf->count < 0) || (buf->count > 3000))
                        printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
                                (unsigned int) buf->count,
                if ((buf->count < 0) || (buf->count > 3000))
                        printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
                                (unsigned int) buf->count,
-                               (unsigned int) buf->count);
+                               (unsigned int) chr);
        }
 /*
  * Update the FCS and if the character needs to be escaped, do it.
        }
 /*
  * Update the FCS and if the character needs to be escaped, do it.
@@ -1922,27 +1974,47 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
                    u_char *data, int count, int non_ip)
 {
        unsigned short int write_fcs;
                    u_char *data, int count, int non_ip)
 {
        unsigned short int write_fcs;
+       int     address, control;
+       int     proto;
 /*
  * Insert the leading FLAG character
  */
        buf->count = 0;
 
 /*
  * Insert the leading FLAG character
  */
        buf->count = 0;
 
-#ifdef OPTIMIZE_FLAG_TIME
-       if (non_ip)
+       if (non_ip || flag_time == 0)
                ins_char (buf, PPP_FLAG);
        else {
                ins_char (buf, PPP_FLAG);
        else {
-               if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
+               if (jiffies - ppp->last_xmit > flag_time)
                        ins_char (buf, PPP_FLAG);
        }
        ppp->last_xmit = jiffies;
                        ins_char (buf, PPP_FLAG);
        }
        ppp->last_xmit = jiffies;
-#else
-       ins_char (buf, PPP_FLAG);
-#endif
+       buf->fcs       = PPP_INITFCS;
+/*
+ * Emit the address/control information if needed
+ */
+       address = PPP_ADDRESS  (data);
+       control = PPP_CONTROL  (data);
+       proto   = PPP_PROTOCOL (data);
+
+       if (address != PPP_ALLSTATIONS ||
+           control != PPP_UI ||
+           (ppp->flags & SC_COMP_AC) == 0) {
+               ppp_stuff_char (ppp, buf, address);
+               ppp_stuff_char (ppp, buf, control);
+       }
+/*
+ * Emit the protocol (compressed if possible)
+ */
+       if ((ppp->flags & SC_COMP_PROT) == 0 || (proto & 0xFF00))
+               ppp_stuff_char (ppp, buf, proto >> 8);
 
 
-       buf->fcs = PPP_INITFCS;
+       ppp_stuff_char (ppp, buf, proto);
 /*
  * Insert the data
  */
 /*
  * Insert the data
  */
+       data  += 4;
+       count -= 4;
+
        while (count-- > 0)
                ppp_stuff_char (ppp, buf, *data++);
 /*
        while (count-- > 0)
                ppp_stuff_char (ppp, buf, *data++);
 /*
@@ -1985,12 +2057,12 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
  *        1 if frame must be re-queued for later driver support.
  */
 
  *        1 if frame must be re-queued for later driver support.
  */
 
-int
+static int
 ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
                    u_char *data, int count)
 {
 ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
                    u_char *data, int count)
 {
-       int     address, control;
        int     proto;
        int     proto;
+       int     address, control;
        u_char *new_data;
        int     new_count;
 /*
        u_char *new_data;
        int     new_count;
 /*
@@ -2002,12 +2074,11 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
  * Determine if the frame may be compressed. Attempt to compress the
  * frame if possible.
  */
  * Determine if the frame may be compressed. Attempt to compress the
  * frame if possible.
  */
+       proto   = PPP_PROTOCOL (data);
        address = PPP_ADDRESS  (data);
        control = PPP_CONTROL  (data);
        address = PPP_ADDRESS  (data);
        control = PPP_CONTROL  (data);
-       proto   = PPP_PROTOCOL (data);
 
 
-#ifdef PPP_COMPRESS  
-       if ((ppp->flags & SC_COMP_RUN != 0)     &&
+       if (((ppp->flags & SC_COMP_RUN) != 0)   &&
            (ppp->sc_xc_state != (void *) 0)    &&
            (address == PPP_ALLSTATIONS)        &&
            (control == PPP_UI)                 &&
            (ppp->sc_xc_state != (void *) 0)    &&
            (address == PPP_ALLSTATIONS)        &&
            (control == PPP_UI)                 &&
@@ -2029,7 +2100,7 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
 
                if (new_count > 0) {
                        ++ppp->stats.ppp_opackets;
 
                if (new_count > 0) {
                        ++ppp->stats.ppp_opackets;
-                       ppp->stats.ppp_ooctects += count;
+                       ppp->stats.ppp_ooctects += new_count;
 
                        ppp_dev_xmit_lower (ppp, buf, new_data,
                                            new_count, 0);
 
                        ppp_dev_xmit_lower (ppp, buf, new_data,
                                            new_count, 0);
@@ -2041,33 +2112,12 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
  */
                kfree (new_data);
        }
  */
                kfree (new_data);
        }
-#endif
 /*
  * The frame may not be compressed. Update the statistics before the
  * count field is destroyed. The frame will be transmitted.
  */
        ++ppp->stats.ppp_opackets;
        ppp->stats.ppp_ooctects += count;
 /*
  * The frame may not be compressed. Update the statistics before the
  * count field is destroyed. The frame will be transmitted.
  */
        ++ppp->stats.ppp_opackets;
        ppp->stats.ppp_ooctects += count;
-/*
- * Do not compress the protocol id if not possible
- */
-       if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xFF00)) {
-               --data;
-               ++count;
-       }
-
-       data  += 3;
-       count -= 3;
-/*
- * Do not compress the address/control if not possible.
- */
-       if (address != PPP_ALLSTATIONS ||
-           control != PPP_UI ||
-           !(ppp->flags & SC_COMP_AC)) {
-               *--data = control;
-               *--data = address;
-               count  += 2;
-       }
 /*
  * Go to the escape encoding
  */
 /*
  * Go to the escape encoding
  */
@@ -2098,12 +2148,12 @@ send_revise_frame (register struct ppp *ppp, u_char *data, int len)
 /*
  * Outbound compression frames
  */
 /*
  * Outbound compression frames
  */
-#ifdef PPP_COMPRESS
-       case PPP_COMP:
-               ppp_proto_ccp (ppp, data, len, 0);
+       case PPP_CCP:
+               ppp_proto_ccp (ppp,
+                              data + PPP_HARD_HDR_LEN,
+                              len  - PPP_HARD_HDR_LEN,
+                              0);
                break;
                break;
-#endif
-
 /*
  * All other frame types
  */
 /*
  * All other frame types
  */
@@ -2120,20 +2170,20 @@ send_revise_frame (register struct ppp *ppp, u_char *data, int len)
  */
 
 static int
  */
 
 static int
-ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data,
+ppp_tty_write (struct tty_struct *tty, struct file *file, const u_char * data,
               unsigned int count)
 {
        struct ppp *ppp = tty2ppp (tty);
        u_char *new_data;
               unsigned int count)
 {
        struct ppp *ppp = tty2ppp (tty);
        u_char *new_data;
+       int status;
 /*
  * Verify the pointer to the PPP data and that the tty is still in PPP mode.
  */
 /*
  * Verify the pointer to the PPP data and that the tty is still in PPP mode.
  */
-       if (!ppp || ppp->magic != PPP_MAGIC) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                               "ppp_tty_write: cannot find ppp unit\n");
+       if (!ppp)
+               return -EIO;
+
+       if (ppp->magic != PPP_MAGIC)
                return -EIO;
                return -EIO;
-       }
 
        CHECK_PPP (-ENXIO);
 /*
 
        CHECK_PPP (-ENXIO);
 /*
@@ -2146,6 +2196,16 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data,
                                "from %u to mtu %d\n", count, PPP_MTU);
                count = PPP_MTU;
        }
                                "from %u to mtu %d\n", count, PPP_MTU);
                count = PPP_MTU;
        }
+/*
+ * Allocate a buffer for the data and fetch it from the user space.
+ */
+       new_data = kmalloc (count, GFP_KERNEL);
+       if (new_data == NULL) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                               "ppp_tty_write: no memory\n");
+               return 0;
+       }
 /*
  * lock this PPP unit so we will be the only writer;
  * sleep if necessary
 /*
  * lock this PPP unit so we will be the only writer;
  * sleep if necessary
@@ -2155,19 +2215,26 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data,
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
                interruptible_sleep_on (&ppp->write_wait);
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
                interruptible_sleep_on (&ppp->write_wait);
-               if (current->signal & ~current->blocked)
+
+               ppp = tty2ppp (tty);
+               if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) {
+                       kfree (new_data);
+                       return 0;
+               }
+
+               if (current->signal & ~current->blocked) {
+                       kfree (new_data);
                        return -EINTR;
                        return -EINTR;
+               }
        }
 /*
        }
 /*
- * Allocate a buffer for the data and fetch it from the user space.
+ * Ensure that the caller's buffer is valid.
  */
  */
-       new_data = kmalloc (count, GFP_ATOMIC);
-       if (new_data == NULL) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                               "ppp_tty_write: no memory\n");
+       status = verify_area (VERIFY_READ, data, count);
+       if (status != 0) {
+               kfree (new_data);
                ppp->tbuf->locked = 0;
                ppp->tbuf->locked = 0;
-               return 0;
+               return status;
        }
 
        memcpy_fromfs (new_data, data, count);
        }
 
        memcpy_fromfs (new_data, data, count);
@@ -2187,80 +2254,80 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data,
  * Process the BSD compression IOCTL event for the tty device.
  */
 
  * Process the BSD compression IOCTL event for the tty device.
  */
 
-#ifdef PPP_COMPRESS
 static int
 ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
 {
 static int
 ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
 {
+       struct compressor *cp;
+       struct ppp_option_data data;
        int error;
        int nb;
        int error;
        int nb;
+       u_char *ptr;
        u_char ccp_option[CCP_MAX_OPTION_LENGTH];
        u_char ccp_option[CCP_MAX_OPTION_LENGTH];
-       struct compressor **cp;
 /*
 /*
- * Validate the range of the ioctl
+ * Fetch the compression parameters
  */
  */
-       error = verify_area (VERIFY_READ, odp,
-                    (unsigned long) (&((struct ppp_option_data *) 0)->length)
-                    + sizeof (odp->length));
-
+       error = verify_area (VERIFY_READ, odp, sizeof (data));
        if (error == 0) {
        if (error == 0) {
-               nb = (int) get_fs_long (odp->length);
-               if ((unsigned long) nb-1 >= (unsigned long) CCP_MAX_OPTION_LENGTH)
+               memcpy_fromfs (&data, odp, sizeof (data));
+               nb  = data.length;
+               ptr = data.ptr;
+               if ((unsigned long) nb >= (unsigned long)CCP_MAX_OPTION_LENGTH)
                        nb = CCP_MAX_OPTION_LENGTH;
                        nb = CCP_MAX_OPTION_LENGTH;
-
-               error = verify_area (VERIFY_READ, odp, nb);
+       
+               error = verify_area (VERIFY_READ, ptr, nb);
        }
 
        if (error != 0)
                return error;
 
        }
 
        if (error != 0)
                return error;
 
-       memcpy_fromfs (ccp_option, odp, nb);
+       memcpy_fromfs (ccp_option, ptr, nb);
+
        if (ccp_option[1] < 2)  /* preliminary check on the length byte */
                return (-EINVAL);
 
        if (ccp_option[1] < 2)  /* preliminary check on the length byte */
                return (-EINVAL);
 
-       for (cp = ppp_compressors; *cp != NULL; ++cp)
-               if ((*cp)->compress_proto == ccp_option[0]) {
+       cp = find_compressor ((int) (unsigned) (unsigned char) ccp_option[0]);
+       if (cp != (struct compressor *) 0) {
                /*
                 * Found a handler for the protocol - try to allocate
                 * a compressor or decompressor.
                 */
                /*
                 * Found a handler for the protocol - try to allocate
                 * a compressor or decompressor.
                 */
-                       error = 0;
-                       if (odp->transmit) {
-                               if (ppp->sc_xc_state != NULL)
-                                       (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
-
-                               ppp->sc_xcomp = *cp;
-                               ppp->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb);
-
-                               if (ppp->sc_xc_state == NULL) {
-                                       if (ppp->flags & SC_DEBUG)
-                                               printk("ppp%ld: comp_alloc failed\n",
-                                                      ppp2dev (ppp)->base_addr);
-                                       error = -ENOBUFS;
-                               }
-                               ppp->flags &= ~SC_COMP_RUN;
-                       } else {
-                               if (ppp->sc_rc_state != NULL)
-                                       (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
-                               ppp->sc_rcomp = *cp;
-                               ppp->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb);
-                               if (ppp->sc_rc_state == NULL) {
-                                       if (ppp->flags & SC_DEBUG)
-                                               printk("ppp%ld: decomp_alloc failed\n",
-                                                      ppp2dev (ppp)->base_addr);
-                                       error = ENOBUFS;
-                               }
-                               ppp->flags &= ~SC_DECOMP_RUN;
+               error = 0;
+               if (data.transmit) {
+                       if (ppp->sc_xc_state != NULL)
+                               (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
+
+                       ppp->sc_xcomp    = cp;
+                       ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
+
+                       if (ppp->sc_xc_state == NULL) {
+                               if (ppp->flags & SC_DEBUG)
+                                       printk("ppp%ld: comp_alloc failed\n",
+                                              ppp2dev (ppp)->base_addr);
+                               error = -ENOBUFS;
                        }
                        }
-                       return (error);
+                       ppp->flags &= ~SC_COMP_RUN;
+               } else {
+                       if (ppp->sc_rc_state != NULL)
+                               (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
+                       ppp->sc_rcomp    = cp;
+                       ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
+                       if (ppp->sc_rc_state == NULL) {
+                               if (ppp->flags & SC_DEBUG)
+                                       printk("ppp%ld: decomp_alloc failed\n",
+                                              ppp2dev (ppp)->base_addr);
+                               error = ENOBUFS;
+                       }
+                       ppp->flags &= ~SC_DECOMP_RUN;
                }
                }
+               return (error);
+       }
 
        if (ppp->flags & SC_DEBUG)
 
        if (ppp->flags & SC_DEBUG)
-               printk (KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n",
-                       ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1],
-                       ccp_option[2], nb);
+               printk(KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n",
+                      ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1],
+                      ccp_option[2], nb);
        return (-EINVAL);       /* no handler found */
 }
        return (-EINVAL);       /* no handler found */
 }
-#endif /* PPP_COMPRESS */
 
 /*
  * Process the IOCTL event for the tty device.
 
 /*
  * Process the IOCTL event for the tty device.
@@ -2276,12 +2343,12 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
 /*
  * Verify the status of the PPP device.
  */
 /*
  * Verify the status of the PPP device.
  */
-       if (!ppp || ppp->magic != PPP_MAGIC) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                       "ppp_tty_ioctl: can't find PPP block from tty!\n");
+       if (!ppp)
                return -EBADF;
                return -EBADF;
-       }
+
+       if (ppp->magic != PPP_MAGIC)
+               return -EBADF;
+
        CHECK_PPP (-ENXIO);
 /*
  * The user must have an euid of root to do these requests.
        CHECK_PPP (-ENXIO);
 /*
  * The user must have an euid of root to do these requests.
@@ -2296,7 +2363,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
-                       temp_i = (int) get_fs_long (param3);
+                       temp_i = get_int_user ((int *) param3);
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                 "ppp_tty_ioctl: set mru to %x\n", temp_i);
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                 "ppp_tty_ioctl: set mru to %x\n", temp_i);
@@ -2317,7 +2384,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                        temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
                                  SC_RCV_ODDP | SC_RCV_EVNP;
 #endif
                        temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
                                  SC_RCV_ODDP | SC_RCV_EVNP;
 #endif
-                       put_fs_long ((long) temp_i, param3);
+                       put_long_user ((long) temp_i, param3);
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_DEBUG
                                "ppp_tty_ioctl: get flags: addr %lx flags "
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_DEBUG
                                "ppp_tty_ioctl: get flags: addr %lx flags "
@@ -2331,15 +2398,13 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
-                       temp_i  = (int) get_fs_long (param3) & SC_MASK;
+                       temp_i  = get_int_user (param3) & SC_MASK;
                        temp_i |= (ppp->flags & ~SC_MASK);
                        temp_i |= (ppp->flags & ~SC_MASK);
-#ifdef PPP_COMPRESS
+
                        if ((ppp->flags & SC_CCP_OPEN) &&
                            (temp_i & SC_CCP_OPEN) == 0)
                                ppp_ccp_closed (ppp);
                        if ((ppp->flags & SC_CCP_OPEN) &&
                            (temp_i & SC_CCP_OPEN) == 0)
                                ppp_ccp_closed (ppp);
-#else
-                       temp_i &= ~SC_CCP_OPEN;
-#endif
+
                        if ((ppp->flags | temp_i) & SC_DEBUG)
                                printk (KERN_INFO
                               "ppp_tty_ioctl: set flags to %x\n", temp_i);
                        if ((ppp->flags | temp_i) & SC_DEBUG)
                                printk (KERN_INFO
                               "ppp_tty_ioctl: set flags to %x\n", temp_i);
@@ -2349,12 +2414,10 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
 /*
  * Set the compression mode
  */
 /*
  * Set the compression mode
  */
-#ifdef PPP_COMPRESS
        case PPPIOCSCOMPRESS:
                error = ppp_set_compression (ppp,
                                            (struct ppp_option_data *) param3);
                break;
        case PPPIOCSCOMPRESS:
                error = ppp_set_compression (ppp,
                                            (struct ppp_option_data *) param3);
                break;
-#endif
 /*
  * Retrieve the transmit async map
  */
 /*
  * Retrieve the transmit async map
  */
@@ -2362,12 +2425,13 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                error = verify_area (VERIFY_WRITE, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
                error = verify_area (VERIFY_WRITE, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
-                       put_fs_long (ppp->xmit_async_map[0], param3);
+                       put_long_user (ppp->xmit_async_map[0], param3);
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
-                                       "ppp_tty_ioctl: get asyncmap: addr "
-                                       "%lx asyncmap %lx\n",
-                                       param3, ppp->xmit_async_map[0]);
+                                    "ppp_tty_ioctl: get asyncmap: addr "
+                                    "%lx asyncmap %lx\n",
+                                    param3,
+                                    (unsigned long) ppp->xmit_async_map[0]);
                }
                break;
 /*
                }
                break;
 /*
@@ -2377,11 +2441,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
-                       ppp->xmit_async_map[0] = get_fs_long (param3);
+                       ppp->xmit_async_map[0] = get_long_user (param3);
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                     "ppp_tty_ioctl: set xmit asyncmap %lx\n",
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                     "ppp_tty_ioctl: set xmit asyncmap %lx\n",
-                                    ppp->xmit_async_map[0]);
+                                    (unsigned long) ppp->xmit_async_map[0]);
                }
                break;
 /*
                }
                break;
 /*
@@ -2391,11 +2455,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
-                       ppp->recv_async_map = get_fs_long (param3);
+                       ppp->recv_async_map = get_long_user (param3);
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                     "ppp_tty_ioctl: set rcv asyncmap %lx\n",
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                     "ppp_tty_ioctl: set rcv asyncmap %lx\n",
-                                    ppp->recv_async_map);
+                                    (unsigned long) ppp->recv_async_map);
                }
                break;
 /*
                }
                break;
 /*
@@ -2405,7 +2469,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                error = verify_area (VERIFY_WRITE, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
                error = verify_area (VERIFY_WRITE, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
-                       put_fs_long (ppp2dev (ppp)->base_addr, param3);
+                       put_long_user (ppp2dev (ppp)->base_addr, param3);
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                        "ppp_tty_ioctl: get unit: %ld",
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                        "ppp_tty_ioctl: get unit: %ld",
@@ -2419,7 +2483,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
-                       temp_i  = (int) (get_fs_long (param3) & 0x1F) << 16;
+                       temp_i  = (get_int_user (param3) & 0x1F) << 16;
                        temp_i |= (ppp->flags & ~0x1F0000);
 
                        if ((ppp->flags | temp_i) & SC_DEBUG)
                        temp_i |= (ppp->flags & ~0x1F0000);
 
                        if ((ppp->flags | temp_i) & SC_DEBUG)
@@ -2436,7 +2500,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                                     sizeof (temp_i));
                if (error == 0) {
                        temp_i = (ppp->flags >> 16) & 0x1F;
                                     sizeof (temp_i));
                if (error == 0) {
                        temp_i = (ppp->flags >> 16) & 0x1F;
-                       put_fs_long ((long) temp_i, param3);
+                       put_long_user ((long) temp_i, param3);
 
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
 
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
@@ -2447,21 +2511,18 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
 /*
  * Get the times since the last send/receive frame operation
  */
 /*
  * Get the times since the last send/receive frame operation
  */
-       case PPPIOCGTIME:
+       case PPPIOCGIDLE:
                error = verify_area (VERIFY_WRITE, (void *) param3,
                error = verify_area (VERIFY_WRITE, (void *) param3,
-                                    sizeof (struct ppp_ddinfo));
+                                    sizeof (struct ppp_idle));
                if (error == 0) {
                if (error == 0) {
-                       struct ppp_ddinfo cur_ddinfo;
+                       struct ppp_idle cur_ddinfo;
                        unsigned long cur_jiffies = jiffies;
 
                        /* change absolute times to relative times. */
                        unsigned long cur_jiffies = jiffies;
 
                        /* change absolute times to relative times. */
-                       cur_ddinfo.ip_sjiffies = cur_jiffies - ppp->ddinfo.ip_sjiffies;
-                       cur_ddinfo.ip_rjiffies = cur_jiffies - ppp->ddinfo.ip_rjiffies;
-                       cur_ddinfo.nip_sjiffies = cur_jiffies - ppp->ddinfo.nip_sjiffies;
-                       cur_ddinfo.nip_rjiffies = cur_jiffies - ppp->ddinfo.nip_rjiffies;
-
+                       cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ;
+                       cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ;
                        memcpy_tofs ((void *) param3, &cur_ddinfo,
                        memcpy_tofs ((void *) param3, &cur_ddinfo,
-                                    sizeof (struct ppp_ddinfo));
+                                    sizeof (cur_ddinfo));
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                "ppp_tty_ioctl: read demand dial info\n");
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                "ppp_tty_ioctl: read demand dial info\n");
@@ -2492,7 +2553,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (ppp->xmit_async_map));
                if (error == 0) {
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (ppp->xmit_async_map));
                if (error == 0) {
-                       unsigned long temp_tbl[8];
+                       __u32 temp_tbl[8];
 
                        memcpy_fromfs (temp_tbl, (void *) param3,
                                       sizeof (ppp->xmit_async_map));
 
                        memcpy_fromfs (temp_tbl, (void *) param3,
                                       sizeof (ppp->xmit_async_map));
@@ -2521,7 +2582,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
                error = verify_area (VERIFY_READ, (void *) param3,
                                     sizeof (temp_i));
                if (error == 0) {
-                       temp_i = (int) get_fs_long (param3) + 1;
+                       temp_i = get_int_user (param3) + 1;
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                     "ppp_tty_ioctl: set maxcid to %d\n",
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                     "ppp_tty_ioctl: set maxcid to %d\n",
@@ -2577,12 +2638,12 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode,
 /*
  * Verify the status of the PPP device.
  */
 /*
  * Verify the status of the PPP device.
  */
-       if (!ppp || ppp->magic != PPP_MAGIC) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                      "ppp_tty_select: can't find PPP block from tty!\n");
+       if (!ppp)
                return -EBADF;
                return -EBADF;
-       }
+
+       if (ppp->magic != PPP_MAGIC)
+               return -EBADF;
+
        CHECK_PPP (0);
 /*
  * Branch on the type of select mode. A read request must lock the user
        CHECK_PPP (0);
 /*
  * Branch on the type of select mode. A read request must lock the user
@@ -2721,7 +2782,7 @@ ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr)
  */
 
 static int
  */
 
 static int
-ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr)
+ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
 {
        struct ppp_stats *result, temp;
        int    error;
 {
        struct ppp_stats *result, temp;
        int    error;
@@ -2736,15 +2797,12 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr)
  * Supply the information for the caller. First move the version data
  * then move the ppp stats; and finally the vj stats.
  */
  * Supply the information for the caller. First move the version data
  * then move the ppp stats; and finally the vj stats.
  */
-       if (error == 0) {
-               memset (&temp, 0, sizeof(temp));
+       memset (&temp, 0, sizeof(temp));
+       if (error == 0 && dev->flags & IFF_UP) {
                memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
                memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
-/*
- * Header Compression statistics
- */
                if (ppp->slcomp != NULL) {
                if (ppp->slcomp != NULL) {
-                       temp.vj.vjs_packets    = ppp->slcomp->sls_o_nontcp +
-                                                ppp->slcomp->sls_o_tcp;
+                       temp.vj.vjs_packets    = ppp->slcomp->sls_o_compressed+
+                                                ppp->slcomp->sls_o_uncompressed;
                        temp.vj.vjs_compressed = ppp->slcomp->sls_o_compressed;
                        temp.vj.vjs_searches   = ppp->slcomp->sls_o_searches;
                        temp.vj.vjs_misses     = ppp->slcomp->sls_o_misses;
                        temp.vj.vjs_compressed = ppp->slcomp->sls_o_compressed;
                        temp.vj.vjs_searches   = ppp->slcomp->sls_o_searches;
                        temp.vj.vjs_misses     = ppp->slcomp->sls_o_misses;
@@ -2753,10 +2811,36 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr)
                        temp.vj.vjs_uncompressedin = ppp->slcomp->sls_i_uncompressed;
                        temp.vj.vjs_compressedin   = ppp->slcomp->sls_i_compressed;
                }
                        temp.vj.vjs_uncompressedin = ppp->slcomp->sls_i_uncompressed;
                        temp.vj.vjs_compressedin   = ppp->slcomp->sls_i_compressed;
                }
+       }
+/*
+ * Move the data to the caller's buffer
+ */
+       if (error == 0)
+               memcpy_tofs (result, &temp, sizeof (temp));
+       return error;
+}
+
+/*
+ * IOCTL to read the compression statistics for the pppstats program.
+ */
+
+static int
+ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
+{
+       struct ppp_comp_stats *result, temp;
+       int    error;
+/*
+ * Must have write access to the buffer.
+ */
+       result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
+       error = verify_area (VERIFY_WRITE,
+                            result,
+                            sizeof (temp));
 /*
 /*
- * Frame data compression statistics
+ * Supply the information for the caller.
  */
  */
-#ifdef PPP_COMPRESS
+       memset (&temp, 0, sizeof(temp));
+       if (error == 0 && dev->flags & IFF_UP) {
                if (ppp->sc_xc_state != NULL)
                        (*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state,
                                                     &temp.c);
                if (ppp->sc_xc_state != NULL)
                        (*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state,
                                                     &temp.c);
@@ -2764,13 +2848,12 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr)
                if (ppp->sc_rc_state != NULL)
                        (*ppp->sc_rcomp->decomp_stat) (ppp->sc_rc_state,
                                                       &temp.d);
                if (ppp->sc_rc_state != NULL)
                        (*ppp->sc_rcomp->decomp_stat) (ppp->sc_rc_state,
                                                       &temp.d);
-#endif /* PPP_COMPRESS */
-
+       }
 /*
  * Move the data to the caller's buffer
  */
 /*
  * Move the data to the caller's buffer
  */
+       if (error == 0)
                memcpy_tofs (result, &temp, sizeof (temp));
                memcpy_tofs (result, &temp, sizeof (temp));
-       }
        return error;
 }
 
        return error;
 }
 
@@ -2788,7 +2871,11 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
  */
        switch (cmd) {
        case SIOCGPPPSTATS:
  */
        switch (cmd) {
        case SIOCGPPPSTATS:
-               error = ppp_dev_ioctl_stats (ppp, ifr);
+               error = ppp_dev_ioctl_stats (ppp, ifr, dev);
+               break;
+
+       case SIOCGPPPCSTATS:
+               error = ppp_dev_ioctl_comp_stats (ppp, ifr, dev);
                break;
 
        case SIOCGPPPVER:
                break;
 
        case SIOCGPPPVER:
@@ -2809,7 +2896,11 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
  *        1 if frame must be re-queued for later driver support.
  */
 
  *        1 if frame must be re-queued for later driver support.
  */
 
-int
+#if defined(IPX_CHANGE)
+#define ppp_dev_xmit_ip1 ppp_dev_xmit_ip
+#endif
+
+static int
 ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data)
 {
        int      proto = PPP_IP;
 ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data)
 {
        int      proto = PPP_IP;
@@ -2872,7 +2963,7 @@ ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data)
                len = slhc_compress (ppp->slcomp, data, len,
                                     buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN,
                                     &data,
                len = slhc_compress (ppp->slcomp, data, len,
                                     buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN,
                                     &data,
-                                    !(ppp->flags & SC_NO_TCP_CCID));
+                                    (ppp->flags & SC_NO_TCP_CCID) == 0);
 
                if (data[0] & SL_TYPE_COMPRESSED_TCP) {
                        proto    = PPP_VJC_COMP;
 
                if (data[0] & SL_TYPE_COMPRESSED_TCP) {
                        proto    = PPP_VJC_COMP;
@@ -2906,10 +2997,11 @@ ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data)
  * by this name.
  */
 
  * by this name.
  */
 
-int
+#if !defined(IPX_CHANGE)
+static int
 ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data)
 {
 ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data)
 {
-       struct ppp_hdr    *hdr;
+       struct ppp_hdr *hdr;
        int     len;
        int     answer;
 
        int     len;
        int     answer;
 
@@ -2929,6 +3021,7 @@ ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data)
 
        return answer;
 }
 
        return answer;
 }
+#endif  /* !defined(IPX_CHANGE) */
 
 /*
  * Send an IPX (or any other non-IP) frame to the remote.
 
 /*
  * Send an IPX (or any other non-IP) frame to the remote.
@@ -2937,7 +3030,12 @@ ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data)
  *        1 if frame must be re-queued for later driver support.
  */
 
  *        1 if frame must be re-queued for later driver support.
  */
 
-int
+#if defined(IPX_CHANGE)
+#define ppp_dev_xmit_ipx1   ppp_dev_xmit_ipx
+#endif
+
+#if defined(NEW_SKBUFF) || defined(IPX_CHANGE)
+static int
 ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp,
                  u_char *data, int len, int proto)
 {
 ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp,
                  u_char *data, int len, int proto)
 {
@@ -3008,7 +3106,8 @@ ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp,
  * by this name.
  */
 
  * by this name.
  */
 
-int
+#if !defined(IPX_CHANGE)
+static int
 ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
                  u_char *data, int len, int proto)
 {
 ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
                  u_char *data, int len, int proto)
 {
@@ -3021,21 +3120,24 @@ ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
                answer = 1;
        else {
                memcpy (&hdr[1], data, len);
                answer = 1;
        else {
                memcpy (&hdr[1], data, len);
-               answer = (dev, ppp, (u_char *) &hdr[1], len, proto);
+               answer = ppp_dev_xmit_ipx1 (dev, ppp, (u_char *) &hdr[1],
+                                           len, proto);
                kfree (hdr);
        }
 
        return answer;
 }
                kfree (hdr);
        }
 
        return answer;
 }
+#endif   /* !defined(IPX_CHANGE) */
+#endif   /* defined(NEW_SKBUFF) || defined(IPX_CHANGE) */
 
 /*
  * Send a frame to the remote.
  */
 
 
 /*
  * Send a frame to the remote.
  */
 
-int
+static int
 ppp_dev_xmit (sk_buff *skb, struct device *dev)
 {
 ppp_dev_xmit (sk_buff *skb, struct device *dev)
 {
-       int answer;
+       int answer, len;
        u_char *data;
        struct ppp        *ppp = dev2ppp (dev);
        struct tty_struct *tty = ppp2tty (ppp);
        u_char *data;
        struct ppp        *ppp = dev2ppp (dev);
        struct tty_struct *tty = ppp2tty (ppp);
@@ -3059,8 +3161,8 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
  * Validate the tty linkage
  */
        if (ppp->flags & SC_DEBUG)
  * Validate the tty linkage
  */
        if (ppp->flags & SC_DEBUG)
-               printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %X\n",
-                       dev->name, (int) skb);
+               printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %p\n",
+                       dev->name, skb);
 /*
  * Validate the tty interface
  */
 /*
  * Validate the tty interface
  */
@@ -3075,35 +3177,49 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
 /*
  * Fetch the pointer to the data
  */
 /*
  * Fetch the pointer to the data
  */
-       data  = skb_data (skb);
+       len   = skb->len;
+       data  = skb_data(skb);
 /*
  * Look at the protocol in the skb to determine the difference between
  * an IP frame and an IPX frame.
  */
 
 /*
  * Look at the protocol in the skb to determine the difference between
  * an IP frame and an IPX frame.
  */
 
-#ifdef NEW_SKBUFF
-       switch (skb->protocol) {
-       case htons (ETH_P_IPX):
-               answer = ppp_dev_xmit_ipx (dev, ppp, data, skb->len, PPP_IPX);
+#if defined(NEW_SKBUFF) || defined(IPX_CHANGE)
+       switch (ntohs (skb->protocol)) {
+       case ETH_P_IPX:
+               answer = ppp_dev_xmit_ipx (dev, ppp, data, len, PPP_IPX);
                break;
 
                break;
 
-       case htons (ETH_P_IP):
+       case ETH_P_IP:
                answer = ppp_dev_xmit_ip (dev, ppp, data);
                break;
 
        default: /* All others have no support at this time. */
                answer = ppp_dev_xmit_ip (dev, ppp, data);
                break;
 
        default: /* All others have no support at this time. */
+#if 1 /* I **REALLY** want to toss this. For the time being, I'll assume
+        that this is IP. However, if you start to see the message below
+        then you should fix the skb->protocol to have the proper values. */
+
+               printk (KERN_ERR
+                       "ppp: strange protocol type %x in ppp_dev_xmit\n",
+                       skb->protocol);
+               answer = ppp_dev_xmit_ip (dev, ppp, data);
+               break;
+#else  /* Shortly, this is what it will be! */
                dev_kfree_skb (skb, FREE_WRITE);
                return 0;
                dev_kfree_skb (skb, FREE_WRITE);
                return 0;
+#endif /* if 1 */
        }
        }
-#else
+#else  /* defined(NEW_SKBUFF) || defined(IPX_CHANGE) */
        answer = ppp_dev_xmit_ip (dev, ppp, data);
 #endif
 
 /*
  * This is the end of the transmission. Release the buffer if it was sent.
  */
        answer = ppp_dev_xmit_ip (dev, ppp, data);
 #endif
 
 /*
  * This is the end of the transmission. Release the buffer if it was sent.
  */
-       if (answer == 0)
+       if (answer == 0) {
                dev_kfree_skb (skb, FREE_WRITE);
                dev_kfree_skb (skb, FREE_WRITE);
+               ppp->ddinfo.xmit_idle = jiffies;
+       }
        return answer;
 }
 
        return answer;
 }
 
@@ -3140,11 +3256,10 @@ ppp_dev_stats (struct device *dev)
        return &ppp_stats;
 }
 
        return &ppp_stats;
 }
 
-#ifdef NEW_SKBUFF
+#if defined(NEW_SKBUFF)
 /*
 /*
- *     The PPP protocol is currently pure IP (no IPX yet). This defines
- *      the protocol layer which is blank since the driver does all the
- *      cooking.
+ *     This defines the protocol layer which is blank since the
+ *     driver does all the cooking.
  */
 
 static int ppp_dev_input (struct protocol *self, struct protocol *lower,
  */
 
 static int ppp_dev_input (struct protocol *self, struct protocol *lower,
@@ -3183,6 +3298,7 @@ static int ppp_dev_getkey(int protocol, int subid, unsigned char *key)
 
 #else
 
 
 #else
 
+#if USE_SKB_PROTOCOL == 0
 /*
  * Called to enquire about the type of the frame in the buffer. Return
  * ETH_P_IP for an IP frame, ETH_P_IPX for an IPX frame.
 /*
  * Called to enquire about the type of the frame in the buffer. Return
  * ETH_P_IP for an IP frame, ETH_P_IPX for an IPX frame.
@@ -3193,10 +3309,17 @@ ppp_dev_type (sk_buff *skb, struct device *dev)
 {
        return (htons (ETH_P_IP));
 }
 {
        return (htons (ETH_P_IP));
 }
+#endif
 
 
-static int
-ppp_dev_header (u_char * buff, struct device *dev, unsigned short type,
-               void *daddr, void *saddr, unsigned len, sk_buff *skb)
+#if USE_SKB_PROTOCOL == 0
+static int ppp_dev_header (unsigned char *buff, struct device *dev,
+                          unsigned short type, void *daddr, void *saddr,
+                          unsigned len, struct sk_buff *skb)
+#else
+static int ppp_dev_header (sk_buff *skb, struct device *dev,
+                          unsigned short type, void *daddr,
+                          void *saddr, unsigned len)
+#endif
 {
        return (0);
 }
 {
        return (0);
 }
@@ -3218,7 +3341,6 @@ ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr,
 static struct ppp *
 ppp_alloc (void)
 {
 static struct ppp *
 ppp_alloc (void)
 {
-#if 1
        int             if_num;
        int             status;
        ppp_ctrl_t      *ctl;
        int             if_num;
        int             status;
        ppp_ctrl_t      *ctl;
@@ -3234,7 +3356,7 @@ ppp_alloc (void)
                if (!set_bit(0, &ppp->inuse))
                        return (ppp);
                ctl = ctl->next;
                if (!set_bit(0, &ppp->inuse))
                        return (ppp);
                ctl = ctl->next;
-               if (++if_num == INT_MAX)
+               if (++if_num == max_dev)
                        return (NULL);
        }
 /*
                        return (NULL);
        }
 /*
@@ -3270,7 +3392,7 @@ ppp_alloc (void)
 
                status = register_netdev (dev);
                if (status == 0) {
 
                status = register_netdev (dev);
                if (status == 0) {
-                       printk ("registered device %s\n", dev->name);
+                       printk (KERN_INFO "registered device %s\n", dev->name);
                        return (ppp);
                }
 
                        return (ppp);
                }
 
@@ -3280,13 +3402,6 @@ ppp_alloc (void)
                /* This one will forever be busy as it is not initialized */
        }
        return (NULL);
                /* This one will forever be busy as it is not initialized */
        }
        return (NULL);
-#else
-  int i;
-  for (i = 0; i < PPP_NRUNIT; i++)
-    if (!set_bit(0, &ppp_ctrl[i].inuse)) return &ppp_ctrl[i];
-
-  return NULL;
-#endif
 }
 
 /*
 }
 
 /*
@@ -3294,7 +3409,7 @@ ppp_alloc (void)
  */
 
 static void
  */
 
 static void
-ppp_print_hex (register u_char * out, u_char * in, int count)
+ppp_print_hex (register u_char * out, const u_char * in, int count)
 {
        register u_char next_ch;
        static char hex[] = "0123456789ABCDEF";
 {
        register u_char next_ch;
        static char hex[] = "0123456789ABCDEF";
@@ -3308,7 +3423,7 @@ ppp_print_hex (register u_char * out, u_char * in, int count)
 }
 
 static void
 }
 
 static void
-ppp_print_char (register u_char * out, u_char * in, int count)
+ppp_print_char (register u_char * out, const u_char * in, int count)
 {
        register u_char next_ch;
 
 {
        register u_char next_ch;
 
@@ -3327,7 +3442,7 @@ ppp_print_char (register u_char * out, u_char * in, int count)
 }
 
 static void
 }
 
 static void
-ppp_print_buffer (const u_char * name, u_char * buf, int count)
+ppp_print_buffer (const u_char * name, const u_char * buf, int count)
 {
        u_char line[44];
 
 {
        u_char line[44];
 
@@ -3351,13 +3466,95 @@ ppp_print_buffer (const u_char * name, u_char * buf, int count)
        }
 }
 
        }
 }
 
+/*************************************************************
+ * Compressor module interface
+ *************************************************************/
+
+struct compressor_link {
+       struct compressor_link  *next;
+       struct compressor       *comp;
+};
+
+static struct compressor_link *ppp_compressors = (struct compressor_link *) 0;
+
+static struct compressor *find_compressor (int type)
+{
+       struct compressor_link *lnk;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+
+       lnk = ppp_compressors;
+       while (lnk != (struct compressor_link *) 0) {
+               if ((int) (unsigned char) lnk->comp->compress_proto == type) {
+                       restore_flags(flags);
+                       return lnk->comp;
+               }
+               lnk = lnk->next;
+       }
+
+       restore_flags(flags);
+       return (struct compressor *) 0;
+}
+
+static int ppp_register_compressor (struct compressor *cp)
+{
+       struct compressor_link *new;
+       unsigned long flags;
+
+       new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL);
+
+       if (new == (struct compressor_link *) 0)
+               return 1;
+
+       save_flags(flags);
+       cli();
+
+       if (find_compressor (cp->compress_proto)) {
+               restore_flags(flags);
+               kfree (new);
+               return 0;
+       }
+
+       new->next       = ppp_compressors;
+       new->comp       = cp;
+       ppp_compressors = new;
+
+       restore_flags(flags);
+       return 0;
+}
+
+static void ppp_unregister_compressor (struct compressor *cp)
+{
+       struct compressor_link *prev = (struct compressor_link *) 0;
+       struct compressor_link *lnk;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+
+       lnk  = ppp_compressors;
+       while (lnk != (struct compressor_link *) 0) {
+               if (lnk->comp == cp) {
+                       if (prev)
+                               prev->next = lnk->next;
+                       else
+                               ppp_compressors = lnk->next;
+                       kfree (lnk);
+                       break;
+               }
+               prev = lnk;
+               lnk  = lnk->next;
+       }
+       restore_flags(flags);
+}
+
 /*************************************************************
  * Module support routines
  *************************************************************/
 
 #ifdef MODULE
 /*************************************************************
  * Module support routines
  *************************************************************/
 
 #ifdef MODULE
-char kernel_version[] = UTS_RELEASE;
-
 int
 init_module(void)
 {
 int
 init_module(void)
 {
@@ -3365,10 +3562,11 @@ init_module(void)
 
        /* register our line disciplines */
        status = ppp_first_time();
 
        /* register our line disciplines */
        status = ppp_first_time();
-       if (status != 0) {
+       if (status != 0)
                printk (KERN_INFO
                       "PPP: ppp_init() failure %d\n", status);
                printk (KERN_INFO
                       "PPP: ppp_init() failure %d\n", status);
-       }
+       else
+               (void) register_symtab (&ppp_syms);
        return (status);
 }
 
        return (status);
 }
 
@@ -3379,27 +3577,30 @@ cleanup_module(void)
        ppp_ctrl_t *ctl, *next_ctl;
        struct device *dev;
        struct ppp *ppp;
        ppp_ctrl_t *ctl, *next_ctl;
        struct device *dev;
        struct ppp *ppp;
-       int busy_flag = MOD_IN_USE;
+       int busy_flag = 0;
 /*
  * Ensure that the devices are not in operation.
  */
 /*
  * Ensure that the devices are not in operation.
  */
-       if (!busy_flag) {
-               ctl = ppp_list;
-               while (ctl) {
-                       ppp = ctl2ppp (ctl);
-                       if (ppp->inuse && ppp->tty != NULL) {
-                               busy_flag = 1;
-                               break;
-                       }
+       ctl = ppp_list;
+       while (ctl) {
+               ppp = ctl2ppp (ctl);
+               if (ppp->inuse && ppp->tty != NULL) {
+                       busy_flag = 1;
+                       break;
+               }
 
 
-                       dev = ctl2dev (ctl);
-                       if (dev->start || dev->flags & IFF_UP) {
-                               busy_flag = 1;
-                               break;
-                       }
-                       ctl = ctl->next;
+               dev = ctl2dev (ctl);
+               if (dev->start || dev->flags & IFF_UP) {
+                       busy_flag = 1;
+                       break;
                }
                }
+               ctl = ctl->next;
        }
        }
+/*
+ * Ensure that there are no compressor modules registered
+ */
+       if (ppp_compressors != NULL)
+               busy_flag = 1;
 
        if (busy_flag) {
                printk (KERN_INFO
 
        if (busy_flag) {
                printk (KERN_INFO
@@ -3417,22 +3618,19 @@ cleanup_module(void)
                        "(err = %d)\n", status);
        else
                printk (KERN_INFO
                        "(err = %d)\n", status);
        else
                printk (KERN_INFO
-                       "PPP: ppp line discipline successfully unregistered\n");
+                      "PPP: ppp line discipline successfully unregistered\n");
 /*
  * De-register the devices so that there is no problem with them
  */    
 /*
  * De-register the devices so that there is no problem with them
  */    
-       next = ppp_list;
-       while (next) {
-               ctl = next;
-               ppp = ctl2ppp (ctl);
-               dev = ctl2dev (ctl);
-
-               ppp_release (ppp);
+       next_ctl = ppp_list;
+       while (next_ctl) {
+               ctl      = next_ctl;
+               next_ctl = ctl->next;
+               ppp      = ctl2ppp (ctl);
+               dev      = ctl2dev (ctl);
+
+               ppp_release       (ppp);
                unregister_netdev (dev);
                unregister_netdev (dev);
-/*
- * Release the storage occupied by the control structures
- */
-               next = ctl->next;
                kfree (ctl);
        }
 }
                kfree (ctl);
        }
 }
diff --git a/linux/ppp_defs.h b/linux/ppp_defs.h
new file mode 100644 (file)
index 0000000..8913ae7
--- /dev/null
@@ -0,0 +1,177 @@
+/*     $Id: ppp_defs.h,v 1.1 1995/12/18 03:38:15 paulus Exp $  */
+
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+/*
+ *  ==FILEVERSION 6==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     ppp_defs.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new ppp_defs.h
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
+
+#ifndef _PPP_DEFS_H_
+#define _PPP_DEFS_H_
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_HDRLEN     4       /* octets for standard ppp header */
+#define PPP_FCSLEN     2       /* octets for FCS */
+#define PPP_MRU                1500    /* default MRU = max length of info field */
+
+#define PPP_ADDRESS(p) (((u_char *)(p))[0])
+#define PPP_CONTROL(p) (((u_char *)(p))[1])
+#define PPP_PROTOCOL(p)        ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
+
+/*
+ * Significant octet values.
+ */
+#define        PPP_ALLSTATIONS 0xff    /* All-Stations broadcast address */
+#define        PPP_UI          0x03    /* Unnumbered Information */
+#define        PPP_FLAG        0x7e    /* Flag Sequence */
+#define        PPP_ESCAPE      0x7d    /* Asynchronous Control Escape */
+#define        PPP_TRANS       0x20    /* Asynchronous transparency modifier */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP         0x21    /* Internet Protocol */
+#define PPP_IPX                0x2b    /* IPX protocol */
+#define        PPP_VJC_COMP    0x2d    /* VJ compressed TCP */
+#define        PPP_VJC_UNCOMP  0x2f    /* VJ uncompressed TCP */
+#define PPP_COMP       0xfd    /* compressed packet */
+#define PPP_IPCP       0x8021  /* IP Control Protocol */
+#define PPP_IPXCP      0x802b  /* IPX Control Protocol */
+#define PPP_CCP                0x80fd  /* Compression Control Protocol */
+#define PPP_LCP                0xc021  /* Link Control Protocol */
+#define PPP_PAP                0xc023  /* Password Authentication Protocol */
+#define PPP_LQR                0xc025  /* Link Quality Report protocol */
+#define PPP_CHAP       0xc223  /* Cryptographic Handshake Auth. Protocol */
+
+/*
+ * A 32-bit unsigned integral type.
+ */
+#ifndef __BIT_TYPES_DEFINED__
+#ifdef UINT32_T
+typedef UINT32_T       u_int32_t;
+#else
+typedef unsigned int   u_int32_t;
+#endif
+#endif
+
+/*
+ * Extended asyncmap - allows any character to be escaped.
+ */
+typedef u_int32_t      ext_accm[8];
+
+/*
+ * What to do with network protocol (NP) packets.
+ */
+enum NPmode {
+    NPMODE_PASS,               /* pass the packet through */
+    NPMODE_DROP,               /* silently drop the packet */
+    NPMODE_ERROR,              /* return an error */
+    NPMODE_QUEUE               /* save it up for later. */
+};
+
+/*
+ * Statistics for LQRP and pppstats
+ */
+struct pppstat {
+    u_int      ppp_discards;   /* # frames discarded */
+
+    u_int      ppp_ibytes;     /* bytes received */
+    u_int      ppp_ioctects;   /* bytes received not in error */
+    u_int      ppp_ipackets;   /* packets received */
+    u_int      ppp_ierrors;    /* receive errors */
+    u_int      ppp_ilqrs;      /* # LQR frames received */
+
+    u_int      ppp_obytes;     /* raw bytes sent */
+    u_int      ppp_ooctects;   /* frame bytes sent */
+    u_int      ppp_opackets;   /* packets sent */
+    u_int      ppp_oerrors;    /* transmit errors */ 
+    u_int      ppp_olqrs;      /* # LQR frames sent */
+};
+
+struct vjstat {
+    u_int      vjs_packets;    /* outbound packets */
+    u_int      vjs_compressed; /* outbound compressed packets */
+    u_int      vjs_searches;   /* searches for connection state */
+    u_int      vjs_misses;     /* times couldn't find conn. state */
+    u_int      vjs_uncompressedin; /* inbound uncompressed packets */
+    u_int      vjs_compressedin;   /* inbound compressed packets */
+    u_int      vjs_errorin;    /* inbound unknown type packets */
+    u_int      vjs_tossed;     /* inbound packets tossed because of error */
+};
+
+struct compstat {
+    u_int      unc_bytes;      /* total uncompressed bytes */
+    u_int      unc_packets;    /* total uncompressed packets */
+    u_int      comp_bytes;     /* compressed bytes */
+    u_int      comp_packets;   /* compressed packets */
+    u_int      inc_bytes;      /* incompressible bytes */
+    u_int      inc_packets;    /* incompressible packets */
+    /* the compression ratio is defined as in_count / bytes_out */
+    u_int       in_count;      /* Bytes received */
+    u_int       bytes_out;     /* Bytes transmitted */
+    double     ratio;          /* not computed in kernel. */
+};
+
+struct ppp_stats {
+    struct pppstat     p;      /* basic PPP statistics */
+    struct vjstat      vj;     /* VJ header compression statistics */
+};
+
+struct ppp_comp_stats {
+    struct compstat    c;      /* packet compression statistics */
+    struct compstat    d;      /* packet decompression statistics */
+};
+
+/*
+ * The following structure records the time in seconds since
+ * the last NP packet was sent or received.
+ */
+struct ppp_idle {
+    time_t xmit_idle;          /* time since last NP packet sent */
+    time_t recv_idle;          /* time since last NP packet received */
+};
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+#endif
+
+#endif /* _PPP_DEFS_H_ */
diff --git a/linux/route.h b/linux/route.h
new file mode 100644 (file)
index 0000000..5be4853
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Global definitions for the IP router interface.
+ *
+ * Version:    @(#)route.h     1.0.3   05/27/93
+ *
+ * Authors:    Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
+ *             for the purposes of compatibility only.
+ *
+ *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_ROUTE_H
+#define _LINUX_ROUTE_H
+
+#include <linux/if.h>
+
+
+/* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */
+struct rtentry 
+{
+       unsigned long   rt_hash;        /* hash key for lookups         */
+       struct sockaddr rt_dst;         /* target address               */
+       struct sockaddr rt_gateway;     /* gateway addr (RTF_GATEWAY)   */
+       struct sockaddr rt_genmask;     /* target network mask (IP)     */
+       short           rt_flags;
+       short           rt_refcnt;
+       unsigned long   rt_use;
+       struct ifnet    *rt_ifp;
+       short           rt_metric;      /* +1 for binary compatibility! */
+       char            *rt_dev;        /* forcing the device at add    */
+       unsigned long   rt_mss;         /* per route MTU/Window         */
+       unsigned long   rt_window;      /* Window clamping              */
+       unsigned short  rt_irtt;        /* Initial RTT                  */
+};
+
+
+#define        RTF_UP          0x0001          /* route usable                   */
+#define        RTF_GATEWAY     0x0002          /* destination is a gateway       */
+#define        RTF_HOST        0x0004          /* host entry (net otherwise)     */
+#define RTF_REINSTATE  0x0008          /* reinstate route after tmout    */
+#define        RTF_DYNAMIC     0x0010          /* created dyn. (by redirect)     */
+#define        RTF_MODIFIED    0x0020          /* modified dyn. (by redirect)    */
+#define RTF_MSS                0x0040          /* specific MSS for this route    */
+#define RTF_WINDOW     0x0080          /* per route window clamping      */
+#define RTF_IRTT       0x0100          /* Initial round trip time        */
+#define RTF_REJECT     0x0200          /* Reject route                   */
+
+/*
+ *     This structure is passed from the kernel to user space by netlink
+ *     routing/device announcements
+ */
+
+struct netlink_rtinfo
+{
+       unsigned long   rtmsg_type;
+       struct sockaddr rtmsg_dst;
+       struct sockaddr rtmsg_gateway;
+       struct sockaddr rtmsg_genmask;
+       short           rtmsg_flags;
+       short           rtmsg_metric;
+       char            rtmsg_device[16];
+};
+
+#define RTMSG_NEWROUTE         0x01
+#define RTMSG_DELROUTE         0x02
+#define RTMSG_NEWDEVICE                0x11
+#define RTMSG_DELDEVICE                0x12
+
+#endif /* _LINUX_ROUTE_H */
+
index b1376ecb52a55f3f9fb106e6a65e76af3730323c..b67d8541184b1768ae4ea8d096ac9571ff2d8b3c 100644 (file)
@@ -1,15 +1,15 @@
 #
 # pppd makefile for Linux
 #
 # pppd makefile for Linux
-# $Id: Makefile.linux,v 1.9 1995/12/11 02:55:25 paulus Exp $
+# $Id: Makefile.linux,v 1.10 1995/12/18 03:32:57 paulus Exp $
 #
 
 PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
 #
 
 PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
-       auth.c options.c sys-linux.c
+       auth.c options.c sys-linux.c ipxcp.c
 HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h
 MANPAGES = pppd.8
 
 PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
 HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h
 MANPAGES = pppd.8
 
 PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
-       auth.o options.o sys-linux.o
+       auth.o options.o sys-linux.o ipxcp.o
 
 all: pppd
 
 
 all: pppd
 
@@ -22,12 +22,12 @@ endif
 
 # CC = gcc
 # DEBUG_FLAGS = -DDEBUGALL
 
 # CC = gcc
 # DEBUG_FLAGS = -DDEBUGALL
-COMPILE_FLAGS = -D_linux_=1 -DHAVE_PATHS_H
+COMPILE_FLAGS = -D_linux_=1 -DHAVE_PATHS_H # -DUSE_MS_DNS=1 # -DIPX_CHANGE=1
 COPTS = -g # -O2
 VER = 0.2.8
 LIBS = -lbsd
 
 COPTS = -g # -O2
 VER = 0.2.8
 LIBS = -lbsd
 
-CFLAGS = $(COPTS) $(DEBUG_FLAGS) $(COMPILE_FLAGS)
+CFLAGS= $(COPTS) $(DEBUG_FLAGS) $(COMPILE_FLAGS)
 SOURCE= RELNOTES Makefile.linux $(PPPDSRCS) $(HEADERS) $(MANPAGES)
 
 install: pppd
 SOURCE= RELNOTES Makefile.linux $(PPPDSRCS) $(HEADERS) $(MANPAGES)
 
 install: pppd
diff --git a/pppd/ipxcp.c b/pppd/ipxcp.c
new file mode 100644 (file)
index 0000000..fcae076
--- /dev/null
@@ -0,0 +1,1360 @@
+/*
+ * ipxcp.c - PPP IPX Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef IPX_CHANGE
+#ifndef lint
+static char rcsid[] = "$Id: ipxcp.c,v 1.1 1995/12/18 03:32:59 paulus Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipxcp.h"
+#include "pathnames.h"
+
+/* global vars */
+ipxcp_options ipxcp_wantoptions[NUM_PPP];      /* Options that we want to request */
+ipxcp_options ipxcp_gotoptions[NUM_PPP];       /* Options that peer ack'd */
+ipxcp_options ipxcp_allowoptions[NUM_PPP];     /* Options we allow peer to request */
+ipxcp_options ipxcp_hisoptions[NUM_PPP];       /* Options that we ack'd */
+
+#define wo (&ipxcp_wantoptions[0])
+#define ao (&ipxcp_allowoptions[0])
+#define go (&ipxcp_gotoptions[0])
+#define ho (&ipxcp_hisoptions[0])
+
+/*
+ * Callbacks for fsm code.  (CI = Configuration Information)
+ */
+static void ipxcp_resetci __P((fsm *));        /* Reset our CI */
+static int  ipxcp_cilen __P((fsm *));          /* Return length of our CI */
+static void ipxcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
+static int  ipxcp_ackci __P((fsm *, u_char *, int));   /* Peer ack'd our CI */
+static int  ipxcp_nakci __P((fsm *, u_char *, int));   /* Peer nak'd our CI */
+static int  ipxcp_rejci __P((fsm *, u_char *, int));   /* Peer rej'd our CI */
+static int  ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
+static void ipxcp_up __P((fsm *));             /* We're UP */
+static void ipxcp_down __P((fsm *));           /* We're DOWN */
+static void ipxcp_script __P((fsm *, char *)); /* Run an up/down script */
+
+fsm ipxcp_fsm[NUM_PPP];                /* IPXCP fsm structure */
+
+static fsm_callbacks ipxcp_callbacks = { /* IPXCP callback routines */
+    ipxcp_resetci,             /* Reset our Configuration Information */
+    ipxcp_cilen,               /* Length of our Configuration Information */
+    ipxcp_addci,               /* Add our Configuration Information */
+    ipxcp_ackci,               /* ACK our Configuration Information */
+    ipxcp_nakci,               /* NAK our Configuration Information */
+    ipxcp_rejci,               /* Reject our Configuration Information */
+    ipxcp_reqci,               /* Request peer's Configuration Information */
+    ipxcp_up,                  /* Called when fsm reaches OPENED state */
+    ipxcp_down,                        /* Called when fsm leaves OPENED state */
+    NULL,                      /* Called when we want the lower layer up */
+    NULL,                      /* Called when we want the lower layer down */
+    NULL,                      /* Called when Protocol-Reject received */
+    NULL,                      /* Retransmission is necessary */
+    NULL,                      /* Called to handle protocol-specific codes */
+    "IPXCP"                    /* String name of protocol */
+};
+
+struct protent ipxcp_protent = {
+    PPP_IPXCP, ipxcp_init, ipxcp_input, ipxcp_protrej,
+    ipxcp_lowerup, ipxcp_lowerdown, ipxcp_open, ipxcp_close,
+    ipxcp_printpkt, NULL, 0, "IPXCP"
+};
+
+
+/*
+ * Lengths of configuration options.
+ */
+
+#define CILEN_VOID     2
+#define CILEN_COMPLETE 2       /* length of complete option */
+#define CILEN_NETN     6       /* network number length option */
+#define CILEN_NODEN    8       /* node number length option */
+#define CILEN_PROTOCOL 4       /* Minimum length of routing protocol */
+#define CILEN_NAME     3       /* Minimum length of router name */
+#define CILEN_COMPRESS 4       /* Minimum length of compression protocol */
+
+#define CODENAME(x)    ((x) == CONFACK ? "ACK" : \
+                        (x) == CONFNAK ? "NAK" : "REJ")
+
+/* Used in printing the node number */
+#define NODE(base) base[0], base[1], base[2], base[3], base[4], base[5]
+
+/* Used to generate the proper bit mask */
+#define BIT(num)   (1 << (num))
+
+/*
+ * Make a string representation of a network IP address.
+ */
+
+char *
+ipx_ntoa(ipxaddr)
+u_int32_t ipxaddr;
+{
+    static char b[64];
+    sprintf(b, "%lx", ipxaddr);
+    return b;
+}
+
+
+/*
+ * ipxcp_init - Initialize IPXCP.
+ */
+void
+ipxcp_init(unit)
+    int unit;
+{
+    fsm *f = &ipxcp_fsm[unit];
+
+    f->unit     = unit;
+    f->protocol         = PPP_IPXCP;
+    f->callbacks = &ipxcp_callbacks;
+    fsm_init(&ipxcp_fsm[unit]);
+
+    memset (wo->name,    0, sizeof (wo->name));
+    memset (wo->our_node, 0, sizeof (wo->our_node));
+    memset (wo->his_node, 0, sizeof (wo->his_node));
+
+    wo->neg_nn        = 1;
+    wo->neg_complete   = 1;
+    wo->network               = 0;
+
+    ao->neg_node       = 1;
+    ao->neg_nn        = 1;
+    ao->neg_name       = 1;
+    ao->neg_complete   = 1;
+    ao->neg_router     = 1;
+
+    ao->accept_local   = 0;
+    ao->accept_remote  = 0;
+    ao->accept_network = 0;
+}
+
+/*
+ * Copy the node number
+ */
+
+static void
+copy_node (src, dst)
+u_char *src, *dst;
+{
+    memcpy (dst, src, sizeof (ipxcp_wantoptions[0].our_node));
+}
+
+/*
+ * Compare node numbers
+ */
+
+static int
+compare_node (src, dst)
+u_char *src, *dst;
+{
+    return memcmp (dst, src, sizeof (ipxcp_wantoptions[0].our_node)) == 0;
+}
+
+/*
+ * Is the node number zero?
+ */
+
+static int
+zero_node (node)
+u_char *node;
+{
+    int indx;
+    for (indx = 0; indx < sizeof (ipxcp_wantoptions[0].our_node); ++indx)
+       if (node [indx] != 0)
+           return 0;
+    return 1;
+}
+
+/*
+ * Increment the node number
+ */
+
+static void
+inc_node (node)
+u_char *node;
+{
+    u_char   *outp;
+    u_int32_t magic_num;
+
+    outp      = node;
+    magic_num = magic();
+    *outp++   = '\0';
+    *outp++   = '\0';
+    PUTLONG (magic_num, outp);
+}
+
+/*
+ * ipxcp_open - IPXCP is allowed to come up.
+ */
+void
+ipxcp_open(unit)
+    int unit;
+{
+    fsm_open(&ipxcp_fsm[unit]);
+}
+
+/*
+ * ipxcp_close - Take IPXCP down.
+ */
+void
+ipxcp_close(unit, reason)
+    int unit;
+    char *reason;
+{
+    fsm_close(&ipxcp_fsm[unit], reason);
+}
+
+
+/*
+ * ipxcp_lowerup - The lower layer is up.
+ */
+void
+ipxcp_lowerup(unit)
+    int unit;
+{
+    extern int ipx_enabled;
+
+    fsm_lowerup(&ipxcp_fsm[unit], ipx_enabled);
+}
+
+
+/*
+ * ipxcp_lowerdown - The lower layer is down.
+ */
+void
+ipxcp_lowerdown(unit)
+    int unit;
+{
+    fsm_lowerdown(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_input - Input IPXCP packet.
+ */
+void
+ipxcp_input(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    fsm_input(&ipxcp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipxcp_protrej - A Protocol-Reject was received for IPXCP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+void
+ipxcp_protrej(unit)
+    int unit;
+{
+    fsm_lowerdown(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_resetci - Reset our CI.
+ */
+static void
+ipxcp_resetci(f)
+    fsm *f;
+{
+    u_int32_t network;
+    int unit = f->unit;
+
+    wo->req_node = wo->neg_node && ao->neg_node;
+    wo->req_nn  = wo->neg_nn   && ao->neg_nn;
+
+    if (wo->our_network == 0) {
+       wo->neg_node       = 1;
+       ao->accept_network = 1;
+    }
+/*
+ * If our node number is zero then change it.
+ */
+    if (zero_node (wo->our_node)) {
+       inc_node (wo->our_node);
+       ao->accept_local = 1;
+       wo->neg_node     = 1;
+    }
+/*
+ * If his node number is zero then change it.
+ */
+    if (zero_node (wo->his_node)) {
+       inc_node (wo->his_node);
+       ao->accept_remote = 1;
+    }
+/*
+ * Unless router protocol is suppressed then assume that we can do RIP.
+ */
+    if (! (wo->router & BIT(0)))
+       wo->router |= BIT(2);
+/*
+ * Router protocol is only negotiated if requested. Others force the
+ * negotiation.
+ */
+    if (wo->router & (BIT(2) | BIT(4)))
+       wo->neg_router = 1;
+/*
+ * Start with these default values
+ */
+    *go = *wo;
+}
+
+/*
+ * ipxcp_cilen - Return length of our CI.
+ */
+static int
+ipxcp_cilen(f)
+    fsm *f;
+{
+    int unit = f->unit;
+    int len;
+
+    len         = go->neg_nn       ? CILEN_NETN     : 0;
+    len += go->neg_node            ? CILEN_NODEN    : 0;
+    len += go->neg_name            ? CILEN_NAME + strlen (go->name) - 1 : 0;
+    len += go->neg_complete ? CILEN_COMPLETE : 0;
+/*
+ * Router protocol 0 is mutually exclusive with the others.
+ */
+    if (go->neg_router) {
+       if (go->router & BIT(0))
+           len += CILEN_PROTOCOL;
+       else {
+           if (go->router & BIT(2))
+               len += CILEN_PROTOCOL;
+           if (go->router & BIT(4))
+               len += CILEN_PROTOCOL;
+       }
+    }
+
+    return (len);
+}
+
+
+/*
+ * ipxcp_addci - Add our desired CIs to a packet.
+ */
+static void
+ipxcp_addci(f, ucp, lenp)
+    fsm *f;
+    u_char *ucp;
+    int *lenp;
+{
+    int len = *lenp;
+    int unit = f->unit;
+/*
+ * Add the options to the record.
+ */
+    if (go->neg_nn) {
+       PUTCHAR (IPX_NETWORK_NUMBER, ucp);
+       PUTCHAR (CILEN_NETN, ucp);
+       PUTLONG (go->our_network, ucp);
+    }
+
+    if (go->neg_node) {
+       int indx;
+       PUTCHAR (IPX_NODE_NUMBER, ucp);
+       PUTCHAR (CILEN_NODEN, ucp);
+       for (indx = 0; indx < sizeof (go->our_node); ++indx)
+           PUTCHAR (go->our_node[indx], ucp);
+    }
+
+    if (go->neg_name) {
+       int cilen = strlen (go->name);
+       int indx;
+       PUTCHAR (IPX_ROUTER_NAME, ucp);
+       PUTCHAR (CILEN_NAME + cilen - 1, ucp);
+       for (indx = 0; indx < cilen; ++indx)
+           PUTCHAR (go->name [indx], ucp);
+    }
+
+    if (go->neg_router && (go->router & (BIT(0) | BIT(2) | BIT(4)))) {
+       if (go->router & BIT(0)) {
+           PUTCHAR  (IPX_ROUTER_PROTOCOL, ucp);
+           PUTCHAR  (CILEN_PROTOCOL,      ucp);
+           PUTSHORT (0,                   ucp);
+       } else {
+           if (go->router & BIT(2)) {
+               PUTCHAR  (IPX_ROUTER_PROTOCOL, ucp);
+               PUTCHAR  (CILEN_PROTOCOL,      ucp);
+               PUTSHORT (2,                   ucp);
+           }
+           
+           if (go->router & BIT(4)) {
+               PUTCHAR  (IPX_ROUTER_PROTOCOL, ucp);
+               PUTCHAR  (CILEN_PROTOCOL,      ucp);
+               PUTSHORT (4,                   ucp);
+           }
+       }
+    }
+
+    if (go->neg_complete) {
+       PUTCHAR (IPX_COMPLETE,   ucp);
+       PUTCHAR (CILEN_COMPLETE, ucp);
+    }
+}
+
+/*
+ * ipxcp_ackci - Ack our CIs.
+ *
+ * Returns:
+ *     0 - Ack was bad.
+ *     1 - Ack was good.
+ */
+static int
+ipxcp_ackci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    int unit = f->unit;
+    u_short cilen, citype, cishort;
+    u_char cichar;
+    u_int32_t cilong;
+
+#define ACKCIVOID(opt, neg) \
+    if (neg) { \
+       if ((len -= CILEN_VOID) < 0) \
+           break; \
+       GETCHAR(citype, p); \
+       GETCHAR(cilen, p); \
+       if (cilen != CILEN_VOID || \
+           citype != opt) \
+           break; \
+    }
+
+#define ACKCICOMPLETE(opt,neg) ACKCIVOID(opt, neg)
+
+#define ACKCICHARS(opt, neg, val, cnt) \
+    if (neg) { \
+       int indx, count = cnt; \
+       len -= (count + 2); \
+       if (len < 0) \
+           break; \
+       GETCHAR(citype, p); \
+       GETCHAR(cilen, p); \
+       if (cilen != (count + 2) || \
+           citype != opt) \
+           break; \
+       for (indx = 0; indx < count; ++indx) {\
+           GETCHAR(cichar, p); \
+           if (cichar != ((u_char *) &val)[indx]) \
+              break; \
+       }\
+       if (indx != count) \
+           break; \
+    }
+
+#define ACKCINODE(opt,neg,val) ACKCICHARS(opt,neg,val,sizeof(val))
+#define ACKCINAME(opt,neg,val) ACKCICHARS(opt,neg,val,strlen(val))
+
+#define ACKCINETWORK(opt, neg, val) \
+    if (neg) { \
+       if ((len -= CILEN_NETN) < 0) \
+           break; \
+       GETCHAR(citype, p); \
+       GETCHAR(cilen, p); \
+       if (cilen != CILEN_NETN || \
+           citype != opt) \
+           break; \
+       GETLONG(cilong, p); \
+       if (cilong != val) \
+           break; \
+    }
+
+#define ACKCIPROTO(opt, neg, val, bit) \
+    if (neg && (val & BIT(bit))) \
+      { \
+       if (len < 2) \
+           break; \
+       GETCHAR(citype, p); \
+       GETCHAR(cilen, p); \
+       if (cilen != CILEN_PROTOCOL || citype != opt) \
+           break; \
+       len -= cilen; \
+       if (len < 0) \
+           break; \
+       GETSHORT(cishort, p); \
+       if (cishort != (bit)) \
+           break; \
+      }
+/*
+ * Process the ACK frame in the order in which the frame was assembled
+ */
+    do {
+       ACKCINETWORK  (IPX_NETWORK_NUMBER,  go->neg_nn,     go->our_network);
+       ACKCINODE     (IPX_NODE_NUMBER,     go->neg_node,   go->our_node);
+       ACKCINAME     (IPX_ROUTER_NAME,     go->neg_name,   go->name);
+       ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router, 0);
+       ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router, 2);
+       ACKCIPROTO    (IPX_ROUTER_PROTOCOL, go->neg_router, go->router, 4);
+       ACKCICOMPLETE (IPX_COMPLETE,        go->neg_complete);
+/*
+ * This is the end of the record.
+ */
+       if (len == 0)
+           return (1);
+    } while (0);
+/*
+ * The frame is invalid
+ */
+    IPXCPDEBUG((LOG_INFO, "ipxcp_ackci: received bad Ack!"));
+    return (0);
+}
+
+/*
+ * ipxcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPXCP is in the OPENED state.
+ *
+ * Returns:
+ *     0 - Nak was bad.
+ *     1 - Nak was good.
+ */
+
+static int
+ipxcp_nakci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    int unit = f->unit;
+    u_char citype, cilen, *next;
+    u_short s;
+    u_int32_t l;
+    ipxcp_options no;          /* options we've seen Naks for */
+    ipxcp_options try;         /* options to request next time */
+
+    BZERO(&no, sizeof(no));
+    try = *go;
+
+    while (len > CILEN_VOID) {
+       GETCHAR (citype, p);
+       GETCHAR (cilen,  p);
+       len -= cilen;
+       if (len < 0)
+           goto bad;
+       next = &p [cilen - CILEN_VOID];
+
+       switch (citype) {
+       case IPX_NETWORK_NUMBER:
+           if (!go->neg_nn || no.neg_nn || (cilen != CILEN_NETN))
+               goto bad;
+           no.neg_nn = 1;
+
+           GETLONG(l, p);
+           IPXCPDEBUG((LOG_INFO, "local IP address %d", l));
+           if (l && ao->accept_network)
+               try.our_network = l;
+           break;
+
+       case IPX_NODE_NUMBER:
+           if (!go->neg_node || no.neg_node || (cilen != CILEN_NODEN))
+               goto bad;
+           no.neg_node = 1;
+
+           IPXCPDEBUG((LOG_INFO,
+                       "local node number %02X%02X%02X%02X%02X%02X",
+                       NODE(p)));
+
+           if (!zero_node (p) && ao->accept_local &&
+               ! compare_node (p, ho->his_node))
+               copy_node (p, try.our_node);
+           break;
+
+           /* These have never been sent. Ignore the NAK frame */
+       case IPX_COMPRESSION_PROTOCOL:
+           goto bad;
+
+       case IPX_ROUTER_PROTOCOL:
+           if (!go->neg_router || (cilen < CILEN_PROTOCOL))
+               goto bad;
+
+           GETSHORT (s, p);
+           if ((s != 0) && (s != 2) && (s != 4))
+               goto bad;
+
+           if (no.router & BIT(s))
+               goto bad;
+
+           if (no.router == 0) /* Reset on first NAK only */
+               try.router = 0;
+           no.router      |= BIT(s);
+           try.router     |= BIT(s);
+           try.neg_router  = 1;
+
+           IPXCPDEBUG((LOG_INFO, "Router protocol number %d", s));
+           break;
+
+           /* These, according to the RFC, must never be NAKed. */
+       case IPX_ROUTER_NAME:
+       case IPX_COMPLETE:
+           goto bad;
+
+           /* These are for options which we have not seen. */
+       default:
+           break;
+       }
+       p = next;
+    }
+
+    /* If there is still anything left, this packet is bad. */
+    if (len != 0)
+       goto bad;
+
+    /*
+     * Do not permit the peer to force a router protocol which we do not
+     * support.
+     */
+    try.router &= go->router;
+    if (try.router == 0 && go->router != 0) {
+        try.neg_router = 1;
+       try.router     = BIT(0);
+    }
+    
+    /*
+     * OK, the Nak is good.  Now we can update state.
+     */
+    if (f->state != OPENED)
+       *go = try;
+
+    return 1;
+
+bad:
+    IPXCPDEBUG((LOG_INFO, "ipxcp_nakci: received bad Nak!"));
+    return 0;
+}
+
+/*
+ * ipxcp_rejci - Reject some of our CIs.
+ */
+static int
+ipxcp_rejci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    int unit = f->unit;
+    u_short cilen, citype, cishort;
+    u_char cichar;
+    u_int32_t cilong;
+    ipxcp_options try;         /* options to request next time */
+
+#define REJCINETWORK(opt, neg, val) \
+    if (neg) { \
+       neg = 0; \
+       if ((len -= CILEN_NETN) < 0) \
+           break; \
+       GETCHAR(citype, p); \
+       GETCHAR(cilen, p); \
+       if (cilen != CILEN_NETN || \
+           citype != opt) \
+           break; \
+       GETLONG(cilong, p); \
+       if (cilong != val) \
+           break; \
+       IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected long opt %d", opt)); \
+    }
+
+#define REJCICHARS(opt, neg, val, cnt) \
+    if (neg) { \
+       int indx, count = cnt; \
+       neg = 0; \
+       len -= (count + 2); \
+       if (len < 0) \
+           break; \
+       GETCHAR(citype, p); \
+       GETCHAR(cilen, p); \
+       if (cilen != (count + 2) || \
+           citype != opt) \
+           break; \
+       for (indx = 0; indx < count; ++indx) {\
+           GETCHAR(cichar, p); \
+           if (cichar != ((u_char *) &val)[indx]) \
+              break; \
+       }\
+       if (indx != count) \
+           break; \
+       IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected opt %d", opt)); \
+    }
+
+#define REJCINODE(opt,neg,val) REJCICHARS(opt,neg,val,sizeof(val))
+#define REJCINAME(opt,neg,val) REJCICHARS(opt,neg,val,strlen(val))
+
+#define REJCIVOID(opt, neg) \
+    if (neg) { \
+       neg = 0; \
+       if ((len -= CILEN_VOID) < 0) \
+           break; \
+       GETCHAR(citype, p); \
+       GETCHAR(cilen, p); \
+       if (cilen != CILEN_VOID || citype != opt) \
+           break; \
+       IPXCPDEBUG((LOG_INFO, "ipxcp_rejci rejected void opt %d", opt)); \
+    }
+
+#define REJCIPROTO(opt, neg, val, bit) \
+    if (neg && (val & BIT(bit))) \
+      { \
+       if (len < 2) \
+           break; \
+       GETCHAR(citype, p); \
+       GETCHAR(cilen, p); \
+       if (cilen != CILEN_PROTOCOL || citype != opt) \
+           break; \
+       len -= cilen; \
+       if (len < 0) \
+           break; \
+       GETSHORT(cishort, p); \
+       if (cishort != (bit)) \
+           break; \
+       IPXCPDEBUG((LOG_INFO, "ipxcp_rejci rejected router proto %d", bit)); \
+       val &= ~BIT(bit); \
+       if (val == 0) \
+           neg = 0; \
+      }
+
+/*
+ * Any Rejected CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+    try = *go;
+
+    do {
+       REJCINETWORK (IPX_NETWORK_NUMBER,  try.neg_nn,     try.our_network);
+       REJCINODE    (IPX_NODE_NUMBER,     try.neg_node,   try.our_node);
+       REJCIPROTO   (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 0);
+       REJCIPROTO   (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 2);
+       REJCIPROTO   (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 4);
+       REJCINAME    (IPX_ROUTER_NAME,     try.neg_name,   try.name);
+       REJCIVOID    (IPX_COMPLETE,        try.neg_complete);
+/*
+ * This is the end of the record.
+ */
+       if (len == 0) {
+           if (f->state != OPENED)
+               *go = try;
+           return (1);
+       }
+    } while (0);
+/*
+ * The frame is invalid at this point.
+ */
+    IPXCPDEBUG((LOG_INFO, "ipxcp_rejci: received bad Reject!"));
+    return 0;
+}
+
+/*
+ * ipxcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+ipxcp_reqci(f, inp, len, reject_if_disagree)
+    fsm *f;
+    u_char *inp;               /* Requested CIs */
+    int *len;                  /* Length of requested CIs */
+    int reject_if_disagree;
+{
+    int unit = f->unit;
+    u_char *cip, *next;                /* Pointer to current and next CIs */
+    u_short cilen, citype;     /* Parsed len, type */
+    u_short cishort, ts;       /* Parsed short value */
+    u_int32_t tl, cinetwork, outnet;/* Parsed address values */
+    int rc = CONFACK;          /* Final packet return code */
+    int orc;                   /* Individual option return code */
+    u_char *p;                 /* Pointer to next char to parse */
+    u_char *ucp = inp;         /* Pointer to current output char */
+    int l = *len;              /* Length left */
+    u_char maxslotindex, cflag;
+
+    /*
+     * Reset all his options.
+     */
+    BZERO(ho, sizeof(*ho));
+    
+    /*
+     * Process all his options.
+     */
+    next = inp;
+    while (l) {
+       orc = CONFACK;                  /* Assume success */
+       cip = p = next;                 /* Remember begining of CI */
+       if (l < 2 ||                    /* Not enough data for CI header or */
+           p[1] < 2 ||                 /*  CI length too small or */
+           p[1] > l) {                 /*  CI length too big? */
+           IPXCPDEBUG((LOG_INFO, "ipxcp_reqci: bad CI length!"));
+           orc = CONFREJ;              /* Reject bad CI */
+           cilen = l;                  /* Reject till end of packet */
+           l = 0;                      /* Don't loop again */
+           goto endswitch;
+       }
+       GETCHAR(citype, p);             /* Parse CI type */
+       GETCHAR(cilen, p);              /* Parse CI length */
+       l -= cilen;                     /* Adjust remaining length */
+       next += cilen;                  /* Step to next CI */
+
+       switch (citype) {               /* Check CI type */
+/*
+ * The network number must match. Choose the larger of the two.
+ */
+       case IPX_NETWORK_NUMBER:
+           IPXCPDEBUG((LOG_INFO, "ipxcp: received Network Number request"));
+           
+           /* if we wont negotiate the network number or the length is wrong
+              then reject the option */
+           if ( !ao->neg_nn || cilen != CILEN_NETN ) {
+               orc = CONFREJ;
+               break;          
+           }
+           GETLONG(cinetwork, p);
+           IPXCPDEBUG((LOG_INFO,"Remote proposed IPX network number is %8Lx",tl));
+
+           /* If the network numbers match then acknowledge them. */
+           if (cinetwork != 0) {
+               ho->his_network = cinetwork;
+               ho->neg_nn      = 1;
+               if (wo->our_network == cinetwork)
+                   break;
+/*
+ * If the network number is not given or we don't accept their change or
+ * the network number is too small then NAK it.
+ */
+               if (! ao->accept_network || cinetwork < wo->our_network) {
+                   DECPTR (sizeof (u_int32_t), p);
+                   PUTLONG (wo->our_network, p);
+                   orc = CONFNAK;
+               }
+               break;
+           }
+/*
+ * The peer sent '0' for the network. Give it ours if we have one.
+ */
+           if (go->our_network != 0) {
+               DECPTR (sizeof (u_int32_t), p);
+               PUTLONG (wo->our_network, p);
+               orc = CONFNAK;
+/*
+ * We don't have one. Reject the value.
+ */
+           } else
+               orc = CONFREJ;
+
+           break;
+/*
+ * The node number is required
+ */
+       case IPX_NODE_NUMBER:
+           IPXCPDEBUG((LOG_INFO, "ipxcp: received Node Number request"));
+
+           /* if we wont negotiate the node number or the length is wrong
+              then reject the option */
+           if ( cilen != CILEN_NODEN ) {
+               orc = CONFREJ;
+               break;
+           }
+
+           copy_node (p, ho->his_node);
+           ho->neg_node = 1;
+/*
+ * If the remote does not have a number and we do then NAK it with the value
+ * which we have for it. (We never have a default value of zero.)
+ */
+           if (zero_node (ho->his_node)) {
+               orc = CONFNAK;
+               copy_node (wo->his_node, p);
+               INCPTR (sizeof (wo->his_node), p);
+               break;
+           }
+/*
+ * If you have given me the expected network node number then I'll accept
+ * it now.
+ */
+           if (compare_node (wo->his_node, ho->his_node)) {
+               orc = CONFACK;
+               ho->neg_node = 1;
+               INCPTR (sizeof (wo->his_node), p);
+               break;
+           }
+/*
+ * If his node number is the same as ours then ask him to try the next
+ * value.
+ */
+           if (compare_node (ho->his_node, go->our_node)) {
+               inc_node (ho->his_node);
+               orc = CONFNAK;
+               copy_node (ho->his_node, p);
+               INCPTR (sizeof (wo->his_node), p);
+               break;
+           }
+/*
+ * If we don't accept a new value then NAK it.
+ */
+           if (! ao->accept_remote) {
+               copy_node (wo->his_node, p);
+               INCPTR (sizeof (wo->his_node), p);
+               orc = CONFNAK;
+               break;
+           }
+           orc = CONFACK;
+           ho->neg_node = 1;
+           INCPTR (sizeof (wo->his_node), p);
+           break;
+/*
+ * Compression is not desired at this time. It is always rejected.
+ */
+       case IPX_COMPRESSION_PROTOCOL:
+           IPXCPDEBUG((LOG_INFO, "ipxcp: received Compression Protocol request "));
+           orc = CONFREJ;
+           break;
+/*
+ * The routing protocol is a bitmask of various types. Any combination
+ * of the values 2 and 4 are permissible. '0' for no routing protocol must
+ * be specified only once.
+ */
+       case IPX_ROUTER_PROTOCOL:
+           if ( !ao->neg_router || cilen < CILEN_PROTOCOL ) {
+               orc = CONFREJ;
+               break;          
+           }
+
+           GETSHORT (cishort, p);
+           IPXCPDEBUG((LOG_INFO,
+                       "Remote router protocol number %d",
+                       cishort));
+
+           if ((cishort == 0 && ho->router != 0) || (ho->router & BIT(0))) {
+               orc = CONFREJ;
+               break;          
+           }
+
+           if (cishort != 0 && cishort != 2 && cishort != 4) {
+               orc = CONFREJ;
+               break;
+           }
+
+           if (ho->router & BIT (cishort)) {
+               orc = CONFREJ;
+               break;
+           }
+
+           ho->router    |= BIT (cishort);
+           ho->neg_router = 1;
+           break;
+/*
+ * The router name is advisorary. Just accept it if it is not too large.
+ */
+       case IPX_ROUTER_NAME:
+           IPXCPDEBUG((LOG_INFO, "ipxcp: received Router Name request"));
+           if (cilen >= CILEN_NAME) {
+               int name_size = cilen - CILEN_NAME;
+               if (name_size > sizeof (ho->name))
+                   name_size = sizeof (ho->name) - 1;
+               memset (ho->name, 0, sizeof (ho->name));
+               memcpy (ho->name, p, name_size);
+               ho->name [name_size] = '\0';
+               ho->neg_name = 1;
+               orc = CONFACK;
+               break;
+           }
+           orc = CONFREJ;
+           break;
+/*
+ * This is advisorary.
+ */
+       case IPX_COMPLETE:
+           IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request"));
+           if (cilen != CILEN_COMPLETE)
+               orc = CONFREJ;
+           else {
+               ho->neg_complete = 1;
+               orc = CONFACK;
+           }
+           break;
+/*
+ * All other entries are not known at this time.
+ */
+       default:
+           IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request"));
+           orc = CONFREJ;
+           break;
+       }
+
+endswitch:
+       IPXCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc)));
+
+       if (orc == CONFACK &&           /* Good CI */
+           rc != CONFACK)              /*  but prior CI wasnt? */
+           continue;                   /* Don't send this one */
+
+       if (orc == CONFNAK) {           /* Nak this CI? */
+           if (reject_if_disagree)     /* Getting fed up with sending NAKs? */
+               orc = CONFREJ;          /* Get tough if so */
+           if (rc == CONFREJ)          /* Rejecting prior CI? */
+               continue;               /* Don't send this one */
+           if (rc == CONFACK) {        /* Ack'd all prior CIs? */
+               rc  = CONFNAK;          /* Not anymore... */
+               ucp = inp;              /* Backup */
+           }
+       }
+
+       if (orc == CONFREJ &&           /* Reject this CI */
+           rc != CONFREJ) {            /*  but no prior ones? */
+           rc = CONFREJ;
+           ucp = inp;                  /* Backup */
+       }
+
+       /* Need to move CI? */
+       if (ucp != cip)
+           BCOPY(cip, ucp, cilen);     /* Move it */
+
+       /* Update output pointer */
+       INCPTR(cilen, ucp);
+    }
+
+    /*
+     * If we aren't rejecting this packet, and we want to negotiate
+     * their address, and they didn't send their address, then we
+     * send a NAK with a IPX_NODE_NUMBER option appended. We assume the
+     * input buffer is long enough that we can append the extra
+     * option safely.
+     */
+
+    if (rc != CONFREJ && !ho->neg_node &&
+       wo->req_nn && !reject_if_disagree) {
+       u_char *ps;
+       if (rc == CONFACK) {
+           rc = CONFNAK;
+           wo->req_nn = 0;             /* don't ask again */
+           ucp = inp;                  /* reset pointer */
+       }
+
+       if (zero_node (wo->his_node))
+           inc_node (wo->his_node);
+
+       PUTCHAR (IPX_NODE_NUMBER, ucp);
+       PUTCHAR (CILEN_NODEN, ucp);
+       copy_node (wo->his_node, ucp);
+       INCPTR (sizeof (wo->his_node), ucp);
+    }
+
+    *len = ucp - inp;                  /* Compute output length */
+    IPXCPDEBUG((LOG_INFO, "ipxcp: returning Configure-%s", CODENAME(rc)));
+    return (rc);                       /* Return final code */
+}
+
+/*
+ * ipxcp_up - IPXCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
+ */
+
+static void
+ipxcp_up(f)
+    fsm *f;
+{
+    int unit = f->unit;
+
+    IPXCPDEBUG((LOG_INFO, "ipxcp: up"));
+
+    if (!ho->neg_nn)
+       ho->his_network = wo->his_network;
+
+    if (!ho->neg_node)
+       copy_node (wo->his_node, ho->his_node);
+
+    if (!wo->neg_node && !go->neg_node)
+       copy_node (wo->our_node, go->our_node);
+
+    if (zero_node (go->our_node)) {
+       IPXCPDEBUG((LOG_ERR, "Could not determine local IPX node address"));
+       ipxcp_close(f->unit, "Could not determine local IPX node address");
+       return;
+    }
+
+    go->network = go->our_network;
+    if (ho->his_network != 0 && ho->his_network > go->network)
+       go->network = ho->his_network;
+
+    if (go->network == 0) {
+       IPXCPDEBUG((LOG_ERR, "Could not determine network number"));
+       ipxcp_close (unit, "Could not determine network number");
+       return;
+    }
+
+    /* bring the interface up */
+    if (!sifup(unit)) {
+       IPXCPDEBUG((LOG_WARNING, "sifup failed"));
+       ipxcp_close(unit, "Interface configuration failed");
+       return;
+    }
+
+    /* set the network number for IPX */
+    if (!sipxfaddr(unit, go->network, go->our_node)) {
+       IPXCPDEBUG((LOG_WARNING, "sipxfaddr failed"));
+       ipxcp_close(unit, "Interface configuration failed");
+       return;
+    }
+
+    /*
+     * Execute the ipx-up script, like this:
+     * /etc/ppp/ipx-up interface tty speed local-IPX remote-IPX
+     */
+
+    ipxcp_script (f, "/etc/ppp/ipx-up");
+}
+
+/*
+ * ipxcp_down - IPXCP has gone DOWN.
+ *
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
+ */
+
+static void
+ipxcp_down(f)
+    fsm *f;
+{
+    u_int32_t ournn, network;
+
+    IPXCPDEBUG((LOG_INFO, "ipxcp: down"));
+
+    cipxfaddr (f->unit);
+    sifdown(f->unit);
+    ipxcp_script (f, "/etc/ppp/ipx-down");
+}
+
+
+/*
+ * ipxcp_script - Execute a script with arguments
+ * interface-name tty-name speed local-IPX remote-IPX networks.
+ */
+static void
+ipxcp_script(f, script)
+    fsm *f;
+    char *script;
+{
+    int         unit = f->unit;
+    char strspeed[32],  strlocal[32],     strremote[32];
+    char strnetwork[32], strpid[32];
+    char *argv[14],     strproto_lcl[32], strproto_rmt[32];
+
+    sprintf (strpid,   "%d", getpid());
+    sprintf (strspeed, "%d", baud_rate);
+
+    strproto_lcl[0] = '\0';
+    if (go->neg_router) {
+       if (go->router & BIT(2))
+           strcpy (strproto_lcl, "RIP ");
+       if (go->router & BIT(4))
+           strcpy (strproto_lcl, "NLSP ");
+    }
+
+    if (strproto_lcl[0] == '\0')
+       strcpy (strproto_lcl, "NONE ");
+
+    strproto_lcl[strlen (strproto_lcl)-1] = '\0';
+
+    strproto_rmt[0] = '\0';
+    if (ho->neg_router) {
+       if (ho->router & BIT(2))
+           strcpy (strproto_rmt, "RIP ");
+       if (ho->router & BIT(4))
+           strcpy (strproto_rmt, "NLSP ");
+    }
+
+    if (strproto_rmt[0] == '\0')
+       strcpy (strproto_rmt, "NONE ");
+
+    strproto_rmt[strlen (strproto_rmt)-1] = '\0';
+
+    strcpy (strnetwork, ipx_ntoa (go->network));
+
+    sprintf (strlocal,
+            "%02X%02X%02X%02X%02X%02X",
+            NODE(go->our_node));
+
+    sprintf (strremote,
+            "%02X%02X%02X%02X%02X%02X",
+            NODE(ho->his_node));
+
+    argv[0]  = script;
+    argv[1]  = ifname;
+    argv[2]  = devnam;
+    argv[3]  = strspeed;
+    argv[4]  = strnetwork;
+    argv[5]  = strlocal;
+    argv[6]  = strremote;
+    argv[7]  = strproto_lcl;
+    argv[8]  = strproto_rmt;
+    argv[9]  = go->name;
+    argv[10] = ho->name;
+    argv[11] = ipparam;
+    argv[12] = strpid;
+    argv[13] = NULL;
+    run_program(script, argv, 0);
+}
+
+/*
+ * ipxcp_printpkt - print the contents of an IPXCP packet.
+ */
+char *ipxcp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej"
+};
+
+int
+ipxcp_printpkt(p, plen, printer, arg)
+    u_char *p;
+    int plen;
+    void (*printer)();
+    void *arg;
+{
+    int code, id, len, olen;
+    u_char *pstart, *optend;
+    u_short cishort;
+    u_int32_t cilong;
+
+    if (plen < HEADERLEN)
+       return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+       return 0;
+
+    if (code >= 1 && code <= sizeof(ipxcp_codenames) / sizeof(char *))
+       printer(arg, " %s", ipxcp_codenames[code-1]);
+    else
+       printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+       /* print option list */
+       while (len >= 2) {
+           GETCHAR(code, p);
+           GETCHAR(olen, p);
+           p -= 2;
+           if (olen < CILEN_VOID || olen > len) {
+               break;
+           }
+           printer(arg, " <");
+           len -= olen;
+           optend = p + olen;
+           switch (code) {
+           case IPX_NETWORK_NUMBER:
+               if (olen == CILEN_NETN) {
+                   p += CILEN_VOID;
+                   GETLONG(cilong, p);
+                   printer (arg, "network %s", ipx_ntoa (cilong));
+               }
+               break;
+           case IPX_NODE_NUMBER:
+               if (olen == CILEN_NODEN) {
+                   p += CILEN_VOID;
+                   printer (arg, "node ");
+                   while (p < optend) {
+                       GETCHAR(code, p);
+                       printer(arg, "%.2x", code);
+                   }
+               }
+               break;
+           case IPX_COMPRESSION_PROTOCOL:
+               if (olen == CILEN_COMPRESS) {
+                   p += CILEN_VOID;
+                   GETSHORT (cishort, p);
+                   printer (arg, "compression %d", cishort);
+               }
+               break;
+           case IPX_ROUTER_PROTOCOL:
+               if (olen == CILEN_PROTOCOL) {
+                   p += CILEN_VOID;
+                   GETSHORT (cishort, p);
+                   printer (arg, "router proto %d", cishort);
+               }
+               break;
+           case IPX_ROUTER_NAME:
+               if (olen >= CILEN_NAME) {
+                   p += CILEN_VOID;
+                   printer (arg, "router name \"");
+                   while (p < optend) {
+                       GETCHAR(code, p);
+                       if (code >= 0x20 && code < 0x7E)
+                           printer (arg, "%c", code);
+                       else
+                           printer (arg, " \\%.2x", code);
+                   }
+                   printer (arg, "\"");
+               }
+               break;
+           case IPX_COMPLETE:
+               if (olen == CILEN_COMPLETE) {
+                   p += CILEN_VOID;
+                   printer (arg, "complete");
+               }
+               break;
+           default:
+               break;
+           }
+
+           while (p < optend) {
+               GETCHAR(code, p);
+               printer(arg, " %.2x", code);
+           }
+           printer(arg, ">");
+       }
+       break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+       GETCHAR(code, p);
+       printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
+#endif /* ifdef IPX_CHANGE */
diff --git a/pppd/ipxcp.h b/pppd/ipxcp.h
new file mode 100644 (file)
index 0000000..64cd062
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * ipxcp.h - IPX Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipxcp.h,v 1.1 1995/12/18 03:33:00 paulus Exp $
+ */
+
+/*
+ * Options.
+ */
+#define IPX_NETWORK_NUMBER        1   /* IPX Network Number */
+#define IPX_NODE_NUMBER           2
+#define IPX_COMPRESSION_PROTOCOL  3
+#define IPX_ROUTER_PROTOCOL       4
+#define IPX_ROUTER_NAME           5
+#define IPX_COMPLETE              6
+
+
+typedef struct ipxcp_options {
+    int neg_node       : 1;    /* Negotiate IPX node number? */
+    int req_node       : 1;    /* Ask peer to send IPX node number? */
+
+    int neg_nn         : 1;    /* Negotiate IPX network number? */
+    int req_nn         : 1;     /* Ask peer to send IPX network number */
+
+    int neg_name       : 1;    /* Negotiate IPX router name */
+    int neg_complete   : 1;     /* Negotiate completion */
+    int neg_router     : 1;    /* Negotiate IPX router number */
+
+    int accept_local   : 1;    /* accept peer's value for ournode */
+    int accept_remote  : 1;    /* accept peer's value for hisnode */
+    int accept_network : 1;    /* accept network number */
+
+    u_int32_t his_network;     /* base network number */
+    u_int32_t our_network;     /* our value for network number */
+    u_int32_t network;         /* the final network number */
+
+    u_char his_node[6];                /* peer's node number */
+    u_char our_node[6];                /* our node number */
+    u_char name [48];          /* name of the router */
+    int    router;             /* routing protocol */
+} ipxcp_options;
+
+extern fsm ipxcp_fsm[];
+extern ipxcp_options ipxcp_wantoptions[];
+extern ipxcp_options ipxcp_gotoptions[];
+extern ipxcp_options ipxcp_allowoptions[];
+extern ipxcp_options ipxcp_hisoptions[];
+
+void ipxcp_init __P((int));
+void ipxcp_open __P((int));
+void ipxcp_close __P((int, char *));
+void ipxcp_lowerup __P((int));
+void ipxcp_lowerdown __P((int));
+void ipxcp_input __P((int, u_char *, int));
+void ipxcp_protrej __P((int));
+int  ipxcp_printpkt __P((u_char *, int, void (*)(), void *));
+
+extern struct protent ipxcp_protent;