]> 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
@@ -7,12 +7,12 @@ CDEF4=        -UNO_SLEEP                      # Use the usleep function
 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
-       $(CC) -o chat chat.o
+       $(CC) -O2 -o chat chat.o
 
 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
-.\" $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
@@ -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
+.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.
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>
@@ -93,6 +93,7 @@ char *program_name;
 #define        DEFAULT_CHAT_TIMEOUT    45
 
 int verbose       = 0;
+int Verbose       = 0;
 int quiet         = 0;
 int report        = 0;
 int exit_code     = 0;
@@ -199,6 +200,10 @@ char **argv;
                ++verbose;
                break;
 
+           case 'V':
+               ++Verbose;
+               break;
+
            case 'f':
                if (arg = OPTARG(argc, argv))
                    {
@@ -580,7 +585,7 @@ int status;
            fprintf (report_fp, "Closing \"%s\".\n", report_file);
            }
        fclose (report_fp);
-       report_fp = (FILE*) NULL;
+       report_fp = (FILE *) NULL;
         }
 
 #if defined(get_term_param)
@@ -752,12 +757,71 @@ int sending;
     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
  */
-void chat_expect(s)
-register char *s;
+
+void chat_expect (s)
+char *s;
     {
+    char *expect;
+    char *reply;
+
     if (strcmp(s, "ABORT") == 0)
        {
        ++abort_next;
@@ -775,82 +839,57 @@ register char *s;
        ++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;
     {
@@ -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 &&
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.
  */
 
 /*
- *  ==PPPVERSION 2.1.3==
+ *  ==FILEVERSION 6==
  *
  *  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.
  */
 #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
  */
@@ -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 PROTO_DNA_RT    0x0027  /* DNA Routing */
+
 
 /*
  * Bit definitions for flags.
@@ -96,11 +104,18 @@ struct ppp_option_data {
 };
 
 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.
  */
@@ -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 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 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
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.
  *
  */
 
 /*
- *  ==PPPVERSION 2.1.3==
+ *  ==FILEVERSION 4==
  *
  *  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.
  */
  * 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        */
-  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)   */
+  unsigned char         filler[4];      /* Extra space if needed        */
 };
 
 /* 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*/
 
-       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   */
@@ -122,7 +124,7 @@ struct ppp {
        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
@@ -140,8 +142,8 @@ struct ppp {
        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 */
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.
  */
 
 /*
- *  ==PPPVERSION 2.1.3==
+ *  ==FILEVERSION 6==
  *
  *  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.
  */
 #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
  */
@@ -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 PROTO_DNA_RT    0x0027  /* DNA Routing */
+
 
 /*
  * Bit definitions for flags.
@@ -96,11 +104,18 @@ struct ppp_option_data {
 };
 
 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.
  */
@@ -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 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 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
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.
  *
  */
 
 /*
- *  ==PPPVERSION 2.1.3==
+ *  ==FILEVERSION 4==
  *
  *  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.
  */
  * 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        */
-  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)   */
+  unsigned char         filler[4];      /* Extra space if needed        */
 };
 
 /* 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*/
 
-       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   */
@@ -122,7 +124,7 @@ struct ppp {
        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
@@ -140,8 +142,8 @@ struct ppp {
        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 */
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:
- *     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;
- *     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.
- *
  */
 
 /*
 
    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.
-
-   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
+
+   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 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.
  *
  *   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 <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>
 #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
 
-#include <ip.h>
-#include <tcp.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
 #include <linux/if_arp.h>
 #include "slhc.h"
-#include <net/ppp_defs.h>
+#include <linux/ppp_defs.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
-#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)
-#endif
 
 #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
 
+static int ppp_register_compressor (struct compressor *cp);
+static void ppp_unregister_compressor (struct compressor *cp);
+
 /*
  * 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_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);
-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_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 *);
 
-/*
- * 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
@@ -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 *);
 
+#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);
@@ -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
-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 unsigned short ppp_dev_type (sk_buff *, struct device *);
 #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_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);
@@ -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 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);
 
-#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) && \
@@ -238,7 +285,6 @@ 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           */
@@ -252,14 +298,6 @@ static ppp_ctrl_t *ppp_list = NULL;
 #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      */
@@ -287,21 +325,26 @@ typedef struct ppp_proto_struct {
        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_LQR,        rcv_proto_lqr       },
-#ifdef PPP_COMPRESS
+       { PPP_LQR,        rcv_proto_lqr        },
        { PPP_CCP,        rcv_proto_ccp        },
-#endif
        { 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,
@@ -369,35 +412,22 @@ ppp_first_time (void)
        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
-               "PPP: version %s " PPP_UNITS
+               "PPP: version %s (dynamic channel allocation)"
 #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");
+#endif
        
-#ifndef PPP_NRUNIT
        printk (KERN_INFO
                "PPP Dynamic channel allocation code copyright 1995 "
                "Caldera, Inc.\n");
-#endif
-
 /*
  * 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.header_space  = 0; /* PPP_HARD_HDR_LEN; */
+       proto_ppp.header_space  = PPP_REQUESTED_HDR_LEN;
 
        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;
+#if USE_SKB_PROTOCOL == 0
        dev->type_trans       = ppp_dev_type;
+#endif
        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 */
@@ -478,7 +510,7 @@ ppp_init_dev (struct device *dev)
        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;
 }
@@ -510,28 +542,28 @@ ppp_init_ctrl_blk (register struct ppp *ppp)
        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 */
-       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;
-#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
@@ -544,20 +576,11 @@ ppp_init (struct device *dev)
        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
@@ -715,7 +738,7 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
        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 ();
@@ -733,21 +756,19 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
  * CCP is down; free (de)compressor state if necessary.
  */
 
-#ifdef PPP_COMPRESS
 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.
@@ -765,11 +786,7 @@ ppp_release (struct ppp *ppp)
        tty = ppp2tty (ppp);
        dev = ppp2dev (ppp);
 
-#ifdef PPP_COMPRESS
        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 */
@@ -814,17 +831,19 @@ ppp_tty_close (struct tty_struct *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
  */
-       ppp = ppp_alloc ();
+       ppp = ppp_alloc();
        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);
 /*
- * 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) {
@@ -964,7 +983,7 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
  */
                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;
 /*
@@ -972,9 +991,9 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
  * 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);
-                               dev_tint (ppp2dev (ppp));
                        }
 /*
  * 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.
  */
+                       cli();
                        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);
+                               return;
                        }
                }
        }
@@ -1019,12 +1041,11 @@ ppp_tty_wakeup (struct tty_struct *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;
-       }
 /*
  * 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
-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_buffer *buf = ppp->rbuf;
+       register struct ppp_buffer *buf = NULL;
        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.
  */
-       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 "
@@ -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 */
-                       ppp->stats.ppp_ibytes = ppp->bytes_rcvd;
+                       ppp->stats.ppp_ibytes += ppp->rbuf->count;
                        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)
 {
-       sk_buff *skb = alloc_skb (count, GFP_ATOMIC);
+       sk_buff *skb = dev_alloc_skb (count);
 /*
  * 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.
  */
-       skb->len = count;               /* Store the length */
        skb->dev = ppp2dev (ppp);       /* We are the device */
-#ifdef NEW_SKBUF
+#if USE_SKB_PROTOCOL == 0
+       skb->len = count;
+#else
        skb->protocol = proto;
+       skb->mac.raw  = skb_data(skb);
 #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;
-       ppp->ddinfo.ip_rjiffies = jiffies;
+       ppp->ddinfo.recv_idle = jiffies;
        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)
 {
-       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;
 }
 
@@ -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)
 {
-#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;
 }
@@ -1390,10 +1418,9 @@ rcv_proto_unknown (struct ppp *ppp, unsigned short proto,
 
                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
@@ -1422,91 +1449,90 @@ failure:
  * 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)
 {
-       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
  */
-                       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.
  */
-                       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;
-                       }
+
+                       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.
  */
-                       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;
+
+               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
  */
-               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)) {
-                               (*ppp->sc_rcomp->decomp_reset)
-                                       (ppp->sc_rc_state);
+                             (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state);
                                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);
 }
-#endif /* PPP_COMPRESS */
 
 /*
  * 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)
 {
+#if 0 /* until support is in the pppd process don't corrupt the reject. */
        register u_char *p;
-
        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;
        }
+#endif
 /*
  * 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 */
 
-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
  */
-       if (count <= 0)
+       if (count <= 4)
                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);
-/*
- * 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.
@@ -1598,8 +1606,10 @@ static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int len)
 /*
  * 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;
 }
@@ -1612,11 +1622,9 @@ ppp_doframe (struct ppp *ppp)
 {
        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;
-#endif
 /*
  * 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 */
+/*
+ * 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) &&
-           ((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 (((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)
@@ -1691,7 +1724,6 @@ ppp_doframe (struct ppp *ppp)
                                                    count,
                                                    new_data,
                                                    ppp->mru + 4);
-
                        switch (new_count) {
                        default:
                                ppp_doframe_lower (ppp, new_data, new_count);
@@ -1721,14 +1753,13 @@ ppp_doframe (struct ppp *ppp)
                        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);
        }
-#endif
 /*
  * Process the uncompressed frame.
  */
@@ -1758,43 +1789,53 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
 
 #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
  */
-       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;
-       }
+
+       if (ppp->magic != PPP_MAGIC)
+               return -EIO;
+
        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 (;;) {
+               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;
-                       current->state = TASK_INTERRUPTIBLE;
+                       current->state   = TASK_INTERRUPTIBLE;
                        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.
  */
@@ -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.
  */
-               ppp->ddinfo.nip_rjiffies = jiffies;
                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;
                }
+/*
+ * 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.
  */
-               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;
 /*
@@ -1866,7 +1917,8 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
  */
                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.
@@ -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,
-                               (unsigned int) buf->count);
+                               (unsigned int) chr);
        }
 /*
  * 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;
+       int     address, control;
+       int     proto;
 /*
  * 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 {
-               if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
+               if (jiffies - ppp->last_xmit > flag_time)
                        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
  */
+       data  += 4;
+       count -= 4;
+
        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.
  */
 
-int
+static int
 ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
                    u_char *data, int count)
 {
-       int     address, control;
        int     proto;
+       int     address, control;
        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.
  */
+       proto   = PPP_PROTOCOL (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)                 &&
@@ -2029,7 +2100,7 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
 
                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);
@@ -2041,33 +2112,12 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
  */
                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;
-/*
- * 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
  */
@@ -2098,12 +2148,12 @@ send_revise_frame (register struct ppp *ppp, u_char *data, int len)
 /*
  * 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;
-#endif
-
 /*
  * All other frame types
  */
@@ -2120,20 +2170,20 @@ send_revise_frame (register struct ppp *ppp, u_char *data, int len)
  */
 
 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;
+       int status;
 /*
  * 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;
-       }
 
        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;
        }
+/*
+ * 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
@@ -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 (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;
+               }
        }
 /*
- * 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;
-               return 0;
+               return status;
        }
 
        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.
  */
 
-#ifdef PPP_COMPRESS
 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;
+       u_char *ptr;
        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) {
-               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;
-
-               error = verify_area (VERIFY_READ, odp, nb);
+       
+               error = verify_area (VERIFY_READ, ptr, nb);
        }
 
        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);
 
-       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.
                 */
-                       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)
-               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 */
 }
-#endif /* PPP_COMPRESS */
 
 /*
  * 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.
  */
-       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;
-       }
+
+       if (ppp->magic != PPP_MAGIC)
+               return -EBADF;
+
        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) {
-                       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);
@@ -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
-                       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 "
@@ -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) {
-                       temp_i  = (int) get_fs_long (param3) & SC_MASK;
+                       temp_i  = get_int_user (param3) & 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);
-#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);
@@ -2349,12 +2414,10 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
 /*
  * Set the compression mode
  */
-#ifdef PPP_COMPRESS
        case PPPIOCSCOMPRESS:
                error = ppp_set_compression (ppp,
                                            (struct ppp_option_data *) param3);
                break;
-#endif
 /*
  * 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) {
-                       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
-                                       "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;
 /*
@@ -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) {
-                       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",
-                                    ppp->xmit_async_map[0]);
+                                    (unsigned long) ppp->xmit_async_map[0]);
                }
                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) {
-                       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",
-                                    ppp->recv_async_map);
+                                    (unsigned long) ppp->recv_async_map);
                }
                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) {
-                       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",
@@ -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) {
-                       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)
@@ -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;
-                       put_fs_long ((long) temp_i, param3);
+                       put_long_user ((long) temp_i, param3);
 
                        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
  */
-       case PPPIOCGTIME:
+       case PPPIOCGIDLE:
                error = verify_area (VERIFY_WRITE, (void *) param3,
-                                    sizeof (struct ppp_ddinfo));
+                                    sizeof (struct ppp_idle));
                if (error == 0) {
-                       struct ppp_ddinfo cur_ddinfo;
+                       struct ppp_idle cur_ddinfo;
                        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,
-                                    sizeof (struct ppp_ddinfo));
+                                    sizeof (cur_ddinfo));
                        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) {
-                       unsigned long temp_tbl[8];
+                       __u32 temp_tbl[8];
 
                        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) {
-                       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",
@@ -2577,12 +2638,12 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode,
 /*
  * 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;
-       }
+
+       if (ppp->magic != PPP_MAGIC)
+               return -EBADF;
+
        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
-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;
@@ -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.
  */
-       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));
-/*
- * Header Compression statistics
- */
                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;
@@ -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;
                }
+       }
+/*
+ * 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);
@@ -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);
-#endif /* PPP_COMPRESS */
-
+       }
 /*
  * Move the data to the caller's buffer
  */
+       if (error == 0)
                memcpy_tofs (result, &temp, sizeof (temp));
-       }
        return error;
 }
 
@@ -2788,7 +2871,11 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
  */
        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:
@@ -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.
  */
 
-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;
@@ -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,
-                                    !(ppp->flags & SC_NO_TCP_CCID));
+                                    (ppp->flags & SC_NO_TCP_CCID) == 0);
 
                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.
  */
 
-int
+#if !defined(IPX_CHANGE)
+static int
 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;
 
@@ -2929,6 +3021,7 @@ ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data)
 
        return answer;
 }
+#endif  /* !defined(IPX_CHANGE) */
 
 /*
  * 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.
  */
 
-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)
 {
@@ -3008,7 +3106,8 @@ ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp,
  * 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)
 {
@@ -3021,21 +3120,24 @@ ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
                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;
 }
+#endif   /* !defined(IPX_CHANGE) */
+#endif   /* defined(NEW_SKBUFF) || defined(IPX_CHANGE) */
 
 /*
  * Send a frame to the remote.
  */
 
-int
+static int
 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);
@@ -3059,8 +3161,8 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
  * 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
  */
@@ -3075,35 +3177,49 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
 /*
  * 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.
  */
 
-#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;
 
-       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. */
+#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;
+#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.
  */
-       if (answer == 0)
+       if (answer == 0) {
                dev_kfree_skb (skb, FREE_WRITE);
+               ppp->ddinfo.xmit_idle = jiffies;
+       }
        return answer;
 }
 
@@ -3140,11 +3256,10 @@ ppp_dev_stats (struct device *dev)
        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,
@@ -3183,6 +3298,7 @@ static int ppp_dev_getkey(int protocol, int subid, unsigned char *key)
 
 #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.
@@ -3193,10 +3309,17 @@ ppp_dev_type (sk_buff *skb, struct device *dev)
 {
        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);
 }
@@ -3218,7 +3341,6 @@ ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr,
 static struct ppp *
 ppp_alloc (void)
 {
-#if 1
        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 (++if_num == INT_MAX)
+               if (++if_num == max_dev)
                        return (NULL);
        }
 /*
@@ -3270,7 +3392,7 @@ ppp_alloc (void)
 
                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);
                }
 
@@ -3280,13 +3402,6 @@ ppp_alloc (void)
                /* 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
-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";
@@ -3308,7 +3423,7 @@ ppp_print_hex (register u_char * out, u_char * in, int count)
 }
 
 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;
 
@@ -3327,7 +3442,7 @@ ppp_print_char (register u_char * out, u_char * in, int count)
 }
 
 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];
 
@@ -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
-char kernel_version[] = UTS_RELEASE;
-
 int
 init_module(void)
 {
@@ -3365,10 +3562,11 @@ init_module(void)
 
        /* register our line disciplines */
        status = ppp_first_time();
-       if (status != 0) {
+       if (status != 0)
                printk (KERN_INFO
                       "PPP: ppp_init() failure %d\n", status);
-       }
+       else
+               (void) register_symtab (&ppp_syms);
        return (status);
 }
 
@@ -3379,27 +3577,30 @@ cleanup_module(void)
        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.
  */
-       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
@@ -3417,22 +3618,19 @@ cleanup_module(void)
                        "(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
  */    
-       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);
-/*
- * Release the storage occupied by the control structures
- */
-               next = ctl->next;
                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
-# $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 \
-       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 \
-       auth.o options.o sys-linux.o
+       auth.o options.o sys-linux.o ipxcp.o
 
 all: pppd
 
@@ -22,12 +22,12 @@ endif
 
 # 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
 
-CFLAGS = $(COPTS) $(DEBUG_FLAGS) $(COMPILE_FLAGS)
+CFLAGS= $(COPTS) $(DEBUG_FLAGS) $(COMPILE_FLAGS)
 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;