Mods from Al Longyear.
authorPaul Mackerras <paulus@samba.org>
Mon, 12 Jun 1995 11:37:02 +0000 (11:37 +0000)
committerPaul Mackerras <paulus@samba.org>
Mon, 12 Jun 1995 11:37:02 +0000 (11:37 +0000)
README.linux
include/linux/if_ppp.h
include/linux/if_pppvar.h
linux/if_ppp.h
linux/if_pppvar.h
linux/ppp.c
pppd/Makefile.linux

index abe7af4385ce146cd54cf8a6c852744a8cb4b328..7d0e77e14745a70fb10b64bd3af88c5c8cbb7c60 100644 (file)
@@ -1,8 +1,7 @@
-
-PPP for Linux                                             Version 0.2.8
+PPP for Linux                                             Version 2.2.0
 =============                                                  based on
-                                                              ppp-2.1.0
-                                                               May 1994
+                                                              ppp-2.2.0
+                                                               Mar 1995
 
 Michael Callahan    callahan@maths.ox.ac.uk
 Al Longyear         longyear@netcom.com
@@ -10,6 +9,7 @@ Al Longyear         longyear@netcom.com
   Contents:
     INTRODUCTION
     CREDITS
+    CHANGES FROM THE PREVIOUS VERSION
     FUTURE PLANS
     INSTALLATION
     GENERAL NETWORK CONFIGURATION
@@ -19,13 +19,20 @@ Al Longyear         longyear@netcom.com
     IF IT STILL DOESN'T WORK (OR, BUG REPORTS)
     DYNAMIC ADDRESS ASSIGNMENT
     SETTING UP A MACHINE FOR INCOMING PPP CONNECTIONS
-    ADDING MORE PPP CHANNELS
-    CHANGES FROM LINUX PPP 0.1.x
+    SETTING UP A MACHINE FOR INCOMING PPP CONNECTIONS WITH DYNAMIC IP
+    ADDITIONAL INFORMATION
+    DIP SUPPORT
     CONCLUSION
 
 
 INTRODUCTION
 
+This file is a substantially derrived from the previous version for
+the pppd process 2.1.2. Michael Callahan wrote that version. This
+particular version was written, modified, hacked, changed, whatever,
+by Al Longyear. If you find errors in this document, they are probably
+mine and not Michael's.
+
 This is a PPP driver for Linux.  It has been used by many people and
 seems to be quite stable.  It is capable of being used either as a
 'client'--for connecting a Linux machine to a local Internet provider,
@@ -50,6 +57,7 @@ directly to the kernel network code.  So once pppd has negotiated the
 link, it in practice lies completely dormant until you want to take
 the link down, when it negotiates a graceful disconnect.
 
+
 CREDITS
 
 I (MJC) wrote the original kernel driver from scratch.  Laurence
@@ -62,8 +70,8 @@ Linux has no support for asynchronous I/O, so I hacked an ioctl into
 the PPP kernel module that provides a signal when packets appear and
 made pppd use this instead.
 
-Al Longyear ported version 2.0.4 of pppd (from the free package
-ppp-2.0.4) to Linux.  He also provided several enhancements to both
+Al Longyear ported version 2.2 of pppd (from the free package
+ppp-2.2.0) to Linux.  He also provided several enhancements to both
 the kernel driver and the OS-independent part of pppd.  His
 contributions to Linux PPP have been immense, and so this release
 is being distributed over both our names.
@@ -73,115 +81,193 @@ The pppd program comes from the free distribution of PPP for Suns and
 "thanks to" Brad Parker, Greg Christy, Drew D. Perkins, Rick Adams and
 Chris Torek.
 
+Jim Freeman added the code to support a ppp module and to dynamically
+extend the number of ppp devices. The Space.c module should not have
+any devices defined for this logic to work.
+
+
+CHANGES FROM THE PREVIOUS VERSION
+
+- The number of devices for the PPP device has been made dynamic. It was
+  previously configured with the default value of four devices.
+
+- The problems dealing with other systems such as Windows NT and their
+  authenticiation has been corrected. It will now generate the proper
+  responses to allow the system to choose a valid authentication protocol.
+
+- The kernel debug value has changed. Previously it was a level. It is now
+  a bit map with various bits meaning certain types of debug information.
+
+     0 - No debug information is generated
+     1 - Debug messages
+     2 - Log incoming packets
+     4 - Log outgoing packets
+     8 - Log tty output buffers
+    16 - Log tty input buffers
+
+  If you wish to use any combination, add the values together. For example,
+  '7' will log debug messages and incoming packages and outgoing packets.
+
+  The default setting is 0.
+
+  The simple IP trace which ppp.c performed when 'kdebug' was greater than
+  127 has been removed. You should use tcpdump for this type of trace
+  actions.
+
+- Support is added for compression control protocol. At the present time
+  only the BSD compression protocol is supported. (Also, as of this time,
+  the ietf-ppp working group has only specified the BSD compression
+  protocol.)
+
+- There are two queues for output frames. This avoids some problems which
+  occured with the previous version and some PPP packages which exchanged
+  echo frames with Linux.
+
+- The echo frames are now proper. Previously, it would generate extra
+  characters and this caused some providers to not respond to the 'junk'.
+
+- The max-echo-failure option will now properly disconnect the line.
+
+- There are other changes which are listed in the general README file. Please
+  read that file as well for changes.
+
+- There is no limit to the number of ppp devices which you may use. Jim Freeman
+  has added code to create them upon demand and to re-use the ones which have
+  been closed. There is no code, nor plans to write code, to remove (delete)
+  the un-used devices. So, if your system goes to a spurt and uses 3000 ppp
+  devices, it will remain at that level until you next reload the kernel.
+
 
 FUTURE PLANS
 
-The main missing feature is the ability to fire up a PPP connection
-automatically when a packet destined for the remote host is generated
-("demand-dialing").  Work is progressing on this, but it involves some
-nontrivial design issues.
+The IPX support is still minimal. There is code which will only work with
+the 1.3 version of the networking software. The pppd process will still
+require changes to support the IPXCP and a change to the driver to properly
+enable/disable the IPX frames. Jim Freeman is reportily working on the IPX
+support.
 
 
 INSTALLATION
 
-This version of PPP has been tested on 1.0.x (x=0..9) and 1.1.x
-(x=0..14) kernels.  It will probably not work on kernels much earlier
-than this due to a change in the routing code.  If you have an earlier
-kernel, please upgrade.
+This version of PPP has been tested on 1.1.x (x>=14) It will probably
+not work on kernels much earlier than this due to a change in the
+routing code.  If you have an earlier kernel, please upgrade.
 
 joining the PPP channel of linux-activists:
 
       This isn't really part of installation, but if you DO use
       Linux PPP you should do this.  Send a message with the line
-       X-Mn-Admin: join PPP
-      contained in the body to linux-activists-request@niksula.hut.fi
-      You can send to the list by mailing to
-      linux-activists@niksula.hut.fi and putting the line
-        X-Mn-Key: PPP
-      at the start of your message.
-
-      The advantage of subscribing is that you'll be informed of
-      updates and patches, and you'll be able to draw on the
-      experience of many PPP users.  If you have a problem, I may not
-      be able to diagnose it, but someone else may have solved it
-      already.
+       subscribe linux-ppp
+      contained in the body to majordomo@vger.rutgers.edu
 
-      Note also that I do not read the linux Usenet newsgroups
-      regularly enough to catch any discussions of PPP; if you want to
-      reach the PPP audience you should join the linux-activists
-      channel.
+      To leave the mail list, send 'unsubscribe linux-ppp' to the same
+      mail address.
 
-      To leave the PPP mailing list :-(, send a message with the line
-        X-Mn-Admin: leave PPP
-      to linux-activists-request.
+      You can send to the list by mailing to
+      linux-ppp@vger.rutgers.edu. This is a majordomo mailing list and
+      is unlike the earlier version on hut.fi. There is no magic header
+      required for this list. In addition, it is mirrored to the usenet
+      group linux.act.ppp. You may choose to read the few messages posted
+      there.
+
+Usenet News Groups
+
+      There are three applicable usenet news groups for the PPP code. Please
+      choose the group which applies the closest to the type of problem
+      which you are experiencing.
+
+      comp.os.linux.networking
+       - Trouble setting routes, running name services, using telnet, ftp,
+         news, etc.
+       - It will not compile.
+
+      comp.os.linux.setup
+       - Trouble installing the package from BINARIES only. This does *NOT*
+         include problems with compiling the package.
+
+      comp.protocols.ppp
+       - How do I use the package?
+       - How do I connect to .... services?
+       - Why does this not work?
+       - All other types of questions on how to use just the PPP code.
+
+      PLEASE don't assume that just because you are using PPP as your
+      network device driver that all problems with your networking are a
+      problem of PPP. PPP is *NOT* responsible for your modem disconnecting,
+      routing to other servers, running telnet, etc. Calling the problem
+      'ppp' on usenet may cause it to be ignored by the people who
+      actually work on the networking code.
 
 kernel driver installation:
 
       This depends on the kernel version you're using.
 
-      Since 1.1.14, Linux kernels have had built-in support for PPP.
-      You'll be asked whether you want PPP when you run "make config".
-      It's as easy as that.
-
-      In 1.1.13, PPP is there but the PPP line in config.in is
-      commented out.  If you have 1.1.13, you probably should just
-      upgrade anyway.
-
-      Kernel versions prior to 1.1.13 (including all 1.0.x kernels)
-      have had (hidden) support for PPP in the kernel configuration
-      setup for quite some time.  Adding the PPP kernel driver is
-      easy:
-
-       1) copy ppp.c from the linux subdirectory of the distribution
-           to drivers/net and ppp.h to include/linux
-       2) uncomment the CONFIG_PPP line in config.in
-        3) if you are using 1.1.3 or earlier (including 1.0.x):
-           uncomment the line in ppp.c that begins
-            /* #define NET02D
-           by removing the "/* " characters
-        4) in the top level of the kernel source
-               make config
-               make dep
-               make
+      Version 1.0.*
+        These versions are not supported.
+
+      Version 1.1.0 through 1.1.14
+        These versions are not supported.
+
+      Version 1.1.15 to 1.2.99
+      - Use the source to the ppp.c driver from the 'linux' directory and
+        replace the driver in the /usr/src/linux/drivers/net.
+      - Delete the file /usr/src/linux/drivers/net/ppp.h
+      - Add the following files to /usr/include/net:
+        if_ppp.h
+        if_pppvar.h
+        ppp_comp.h
+        ppp_defs.h
+
+      - IF AND ONLY IF you are missing the following files then use the
+        copy provided in the 'linux' directory to supplement the files.
+
+        DO **NOT** REPLACE THE FILE IF IT CURRENTLY EXISTS.
+
+        if_arp.h
+        if_route.h
+
+      Version 1.3.0 and later
+        The files have been properly updated.
 
       Reboot with the new kernel.  At startup, you should see
       something line this:
 
-  PPP: version 0.2.8 (4 channels)
+  PPP: version 2.2.0 (dynamic channel allocation)
   TCP compression code copyright 1989 Regents of the University of California
+  Dynamic channel allocation code copyright 1995 Caldera, Inc.
   PPP line discipline registered.
 
-      (If you want more than 4 channels, see the section "ADDING MORE
-      PPP CHANNELS" below.)
+pppd installation:
 
-      Now, try looking at the contents of /proc/net/dev.  It should
-      look something like this:
+      Go to the 'pppd' directory and issue the commands:
 
-  Inter-|   Receive                  |  Transmit
-   face |packets errs drop fifo frame|packets errs drop fifo colls carrier
-      lo:      0    0    0    0    0        0    0    0    0     0    0
-    ppp0:      0    0    0    0    0        0    0    0    0     0    0
-    ppp1:      0    0    0    0    0        0    0    0    0     0    0
-    ppp2:      0    0    0    0    0        0    0    0    0     0    0
-    ppp3:      0    0    0    0    0        0    0    0    0     0    0
+      make -f Makefile.linux depend
+      make -f Makefile.linux
 
-      This indicates that the driver is successfully installed.
+      This should build the program. If you have any errors then ensure
+      that you have the proper include files and haven't missed one.
 
-      (Of course, you should keep a kernel without PPP around, in case
-      something goes wrong.)
+      If you are using shadow passwords *AND* have it installed, then you
+      should use the command:
 
-pppd installation:
+      make -f Makefile.linux shadow
 
-      First execute the following commands (in the ppp-2.2 directory):
+      rather than the non-shadow command listed earlier.
 
-       ./configure
-       make
+      (Shadow library support will require the addition of some modules
+      to the shadow library. These were overlooked by the package author
+      and I will, or have already, notified him.)
+      
+      This code has been built with the 4.5 and 4.6 subroutine libraries
+      and include files. If your include files are too old then you should
+      upgrade them.
 
-      This will make the pppd and chat programs.
+      To install the package, issue the command:
 
-      To install, type 'make install' (in the ppp-2.2 directory).
-      This will put chat and pppd binaries in /usr/etc
-      and the pppd.8 manual page in /usr/man/man8.
+      make -f Makefile.linux install
+
+      This will install the binary in /usr/sbin and the man page into
+      /usr/man/man8.
 
       pppd needs to be run as root.  You can either make it setuid
       root or just use it when you are root.  'make install' will try
@@ -190,6 +276,51 @@ pppd installation:
       implications which you should investigate carefully before
       making it available on a multiuser machine.
 
+      The pppd process must have the following directories to work:
+
+      /var/run
+      /etc/ppp
+
+      In addition, for the program to run, there must be a 'options' file
+      in the /etc/ppp directory. So, the following commands will accomplish
+      the required operations. They may have errors if the entries currently
+      exist.
+
+      Perform these commands as the 'root' user.
+
+      mkdir /var /etc
+      mkdir /var/run /etc/ppp
+      touch /etc/ppp/options
+
+chat installation:
+
+      To compile the chat program, go to the 'chat' directory and issue
+      the command:
+
+      make -f Makefile.linux
+
+      To install the package, issue the command:
+
+      make -f Makefile.linux install
+
+      This will install the binary in /usr/sbin and the man page into
+      /usr/man/man8.
+
+pppstats installation:
+
+      To compile the pppstats program, go to the 'pppstats' directory
+      and issue the command:
+
+      make -f Makefile.linux
+
+      To install the package, issue the command:
+
+      make -f Makefile.linux install
+
+      This will install the binary in /usr/sbin and the man page into
+      /usr/man/man8.
+
+
 GENERAL NETWORK CONFIGURATION
 
 Since many people don't use the Linux networking code at all until
@@ -204,6 +335,7 @@ network configuration at boot time, called /etc/rc.net or
 distribution.  This file should 'ifconfig' the loopback interface lo,
 and should add an interface route for it.  These lines might look
 something like this:
+
         $CONFIG lo 127.0.0.1
        $ROUTE add loopback
 or
@@ -223,25 +355,33 @@ Next, you should set up /etc/hosts to have two lines.  The first
 should just give the loopback or localhost address and the second
 should give your own host name and the IP address your PPP connection
 will use.  For example:
-     127.0.0.1  loopback localhost   # useful aliases
-     192.1.1.17  billpc.whitehouse.gov bill  # my hostname
+
+     127.0.0.1   loopback localhost                    # useful aliases
+     192.1.1.17  billpc.president.whitehouse.gov bill  # my hostname
+     192.1.1.23  chelseapc.president.whitehouse.gov chelseapc
+
 where my IP address is 192.1.1.17 and my hostname is
-billpc.whitehouse.gov.  (Not really, you understand.)  If your PPP
-server does dynamic IP address assignment, give a guess as to an
-address you might get (see also "Dynamic Address Assignment" below).
+billpc.president.whitehouse.gov.  (Not really, you understand.)  If
+your PPP server does dynamic IP address assignment, give a guess as to
+an address you might get (see also "Dynamic Address Assignment"
+below).
 
 Finally, you need to configure the domain name system by putting
 appropriate lines in /etc/resolv.conf .  It should look something like
 this:
-     domain whitehouse.gov
+
+     domain     president.whitehouse.gov
+     search     president.whitehouse.gov  whitehouse.gov
      nameserver 192.1.2.1
      nameserver 192.1.2.10
+
 Assuming there are nameservers at 192.1.2.1 and 192.1.2.10, then when
 you get connected with PPP, you can reach hosts whose full names are
-'hillarypc.whitehouse.gov' and 'chelseapc.whitehouse.gov' by the names
-'hillarypc' and 'chelseapc'.  You can probably find out the right
-domain name to use and the IP numbers of nameservers from whoever's
-providing your PPP link.
+'hillarypc.president.whitehouse.gov' and 'chelseapc.whitehouse.gov' by
+the names 'hillarypc' and 'chelseapc'.  You can probably find out the
+right domain name to use and the IP numbers of nameservers from
+whoever's providing your PPP link.
+
 
 CONNECTING TO A PPP SERVER
 
@@ -253,43 +393,35 @@ Example 1: A simple dial-up connection.
 
 Here's a command for connecting to a PPP server by modem.
 
-  pppd connect 'chat -v -f chat-script' \
-      /dev/cua1 38400 -detach debug crtscts modem defaultroute 192.1.1.17:
-
-where the file chat-script contains:
-
-  "" ATDT5551212 CONNECT "" ogin: ppp word: whitewater
+  pppd connect 'chat -v "" ATDT5551212 CONNECT "" ogin: ppp word: whitewater' \
+      /dev/cua1 38400 debug crtscts modem defaultroute 192.1.1.17
 
 Going through pppd's options in order:
-   connect 'chat ...'  This gives a command to run to contact the
+   connect 'chat etc...'  This gives a command to run to contact the
     PPP server.  Here the supplied 'chat' program is used to dial a
     remote computer.  The whole command is enclosed in single quotes
     because pppd expects a one-word argument for the 'connect' option.
     The options to 'chat' itself are:
-         -v              verbose mode; log what we do to syslog
-        -f chat-script  expect-send strings are in the file chat-script
-    The strings for chat to look for and to send are stored in the
-    chat-script file.  The strings can be put on the chat command line,
-    but this is not recommended because it makes your password visible
-    to anyone running ps while chat is running.  The strings are:
+
+         -v            verbose mode; log what we do to syslog
          ""            don't wait for any prompt, but instead...
          ATDT5551212   dial the modem, then
          CONNECT       wait for answer
          ""            send a return (null text followed by usual return)
          ogin: ppp word: whitewater    log in.
-   /dev/cua1  specify the callout serial port cua1
-   38400  specify baud rate
-   -detach   normally, pppd forks and puts itself in the background;
-        this option prevents this
-   debug  log status in syslog
-   crtscts  use hardware flow control between computer and modem
-        (at 38400 this is a must)
-   modem  indicate that this is a modem device; pppd will hang up the
-        phone before and after making the call
-   defaultroute  once the PPP link is established, make it the
-        default route; if you have a PPP link to the Internet this
-        is probably what you want
-   192.1.1.17:  this is a degenerate case of a general option
+
+   /dev/cua1     specify the callout serial port cua1
+   38400         specify baud rate
+   debug         log status in syslog
+   crtscts       use hardware flow control between computer and modem
+                    (at 38400 this is a must)
+   modem         indicate that this is a modem device; pppd will hang up the
+                    phone before and after making the call
+   defaultroute  once the PPP link is established, make it the default
+                    route; if you have a PPP link to the Internet this
+                    is probably what you want
+
+   192.1.1.17  this is a degenerate case of a general option
         of the form  x.x.x.x:y.y.y.y  .  Here x.x.x.x is the local IP
         address and y.y.y.y is the IP address of the remote end of the
         PPP connection.  If this option is not specified, or if just
@@ -300,12 +432,16 @@ Going through pppd's options in order:
         this option would actually be redundant.
 
 pppd will write error messages and debugging logs to the syslogd
-daemon using the facility name "daemon".  (Verbose output from chat
-uses facility "local2".)  These messages may already be logged to the
-console or to a file like /usr/adm/messages; consult your
-/etc/syslog.conf file to see.  If you want to make all pppd and chat
-messages go to the console, add the line
-   daemon,local2.*                             /dev/console
+daemon using the facility name "local2".  (Verbose output from chat is
+the same.)  These messages may already be logged to the console or to
+a file like /usr/adm/messages; consult your /etc/syslog.conf file to
+see.  If you want to make all pppd and chat messages go to the
+console, add the line
+
+   local2.*                                    /dev/console
+           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+           This is one or more tabs. Do not use spaces.
+
 to syslog.conf; make sure to put one or more TAB characters between
 the two fields.
 
@@ -316,10 +452,10 @@ to make my own PPP link, which is over a hard-wired Gandalf link to an
 Ultrix machine running Morningstar PPP.
 
   pppd connect /etc/ppp/ppp-connect defaultroute noipdefault debug \
-      kdebug 2 /dev/cua0 9600
+      kdebug 0 /dev/cua0 9600
 
 Here /etc/ppp/ppp-connect is the following script:
-  #! /bin/sh
+  #!/bin/sh
   /etc/ppp/sendbreak
   chat -v -t60 "" \; "service :" blackice ogin: callahan word: PASSWORD \
       black% "stty -echo; ppp" "Starting PPP now"  && sleep 5
@@ -328,8 +464,7 @@ This sends a break to wake up my terminal server, sends a semicolon
 (which lets my terminal server do autobaud detection), then says we
 want the service "blackice".  It logs in, waits for a shell prompt
 ("black%"), then starts PPP.  The -t60 argument sets the timeout to a
-minute, since things here are sometimes very slow.  (Ideally the
-expect-send strings for chat should be in a file.)
+minute, since things here are sometimes very slow.
 
 The "&& sleep 5" causes the script to pause for 5 seconds, unless chat
 fails in which case it exits immediately.  This is just to give the
@@ -346,15 +481,13 @@ but I wanted to mention it because it took me several frustrating
 hours to figure out.
 
 The pppd options are mostly familiar.  Two that are new are
-"noipdefault" and "kdebug 2".  "noipdefault" tells pppd to ask the
+"noipdefault" and "kdebug 1".  "noipdefault" tells pppd to ask the
 remote end for the IP address to use; this is necessary if the PPP
 server implements dynamic IP address assignment as mine does (i.e., I
-don't know what address I'll get ahead of time).  "kdebug 2" sets the
-kernel debugging level to 2, enabling slightly chattier messages from
+don't know what address I'll get ahead of time).  "kdebug 1" sets the
+kernel debugging level to 1, enabling slightly chattier messages from
 the ppp kernel code.
 
-
-
 Anyway, assuming your connection is working, you should see chat dial
 the modem, then perhaps some messages from pppd (depending on your
 syslog.conf setup), then some kernel messages like this:
@@ -363,23 +496,26 @@ syslog.conf setup), then some kernel messages like this:
        ppp: channel ppp0 open
        ppp: channel ppp0 going up for IP packets!
 
-(These messages will only appear if you gave the option "kdebug 2" and
+(These messages will only appear if you gave the option "kdebug 1" and
 have kern.info messages directed to the screen.)  Simultaneously, pppd
 is also writing interesting things to /usr/adm/messages (or other log
 file, depending on syslog.conf).
 
+
 IF IT WORKS
 
 If you think you've got a connection, there are a number of things you
 can do to test it.
 
 First, type
+
        /sbin/ifconfig
-(ifconfig may live elsewhere, depending on your distribution.)  This
-should show you all the network interfaces that are 'UP'.  ppp0 should
-be one of them, and you should recognize the first IP address as your
-own and the "POINT-TO-POINT ADDR" as the address of your server.
-Here's what it looks like on my machine:
+
+     (ifconfig may live elsewhere, depending on your distribution.)
+This should show you all the network interfaces that are 'UP'.  ppp0
+should be one of them, and you should recognize the first IP address
+as your own and the "P-t-P address" (or point-to-point address) the
+address of your server.  Here's what it looks like on my machine:
 
 lo        Link encap Local Loopback  
           inet addr 127.0.0.1  Bcast 127.255.255.255  Mask 255.0.0.0
@@ -387,16 +523,19 @@ lo        Link encap Local Loopback
           RX packets 0 errors 0 dropped 0 overrun 0
           TX packets 0 errors 0 dropped 0 overrun 0
 
-ppp0      Link encap Serial Line IP  
+ppp0      Link encap Point-to-Point Protocol
           inet addr 192.76.32.2  P-t-P 129.67.1.165  Mask 255.255.255.0
           UP POINTOPOINT RUNNING  MTU 1500  Metric 1
           RX packets 33 errors 0 dropped 0 overrun 0
           TX packets 42 errors 0 dropped 0 overrun 0
 
 Now, type
+
        ping z.z.z.z
-where z.z.z.z is the address of your server.  This should work.
+
+where z.z.z.z is the address of your name server.  This should work.
 Here's what it looks like for me:
+
   waddington:~$ ping 129.67.1.165
   PING 129.67.1.165 (129.67.1.165): 56 data bytes
   64 bytes from 129.67.1.165: icmp_seq=0 ttl=255 time=268 ms
@@ -409,8 +548,11 @@ Here's what it looks like for me:
   waddington:~$
 
 Try typing:
+
        netstat -nr
+
 This should show three routes, something like this:
+
 Kernel routing table
 Destination     Gateway         Genmask         Flags Metric Ref Use    Iface
 129.67.1.165    0.0.0.0         255.255.255.255 UH    0      0        6 ppp0
@@ -425,14 +567,17 @@ At this point you can try telnetting/ftping/fingering whereever you
 want, bearing in mind that you'll have to use numeric IP addresses
 unless you've set up your /etc/resolv.conf correctly.
 
+
 IF IT DOESN'T WORK
 
 If you don't seem to get a connection, the thing to do is to collect
 'debug' output from pppd.  To do this, make sure you run pppd with the
 'debug' option, and put the following two lines in your
 /etc/syslog.conf file:
-    daemon,local2.*                            /dev/console
-    daemon,local2.*                            /usr/adm/ppplog
+
+    local2.*                                   /dev/console
+    local2.*                                   /usr/adm/ppplog
+
 This will cause pppd's messages to be written to the current virtual
 console and to the file /usr/adm/ppplog.  Note that the left-hand
 field and the right-hand field must be separated by at least one TAB
@@ -457,14 +602,18 @@ bits.)  If that's the case, it would be useful to collect a debug log
 which contains all the bytes being passed between your computer and
 the remote PPP server.  To do this, alter your syslog.conf lines to
 look like this
+
     local2.*,kern.*                            /dev/console
     local2.*,kern.*                            /usr/adm/ppplog
+
 and HUP the syslog daemon as before.  Then, run pppd with the option
-"kdebug 5".  Whatever characters arrive over the PPP terminal line
+"kdebug 25".  Whatever characters arrive over the PPP terminal line
 will appear in the debugging output.
 
 Occasionally you may see a message like
+
    ppp_toss: tossing frame, reason = 4
+
 The PPP code is throwing away a packet ("frame") from the remote
 server because of a serial overrun.  This means your CPU isn't able to
 read characters from the serial port as quickly as they arrive; the
@@ -478,13 +627,15 @@ a received PPP frame, and usually occurs at the start of a session
 when the peer system is sending some "text" messages, such as "hello
 this is the XYZ company".  Messages of "bad fcs" once the link is
 established and the routes have been added are not normal and indicate
-transmssion errors or noise on the telephone line.
+transmission errors or noise on the telephone line.
+
 
 IF IT STILL DOESN'T WORK (OR, BUG REPORTS)
 
-If you're still having difficulty, send the linux-activists PPP
-channel a bug report.  It is extremely important to include as much
-information as possible; for example:
+If you're still having difficulty, send the linux-ppp list a bug
+report. It is extremely important to include as much information as
+possible; for example:
+
  - the version number of the kernel you are using
  - the version number of Linux PPP you are using
  - the exact command you use to start the PPP session
@@ -494,11 +645,21 @@ information as possible; for example:
    terminal server, Morningstar PPP software, etc)
  - the kind of connection you use (modem, hardwired, etc...)
 
+
 DYNAMIC ADDRESS ASSIGNMENT
 
 You can use Linux PPP with a PPP server which assigns a different IP
-address every time you connect.  You need to use the 'noipdefault'
-option to tell pppd to request the IP address from the remote host.
+address every time you connect. This action is automatically performed
+when you don't have a local IP address.
+
+  pppd connect 'chat -v "" ATDT5551212 CONNECT "" ogin: ppp word: whitewater' \
+      /dev/cua1 38400 noipdefault debug crtscts modem defaultroute
+
+The noipdefault, added to the above example, suppresses the attempts
+of pppd to deduce its own IP address by looking it up in the
+/etc/hosts file. Since the process does not have an IP address, one
+will be assigned to it from the configuration file on the remote
+system.
 
 Sometimes you may get an error message like "Cannot assign requested
 address" when you use a Linux client (for example, "talk").  This
@@ -507,6 +668,7 @@ differs from the IP address used by the PPP interface.  The solution
 is to use ifconfig ppp0 to get the interface address and then edit
 /etc/hosts appropriately.
 
+
 SETTING UP A MACHINE FOR INCOMING PPP CONNECTIONS
 
 Suppose you want to permit another machine to call yours up and start
@@ -515,19 +677,34 @@ a PPP session.  This is possible using Linux PPP.
 One way is to create an account named, say, 'ppp', with the login
 shell being a short script that starts pppd.  For example, the passwd
 entry might look like this:
-  ppp:(encrypted password):102:50:PPP client login:/tmp:/etc/ppp/ppplogin
-Here the file /etc/ppp/ppplogin would be an executable script
-containing something like:
-  #!/bin/sh
-  exec /usr/etc/pppd passive :192.1.2.23
+
+  ppp:(encrypted password):102:50:PPP client login:/home/ppp:/usr/sbin/pppd
+
+In addition, you would edit the file ~ppp/.ppprc to have the following
+pieces of information:
+
+-detach
+modem
+crtscts
+lock
+:192.1.2.23
+
 Here we will insist that the remote machine use IP address 192.1.2.23,
 while the local PPP interface will use the IP address associated with
-this machine's hostname in /etc/hosts.  The 'passive' option (which is
-not required) just means that pppd will try to open negotiations when
-it starts, but if it receives no reply it will just wait silently.
-This is appropriate if the remote end might take some time before it's
-ready to negotiate.  (Note that the meaning of the 'passive' option
-changed between ppp-1.3 and ppp-2.0.)
+this machine's hostname in /etc/hosts.  The '-detach' option is required
+for a server. It tells the pppd process not to terminate until the modem
+is disconnected. Should it fork, the init process would restart the getty
+process and the this would cause a severe conflict over the port.
+
+The 'modem' option indicates that the connection is via a switched circuit
+(using a modem) and that the pppd process should monitor the DCD signal
+from the modem.
+
+The 'crtscts' option tells the pppd process to use hardware RTS/CTS flow
+control for the modem.
+
+The 'lock' option tells pppd to lock the tty device. This will use the UUCP
+style locking file in the lock directory.
 
 This setup is sufficient if you just want to connect two machines so
 that they can talk to one another.  If you want to use Linux PPP to
@@ -557,9 +734,19 @@ Here the PPP and Ethernet interfaces of billpc will have IP address
 192.1.2.17.  (It's OK for one or more PPP interfaces on a machine to
 share an IP address with an Ethernet interface.)  There is an
 appropriate entry in /etc/passwd on billpc to allow chelseapc to call
-in, with the /etc/ppp/ppplogin script containing
-  #!/bin/sh
-  exec /usr/etc/pppd passive proxyarp :192.1.2.23
+in. It will run pppd when the user signs on to the system and pppd will
+take the options from the user option file.
+
+In addition, you would edit the file ~ppp/.ppprc to have the following
+piece of information:
+
+-detach
+modem
+crtscts
+lock
+192.1.2.17:192.1.2.23
+proxyarp
+
 When the link comes up, pppd will enter a "proxy arp" entry for
 chelseapc into the arp table on billpc.  What this means effectively
 is that billpc will pretend to the other machines on the 192.1.2.x
@@ -568,79 +755,169 @@ chelseapc (192.1.2.23) as well as billpc (192.1.2.17).  In practice
 this means that chelseapc can communicate just as if it was directly
 connected to the Ethernet.
 
-ADDING MORE PPP CHANNELS
-
-By default, Linux PPP comes with 4 kernel channels, which means that
-at most 4 simultaneous PPP sessions are possible.  If you desire more
-such sessions (for example if you are serving many dialup lines), you
-can easily reconfigure the kernel to add new channels.  There are two
-steps.
-
-First you need to edit the kernel file drivers/net/Space.c .  As
-distributed, it contains a section that looks like this:
-  
-#if defined(CONFIG_PPP)
-extern int ppp_init(struct device *);
-static struct device ppp3_dev = {
-    "ppp3", 0x0, 0x0, 0x0, 0x0, 3, 0, 0, 0, 0, NEXT_DEV,  ppp_init, };
-static struct device ppp2_dev = {
-    "ppp2", 0x0, 0x0, 0x0, 0x0, 2, 0, 0, 0, 0, &ppp3_dev, ppp_init, };
-static struct device ppp1_dev = {
-    "ppp1", 0x0, 0x0, 0x0, 0x0, 1, 0, 0, 0, 0, &ppp2_dev, ppp_init, };
-static struct device ppp0_dev = {
-    "ppp0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, &ppp1_dev, ppp_init, };
-#undef NEXT_DEV
-#define NEXT_DEV (&ppp0_dev)
-#endif   /* PPP */
-
-The pattern should be obvious.  For more channels, you need to add
-more "static struct device pppN_dev" lines, changing the first, sixth
-and eleventh structure entries as appropriate.  The highest numbered
-PPP device should have NEXT_DEV in its eleventh structure field, and
-you should change the ppp3_dev structure to have &ppp4_dev there
-instead.
-
-For example, to add 2 extra channels, you would have
-
-#if defined(CONFIG_PPP)
-extern int ppp_init(struct device *);
-static struct device ppp5_dev = {
-    "ppp5", 0x0, 0x0, 0x0, 0x0, 5, 0, 0, 0, 0, NEXT_DEV,  ppp_init, };
-static struct device ppp4_dev = {
-    "ppp4", 0x0, 0x0, 0x0, 0x0, 4, 0, 0, 0, 0, &ppp5_dev,  ppp_init, };
-static struct device ppp3_dev = {
-    "ppp3", 0x0, 0x0, 0x0, 0x0, 3, 0, 0, 0, 0, &ppp4_dev,  ppp_init, };
-... etc.
-
-Second, you need to change the line in ppp.h (in include/linux) to
-change the line that reads
-
-#define PPP_NRUNIT     4
-
-to show the new number of channels; in our case it would become
-
-#define PPP_NRUNIT     6
-
-Finally, recompile and reboot.  The bootup message and the contents of
-/proc/net/dev should show the correct number of channels.
-
-CHANGES FROM LINUX PPP 0.1.x
-
-Linux PPP 0.1.x was based on the free PPP package PPP-1.3.  Linux PPP
-0.2.1 is based on PPP-2.0.4.  There have been some changes to the pppd
-options along with significant enhancements.  You should read
-"RELNOTES" in the pppd directory for a description of the changes.
-
-Also, some options which were added to PPP-1.3 for the Linux version
-have now changed names:
-    'defroute'  is now 'defaultroute'
-    'kerndebug' is now 'kdebug'
-    'dropdtr'   is now 'modem'
-In addition, it is now necessary to use the 'noipdefault' option if
-you want to get the local IP address from the remote PPP server.
+
+SETTING UP A MACHINE FOR INCOMING PPP CONNECTIONS WITH DYNAMIC IP
+
+The use of dynamic IP assignments is not much different from that
+using static IP addresses. Rather than putting the IP address into the
+single file ~ppp/.ppprc, you would put the IP address for each of the
+incoming terminals into the /etc/ppp/options.tty files. ('tty' is the
+name of the tty device. For example /etc/ppp/options.ttyS0 is used for
+the /dev/ttyS0 device.)
+
+To each of the serial devices, you would attach a modem. To the
+modems, attach the telephone lines. Place all of the telephone lines
+into a hunt group so that the telephone system will select the
+non-busy telephone and subsequently, the modem. By selecting the
+modem, the user will select a tty device and the tty device will
+select the IP address. Run a getty process against the tty device such
+as /dev/ttyS0.
+
+(The general consensus among the users is that you should *not* use
+the agetty process to monitor a modem. Use either getty_ps' uugetty
+process or mgetty from the mgetty+sendfax package.)
+
+
+SECURITY CONCERNS ABOUT INCOMING PPP CONNECTIONS
+
+The following security should be considered with the ppp connections.
+
+1. Never put the pppd program file into the /etc/shells file. It is not
+a legal shell for the general user. In addition, if the shell is missing
+from the shells file, the ftpd process will not allow the user to access
+the system via ftp. You would not want Joe Hacker using the ppp account
+via ftp.
+
+2. Ensure that the directory /etc/ppp is owned by 'root' and permits
+only write access to the root user.
+
+3. The files /etc/ppp/options must be owned by root and accessible only
+from that user. Never permit any other user access to this file.
+
+4. The files /etc/ppp/ip-up and /etc/ppp/ip-down will be executed by the
+pppd process while it is root. Ensure that these files are writable only
+from the root user.
+
+5. If you use an incoming PPP connection, you should do the following as
+the root user:
+
+a) Invalidate the files for rhosts and forward
+rm -f     ~ppp/.rhosts ~ppp/.forward
+touch     ~ppp/.rhosts ~ppp/.forward
+chmod 444 ~ppp/.rhosts ~ppp/.forward
+
+b) Prevent users from sending mail to the user 'ppp'.
+
+This is best performed by creating a system alias 'ppp' and have it
+point to the name "THIS_USER_CANNOT_RECEIVE_MAIL". It has no special
+meaning other than the obvious one.
+
+For sendmail, the sequence is fairly easy. Edit the /etc/aliases file
+and add the line:
+
+ppp:THIS_USER_CANNOT_RECEIVE_MAIL
+
+Then run the sendmail program with the option '-bi' to rebuild the
+alias database.
+
+c) Secure the ppp file properly.
+chown root ~ppp/.ppprc
+chmod 444  ~ppp/.ppprc
+
+You may wish to extend the security by creating a group 'ppp' and putting
+the ppp user into that group, along with the binaries for pppd and pppstats.
+Then you may secure the binaries so that they are executable from the owner
+(which should be root) and the group only. All other users would be denied
+all access to the files and executables.
+
+
+ADDITIONAL INFORMATION
+
+Besides this document, additional information may be found in:
+
+- The file README in the source package
+- The PPP-HOWTO on sunsite.unc.edu
+- The Net-2-HOWTO on sunsite.unc.edu
+- The Network Administration Guide published by O'Rielly and Associates
+
+Please consult these sources of information should you have questions
+about the program. If you still can not find your answer then ask either
+the usenet news groups or the mail list.
+
+
+
+DIP SUPPORT
+
+The dip program used by Linux is not directly supported by the PPP
+package as such. Please don't ask the PPP porting group questions
+about dip. It does work in two areas.
+
+1. If you use it as a parameter to 'connect' then you can use the scripting
+   language and establish the connection. You would use the standard set of
+   PPP options.
+
+2. dip-3.3.7m-uri and later versions support a 'mode ppp' function
+   which will invoke the pppd program. That is all that it does. It will
+   not pass any parameters to pppd other than its required '-detach' to
+   allow dip to detect the normal termination of pppd.
+
+   The following information comes from John Phillips in an article which he
+   posted to comp.os.linux.setup.
+
+Assuming that you already know how dip supports SLIP, these points 
+are relative to a working SLIP set-up.
+
+1.  You need dip-3.3.7m-uri, and, of course, PPP compiled into the
+kernel.
+
+2.  Make sure pppd is where dip thinks it is: /usr/lib/ppp/pppd, or 
+make a link from there to where pppd really is.  (Or re-compile dip 
+to tell it where pppd is on your system - see pathnames.h).
+
+3.  The key differences between the dip script for PPP, compared to one 
+for SLIP are:
+
+    a.  Use "mode PPP" instead of "mode SLIP"
+
+    b.  Don't set certain options such as mtu and default - these are set 
+    by pppd from the file /etc/ppp/options.  Mine looks like this:
+
+        crtscts
+        modem
+        defaultroute
+        asyncmap 0x00000000
+        mru 576
+        mtu 576
+
+    The actual parameters and values may depend on your IP supplier 
+    and his set-up.
+
+    c. Tell your IP supplier's start-up code to use ppp, not slip:  I
+    use "send nolqm,idle=240\n" instead of "send slip,idle=240,mru=576\n" 
+    at the "protocol: " prompt.  ("nolqm" asks for ppp without the line 
+    quality monitoring protocol, which is not - I think - supported in 
+    Linux PPP.)  This prompt may be different (or absent) with another 
+    IP supplier.
+
+    d. You don't need "get $local <name>", since the ppp protocol 
+    negotiates this at start-up.  You still need "get $remote <name>".  
+    (This may also vary with IP supplier - you may need to set some 
+    more parameters in /etc/ppp/options to work with yours - see "man 
+    pppd" for details of the options supported by pppd.)
+
+4.  The dip script will exit after dialling and starting up pppd.  When 
+ppp negotiation is completed and IP comes up, pppd runs /etc/ppp/ip-up.  
+This file can contain things you want to run when the network comes up 
+(e.g. running the mail queue).
+
+5.  When IP goes down (e.g. after you close down the link with "dip -k"), 
+pppd runs /etc/ppp/ip-down, which can contain things you want to do on 
+close-down.
+
+
 
 CONCLUSION
 
 Good luck!
 
-Michael
+Al and Michael
index 79b1c962b3b7a81581032f21532c66787687af74..ebf3ea36d732c307e67f8d380625bf87ddf06329 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: if_ppp.h,v 1.2 1995/04/28 06:27:55 paulus Exp $    */
+/*     $Id: if_ppp.h,v 1.3 1995/06/12 11:36:50 paulus Exp $    */
 
 /*
  * if_ppp.h - Point-to-Point Protocol definitions.
  * 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.
+ *
+ */
+
+/*
+ *  ==PPPVERSION 2.1.3==
+ *
+ *  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
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
  */
 
 #ifndef _IF_PPP_H_
@@ -28,7 +41,6 @@
 
 #define        PPP_MTU         1500    /* Default MTU (size of Info field) */
 #define PPP_MAXMRU     65000   /* Largest MRU we allow */
-#define PPP_NRUNIT     4       /* how many PPP units? */
 #define PPP_VERSION    "2.2.0"
 #define PPP_MAGIC      0x5002  /* Magic value for the ppp structure */
 #define PROTO_IPX      0x002b  /* protocol numbers */
 #define SC_LOG_OUTPKT  0x00040000      /* log contents of pkts sent */
 #define SC_LOG_RAWIN   0x00080000      /* log all chars received */
 #define SC_LOG_FLUSH   0x00100000      /* log all chars flushed */
-#define        SC_MASK         0x0fffffff      /* bits that user can change */
+#define        SC_MASK         0x0fE0ffff      /* bits that user can change */
 
 /* state bits */
 #define        SC_ESCAPED      0x80000000      /* saw a PPP_ESCAPE */
 #define        SC_FLUSH        0x40000000      /* flush input until next PPP_FLAG */
 #define SC_VJ_RESET    0x20000000      /* Need to reset the VJ decompressor */
 #define SC_XMIT_BUSY   0x10000000      /* ppp_write_wakeup is active */
-#define SC_RCV_B7_0    0x01000000      /* have rcvd char with bit 7 = 0 */
-#define SC_RCV_B7_1    0x02000000      /* have rcvd char with bit 7 = 1 */
-#define SC_RCV_EVNP    0x04000000      /* have rcvd char with even parity */
 #define SC_RCV_ODDP    0x08000000      /* have rcvd char with odd parity */
-#define SC_DC_ERROR    0x00400000      /* non-fatal decomp error detected */
+#define SC_RCV_EVNP    0x04000000      /* have rcvd char with even parity */
+#define SC_RCV_B7_1    0x02000000      /* have rcvd char with bit 7 = 1 */
+#define SC_RCV_B7_0    0x01000000      /* have rcvd char with bit 7 = 0 */
 #define SC_DC_FERROR   0x00800000      /* fatal decomp error detected */
+#define SC_DC_ERROR    0x00400000      /* non-fatal decomp error detected */
 
 /*
  * Ioctl definitions.
@@ -89,13 +101,6 @@ struct ifpppstatsreq {
     struct ppp_stats stats;            /* statistic information */
 };
 
-struct ppp_ddinfo {
-  unsigned long                ip_sjiffies;    /* time when last IP frame sent */
-  unsigned long                ip_rjiffies;    /* time when last IP frame recvd*/
-  unsigned long                nip_sjiffies;   /* time when last NON-IP sent   */
-  unsigned long                nip_rjiffies;   /* time when last NON-IP recvd  */
-};
-
 /*
  * Ioctl definitions.
  */
@@ -122,7 +127,6 @@ struct ppp_ddinfo {
 #define PPPIOCGTIME    _IOR('t', 63, struct ppp_ddinfo) /* Read time info */
 
 #define SIOCGPPPSTATS   (SIOCDEVPRIVATE + 0)
-#define SIOCGPPPCSTATS (SIOCDEVPRIVATE + 2)
 #define SIOCGPPPVER     (SIOCDEVPRIVATE + 1)
 
 #if !defined(ifr_mtu)
index 0c6a39b9bbdce80f0a3b254f8b0d768fcba87ef5..89be343e4f41e18b7da2967be3743c579e163c81 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: if_pppvar.h,v 1.1 1994/12/08 01:59:58 paulus Exp $ */
+/*     $Id: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp $ */
 /*
  * if_pppvar.h - private structures and declarations for PPP.
  *
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
+/*
+ *  ==PPPVERSION 2.1.3==
+ *
+ *  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
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
+
 /*
  * Supported network protocols.  These values are used for
  * indexing sc_npmode.
@@ -128,7 +140,7 @@ struct ppp {
        struct wait_queue *read_wait;   /* queue for writing processes  */
 
   /* Statistic information */
-       struct pppstat    p;            /* statistic information        */
+       struct pppstat    stats;        /* statistic information        */
        struct ppp_ddinfo ddinfo;       /* demand dial information      */
 
   /* PPP compression protocol information */
index 79b1c962b3b7a81581032f21532c66787687af74..ebf3ea36d732c307e67f8d380625bf87ddf06329 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: if_ppp.h,v 1.2 1995/04/28 06:27:55 paulus Exp $    */
+/*     $Id: if_ppp.h,v 1.3 1995/06/12 11:36:50 paulus Exp $    */
 
 /*
  * if_ppp.h - Point-to-Point Protocol definitions.
  * 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.
+ *
+ */
+
+/*
+ *  ==PPPVERSION 2.1.3==
+ *
+ *  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
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
  */
 
 #ifndef _IF_PPP_H_
@@ -28,7 +41,6 @@
 
 #define        PPP_MTU         1500    /* Default MTU (size of Info field) */
 #define PPP_MAXMRU     65000   /* Largest MRU we allow */
-#define PPP_NRUNIT     4       /* how many PPP units? */
 #define PPP_VERSION    "2.2.0"
 #define PPP_MAGIC      0x5002  /* Magic value for the ppp structure */
 #define PROTO_IPX      0x002b  /* protocol numbers */
 #define SC_LOG_OUTPKT  0x00040000      /* log contents of pkts sent */
 #define SC_LOG_RAWIN   0x00080000      /* log all chars received */
 #define SC_LOG_FLUSH   0x00100000      /* log all chars flushed */
-#define        SC_MASK         0x0fffffff      /* bits that user can change */
+#define        SC_MASK         0x0fE0ffff      /* bits that user can change */
 
 /* state bits */
 #define        SC_ESCAPED      0x80000000      /* saw a PPP_ESCAPE */
 #define        SC_FLUSH        0x40000000      /* flush input until next PPP_FLAG */
 #define SC_VJ_RESET    0x20000000      /* Need to reset the VJ decompressor */
 #define SC_XMIT_BUSY   0x10000000      /* ppp_write_wakeup is active */
-#define SC_RCV_B7_0    0x01000000      /* have rcvd char with bit 7 = 0 */
-#define SC_RCV_B7_1    0x02000000      /* have rcvd char with bit 7 = 1 */
-#define SC_RCV_EVNP    0x04000000      /* have rcvd char with even parity */
 #define SC_RCV_ODDP    0x08000000      /* have rcvd char with odd parity */
-#define SC_DC_ERROR    0x00400000      /* non-fatal decomp error detected */
+#define SC_RCV_EVNP    0x04000000      /* have rcvd char with even parity */
+#define SC_RCV_B7_1    0x02000000      /* have rcvd char with bit 7 = 1 */
+#define SC_RCV_B7_0    0x01000000      /* have rcvd char with bit 7 = 0 */
 #define SC_DC_FERROR   0x00800000      /* fatal decomp error detected */
+#define SC_DC_ERROR    0x00400000      /* non-fatal decomp error detected */
 
 /*
  * Ioctl definitions.
@@ -89,13 +101,6 @@ struct ifpppstatsreq {
     struct ppp_stats stats;            /* statistic information */
 };
 
-struct ppp_ddinfo {
-  unsigned long                ip_sjiffies;    /* time when last IP frame sent */
-  unsigned long                ip_rjiffies;    /* time when last IP frame recvd*/
-  unsigned long                nip_sjiffies;   /* time when last NON-IP sent   */
-  unsigned long                nip_rjiffies;   /* time when last NON-IP recvd  */
-};
-
 /*
  * Ioctl definitions.
  */
@@ -122,7 +127,6 @@ struct ppp_ddinfo {
 #define PPPIOCGTIME    _IOR('t', 63, struct ppp_ddinfo) /* Read time info */
 
 #define SIOCGPPPSTATS   (SIOCDEVPRIVATE + 0)
-#define SIOCGPPPCSTATS (SIOCDEVPRIVATE + 2)
 #define SIOCGPPPVER     (SIOCDEVPRIVATE + 1)
 
 #if !defined(ifr_mtu)
index 0c6a39b9bbdce80f0a3b254f8b0d768fcba87ef5..89be343e4f41e18b7da2967be3743c579e163c81 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: if_pppvar.h,v 1.1 1994/12/08 01:59:58 paulus Exp $ */
+/*     $Id: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp $ */
 /*
  * if_pppvar.h - private structures and declarations for PPP.
  *
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
+/*
+ *  ==PPPVERSION 2.1.3==
+ *
+ *  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
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
+
 /*
  * Supported network protocols.  These values are used for
  * indexing sc_npmode.
@@ -128,7 +140,7 @@ struct ppp {
        struct wait_queue *read_wait;   /* queue for writing processes  */
 
   /* Statistic information */
-       struct pppstat    p;            /* statistic information        */
+       struct pppstat    stats;        /* statistic information        */
        struct ppp_ddinfo ddinfo;       /* demand dial information      */
 
   /* PPP compression protocol information */
index 6daff3c8a3aa57aa37b0e64c812b0feaf3e272c7..cd7e605ac1bf771bfa91847f3fc3819c99165e71 100644 (file)
@@ -1,8 +1,17 @@
 /*
-   PPP for Linux
-
-   $Id: ppp.c,v 1.4 1995/04/28 06:28:22 paulus Exp $
-*/
+ *  PPP for Linux
+ *
+ *  ==PPPVERSION 2.1.3==
+ *
+ *  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
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ *
+ */
 
 /*
    Sources:
    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
 */
 
-/* #define NEW_SKBUFF */
-#define OPTIMIZE_FLAG_TIME  ((HZ * 3)/2)       /* */
+/* #define NEW_SKBUFF          1 */
+#define OPTIMIZE_FLAG_TIME     ((HZ * 3)/2)
+#define CHECK_CHARACTERS       1
+#define PPP_COMPRESS           1
+
+/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp $
+ * Added dynamic allocation of channels to eliminate
+ *   compiled-in limits on the number of channels.
+ *
+ * Dynamic channel allocation code Copyright 1995 Caldera, Inc.,
+ *   released under the GNU General Public License Version 2.
+ */
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -62,7 +85,7 @@
 #ifdef NEW_SKBUFF
 #include <linux/netprotocol.h>
 #else
-#define skb_data(skb)  ((skb)->data)
+#define skb_data(skb)  ((unsigned char *) (skb)->data)
 typedef struct sk_buff sk_buff;
 #endif
 
@@ -75,10 +98,33 @@ typedef struct sk_buff      sk_buff;
 #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 */
+
+#ifdef PPP_COMPRESS
+#undef   PACKETPTR
+#define  PACKETPTR 1
+#include <net/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 */
 #endif
 
+#ifndef PPP_LQR
+#define PPP_LQR 0xc025  /* Link Quality Reporting Protocol */
+#endif
+
 /*
  * Local functions
  */
@@ -86,14 +132,37 @@ typedef struct sk_buff     sk_buff;
 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 int ppp_do_ip (struct ppp *, unsigned short, u_char *, int);
-static int ppp_us_queue (struct ppp *, unsigned short, u_char *, int);
 static struct ppp *ppp_alloc (void);
-static void ppp_print_buffer (const u_char *, u_char *, int, int);
+static void ppp_print_buffer (const u_char *, 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.
+ */
+
+#ifdef PPP_COMPRESS
+extern struct compressor ppp_bsd_compress;
+
+struct compressor *ppp_compressors[8] = {
+    &ppp_bsd_compress,
+    NULL
+};
+#endif /* PPP_COMPRESS */
 
 #define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c))
 
@@ -146,10 +215,7 @@ static void ppp_tty_receive (struct tty_struct *tty, u_char * cp,
                             char *fp, int count);
 static void ppp_tty_wakeup (struct tty_struct *tty);
 
-
 #define PRINTK(p) printk p ;
-#define ASSERT(p) if (!p) PRINTK ((KERN_CRIT "assertion failed: " # p))
-#define PRINTKN(n,p) {if (ppp_debug >= n) 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;}
 
@@ -159,26 +225,79 @@ static void ppp_tty_wakeup (struct tty_struct *tty);
 
 #define bset(p,b)      ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
 
+#define tty2ppp(tty)   ((struct ppp *) (tty->disc_data))
+#define dev2ppp(dev)   ((struct ppp *) (dev->priv))
+#define ppp2tty(ppp)   ((struct tty_struct *) ppp->tty)
+#define ppp2dev(ppp)   ((struct device *) ppp->dev)
+
+struct ppp_hdr {
+       unsigned char address;
+       unsigned char control;
+       unsigned char protocol[2];
+};
+
+#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           */
+       struct ppp      ppp;            /* PPP control table            */
+       struct device   dev;            /* Device information table     */
+} ppp_ctrl_t;
+
+static ppp_ctrl_t *ppp_list = NULL;
+
+#define ctl2ppp(ctl) (struct ppp *)    &ctl->ppp
+#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     */
-#define BUFFER_TYPE_DEV_WR    2  /* ppp? write buffer     */
-#define BUFFER_TYPE_TTY_RD    3  /* tty? read buffer      */
-#define BUFFER_TYPE_VJ        4  /* vj compression buffer */
+#define BUFFER_TYPE_DEV_RD     0  /* ppp read buffer       */
+#define BUFFER_TYPE_TTY_WR     1  /* tty write buffer      */
+#define BUFFER_TYPE_DEV_WR     2  /* ppp write buffer      */
+#define BUFFER_TYPE_TTY_RD     3  /* tty read buffer       */
+#define BUFFER_TYPE_VJ         4  /* vj compression buffer */
 
 /* Define this string only once for all macro envocations */
 static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
 
-static int first_time           = 1;
 static char szVersion[]         = PPP_VERSION;
-static int ppp_debug            = 5;
-static int ppp_debug_netpackets = 0;
-static struct tty_ldisc ppp_ldisc;
-static struct ppp       ppp_ctrl   [PPP_NRUNIT];
  
 #ifdef NEW_SKBUFF
-struct protocol proto_ppp;
+static struct protocol proto_ppp;
+#endif
+
+/*
+ * Information for the protocol decoder
+ */
+
+typedef int (*pfn_proto)  (struct ppp *, u_short, u_char *, int);
+
+typedef struct ppp_proto_struct {
+       int             proto;
+       pfn_proto       func;
+} ppp_proto_type;
+
+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_CCP,        rcv_proto_ccp        },
 #endif
+       { 0,              rcv_proto_unknown    }  /* !!! MUST BE LAST !!! */
+};
 
 /* FCS table from RFC1331 */
 
@@ -218,83 +337,126 @@ static unsigned short fcstab[256] =
        0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
 };
 
+#ifdef CHECK_CHARACTERS
+static unsigned paritytab[8] =
+{
+       0x96696996, 0x69969669, 0x69969669, 0x96696996,
+       0x69969669, 0x96696996, 0x96696996, 0x69969669
+};
+#endif
+
+/* local function to store a value into the LQR frame */
+extern inline u_char * store_long (register u_char *p, register int value) {
+       *p++ = (u_char) (value >> 24);
+       *p++ = (u_char) (value >> 16);
+       *p++ = (u_char) (value >>  8);
+       *p++ = (u_char) value;
+       return p;
+}
+
 /*************************************************************
  * INITIALIZATION
  *************************************************************/
 
-/* called at boot time for each ppp device */
+/* This procedure is called once and once only to define who we are to
+ * the operating system and the various procedures that it may use in
+ * accessing the ppp protocol.
+ */
 
-int
-ppp_init (struct device *dev)
+static int
+ppp_first_time (void)
 {
-       struct ppp *ppp;
-       int i;
-
-       ppp = &ppp_ctrl[dev->base_addr];
-
-       if (first_time) {
-               first_time = 0;
-
-               printk (KERN_INFO "PPP: version %s (%d channels)"
+       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
 #ifdef NEW_SKBUFF
-                       " NEW_SKBUFF"
+               " NEW_SKBUFF"
+#endif
+               "\n", szVersion);
+#undef PPP_UNITS
+#undef PPP_UNITS1
+#undef PPP_UNITS2
+#undef PPP_UNITS3
+
+       printk (KERN_INFO
+               "TCP compression code copyright 1989 Regents of the "
+               "University of California\n");
+       
+#ifndef PPP_NRUNIT
+       printk (KERN_INFO
+               "PPP Dynamic channel allocation code copyright 1995 "
+               "Caldera, Inc.\n");
 #endif
-                       "\n", szVersion, PPP_NRUNIT);
 
-               printk (KERN_INFO
-                       "TCP compression code copyright 1989 Regents of the "
-                       "University of California\n");
-
-               (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
-               ppp_ldisc.magic         = TTY_LDISC_MAGIC;
-               ppp_ldisc.open          = ppp_tty_open;
-               ppp_ldisc.close         = ppp_tty_close;
-               ppp_ldisc.read          = ppp_tty_read;
-               ppp_ldisc.write         = ppp_tty_write;
-               ppp_ldisc.ioctl         = ppp_tty_ioctl;
-               ppp_ldisc.select        = ppp_tty_select;
-               ppp_ldisc.receive_room  = ppp_tty_room;
-               ppp_ldisc.receive_buf   = ppp_tty_receive;
-               ppp_ldisc.write_wakeup  = ppp_tty_wakeup;
-
-               i = tty_register_ldisc (N_PPP, &ppp_ldisc);
-               if (i == 0) {
-                       printk (KERN_INFO "PPP line discipline registered.\n");
-               } else {
-                       printk (KERN_ERR "error registering line discipline: %d\n", i);
-               }
+/*
+ * Register the protocol for the device
+ */
 
 #ifdef NEW_SKBUFF  
-               memset (&proto_ppp, 0, sizeof (proto_ppp));
+       memset (&proto_ppp, 0, sizeof (proto_ppp));
 
-               proto_ppp.name          = "PPP";
-               proto_ppp.output        = ppp_dev_output;
-               proto_ppp.input         = ppp_dev_input;
-               proto_ppp.bh_input      = ppp_dev_input;
-               proto_ppp.control_event = default_protocol_control;
-               proto_ppp.get_binding   = ppp_dev_getkey;
+       proto_ppp.name          = "PPP";
+       proto_ppp.output        = ppp_dev_output;
+       proto_ppp.input         = ppp_dev_input;
+       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; */
 
-               protocol_register(&proto_ppp);
+       protocol_register(&proto_ppp);
 #endif
 
-       }
-       /* initialize PPP control block */
-       ppp_init_ctrl_blk (ppp);
-       ppp->inuse = 0;
-       ppp->line  = dev->base_addr;
-       ppp->tty   = NULL;
-       ppp->dev   = dev;
+/*
+ * Register the tty dicipline
+ */    
+       (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
+       ppp_ldisc.magic         = TTY_LDISC_MAGIC;
+       ppp_ldisc.open          = ppp_tty_open;
+       ppp_ldisc.close         = ppp_tty_close;
+       ppp_ldisc.read          = ppp_tty_read;
+       ppp_ldisc.write         = ppp_tty_write;
+       ppp_ldisc.ioctl         = ppp_tty_ioctl;
+       ppp_ldisc.select        = ppp_tty_select;
+       ppp_ldisc.receive_room  = ppp_tty_room;
+       ppp_ldisc.receive_buf   = ppp_tty_receive;
+       ppp_ldisc.write_wakeup  = ppp_tty_wakeup;
+       
+       status = tty_register_ldisc (N_PPP, &ppp_ldisc);
+       if (status == 0)
+               printk (KERN_INFO "PPP line discipline registered.\n");
+       else
+               printk (KERN_ERR "error registering line discipline: %d\n",
+                       status);
+       return status;
+}
 
-       /* clear statistics */
-       memset (&ppp->p, '\0', sizeof (struct ppp_stats));
+/*************************************************************
+ * INITIALIZATION
+ *************************************************************/
 
+/* called when the device is actually created */
+
+static int
+ppp_init_dev (struct device *dev)
+{
+       int    indx;
 #ifdef NEW_SKBUFF  
        dev->default_protocol = &proto_ppp;     /* Our protocol layer is PPP */
 #else
        dev->hard_header      = ppp_dev_header;
        dev->type_trans       = ppp_dev_type;
        dev->rebuild_header   = ppp_dev_rebuild;
-       dev->hard_header_len  = 0;
+       dev->hard_header_len  = 0; /* PPP_HARD_HDR_LEN; */
 #endif
 
        /* device INFO */
@@ -307,9 +469,8 @@ ppp_init (struct device *dev)
        dev->addr_len         = 0;
        dev->type             = ARPHRD_PPP;
 
-       for (i = 0; i < DEV_NUMBUFFS; i++) {
-               skb_queue_head_init (&dev->buffs[i]);
-       }
+       for (indx = 0; indx < DEV_NUMBUFFS; indx++)
+               skb_queue_head_init (&dev->buffs[indx]);
 
        /* New-style flags */
        dev->flags      = IFF_POINTOPOINT;
@@ -357,14 +518,49 @@ ppp_init_ctrl_blk (register struct ppp *ppp)
 #endif
 
        /* clear statistics */
-       memset (&ppp->p, '\0', sizeof (struct ppp_stats));
+       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;
+
+#ifdef PPP_COMPRESS
+       ppp->sc_xc_state =
+       ppp->sc_rc_state = NULL;
+#endif /* PPP_COMPRESS */
+}
+
+/* called at boot/load time for each ppp device defined in the kernel */
+
+#ifndef MODULE
+int
+ppp_init (struct device *dev)
+{
+       static int first_time = 1;
+       int    answer = 0;
+
+       if (first_time) {
+               first_time = 0;
+               answer     = ppp_first_time();
+       }
+/*
+ * 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
+       return answer;
 }
+#endif
 
 /*
  * Routine to allocate a buffer for later use by the driver.
@@ -397,9 +593,8 @@ ppp_alloc_buf (int size, int type)
 static void
 ppp_free_buf (struct ppp_buffer *ptr)
 {
-       if (ptr != NULL) {
+       if (ptr != NULL)
                kfree (ptr);
-       }
 }
 
 /*
@@ -417,9 +612,8 @@ lock_buffer (register struct ppp_buffer *buf)
        save_flags (flags);
        cli ();
        state = buf->locked;
-       if (state == 0) {
+       if (state == 0)
                buf->locked = 2;
-       }
 /*
  * Restore the flags and return the previous state. 0 implies success.
  */
@@ -452,30 +646,35 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
 /*
  *  Allocate the buffer from the kernel for the data
  */
-       dev = ppp->dev;
+       dev = ppp2dev (ppp);
        mru = new_mru;
+       /* allow for possible escapement of every character */
        mtu = (new_mtu * 2) + 20;
 
        /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
-       if (mru < PPP_MRU) {
+       if (mru < PPP_MRU)
                mru = PPP_MRU;
-       }
-       mru += 10;
 
-       PRINTKN (2, (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
-                    dev->name, new_mtu, new_mru));
+       mru += 10;
+       
+       if (ppp->flags & SC_DEBUG)
+               printk (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
+                       dev->name, new_mtu, new_mru);
 
-       new_wbuf = ppp_alloc_buf (mtu + 4, BUFFER_TYPE_DEV_WR);
-       new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24, BUFFER_TYPE_TTY_WR);
-       new_rbuf = ppp_alloc_buf (mru + 84, BUFFER_TYPE_DEV_RD);
-       new_cbuf = ppp_alloc_buf (mru + 4, BUFFER_TYPE_VJ);
+       new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN, BUFFER_TYPE_DEV_WR);
+       new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24,   BUFFER_TYPE_TTY_WR);
+       new_rbuf = ppp_alloc_buf (mru + 84,             BUFFER_TYPE_DEV_RD);
+       new_cbuf = ppp_alloc_buf (mru+PPP_HARD_HDR_LEN, BUFFER_TYPE_VJ);
 /*
  *  If the buffers failed to allocate then complain and release the partial
  *  allocations.
  */
        if (new_wbuf == NULL || new_tbuf == NULL ||
            new_rbuf == NULL || new_cbuf == NULL) {
-               PRINTKN (2,(KERN_ERR "ppp: failed to allocate new buffers\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                               "ppp: failed to allocate new buffers\n");
+
                ppp_free_buf (new_wbuf);
                ppp_free_buf (new_tbuf);
                ppp_free_buf (new_rbuf);
@@ -505,16 +704,16 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
 /*
  *  Update the parameters for the new buffer sizes
  */
-       ppp->toss = 0xE0;       /* To ignore characters until new FLAG */
+       ppp->toss   = 0xE0;     /* To ignore characters until new FLAG */
        ppp->escape = 0;        /* No pending escape character */
 
-       dev->mtu   =
-       ppp->mtu   = new_mtu;
-       ppp->mru   = new_mru;
+       dev->mtu    =
+       ppp->mtu    = new_mtu;
+       ppp->mru    = new_mru;
 
-       ppp->s1buf = NULL;
-       ppp->s2buf = NULL;
-       ppp->xbuf  = NULL;
+       ppp->s1buf  = NULL;
+       ppp->s2buf  = NULL;
+       ppp->xbuf   = NULL;
 
        ppp->tty->flags &= ~TTY_DO_WRITE_WAKEUP;
        ppp->flags      &= ~SC_XMIT_BUSY;
@@ -530,6 +729,26 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
        return 1;
 }
 
+/*
+ * 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_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.
  *
@@ -540,13 +759,26 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
 static void
 ppp_release (struct ppp *ppp)
 {
-       if (ppp->tty != NULL && ppp->tty->disc_data == ppp) {
-               ppp->tty->disc_data = NULL;     /* Break the tty->ppp link */
-       }
-       if (ppp->dev) {
-               ppp->dev->flags &= ~IFF_UP;     /* down the device */
-               ppp->dev->flags |= IFF_POINTOPOINT;
+       struct tty_struct *tty;
+       struct device *dev;
+
+       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 */
+
+       if (dev && dev->flags & IFF_UP) {
+               dev_close (dev); /* close the device properly */
+               dev->flags = 0;  /* prevent recursion */
        }
+
        ppp_free_buf (ppp->rbuf);
        ppp_free_buf (ppp->wbuf);
        ppp_free_buf (ppp->cbuf);
@@ -566,8 +798,9 @@ ppp_release (struct ppp *ppp)
                slhc_free (ppp->slcomp);
                ppp->slcomp = NULL;
        }
+
        ppp->inuse = 0;
-       ppp->tty = NULL;
+       ppp->tty   = NULL;
 }
 
 /*
@@ -579,37 +812,41 @@ ppp_release (struct ppp *ppp)
 static void
 ppp_tty_close (struct tty_struct *tty)
 {
-       struct ppp *ppp = (struct ppp *) tty->disc_data;
+       struct ppp *ppp = tty2ppp (tty);
 
        if (ppp == NULL || ppp->magic != PPP_MAGIC) {
-               PRINTKN (1,
-                    (KERN_WARNING "ppp: trying to close unopened tty!\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_WARNING
+                               "ppp: trying to close unopened tty!\n");
        } else {
-               CHECK_PPP_VOID ();
-               PRINTKN (2,
-                 (KERN_INFO "ppp: channel %s closing.\n", ppp->dev->name));
+               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;
        }
 }
 
 /*
  * TTY callback.
  *
- * Called when the tty dicipline is switched to PPP.
+ * Called when the tty discipline is switched to PPP.
  */
 
 static int
 ppp_tty_open (struct tty_struct *tty)
 {
-       struct ppp *ppp = (struct ppp *) tty->disc_data;
+       struct ppp *ppp = tty2ppp (tty);
 /*
  * There should not be an existing table for this slot.
  */
        if (ppp) {
-               PRINTKN (1, (KERN_ERR
-                     "ppp_tty_open: gack! tty already associated to %s!\n",
-                            ppp->magic == PPP_MAGIC ? ppp->dev->name
-                            : "unknown"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                       "ppp_tty_open: gack! tty already associated to %s!\n",
+                       ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name
+                                               : "unknown");
                return -EEXIST;
        }
 /*
@@ -617,8 +854,9 @@ ppp_tty_open (struct tty_struct *tty)
  */
        ppp = ppp_alloc ();
        if (ppp == NULL) {
-               PRINTKN (1, (KERN_ERR
-                         "ppp_tty_open: couldn't allocate ppp channel\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                       "ppp_tty_open: couldn't allocate ppp channel\n");
                return -ENFILE;
        }
 /*
@@ -628,29 +866,28 @@ ppp_tty_open (struct tty_struct *tty)
        ppp->tty       = tty;
        tty->disc_data = ppp;
 /*
- * Flush any pending characters in the driver and dicipline.
+ * Flush any pending characters in the driver and discipline.
  */
-       if (tty->ldisc.flush_buffer) {
+       if (tty->ldisc.flush_buffer)
                tty->ldisc.flush_buffer (tty);
-       }
 
-       if (tty->driver.flush_buffer) {
+       if (tty->driver.flush_buffer)
                tty->driver.flush_buffer (tty);
-       }
 /*
  * Allocate space for the default VJ header compression slots (16)
  */
        ppp->slcomp = slhc_init (16, 16);
        if (ppp->slcomp == NULL) {
-               PRINTKN (1, (KERN_ERR
-                     "ppp_tty_open: no space for compression buffers!\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                       "ppp_tty_open: no space for compression buffers!\n");
                ppp_release (ppp);
                return -ENOMEM;
        }
 /*
  * Allocate space for the MTU and MRU buffers
  */
-       if (ppp_changedmtu (ppp, ppp->dev->mtu, ppp->mru) == 0) {
+       if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
                ppp_release (ppp);
                return -ENOMEM;
        }
@@ -659,13 +896,18 @@ ppp_tty_open (struct tty_struct *tty)
  */
        ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
        if (ppp->ubuf == NULL) {
-               PRINTKN (1, (KERN_ERR
-                      "ppp_tty_open: no space for user receive buffer\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                      "ppp_tty_open: no space for user receive buffer\n");
                ppp_release (ppp);
                return -ENOMEM;
        }
 
-       PRINTKN (2, (KERN_INFO "ppp: channel %s open\n", ppp->dev->name));
+       if (ppp->flags & SC_DEBUG)
+               printk (KERN_INFO "ppp: channel %s open\n",
+                       ppp2dev(ppp)->name);
+
+       MOD_INC_USE_COUNT;
        return (ppp->line);
 }
 
@@ -706,11 +948,10 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
  * This could occur should the carrier drop.
  */
        if (actual < 0) {
-               ppp->p.ppp_oerrors++;
+               ppp->stats.ppp_oerrors++;
                actual = count;
-       } else {
+       } else
                ppp->bytes_sent += actual;
-       }
 /*
  * If the buffer has been transmitted then clear the indicators.
  */
@@ -719,7 +960,7 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
                xbuf = NULL;
                ppp->flags &= ~SC_XMIT_BUSY;
 /*
- * Complete the transmisson on the current buffer.
+ * Complete the transmission on the current buffer.
  */
                xbuf = ppp->xbuf;
                if (xbuf != NULL) {
@@ -730,10 +971,10 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
  * If the completed buffer came from the device write, then complete the
  * transmission block.
  */
-                       if (ppp->dev->flags & IFF_UP) {
-                               ppp->dev->tbusy = 0;
+                       if (ppp2dev (ppp) -> flags & IFF_UP) {
+                               ppp2dev (ppp)->tbusy = 0;
                                mark_bh (NET_BH);
-                               dev_tint (ppp->dev);
+                               dev_tint (ppp2dev (ppp));
                        }
 /*
  * Wake up the transmission queue for all completion events.
@@ -776,11 +1017,12 @@ static void
 ppp_tty_wakeup (struct tty_struct *tty)
 {
        struct ppp_buffer *xbuf;
-       struct ppp *ppp = (struct ppp *) tty->disc_data;
+       struct ppp *ppp = tty2ppp (tty);
 
        if (!ppp || ppp->magic != PPP_MAGIC) {
-               PRINTKN (1, (KERN_ERR "PPP: write_wakeup called but couldn't "
-                            "find PPP struct.\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_DEBUG "PPP: write_wakeup called but "
+                               "couldn't find PPP struct.\n");
                return;
        }
 /*
@@ -788,15 +1030,14 @@ ppp_tty_wakeup (struct tty_struct *tty)
  * there is no pending buffer. Otherwise, send the buffer.
  */
        xbuf = ppp->xbuf;
-       if (xbuf == NULL) {
+       if (xbuf == NULL)
                tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-       } else {
+       else
                ppp_tty_wakeup_code (ppp, tty, xbuf);
-       }
 }
 
 /*
- * This function is called to transmit a buffer to the rmeote. The buffer
+ * This function is called to transmit a buffer to the remote. The buffer
  * is placed on the pending queue if there is presently a buffer being
  * sent or it is transmitted with the aid of ppp_tty_wakeup.
  */
@@ -820,11 +1061,10 @@ ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
  * priority queue.
  */
        if (ppp->xbuf != NULL) {
-               if (xbuf->type == BUFFER_TYPE_TTY_WR) {
+               if (xbuf->type == BUFFER_TYPE_TTY_WR)
                        ppp->s1buf = xbuf;
-               } else {
+               else
                        ppp->s2buf = xbuf;
-               }
                restore_flags (flags);
                return;
        }
@@ -838,7 +1078,7 @@ ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
 /*
  * Do the "tty wakeup_code" to actually send this buffer.
  */
-       ppp_tty_wakeup_code (ppp, ppp->tty, xbuf);
+       ppp_tty_wakeup_code (ppp, ppp2tty (ppp), xbuf);
 }
 
 /*************************************************************
@@ -849,14 +1089,6 @@ ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
  *    user process reading this TTY.
  *************************************************************/
 
-#ifdef CHECK_CHARACTERS
-static unsigned paritytab[8] =
-{
-       0x96696996, 0x69969669, 0x69969669, 0x96696996,
-       0x69969669, 0x96696996, 0x96696996, 0x69969669
-};
-#endif
-
 /*
  * Callback function from tty driver. Return the amount of space left
  * in the receiver's buffer to decide if remote transmitter is to be
@@ -876,24 +1108,26 @@ ppp_tty_room (struct tty_struct *tty)
 static void
 ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
 {
-       register struct ppp *ppp = (struct ppp *) tty->disc_data;
+       register struct ppp *ppp = tty2ppp (tty);
        register struct ppp_buffer *buf = ppp->rbuf;
        u_char chr;
 /*
- * Verify the table pointer and ensure that the line is still in PPP dicipline.
+ * Verify the table pointer and ensure that the line is
+ * still in PPP discipline.
  */
        if (!ppp || ppp->magic != PPP_MAGIC) {
-               PRINTKN (1, ("PPP: handler called but couldn't find "
-                            "PPP struct.\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_DEBUG
+                               "PPP: handler called but couldn't find "
+                               "PPP struct.\n");
                return;
        }
        CHECK_PPP_VOID ();
 /*
  * Print the buffer if desired
  */
-       if (ppp_debug >= 5) {
-               ppp_print_buffer ("receive buffer", data, count, KERNEL_DS);
-       }
+       if (ppp->flags & SC_LOG_RAWIN)
+               ppp_print_buffer ("receive buffer", data, count);
 /*
  * Collect the character and error condition for the character. Set the toss
  * flag for the first character error.
@@ -902,9 +1136,8 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
                ppp->bytes_rcvd++;
                chr = *data++;
                if (flags) {
-                       if (*flags && ppp->toss == 0) {
+                       if (*flags && ppp->toss == 0)
                                ppp->toss = *flags;
-                       }
                        ++flags;
                }
 /*
@@ -914,18 +1147,17 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
  * so that the normal processing would have all flags set at the end of the
  * session. A missing flag bit would denote an error condition.
  */
+
 #ifdef CHECK_CHARACTERS
-               if (chr & 0x80) {
+               if (chr & 0x80)
                        ppp->flags |= SC_RCV_B7_1;
-               } else {
+               else
                        ppp->flags |= SC_RCV_B7_0;
-               }
 
-               if (paritytab[chr >> 5] & (1 << (chr & 0x1F))) {
+               if (paritytab[chr >> 5] & (1 << (chr & 0x1F)))
                        ppp->flags |= SC_RCV_ODDP;
-               } else {
+               else
                        ppp->flags |= SC_RCV_EVNP;
-               }
 #endif
 /*
  * Branch on the character. Process the escape character. The sequence ESC ESC
@@ -941,10 +1173,9 @@ 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->p.ppp_ibytes = ppp->bytes_rcvd;
-                       if (ppp->escape) {
+                       ppp->stats.ppp_ibytes = ppp->bytes_rcvd;
+                       if (ppp->escape)
                                ppp->toss |= 0x80;
-                       }
 /*
  * Process frames which are not to be ignored. If the processing failed,
  * then clean up the VJ tables.
@@ -963,12 +1194,11 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
                        break;
 /*
  * All other characters in the data come here. If the character is in the
- * recieve mask then ignore the character.
+ * receive mask then ignore the character.
  */
                default:
-                       if (in_rmap (ppp, chr)) {
+                       if (in_rmap (ppp, chr))
                                break;
-                       }
 /*
  * Adjust the character and if the frame is to be discarded then simply
  * ignore the character until the ending FLAG is received.
@@ -976,9 +1206,8 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
                        chr ^= ppp->escape;
                        ppp->escape = 0;
 
-                       if (ppp->toss != 0) {
+                       if (ppp->toss != 0)
                                break;
-                       }
 /*
  * If the count sent is within reason then store the character, bump the
  * count, and update the FCS for the character.
@@ -992,277 +1221,519 @@ ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
  * The peer sent too much data. Set the flags to discard the current frame
  * and wait for the re-synchronization FLAG to be sent.
  */
-                       ppp->p.ppp_ierrors++;
+                       ppp->stats.ppp_ierrors++;
                        ppp->toss |= 0xC0;
                        break;
                }
        }
 }
 
-/* on entry, a received frame is in ppp->rbuf.bufr
-   check it and dispose as appropriate */
+/*
+ * Put the input frame into the networking system for the indicated protocol
+ */
 
 static int
-ppp_doframe (struct ppp *ppp)
+ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
 {
-       u_short proto;
-       u_char *data = buf_base (ppp->rbuf);
-       int count    = ppp->rbuf->count;
+       sk_buff *skb = alloc_skb (count, GFP_ATOMIC);
 /*
- * If there is a pending error from the receiver then log it and discard
- * the damaged frame.
+ * Generate a skb buffer for the new frame.
  */
-       if (ppp->toss) {
-               PRINTKN (1, (KERN_WARNING
-                            "ppp_toss: tossing frame, reason = %d\n",
-                            ppp->toss));
-               ppp->p.ppp_ierrors++;
+       if (skb == NULL) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                        "ppp_do_ip: packet dropped on %s (no memory)!\n",
+                        ppp2dev (ppp)->name);
                return 0;
        }
 /*
- * An empty frame is ignored. This occurs if the FLAG sequence precedes and
- * follows each frame.
+ * Move the received data from the input buffer to the skb buffer.
  */
-       if (count == 0) {
-               return 1;
-       }
+       skb->len = count;               /* Store the length */
+       skb->dev = ppp2dev (ppp);       /* We are the device */
+#ifdef NEW_SKBUF
+       skb->protocol = proto;
+#endif
+       memcpy ((u_char *) skb_data(skb), data, count); /* move data */
 /*
- * Print the received data.
+ * Tag the frame and kick it to the proper receive routine
  */
-       if (ppp_debug >= 3) {
-               ppp_print_buffer ("receive frame", data, count, KERNEL_DS);
-       }
+       skb->free = 1;
+       ppp->ddinfo.ip_rjiffies = jiffies;
+       netif_rx (skb);
+       return 1;
+}
+
 /*
- * Generate an error if the frame is too small.
+ * Process the receipt of an IP frame
  */
-       if (count < 4) {
-               PRINTKN (1, (KERN_WARNING
-                            "ppp: got runt ppp frame, %d chars\n", count));
-               ppp->p.ppp_ierrors++;
-               return 1;
+
+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);
        }
+       return 0;
+}
+
 /*
- * Verify the CRC of the frame and discard the CRC characters from the
- * end of the buffer.
+ * Process the receipt of an IPX frame
  */
-       if (ppp->rbuf->fcs != PPP_GOODFCS) {
-               PRINTKN (1, (KERN_WARNING
-                            "ppp: frame with bad fcs, excess = %x\n",
-                            ppp->rbuf->fcs ^ PPP_GOODFCS));
-               ppp->p.ppp_ierrors++;
-               return 0;
-       }
-       count -= 2;             /* ignore the fcs characters */
+
+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
+#endif
+       return 0;
+}
+
 /*
- * Ignore the leading ADDRESS and CONTROL fields in the frame.
+ * Process the receipt of an VJ Compressed frame
  */
-       if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
-               data  += 2;
-               count -= 2;
-       }
-
-       proto = (u_short) * data++;     /* PROTO compressed */
-       if (proto & 1) {
-               count--;
-       } else {
-               proto = (proto << 8) | (u_short) * data++;
-               count -= 2;
-       }
 
-       /* Send the frame to the network if the ppp device is up */
-       if (ppp->dev->flags & IFF_UP) {
-               if (ppp_do_ip (ppp, proto, data, count)) {
-                       ppp->ddinfo.ip_rjiffies = jiffies;
-                       return 1;
+static int
+rcv_proto_vjc_comp (struct ppp *ppp, unsigned short proto,
+                   u_char *data, int count)
+{
+       if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
+               int new_count = slhc_uncompress (ppp->slcomp, data, count);
+               if (new_count >= 0) {
+                       return rcv_proto_ip (ppp, PPP_IP, data, new_count);
                }
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_NOTICE
+                               "ppp: error in VJ decompression\n");
        }
-
-       /* If we got here, it has to go to a user process doing a read,
-          so queue it. */
-       if (ppp_us_queue (ppp, proto, data, count)) {
-               ppp->ddinfo.nip_rjiffies = jiffies;
-               return 1;
-       }
-
-       /* couldn't cope. */
-       PRINTKN (1, (KERN_WARNING
-            "ppp: dropping packet on the floor: nobody could take it.\n"));
-       ppp->p.ppp_ierrors++;
-       return 1;
+       return 0;
 }
 
-/* Examine packet at C, attempt to pass up to net layer.
-   PROTO is the protocol field from the PPP frame.
-   Return 1 if could handle it, 0 otherwise.  */
-
-static int
-ppp_do_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count)
-{
-       sk_buff *skb;
 /*
- * Log the IP information
+ * Process the receipt of an VJ Un-compressed frame
  */
-       PRINTKN (4, (KERN_DEBUG "ppp_do_ip: proto %x len %d first byte %x\n",
-                    (int) proto, count, data[0]));
 
-       if (ppp_debug_netpackets) {
-               PRINTK ((KERN_DEBUG "%s <-- proto %x len %d\n", ppp->dev->name,
-                        (int) proto, count));
+static int
+rcv_proto_vjc_uncomp (struct ppp *ppp, unsigned short proto,
+                     u_char *data, int count)
+{
+       if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
+               if (slhc_remember (ppp->slcomp, data, count) > 0) {
+                       return rcv_proto_ip (ppp, PPP_IP, data, count);
+               }
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_NOTICE
+                               "ppp: error in VJ memorizing\n");
        }
+       return 0;
+}
+
 /*
- * If this is uncompressed IP data then receive the data
+ * Receive all unclassified protocols.
  */
-       switch (proto) {
-       case PPP_IP:
-               break;
+
+static int
+rcv_proto_unknown (struct ppp *ppp, unsigned short proto,
+                  u_char *data, int len)
+{
+       int totlen;
+       register int current_idx;
+
+#define PUTC(c)                                                 \
+{                                                       \
+    buf_base (ppp->ubuf) [current_idx++] = (u_char) (c); \
+    current_idx &= ppp->ubuf->size;                     \
+    if (current_idx == ppp->ubuf->tail)                         \
+           goto failure;                                \
+}
+
 /*
- * For now, reject the IPX frames. Return 1 to indicate that it has been
- * processed so that it is simply discarded.
+ * The total length includes the protocol data.
+ * Lock the user information buffer.
  */
-       case PPP_IPX:
-               return 1;
+       if (set_bit (0, &ppp->ubuf->locked)) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_DEBUG
+                               "ppp_us_queue: can't get lock\n");
+       } else {
+               current_idx = ppp->ubuf->head;
 /*
- * Process compressed IP frame. If the remote told us to reject frames then
- * do so now. Otherwise ensure that there is space in the buffer.
+ * Insert the buffer length (not counted), the protocol, and the data
  */
-       case PPP_VJC_COMP:
-               if (ppp->flags & SC_REJ_COMP_TCP) {
-                       return 1;
+               totlen = len + 2;
+               PUTC (totlen >> 8);
+               PUTC (totlen);
+
+               PUTC (proto >> 8);
+               PUTC (proto);
+
+               totlen -= 2;
+               while (totlen-- > 0) {
+                       PUTC (*data++);
                }
+#undef PUTC
 /*
- * Uncompress the header. We now can _guarantee_ that there is room.
+ * The frame is complete. Update the head pointer and wakeup the pppd
+ * process.
  */
-               count = slhc_uncompress (ppp->slcomp, data, count);
-               if (count <= 0) {
-                       ppp->p.ppp_ierrors++;
-                       PRINTKN (1, (KERN_NOTICE
-                                    "ppp: error in VJ decompression\n"));
-                       return 1;
-               }
-               proto = PPP_IP;
-               break;
+               ppp->ubuf->head = current_idx;
+
+               clear_bit (0, &ppp->ubuf->locked);
+               wake_up_interruptible (&ppp->read_wait);
+               if (ppp->tty->fasync != NULL)
+                       kill_fasync (ppp->tty->fasync, SIGIO);
+
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_INFO
+                               "ppp: successfully queued %d bytes\n",
+                               len + 2);
+
+               ppp->ddinfo.nip_rjiffies = jiffies;
+               return 1;
 /*
- * Process uncompressed IP frame
+ * The buffer is full. Unlock the header
  */
-       case PPP_VJC_UNCOMP:
-               if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
-                       if (slhc_remember (ppp->slcomp,
-                                          data, count) <= 0) {
-                               ppp->p.ppp_ierrors++;
-                               PRINTKN (1, (KERN_NOTICE
-                                         "ppp: error in VJ memorizing\n"));
-                               return 1;
+failure:
+               clear_bit (0, &ppp->ubuf->locked);
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_INFO
+                               "ppp_us_queue: ran out of buffer space.\n");
+       }
+/*
+ * Discard the frame. There are no takers for this protocol.
+ */
+       if (ppp->flags & SC_DEBUG)
+               printk (KERN_WARNING
+                       "ppp: dropping packet on the floor.\n");
+       slhc_toss (ppp->slcomp);
+       return 0;
+}
+
+/*
+ * Handle a CCP packet.
+ *
+ * The CCP packet is passed along to the pppd process just like any
+ * other PPP frame. The difference is that some processing needs to be
+ * 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);
+
+       if (slen <= len) {
+               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);
                        }
-               }
-               proto = PPP_IP;
-               break;
+                       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;
 /*
- * The frame is not a valid IP frame. Ignore it.
+ * we're agreeing to send compressed packets.
  */
-       default:
-               return 0;
-       }
+                       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;
+                               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);
+                       }
+                       break;
 /*
- * If debugging net packets then print the information. Process the IP
- * frames first.
+ * The protocol sequence is complete at this end
  */
-       if (ppp_debug_netpackets && proto == PPP_IP) {
-               struct iphdr *iph = (struct iphdr *) data;
-               PRINTK ((KERN_INFO
-                       "%s <--   src %lx dst %lx len %d\n",
-                       ppp->dev->name,
-                       iph->saddr,
-                       iph->daddr,
-                       count));
+               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;
+                       }
+
+                       if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) {
+                               (*ppp->sc_rcomp->decomp_reset)
+                                       (ppp->sc_rc_state);
+                               ppp->flags &= ~SC_DC_ERROR;
+                       }
+                       break;
+               }
        }
+}
+
+static int
+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 */
+
 /*
- * Generate a skb buffer for the new frame.
+ * Handle a LQR packet.
+ *
+ * The LQR packet is passed along to the pppd process just like any
+ * other PPP frame. The difference is that some processing needs to be
+ * performed to append the current data to the end of the frame.
  */
-       skb = alloc_skb (count, GFP_ATOMIC);
-       if (skb == NULL) {
-               PRINTK ((KERN_ERR
-                        "ppp_do_ip: packet dropped on %s (no memory)!\n",
-                        ppp->dev->name));
+
+static int
+rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len)
+{
+       register u_char *p;
+
+       if (len > 8) {
+               if (len < 48)
+                       memset (&data [len], '\0', 48 - len);
+/*
+ * Fill in the fields from the driver data
+ */
+               p = &data [48];
+               p = store_long (p, ++ppp->stats.ppp_ilqrs);
+               p = store_long (p, ppp->stats.ppp_ipackets);
+               p = store_long (p, ppp->stats.ppp_discards);
+               p = store_long (p, ppp->stats.ppp_ierrors);
+               p = store_long (p, ppp->stats.ppp_ioctects + len);
+
+               len = 68;
        }
 /*
- * Move the received data from the input buffer to the skb buffer.
+ * Pass the frame to the pppd daemon.
  */
-       else {
+       return rcv_proto_unknown (ppp, proto, data, len);
+}
 
-               skb->len = count;       /* Store the length */
-               skb->dev = ppp->dev;    /* We are the device */
-               memcpy ((u_char *) skb_data(skb), data, count); /* move data */
+/* 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)
+{
+       u_short         proto;
+       int             count = len;
+       ppp_proto_type  *proto_ptr;
 /*
- * Tag the frame and kick it to the proper receive routine
+ * Ignore empty frames
+ */
+       if (count <= 0)
+               return;
+/*
+ * Count the frame and print it
+ */
+       ++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.
  */
-               skb->free = 1;
-               netif_rx (skb); /* Receive the buffer */
+       if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
+               data  += 2;
+               count -= 2;
        }
-       return 1;
+/*
+ * 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.
+ */
+       proto_ptr = proto_list;
+       while (proto_ptr->proto != 0 && proto_ptr->proto != proto)
+               ++proto_ptr;
+/*
+ * Update the appropriate statistic counter.
+ */
+       if ((*proto_ptr->func) (ppp, proto, data, count))
+               ppp->stats.ppp_ioctects += len;
+       else
+               ++ppp->stats.ppp_discards;
 }
 
-/* stuff packet at BUF, length LEN, into the us_rbuff buffer
-   prepend PROTO information */
+/* on entry, a received frame is in ppp->rbuf.bufr
+   check it and dispose as appropriate */
 
 static int
-ppp_us_queue (struct ppp *ppp, unsigned short proto, u_char * data, int len)
+ppp_doframe (struct ppp *ppp)
 {
-       int totlen;
-       register int current_idx;
+       u_char  *data = buf_base (ppp->rbuf);
+       int     count = ppp->rbuf->count;
+#ifdef PPP_COMPRESS
+       int     proto;
+       int     new_count;
+       u_char *new_data;
+#endif
 /*
- * The total length includes the protocol data.
- * Lock the user information buffer.
+ * If there is a pending error from the receiver then log it and discard
+ * the damaged frame.
  */
-       if (set_bit (0, &ppp->ubuf->locked)) {
-               PRINTKN (1, (KERN_NOTICE "ppp_us_queue: can't get lock\n"));
+       if (ppp->toss) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_WARNING
+                               "ppp_toss: tossing frame, reason = %d\n",
+                               ppp->toss);
+               ppp->stats.ppp_ierrors++;
                return 0;
        }
-       current_idx = ppp->ubuf->head;
-
-#define PUTC(c)                                                \
-{                                                      \
-    buf_base (ppp->ubuf) [current_idx++] = (u_char) (c);\
-    current_idx &= ppp->ubuf->size;                    \
-    if (current_idx == ppp->ubuf->tail)        {               \
-           goto failure;                               \
-    }                                                  \
-}
+/*
+ * An empty frame is ignored. This occurs if the FLAG sequence precedes and
+ * follows each frame.
+ */
+       if (count == 0)
+               return 1;
+/*
+ * Generate an error if the frame is too small.
+ */
+       if (count < PPP_HARD_HDR_LEN) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_WARNING
+                               "ppp: got runt ppp frame, %d chars\n", count);
+               slhc_toss (ppp->slcomp);
+               ppp->stats.ppp_ierrors++;
+               return 1;
+       }
+/*
+ * Verify the CRC of the frame and discard the CRC characters from the
+ * end of the buffer.
+ */
+       if (ppp->rbuf->fcs != PPP_GOODFCS) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_WARNING
+                               "ppp: frame with bad fcs, excess = %x\n",
+                               ppp->rbuf->fcs ^ PPP_GOODFCS);
+               ppp->stats.ppp_ierrors++;
+               return 0;
+       }
+       count -= 2;             /* ignore the fcs characters */
 
+#ifdef PPP_COMPRESS
+       proto  = PPP_PROTOCOL (data);
 /*
- * Insert the buffer length (not counted), the protocol, and the data
+ * Process the active decompressor.
+ */
+       if ((ppp->sc_rc_state != (void *) 0) &&
+           ((ppp->flags & SC_DECOMP_RUN) == 0)) {
+/*
+ * 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)
+                                       printk (KERN_ERR
+                                               "ppp_doframe: no memory\n");
+                               slhc_toss (ppp->slcomp);
+                               (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
+                                                         data,
+                                                         count);
+                               return 1;
+                       }
+/*
+ * Decompress the frame
  */
-       totlen = len + 2;
-       PUTC (totlen >> 8);
-       PUTC (totlen);
+                       new_count = bsd_decompress (ppp->sc_rc_state,
+                                                   data,
+                                                   count,
+                                                   new_data,
+                                                   ppp->mru + 4);
 
-       PUTC (proto >> 8);
-       PUTC (proto);
+                       switch (new_count) {
+                       default:
+                               ppp_doframe_lower (ppp, new_data, new_count);
+                               kfree (new_data);
+                               return 1;
 
-       while (len-- > 0) {
-               PUTC (*data++);
-       }
-#undef PUTC
+                       case DECOMP_OK:
+                               break;
+
+                       case DECOMP_ERROR:
+                               ppp->flags |= SC_DC_ERROR;
+                               break;
+
+                       case DECOMP_FATALERROR:
+                               ppp->flags |= SC_DC_FERROR;
+                               break;
+                       }
 /*
- * The frame is complete. Update the head pointer and wakeup the pppd
- * process.
+ * Log the error condition and discard the frame.
  */
-       ppp->ubuf->head = current_idx;
-
-       clear_bit (0, &ppp->ubuf->locked);       /* Unlock the buffer header */
-       wake_up_interruptible (&ppp->read_wait); /* select() processing */
-       if (ppp->tty->fasync != NULL) {
-               kill_fasync (ppp->tty->fasync, SIGIO);  /* SIGIO processing */
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_ERR
+                                       "ppp_proto_comp: "
+                                       "decompress err %d\n", new_count);
+                       kfree (new_data);
+                       slhc_toss (ppp->slcomp);
+                       return 1;
+               }
+/*
+ * The frame is not special. Pass it through the decompressor without
+ * actually decompressing the data
+ */
+               (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
+                                         data,
+                                         count);
        }
-
-       PRINTKN (3, (KERN_INFO "ppp: successfully queued %d bytes\n", totlen));
-       return 1;
+#endif
 /*
- * The buffer is full. Unlock the header and return the failure condition.
+ * Process the uncompressed frame.
  */
-      failure:
-       clear_bit (0, &ppp->ubuf->locked);
-       PRINTKN (1, (KERN_NOTICE "ppp_us_queue: ran out of buffer space.\n"));
-       return 0;
+       ppp_doframe_lower (ppp, data, count);
+       return 1;
 }
 
 /*************************************************************
@@ -1281,7 +1752,7 @@ static int
 ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
              unsigned int nr)
 {
-       struct ppp *ppp = (struct ppp *) tty->disc_data;
+       struct ppp *ppp = tty2ppp (tty);
        u_char c;
        int len, indx;
 
@@ -1295,38 +1766,41 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
  * Validate the pointer to the PPP structure
  */
        if (!ppp || ppp->magic != PPP_MAGIC) {
-               PRINTKN (1, (KERN_ERR
-                            "ppp_tty_read: cannnot find ppp channel\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                               "ppp_tty_read: cannot find ppp channel\n");
                return -EIO;
        }
        CHECK_PPP (-ENXIO);
 
-       PRINTKN (4, (KERN_DEBUG "ppp_tty_read: called %x num %u\n",
-                    (unsigned int) buf,
-                    nr));
+       if (ppp->flags & SC_DEBUG)
+               printk (KERN_DEBUG
+                       "ppp_tty_read: called %x num %u\n",
+                       (unsigned int) buf,
+                       nr);
 /*
  * Acquire the read lock.
  */
        for (;;) {
                if (set_bit (0, &ppp->ubuf->locked) != 0) {
-                       PRINTKN (3, (KERN_DEBUG
-                                    "ppp_tty_read: sleeping(ubuf)\n"));
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_DEBUG
+                                    "ppp_tty_read: sleeping(ubuf)\n");
 
                        current->timeout = 0;
                        current->state = TASK_INTERRUPTIBLE;
                        schedule ();
 
-                       if (current->signal & ~current->blocked) {
+                       if (current->signal & ~current->blocked)
                                return -EINTR;
-                       }
                        continue;
                }
 /*
  * Fetch the length of the buffer from the first two bytes.
  */
-               if (ppp->ubuf->head == ppp->ubuf->tail) {
+               if (ppp->ubuf->head == ppp->ubuf->tail)
                        len = 0;
-               else {
+               else {
                        GETC (c);
                        len = c << 8;
                        GETC (c);
@@ -1339,37 +1813,44 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
                        /* no data */
                        clear_bit (0, &ppp->ubuf->locked);
                        if (file->f_flags & O_NONBLOCK) {
-                               PRINTKN (4, (KERN_DEBUG
-                                 "ppp_tty_read: no data (EWOULDBLOCK)\n"));
+                               if (ppp->flags & SC_DEBUG)
+                                       printk (KERN_DEBUG
+                                               "ppp_tty_read: no data "
+                                               "(EWOULDBLOCK)\n");
                                return -EWOULDBLOCK;
                        }
                        current->timeout = 0;
-                       PRINTKN (3, (KERN_DEBUG
-                                    "ppp_tty_read: sleeping(read_wait)\n"));
+
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_DEBUG
+                                       "ppp_tty_read: sleeping(read_wait)\n");
+
                        interruptible_sleep_on (&ppp->read_wait);
-                       if (current->signal & ~current->blocked) {
+                       if (current->signal & ~current->blocked)
                                return -EINTR;
-                       }
                        continue;
                }
 /*
  * Reset the time of the last read operation.
  */
                ppp->ddinfo.nip_rjiffies = jiffies;
-               PRINTKN (4, (KERN_DEBUG "ppp_tty_read: len = %d\n", len));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len);
 /*
  * Ensure that the frame will fit within the caller's buffer. If not, then
  * discard the frame from the input buffer and return an error to the caller.
  */
                if (len + 2 > nr) {
                        /* Can't copy it, update us_rbuff_head */
-                       PRINTKN (1, (KERN_DEBUG
-                          "ppp: read of %u bytes too small for %d frame\n",
-                                    nr, len + 2));
+
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_DEBUG
+                               "ppp: read of %u bytes too small for %d "
+                               "frame\n", nr, len + 2);
                        ppp->ubuf->tail += len;
                        ppp->ubuf->tail &= ppp->ubuf->size;
                        clear_bit (0, &ppp->ubuf->locked);
-                       ppp->p.ppp_ierrors++;
+                       ppp->stats.ppp_ierrors++;
                        return -EOVERFLOW;
                }
 /*
@@ -1378,6 +1859,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
  */
                put_fs_byte (PPP_ALLSTATIONS, buf++);
                put_fs_byte (PPP_UI,          buf++);
+
                indx = len;
 /*
  * Copy the received data from the buffer to the caller's area.
@@ -1391,8 +1873,9 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
  */
                clear_bit (0, &ppp->ubuf->locked);
                len += 2; /* Account for ADDRESS and CONTROL bytes */
-               PRINTKN (3,
-               (KERN_DEBUG "ppp_tty_read: passing %d bytes up\n", len));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_DEBUG
+                               "ppp_tty_read: passing %d bytes up\n", len);
                return len;
        }
 #undef GETC
@@ -1409,10 +1892,11 @@ ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
 /*
  * The buffer should not be full.
  */
-       if ((buf->count < 0) || (buf->count > 3000)) {
-               PRINTK ((KERN_DEBUG "ppp_stuff_char: %x %d\n",
-                        (unsigned int) buf->count,
-                        (unsigned int) buf->count))
+       if (ppp->flags & SC_DEBUG) {
+               if ((buf->count < 0) || (buf->count > 3000))
+                       printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
+                               (unsigned int) buf->count,
+                               (unsigned int) buf->count);
        }
 /*
  * Update the FCS and if the character needs to be escaped, do it.
@@ -1428,119 +1912,355 @@ ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
        ins_char (buf, chr);
 }
 
+/*
+ * Procedure to encode the data with the proper escapement and send the
+ * data to the remote system.
+ */
+
+static void
+ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
+                   u_char *data, int count, int non_ip)
+{
+       unsigned short int write_fcs;
+/*
+ * Insert the leading FLAG character
+ */
+       buf->count = 0;
+
+#ifdef OPTIMIZE_FLAG_TIME
+       if (non_ip)
+               ins_char (buf, PPP_FLAG);
+       else {
+               if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
+                       ins_char (buf, PPP_FLAG);
+       }
+       ppp->last_xmit = jiffies;
+#else
+       ins_char (buf, PPP_FLAG);
+#endif
+
+       buf->fcs = PPP_INITFCS;
+/*
+ * Insert the data
+ */
+       while (count-- > 0)
+               ppp_stuff_char (ppp, buf, *data++);
+/*
+ * Add the trailing CRC and the final flag character
+ */
+       write_fcs = buf->fcs ^ 0xFFFF;
+       ppp_stuff_char (ppp, buf, write_fcs);
+       ppp_stuff_char (ppp, buf, write_fcs >> 8);
+
+       if (ppp->flags & SC_DEBUG)
+               printk (KERN_DEBUG "ppp_dev_xmit_lower: fcs is %hx\n",
+                       write_fcs);
+/*
+ * Add the trailing flag character
+ */
+       ins_char (buf, PPP_FLAG);
+/*
+ * Print the buffer
+ */
+       if (ppp->flags & SC_LOG_FLUSH)
+               ppp_print_buffer ("ppp flush", buf_base (buf),
+                                 buf->count);
+       else {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_DEBUG
+                               "ppp_dev_xmit: writing %d chars\n",
+                               buf->count);
+       }
+/*
+ * Send the block to the tty driver.
+ */
+       ppp->stats.ppp_obytes += buf->count;
+       ppp_kick_tty (ppp, buf);
+}
+
+/*
+ * Send an frame to the remote with the proper bsd compression.
+ *
+ * Return 0 if frame was queued for transmission.
+ *        1 if frame must be re-queued for later driver support.
+ */
+
+int
+ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
+                   u_char *data, int count)
+{
+       int     address, control;
+       int     proto;
+       u_char *new_data;
+       int     new_count;
+/*
+ * Print the buffer
+ */
+       if (ppp->flags & SC_LOG_OUTPKT)
+               ppp_print_buffer ("write frame", data, count);
+/*
+ * Determine if the frame may be compressed. Attempt to compress the
+ * frame if possible.
+ */
+       address = PPP_ADDRESS  (data);
+       control = PPP_CONTROL  (data);
+       proto   = PPP_PROTOCOL (data);
+
+#ifdef PPP_COMPRESS  
+       if ((ppp->flags & SC_COMP_RUN != 0)     &&
+           (ppp->sc_xc_state != (void *) 0)    &&
+           (address == PPP_ALLSTATIONS)        &&
+           (control == PPP_UI)                 &&
+           (proto != PPP_LCP)                  &&
+           (proto != PPP_CCP)) {
+               new_data = kmalloc (count, GFP_ATOMIC);
+               if (new_data == NULL) {
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_ERR
+                                       "ppp_dev_xmit_frame: no memory\n");
+                       return 1;
+               }
+
+               new_count = bsd_compress (ppp->sc_xc_state,
+                                         data,
+                                         new_data,
+                                         count,
+                                         count);
+
+               if (new_count > 0) {
+                       ++ppp->stats.ppp_opackets;
+                       ppp->stats.ppp_ooctects += count;
+
+                       ppp_dev_xmit_lower (ppp, buf, new_data,
+                                           new_count, 0);
+                       kfree (new_data);
+                       return 0;
+               }
+/*
+ * The frame could not be compressed.
+ */
+               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
+ */
+       ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00));
+       return 0;
+}
+
+/*
+ * Revise the tty frame for specific protocols.
+ */
+
+static int
+send_revise_frame (register struct ppp *ppp, u_char *data, int len)
+{
+       u_char *p;
+
+       switch (PPP_PROTOCOL (data)) {
+/*
+ * Update the LQR frame with the current MIB information. This saves having
+ * the daemon read old MIB data from the driver.
+ */
+       case PPP_LQR:
+               len = 48;                       /* total size of this frame */
+               p   = (u_char *) &data [40];    /* Point to last two items. */
+               p   = store_long (p, ppp->stats.ppp_opackets + 1);
+               p   = store_long (p, ppp->stats.ppp_ooctects + len);
+               break;
+/*
+ * Outbound compression frames
+ */
+#ifdef PPP_COMPRESS
+       case PPP_COMP:
+               ppp_proto_ccp (ppp, data, len, 0);
+               break;
+#endif
+
+/*
+ * All other frame types
+ */
+       default:
+               break;
+       }
+
+       return len;
+}
+
 /*
  * write a frame with NR chars from BUF to TTY
  * we have to put the FCS field on ourselves
  */
 
 static int
-ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * buf,
+ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data,
               unsigned int count)
 {
-       struct ppp *ppp = (struct ppp *) tty->disc_data;
-       int indx;
-       unsigned short write_fcs;
+       struct ppp *ppp = tty2ppp (tty);
+       u_char *new_data;
 /*
  * Verify the pointer to the PPP data and that the tty is still in PPP mode.
  */
        if (!ppp || ppp->magic != PPP_MAGIC) {
-               PRINTKN (1,(KERN_ERR "ppp_tty_write: cannot find ppp unit\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                               "ppp_tty_write: cannot find ppp unit\n");
                return -EIO;
        }
+
        CHECK_PPP (-ENXIO);
-/*
- * Detech a change in the transfer size
- */
-       if (ppp->mtu != ppp->dev->mtu) {    /* Someone has been ifconfigging */
-               ppp_changedmtu (ppp,
-                               ppp->dev->mtu,
-                               ppp->mru);
-       }
 /*
  * Ensure that the caller does not wish to send too much.
  */
        if (count > PPP_MTU) {
-               PRINTKN (1, (KERN_WARNING
-               "ppp_tty_write: truncating user packet from %u to mtu %d\n",
-                            count, PPP_MTU));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_WARNING
+                               "ppp_tty_write: truncating user packet "
+                               "from %u to mtu %d\n", count, PPP_MTU);
                count = PPP_MTU;
        }
-/*
- * Print the buffer
- */
-       if (ppp_debug >= 3) {
-               ppp_print_buffer ("write frame", buf, count, USER_DS);
-       }
 /*
  * lock this PPP unit so we will be the only writer;
  * sleep if necessary
  */
        while (lock_buffer (ppp->tbuf) != 0) {
                current->timeout = 0;
-               PRINTKN (3, (KERN_DEBUG "ppp_tty_write: sleeping\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
                interruptible_sleep_on (&ppp->write_wait);
-               if (current->signal & ~current->blocked) {
+               if (current->signal & ~current->blocked)
                        return -EINTR;
-               }
        }
 /*
- * OK, locked. Add the leading FLAG character to the buffer.
+ * Allocate a buffer for the data and fetch it from the user space.
  */
-       PRINTKN (4, (KERN_DEBUG "ppp_tty_write: acquired write lock\n"));
-       ppp->tbuf->count = 0;
-
-#ifdef OPTIMIZE_FLAG_TIME
-       if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME) {
-               ins_char (ppp->tbuf, PPP_FLAG);
+       new_data = kmalloc (count, GFP_ATOMIC);
+       if (new_data == NULL) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                               "ppp_tty_write: no memory\n");
+               ppp->tbuf->locked = 0;
+               return 0;
        }
-       ppp->last_xmit = jiffies;
-#else
-       ins_char (ppp->tbuf, PPP_FLAG);
-#endif
+
+       memcpy_fromfs (new_data, data, count);
 /*
- * Add the data for the frame to the buffer.
+ * Change the LQR frame
  */
-       ppp->tbuf->fcs = PPP_INITFCS;
-       indx = count;
-       while (indx-- > 0) {
-               register char chr = get_fs_byte (buf++);
-               ppp_stuff_char (ppp, ppp->tbuf, chr);
-       }
+       count = send_revise_frame (ppp, new_data, count);
 /*
- * Add the trailing CRC and the final flag character
+ * Send the data
  */
-       write_fcs = ppp->tbuf->fcs ^ 0xFFFF;
-       ppp_stuff_char (ppp, ppp->tbuf, write_fcs);
-       ppp_stuff_char (ppp, ppp->tbuf, write_fcs >> 8);
+       ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count);
+       kfree (new_data);
+       return (int) count;
+}
 
-       PRINTKN (4, (KERN_DEBUG "ppp_tty_write: fcs is %hx\n", write_fcs));
 /*
- * Add the trailing FLAG character
+ * Process the BSD compression IOCTL event for the tty device.
  */
-       ins_char (ppp->tbuf, PPP_FLAG);
+
+#ifdef PPP_COMPRESS
+static int
+ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
+{
+       int error;
+       int nb;
+       u_char ccp_option[CCP_MAX_OPTION_LENGTH];
+       struct compressor **cp;
 /*
- * Update the time and print the data to the debug log.
+ * Validate the range of the ioctl
  */
-       ppp->ddinfo.nip_sjiffies = jiffies;
+       error = verify_area (VERIFY_READ, odp,
+                    (unsigned long) (&((struct ppp_option_data *) 0)->length)
+                    + sizeof (odp->length));
 
-       if (ppp_debug >= 6) {
-               ppp_print_buffer ("xmit buffer",
-                                 buf_base (ppp->tbuf),
-                                 ppp->tbuf->count,
-                                 KERNEL_DS);
-       } else {
-               PRINTKN (4, (KERN_DEBUG
-                   "ppp_tty_write: writing %d chars\n", ppp->tbuf->count));
+       if (error == 0) {
+               nb = (int) get_fs_long (odp->length);
+               if ((unsigned long) nb-1 >= (unsigned long) CCP_MAX_OPTION_LENGTH)
+                       nb = CCP_MAX_OPTION_LENGTH;
+
+               error = verify_area (VERIFY_READ, odp, nb);
        }
-/*
- * Start the transmitter and the request is complete.
- */
-       ppp->p.ppp_obytes += ppp->tbuf->count;
-       ++ppp->p.ppp_opackets;
 
-       ppp_kick_tty (ppp, ppp->tbuf);
-       return ((int) count);
+       if (error != 0)
+               return error;
+
+       memcpy_fromfs (ccp_option, odp, 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]) {
+               /*
+                * 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;
+                       }
+                       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);
+       return (-EINVAL);       /* no handler found */
 }
+#endif /* PPP_COMPRESS */
 
 /*
  * Process the IOCTL event for the tty device.
@@ -1550,24 +2270,24 @@ static int
 ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
               unsigned long param3)
 {
-       struct ppp *ppp = (struct ppp *) tty->disc_data;
+       struct ppp *ppp = tty2ppp (tty);
        register int temp_i = 0;
        int error;
 /*
  * Verify the status of the PPP device.
  */
        if (!ppp || ppp->magic != PPP_MAGIC) {
-               PRINTK ((KERN_ERR
-                        "ppp_tty_ioctl: can't find PPP block from tty!\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                       "ppp_tty_ioctl: can't find PPP block from tty!\n");
                return -EBADF;
        }
        CHECK_PPP (-ENXIO);
 /*
  * The user must have an euid of root to do these requests.
  */
-       if (!suser ()) {
+       if (!suser ())
                return -EPERM;
-       }
 /*
  * Set the MRU value
  */
@@ -1576,12 +2296,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) {
-                       PRINTKN (3, (KERN_INFO
-                                "ppp_tty_ioctl: set mru to %x\n", temp_i));
                        temp_i = (int) get_fs_long (param3);
-                       if (ppp->mru != temp_i) {
-                               ppp_changedmtu (ppp, ppp->dev->mtu, temp_i);
-                       }
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_INFO
+                                "ppp_tty_ioctl: set mru to %x\n", temp_i);
+
+                       if (ppp->mru != temp_i)
+                               ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i);
                }
                break;
 /*
@@ -1597,9 +2318,10 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                                  SC_RCV_ODDP | SC_RCV_EVNP;
 #endif
                        put_fs_long ((long) temp_i, param3);
-                       PRINTKN (3, (KERN_DEBUG
-                           "ppp_tty_ioctl: get flags: addr %lx flags %x\n",
-                                    param3, temp_i));
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_DEBUG
+                               "ppp_tty_ioctl: get flags: addr %lx flags "
+                               "%x\n", param3, temp_i);
                }
                break;
 /*
@@ -1609,12 +2331,30 @@ 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);
-                       ppp->flags ^= ((ppp->flags ^ temp_i) & SC_MASK);
-                       PRINTKN (3, (KERN_INFO
-                              "ppp_tty_ioctl: set flags to %x\n", temp_i));
+                       temp_i  = (int) get_fs_long (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);
+                       ppp->flags = temp_i;
                }
                break;
+/*
+ * 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
  */
@@ -1623,9 +2363,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                                     sizeof (temp_i));
                if (error == 0) {
                        put_fs_long (ppp->xmit_async_map[0], param3);
-                       PRINTKN (3, (KERN_INFO
-                       "ppp_tty_ioctl: get asyncmap: addr %lx asyncmap %lx\n",
-                                    param3, ppp->xmit_async_map[0]));
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_INFO
+                                       "ppp_tty_ioctl: get asyncmap: addr "
+                                       "%lx asyncmap %lx\n",
+                                       param3, ppp->xmit_async_map[0]);
                }
                break;
 /*
@@ -1636,9 +2378,10 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                                     sizeof (temp_i));
                if (error == 0) {
                        ppp->xmit_async_map[0] = get_fs_long (param3);
-                       PRINTKN (3, (KERN_INFO
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_INFO
                                     "ppp_tty_ioctl: set xmit asyncmap %lx\n",
-                                    ppp->xmit_async_map[0]));
+                                    ppp->xmit_async_map[0]);
                }
                break;
 /*
@@ -1649,9 +2392,10 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                                     sizeof (temp_i));
                if (error == 0) {
                        ppp->recv_async_map = get_fs_long (param3);
-                       PRINTKN (3, (KERN_INFO
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_INFO
                                     "ppp_tty_ioctl: set rcv asyncmap %lx\n",
-                                    ppp->recv_async_map));
+                                    ppp->recv_async_map);
                }
                break;
 /*
@@ -1661,10 +2405,11 @@ 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->dev->base_addr, param3);
-                       PRINTKN (3,
-                                (KERN_INFO "ppp_tty_ioctl: get unit: %d",
-                                 ppp->dev->base_addr));
+                       put_fs_long (ppp2dev (ppp)->base_addr, param3);
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_INFO
+                                       "ppp_tty_ioctl: get unit: %ld",
+                                       ppp2dev (ppp)->base_addr);
                }
                break;
 /*
@@ -1674,12 +2419,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) {
-                       ppp_debug = (int) get_fs_long (param3);
-                       ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8;
-                       ppp_debug &= 0xff;
-                       PRINTKN (1, (KERN_INFO
-                       "ppp_tty_ioctl: set debug level %d, netpacket %d\n",
-                                    ppp_debug, ppp_debug_netpackets));
+                       temp_i  = (int) (get_fs_long (param3) & 0x1F) << 16;
+                       temp_i |= (ppp->flags & ~0x1F0000);
+
+                       if ((ppp->flags | temp_i) & SC_DEBUG)
+                               printk (KERN_INFO
+                              "ppp_tty_ioctl: set flags to %x\n", temp_i);
+                       ppp->flags = temp_i;
                }
                break;
 /*
@@ -1689,14 +2435,14 @@ 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 ((long) (ppp_debug |
-                                           (ppp_debug_netpackets << 8)),
-                                    param3);
+                       temp_i = (ppp->flags >> 16) & 0x1F;
+                       put_fs_long ((long) temp_i, param3);
 
-                       PRINTKN (3, (KERN_INFO
-                                    "ppp_tty_ioctl: get debug level %d\n",
-                                 ppp_debug | (ppp_debug_netpackets << 8)));
-               }
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_INFO
+                                       "ppp_tty_ioctl: get debug level %d\n",
+                                       temp_i);
+               }
                break;
 /*
  * Get the times since the last send/receive frame operation
@@ -1716,8 +2462,9 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
 
                        memcpy_tofs ((void *) param3, &cur_ddinfo,
                                     sizeof (struct ppp_ddinfo));
-                       PRINTKN (3, (KERN_INFO
-                                "ppp_tty_ioctl: read demand dial info\n"));
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_INFO
+                               "ppp_tty_ioctl: read demand dial info\n");
                }
                break;
 /*
@@ -1731,9 +2478,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                        memcpy_tofs ((void *) param3,
                                     ppp->xmit_async_map,
                                     sizeof (ppp->xmit_async_map));
-                       PRINTKN (3, (KERN_INFO
-                                "ppp_tty_ioctl: get xasyncmap: addr %lx\n",
-                                    param3));
+
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_INFO
+                               "ppp_tty_ioctl: get xasyncmap: addr %lx\n",
+                               param3);
                }
                break;
 /*
@@ -1747,19 +2496,21 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
 
                        memcpy_fromfs (temp_tbl, (void *) param3,
                                       sizeof (ppp->xmit_async_map));
-                       temp_tbl[1]  = 0x00000000;
+                       temp_tbl[1]  =  0x00000000;
                        temp_tbl[2] &= ~0x40000000;
-                       temp_tbl[3] |= 0x60000000;
+                       temp_tbl[3] |=  0x60000000;
 
                        if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
                            (temp_tbl[4] & temp_tbl[5]) != 0 ||
-                           (temp_tbl[6] & temp_tbl[7]) != 0) {
+                           (temp_tbl[6] & temp_tbl[7]) != 0)
                                error = -EINVAL;
-                       else {
+                       else {
                                memcpy (ppp->xmit_async_map, temp_tbl,
                                        sizeof (ppp->xmit_async_map));
-                               PRINTKN (3, (KERN_INFO
-                                        "ppp_tty_ioctl: set xasyncmap\n"));
+
+                               if (ppp->flags & SC_DEBUG)
+                                       printk (KERN_INFO
+                                       "ppp_tty_ioctl: set xasyncmap\n");
                        }
                }
                break;
@@ -1771,17 +2522,18 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
                                     sizeof (temp_i));
                if (error == 0) {
                        temp_i = (int) get_fs_long (param3) + 1;
-                       PRINTKN (3, (KERN_INFO
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_INFO
                                     "ppp_tty_ioctl: set maxcid to %d\n",
-                                    temp_i));
-                       if (ppp->slcomp != NULL) {
+                                    temp_i);
+                       if (ppp->slcomp != NULL)
                                slhc_free (ppp->slcomp);
-                       }
-                       ppp->slcomp = slhc_init (temp_i, temp_i);
+                       ppp->slcomp = slhc_init (16, temp_i);
 
                        if (ppp->slcomp == NULL) {
-                               PRINTKN (1, (KERN_ERR
-                               "ppp: no space for compression buffers!\n"));
+                               if (ppp->flags & SC_DEBUG)
+                                       printk (KERN_ERR
+                                       "ppp: no space for compression buffers!\n");
                                ppp_release (ppp);
                                error = -ENOMEM;
                        }
@@ -1798,10 +2550,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
  *  All other ioctl() events will come here.
  */
        default:
-               PRINTKN (1, (KERN_ERR
-                            "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n",
-                            param2,
-                            param3));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                               "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n",
+                               param2,
+                               param3);
 
                error = -ENOIOCTLCMD;
                break;
@@ -1819,14 +2572,15 @@ static int
 ppp_tty_select (struct tty_struct *tty, struct inode *inode,
                struct file *filp, int sel_type, select_table * wait)
 {
-       struct ppp *ppp = (struct ppp *) tty->disc_data;
+       struct ppp *ppp = tty2ppp (tty);
        int result = 1;
 /*
  * Verify the status of the PPP device.
  */
        if (!ppp || ppp->magic != PPP_MAGIC) {
-               PRINTK ((KERN_ERR
-                      "ppp_tty_select: can't find PPP block from tty!\n"));
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                      "ppp_tty_select: can't find PPP block from tty!\n");
                return -EBADF;
        }
        CHECK_PPP (0);
@@ -1849,13 +2603,13 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode,
  */
        case SEL_EX:
                /* Is this a pty link and the remote disconnected? */
-               if (tty->flags & (1 << TTY_SLAVE_CLOSED)) {
+               if (tty->flags & (1 << TTY_SLAVE_CLOSED))
                        break;
-               }
+
                /* Is this a local link and the modem disconnected? */
-               if (tty_hung_up_p (filp)) {
+               if (tty_hung_up_p (filp))
                        break;
-               }
+
                select_wait (&ppp->read_wait, wait);
                result = 0;
                break;
@@ -1869,7 +2623,6 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode,
                }
                break;
        }
-
        return result;
 }
 
@@ -1888,20 +2641,23 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode,
 static int
 ppp_dev_open (struct device *dev)
 {
-       struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+       struct ppp *ppp = dev2ppp (dev);
 
        /* reset POINTOPOINT every time, since dev_close zaps it! */
        dev->flags |= IFF_POINTOPOINT;
 
-       if (ppp->tty == NULL) {
-               PRINTKN (1,
-               (KERN_ERR "ppp: %s not connected to a TTY! can't go open!\n",
-                dev->name));
+       if (ppp2tty (ppp) == NULL) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                       "ppp: %s not connected to a TTY! can't go open!\n",
+                       dev->name);
                return -ENXIO;
        }
 
-       PRINTKN (2, (KERN_INFO "ppp: channel %s going up for IP packets!\n",
-                    dev->name));
+       if (ppp->flags & SC_DEBUG)
+               printk (KERN_INFO
+                       "ppp: channel %s going up for IP packets!\n",
+                       dev->name);
 
        CHECK_PPP (-ENXIO);
        return 0;
@@ -1914,20 +2670,23 @@ ppp_dev_open (struct device *dev)
 static int
 ppp_dev_close (struct device *dev)
 {
-       struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+       struct ppp *ppp = dev2ppp (dev);
 
-       if (ppp->tty == NULL) {
-               PRINTKN (1,
-               (KERN_ERR "ppp: %s not connected to a TTY! can't go down!\n",
-                dev->name));
+       if (ppp2tty (ppp) == NULL) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                       "ppp: %s not connected to a TTY! can't go down!\n",
+                       dev->name);
                return -ENXIO;
        }
 /*
  * We don't do anything about the device going down. It is not important
  * for us.
  */
-       PRINTKN (2, (KERN_INFO "ppp: channel %s going down for IP packets!\n",
-                    dev->name));
+       if (ppp->flags & SC_DEBUG)
+               printk (KERN_INFO
+                       "ppp: channel %s going down for IP packets!\n",
+                       dev->name);
        CHECK_PPP (-ENXIO);
        return 0;
 }
@@ -1979,7 +2738,7 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr)
  */
        if (error == 0) {
                memset (&temp, 0, sizeof(temp));
-               memcpy (&temp.p, &ppp->p, sizeof (struct pppstat));
+               memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
 /*
  * Header Compression statistics
  */
@@ -1994,36 +2753,10 @@ 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
+ * Frame data compression statistics
  */
-               memcpy_tofs (result, &temp, sizeof (temp));
-       }
-       return error;
-}
-
 #ifdef PPP_COMPRESS
-
-static int
-ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr)
-{
-       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));
-/*
- * Supply the information for the caller.  Get the frame data compression
- * statistics and move them out to the caller.
- */
-       if (error == 0) {
-               memset (&temp, 0, sizeof(temp));
-
                if (ppp->sc_xc_state != NULL)
                        (*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state,
                                                     &temp.c);
@@ -2031,6 +2764,7 @@ 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
@@ -2040,8 +2774,6 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr)
        return error;
 }
 
-#endif /* PPP_COMPRESS */
-
 /*
  * Callback from the network layer to process the sockioctl functions.
  */
@@ -2049,7 +2781,7 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr)
 static int
 ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
 {
-       struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+       struct ppp *ppp = dev2ppp (dev);
        int error;
 /*
  * Process the requests
@@ -2059,12 +2791,6 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
                error = ppp_dev_ioctl_stats (ppp, ifr);
                break;
 
-#ifdef PPP_COMPRESS
-       case SIOCGPPPCSTATS:
-               error = ppp_dev_ioctl_cstats (ppp, ifr);
-               break;
-#endif /* PPP_COMPRESS */
-
        case SIOCGPPPVER:
                error = ppp_dev_ioctl_version (ppp, ifr);
                break;
@@ -2077,206 +2803,330 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
 }
 
 /*
- * Send a frame to the remote.
+ * Send an IP frame to the remote with vj header compression.
+ *
+ * Return 0 if frame was queued for transmission.
+ *        1 if frame must be re-queued for later driver support.
  */
 
 int
-ppp_dev_xmit (sk_buff *skb, struct device *dev)
+ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data)
 {
-       struct tty_struct *tty;
-       struct ppp *ppp;
-       u_char *data;
-       unsigned short proto;
-       int len;
-       unsigned short write_fcs;
-/*
- * just a little sanity check.
- */
-       if (skb == NULL) {
-               PRINTKN (3, (KERN_WARNING "ppp_dev_xmit: null packet!\n"));
-               return 0;
-       }
+       int      proto = PPP_IP;
+       int      len;
+       struct ppp_hdr    *hdr;
+       struct tty_struct *tty = ppp2tty (ppp);
 /*
- * Fetch the poitners to the data
+ * Obtain the length from the IP header.
  */
-       ppp   = &ppp_ctrl[dev->base_addr];
-       tty   = ppp->tty;
-       data  = (u_char *) (&skb[1]);
-       len   = skb->len;
-       proto = PPP_IP;
-
-       PRINTKN (4, (KERN_DEBUG "ppp_dev_xmit [%s]: skb %lX busy %d\n",
-                    dev->name,
-                    (unsigned long int) skb, ppp->wbuf->locked));
-
-       CHECK_PPP (0);
+       len = ((struct iphdr *)data) -> tot_len;
+       len = ntohs (len);
 /*
  * Validate the tty interface
  */
-       do {
-               if (tty == NULL) {
-                       PRINTKN (1,
-                       (KERN_ERR "ppp_dev_xmit: %s not connected to a TTY!\n",
-                                 dev->name));
-                       break;
-               }
+       if (tty == NULL) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                               "ppp_dev_xmit: %s not connected to a TTY!\n",
+                               dev->name);
+               return 0;
+       }
 /*
  * Ensure that the PPP device is still up
  */
-               if (!(dev->flags & IFF_UP)) {
-                       PRINTKN (1, (KERN_WARNING
+       if (!(dev->flags & IFF_UP)) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_WARNING
                                "ppp_dev_xmit: packet sent on interface %s,"
                                " which is down for IP\n",
-                               dev->name));
-                       break;
-               }
+                               dev->name);
+               return 0;
+       }
 /*
  * Detect a change in the transfer size
  */
-               if (ppp->mtu != ppp->dev->mtu) {
-                       ppp_changedmtu (ppp,
-                                       ppp->dev->mtu,
-                                       ppp->mru);
-               }
-/*
- * Fetch the length from the IP header.
- */
-               if (len < sizeof (struct iphdr)) {
-                       PRINTKN (0, (KERN_ERR
-                           "ppp_dev_xmit: given runt packet, ignoring\n"));
-                       break;
-               }
-               len = ntohs (((struct iphdr *) skb_data(skb))->tot_len);
+       if (ppp->mtu != ppp2dev (ppp)->mtu) {
+               ppp_changedmtu (ppp,
+                               ppp2dev (ppp)->mtu,
+                               ppp->mru);
+       }
 /*
  * Acquire the lock on the transmission buffer. If the buffer was busy then
  * mark the device as busy and return "failure to send, try back later" error.
  */
-               if (lock_buffer (ppp->wbuf) != 0) {
-                       dev->tbusy = 1;
-                       return 1;
-               }
+       if (lock_buffer (ppp->wbuf) != 0) {
+               dev->tbusy = 1;
+               return 1;
+       }
+/*
+ * Print the frame being sent
+ */
+       if (ppp->flags & SC_LOG_OUTPKT)
+               ppp_print_buffer ("ppp outpkt", data, len);
 /*
  * At this point, the buffer will be transmitted. There is no other exit.
  *
  * Try to compress the header.
  */
-               if (ppp->flags & SC_COMP_TCP) {
-                       /* last 0 argument says don't compress connection ID */
-                       len = slhc_compress (ppp->slcomp, data, len,
-                                            buf_base (ppp->cbuf),
-                                            &data, 0);
+       if (ppp->flags & SC_COMP_TCP) {
+               len = slhc_compress (ppp->slcomp, data, len,
+                                    buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN,
+                                    &data,
+                                    !(ppp->flags & SC_NO_TCP_CCID));
 
-                       if (data[0] & SL_TYPE_COMPRESSED_TCP) {
-                               proto = PPP_VJC_COMP;
-                       } else {
-                               if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP) {
-                                       proto   = PPP_VJC_UNCOMP;
-                                       data[0] = (data[0] & 0x0f) | 0x40;
-                               }
-                       }
+               if (data[0] & SL_TYPE_COMPRESSED_TCP) {
+                       proto    = PPP_VJC_COMP;
+                       data[0] ^= SL_TYPE_COMPRESSED_TCP;
+               } else {
+                       if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
+                               proto = PPP_VJC_UNCOMP;
+                       data[0] = (data[0] & 0x0f) | 0x40;
                }
+       }
+/*
+ * Send the frame
+ */
+       len  += PPP_HARD_HDR_LEN;
+       hdr   = &((struct ppp_hdr *) data)[-1];
+
+       hdr->address     = PPP_ALLSTATIONS;
+       hdr->control     = PPP_UI;
+       hdr->protocol[0] = 0;
+       hdr->protocol[1] = proto;
+
+       return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len);
+}
 
-               if (ppp_debug_netpackets) {
-                       struct iphdr *iph = (struct iphdr *) skb_data(skb);
-                       PRINTK ((KERN_DEBUG "%s ==> proto %x len %d src %x "
-                                "dst %x proto %d\n",
-                       dev->name, (int) proto, (int) len, (int) iph->saddr,
-                                (int) iph->daddr, (int) iph->protocol))
-               }
 /*
- * Insert the leading FLAG character
+ * This is just an interum solution until the 1.3 kernel's networking is
+ * available. The 1.2 kernel has problems with device headers before the
+ * buffers.
+ *
+ * This routine should be deleted, and the ppp_dev_xmit_ip1 routine called
+ * by this name.
  */
-               ppp->wbuf->count = 0;
 
-#ifdef OPTIMIZE_FLAG_TIME
-               if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME) {
-                       ins_char (ppp->wbuf, PPP_FLAG);
-               }
-               ppp->last_xmit = jiffies;
-#else
-               ins_char (ppp->wbuf, PPP_FLAG);
-#endif
+int
+ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data)
+{
+       struct ppp_hdr    *hdr;
+       int     len;
+       int     answer;
+
+       len = ((struct iphdr *)data) -> tot_len;
+       len = ntohs (len);
+
+       hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr),
+                                         GFP_ATOMIC);
+
+       if (hdr == NULL)
+               answer = 1;
+       else {
+               memcpy (&hdr[1], data, len);
+               answer = ppp_dev_xmit_ip1 (dev, ppp, (u_char *) &hdr[1]);
+               kfree (hdr);
+       }
+
+       return answer;
+}
 
-               ppp->wbuf->fcs = PPP_INITFCS;
 /*
- * Insert the address and control data
+ * Send an IPX (or any other non-IP) frame to the remote.
+ *
+ * Return 0 if frame was queued for transmission.
+ *        1 if frame must be re-queued for later driver support.
  */
-               if (!(ppp->flags & SC_COMP_AC)) {
-                       ppp_stuff_char (ppp, ppp->wbuf, PPP_ALLSTATIONS);
-                       ppp_stuff_char (ppp, ppp->wbuf, PPP_UI);
-               }
+
+int
+ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp,
+                 u_char *data, int len, int proto)
+{
+       struct tty_struct *tty = ppp2tty (ppp);
+       struct ppp_hdr    *hdr;
 /*
- * Insert the protocol.
+ * Validate the tty interface
  */
-               if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xff00)) {
-                       ppp_stuff_char (ppp, ppp->wbuf, proto >> 8);
-               }
-               ppp_stuff_char (ppp, ppp->wbuf, proto);
+       if (tty == NULL) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                               "ppp_dev_xmit: %s not connected to a TTY!\n",
+                               dev->name);
+               return 0;
+       }
 /*
- * Insert the data
+ * Ensure that the PPP device is still up
  */
-               while (len-- > 0) {
-                       ppp_stuff_char (ppp, ppp->wbuf, *data++);
-               }
+       if (!(dev->flags & IFF_UP)) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_WARNING
+                               "ppp_dev_xmit: packet sent on interface %s,"
+                               " which is down\n",
+                               dev->name);
+               return 0;
+       }
 /*
- * Add the trailing CRC and the final flag character
+ * Detect a change in the transfer size
+ */
+       if (ppp->mtu != ppp2dev (ppp)->mtu) {
+               ppp_changedmtu (ppp,
+                               ppp2dev (ppp)->mtu,
+                               ppp->mru);
+       }
+/*
+ * Acquire the lock on the transmission buffer. If the buffer was busy then
+ * mark the device as busy and return "failure to send, try back later" error.
+ */
+       if (lock_buffer (ppp->wbuf) != 0) {
+               dev->tbusy = 1;
+               return 1;
+       }
+/*
+ * Print the frame being sent
  */
-               write_fcs = ppp->wbuf->fcs ^ 0xFFFF;
-               ppp_stuff_char (ppp, ppp->wbuf, write_fcs);
-               ppp_stuff_char (ppp, ppp->wbuf, write_fcs >> 8);
+       if (ppp->flags & SC_LOG_OUTPKT)
+               ppp_print_buffer ("ppp outpkt", data, len);
+/*
+ * Send the frame
+ */
+       len  += PPP_HARD_HDR_LEN;
+       hdr   = &((struct ppp_hdr *) data)[-1];
+
+       hdr->address     = PPP_ALLSTATIONS;
+       hdr->control     = PPP_UI;
+       hdr->protocol[0] = proto >> 8;
+       hdr->protocol[1] = proto;
+
+       return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len);
+}
 
-               PRINTKN (4,
-                     (KERN_DEBUG "ppp_dev_xmit: fcs is %hx\n", write_fcs));
 /*
- * Add the trailing flag character
+ * This is just an interum solution until the 1.3 kernel's networking is
+ * available. The 1.2 kernel has problems with device headers before the
+ * buffers.
+ *
+ * This routine should be deleted, and the ppp_dev_xmit_ipx1 routine called
+ * by this name.
+ */
+
+int
+ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
+                 u_char *data, int len, int proto)
+{
+       struct ppp_hdr    *hdr;
+       int     answer;
+
+       hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr),
+                                         GFP_ATOMIC);
+       if (hdr == NULL)
+               answer = 1;
+       else {
+               memcpy (&hdr[1], data, len);
+               answer = (dev, ppp, (u_char *) &hdr[1], len, proto);
+               kfree (hdr);
+       }
+
+       return answer;
+}
+
+/*
+ * Send a frame to the remote.
+ */
+
+int
+ppp_dev_xmit (sk_buff *skb, struct device *dev)
+{
+       int answer;
+       u_char *data;
+       struct ppp        *ppp = dev2ppp (dev);
+       struct tty_struct *tty = ppp2tty (ppp);
+/*
+ * just a little sanity check.
  */
-               ins_char (ppp->wbuf, PPP_FLAG);
+       if (skb == NULL) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_WARNING "ppp_dev_xmit: null packet!\n");
+               return 0;
+       }
 /*
- * Update the times for the transmission.
+ * Avoid timing problem should tty hangup while data is queued to be sent
  */
-               ppp->ddinfo.ip_sjiffies = jiffies;
+       if (!ppp->inuse) {
+               dev_kfree_skb (skb, FREE_WRITE);
+               dev_close (dev);
+               return 0;
+       }
 /*
- * Print the buffer
+ * Validate the tty linkage
  */
-               if (ppp_debug >= 6) {
-                       ppp_print_buffer ("xmit buffer", buf_base (ppp->wbuf),
-                                         ppp->wbuf->count, KERNEL_DS);
-               } else {
-                       PRINTKN (4, (KERN_DEBUG
-                                    "ppp_dev_xmit: writing %d chars\n",
-                                    ppp->wbuf->count));
-               }
+       if (ppp->flags & SC_DEBUG)
+               printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %X\n",
+                       dev->name, (int) skb);
 /*
- * Send the block to the tty driver.
+ * Validate the tty interface
  */
-               ppp->p.ppp_obytes += ppp->wbuf->count;
-               ++ppp->p.ppp_opackets;
-               ppp_kick_tty (ppp, ppp->wbuf);
+       if (tty == NULL) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_ERR
+                               "ppp_dev_xmit: %s not connected to a TTY!\n",
+                               dev->name);
+               dev_kfree_skb (skb, FREE_WRITE);
+               return 0;
        }
-       while (0);
 /*
- * This is the end of the transmission. Release the buffer.
+ * Fetch the pointer to the data
  */
-       dev_kfree_skb (skb, FREE_WRITE);
-       return 0;
+       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);
+               break;
+
+       case htons (ETH_P_IP):
+               answer = ppp_dev_xmit_ip (dev, ppp, data);
+               break;
+
+       default: /* All others have no support at this time. */
+               dev_kfree_skb (skb, FREE_WRITE);
+               return 0;
+       }
+#else
+       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)
+               dev_kfree_skb (skb, FREE_WRITE);
+       return answer;
 }
 
+/*
+ * Generate the statistic information for the /proc/net/dev listing.
+ */
+
 static struct enet_statistics *
 ppp_dev_stats (struct device *dev)
 {
-       struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+       struct ppp *ppp = dev2ppp (dev);
        static struct enet_statistics ppp_stats;
 
-       ppp_stats.rx_packets          = ppp->p.ppp_ipackets;
-       ppp_stats.rx_errors           = ppp->p.ppp_ierrors;
-       ppp_stats.rx_dropped          = ppp->p.ppp_ierrors;
+       ppp_stats.rx_packets          = ppp->stats.ppp_ipackets;
+       ppp_stats.rx_errors           = ppp->stats.ppp_ierrors;
+       ppp_stats.rx_dropped          = ppp->stats.ppp_ierrors;
        ppp_stats.rx_fifo_errors      = 0;
        ppp_stats.rx_length_errors    = 0;
        ppp_stats.rx_over_errors      = 0;
        ppp_stats.rx_crc_errors       = 0;
        ppp_stats.rx_frame_errors     = 0;
-       ppp_stats.tx_packets          = ppp->p.ppp_opackets;
-       ppp_stats.tx_errors           = ppp->p.ppp_oerrors;
+       ppp_stats.tx_packets          = ppp->stats.ppp_opackets;
+       ppp_stats.tx_errors           = ppp->stats.ppp_oerrors;
        ppp_stats.tx_dropped          = 0;
        ppp_stats.tx_fifo_errors      = 0;
        ppp_stats.collisions          = 0;
@@ -2285,7 +3135,8 @@ ppp_dev_stats (struct device *dev)
        ppp_stats.tx_window_errors    = 0;
        ppp_stats.tx_heartbeat_errors = 0;
 
-       PRINTKN (3, (KERN_INFO "ppp_dev_stats called"));
+       if (ppp->flags & SC_DEBUG)
+               printk (KERN_INFO "ppp_dev_stats called");
        return &ppp_stats;
 }
 
@@ -2319,7 +3170,8 @@ static int ppp_dev_getkey(int protocol, int subid, unsigned char *key)
 {
        switch (protocol)
        {
-       case ETH_P_IP:
+       case htons (ETH_P_IP):
+       case htons (ETH_P_IPX):
                return 0;
 
        default:
@@ -2362,17 +3214,79 @@ ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr,
  *    Miscellany called by various functions above.
  *************************************************************/
 
-/* allocate a PPP channel */
+/* allocate or create a PPP channel */
 static struct ppp *
 ppp_alloc (void)
 {
-       int i;
-       for (i = 0; i < PPP_NRUNIT; i++) {
-               if (!set_bit (0, &ppp_ctrl[i].inuse)) {
-                       return &ppp_ctrl[i];
+#if 1
+       int             if_num;
+       int             status;
+       ppp_ctrl_t      *ctl;
+       struct device   *dev;
+       struct ppp      *ppp;
+
+       /* try to find an free device */
+       ctl      = ppp_list;
+       if_num   = 0;
+  
+       while (ctl) {
+               ppp = ctl2ppp (ctl);
+               if (!set_bit(0, &ppp->inuse))
+                       return (ppp);
+               ctl = ctl->next;
+               if (++if_num == INT_MAX)
+                       return (NULL);
+       }
+/*
+ * There are no available items. Allocate a device from the system pool
+ */
+       ctl = (ppp_ctrl_t *) kmalloc (sizeof(ppp_ctrl_t), GFP_KERNEL);
+       if (ctl) {
+               (void) memset(ctl, 0, sizeof(ppp_ctrl_t));
+               ppp = ctl2ppp (ctl);
+               dev = ctl2dev (ctl);
+
+               /* initialize channel control data */
+               set_bit(0, &ppp->inuse);
+
+               ppp->line      = if_num;
+               ppp->tty       = NULL;
+               ppp->dev       = dev;
+    
+               dev->next      = NULL;
+               dev->init      = ppp_init_dev;
+               dev->name      = ctl->name;
+               dev->base_addr = (unsigned long) if_num;
+               dev->priv      = (void *) ppp;
+
+               sprintf (dev->name, "ppp%d", if_num);
+    
+               /* link in the new channel */
+               ctl->next      = ppp_list;
+               ppp_list       = ctl;
+
+/* register device so that we can be ifconfig'd */
+/* ppp_init_dev() will be called as a side-effect */
+
+               status = register_netdev (dev);
+               if (status == 0) {
+                       printk ("registered device %s\n", dev->name);
+                       return (ppp);
                }
+
+               printk (KERN_ERR
+                      "ppp_alloc - register_netdev(%s) = %d failure.\n",
+                       dev->name, status);
+               /* This one will forever be busy as it is not initialized */
        }
-       return NULL;
+       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
 }
 
 /*
@@ -2386,11 +3300,10 @@ ppp_print_hex (register u_char * out, u_char * in, int count)
        static char hex[] = "0123456789ABCDEF";
 
        while (count-- > 0) {
-               next_ch = (u_char) get_fs_byte (in);
+               next_ch = *in++;
                *out++ = hex[(next_ch >> 4) & 0x0F];
                *out++ = hex[next_ch & 0x0F];
                ++out;
-               ++in;
        }
 }
 
@@ -2400,46 +3313,127 @@ ppp_print_char (register u_char * out, u_char * in, int count)
        register u_char next_ch;
 
        while (count-- > 0) {
-               next_ch = (u_char) get_fs_byte (in);
+               next_ch = *in++;
 
-               if (next_ch < 0x20 || next_ch > 0x7e) {
+               if (next_ch < 0x20 || next_ch > 0x7e)
                        *out++ = '.';
-               else {
+               else {
                        *out++ = next_ch;
-                       if (next_ch == '%') { /* printk/syslogd has a bug !! */
+                       if (next_ch == '%')   /* printk/syslogd has a bug !! */
                                *out++ = '%';
-                       }
                }
-               ++in;
        }
        *out = '\0';
 }
 
 static void
-ppp_print_buffer (const u_char * name, u_char * buf, int count, int seg)
+ppp_print_buffer (const u_char * name, u_char * buf, int count)
 {
        u_char line[44];
-       int old_fs = get_fs ();
 
-       set_fs (seg);
+       if (name != (u_char *) NULL)
+               printk (KERN_DEBUG "ppp: %s, count = %d\n", name, count);
 
-       if (name != (u_char *) NULL) {
-               PRINTK ((KERN_DEBUG "ppp: %s, count = %d\n", name, count));
-       }
        while (count > 8) {
-               memset (line, ' ', sizeof (line));
+               memset (line, 32, 44);
                ppp_print_hex (line, buf, 8);
                ppp_print_char (&line[8 * 3], buf, 8);
-               PRINTK ((KERN_DEBUG "%s\n", line));
+               printk (KERN_DEBUG "%s\n", line);
                count -= 8;
                buf += 8;
        }
 
        if (count > 0) {
-               memset (line, ' ', sizeof (line));
+               memset (line, 32, 44);
                ppp_print_hex (line, buf, count);
                ppp_print_char (&line[8 * 3], buf, count);
-               PRINTK ((KERN_DEBUG "%s\n", line));
+               printk (KERN_DEBUG "%s\n", line);
+       }
+}
+
+/*************************************************************
+ * Module support routines
+ *************************************************************/
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+
+int
+init_module(void)
+{
+       int status;
+
+       /* register our line disciplines */
+       status = ppp_first_time();
+       if (status != 0) {
+               printk (KERN_INFO
+                      "PPP: ppp_init() failure %d\n", status);
+       }
+       return (status);
+}
+
+void
+cleanup_module(void)
+{
+       int status;
+       ppp_ctrl_t *ctl, *next_ctl;
+       struct device *dev;
+       struct ppp *ppp;
+       int busy_flag = MOD_IN_USE;
+/*
+ * 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;
+                       }
+
+                       dev = ctl2dev (ctl);
+                       if (dev->start || dev->flags & IFF_UP) {
+                               busy_flag = 1;
+                               break;
+                       }
+                       ctl = ctl->next;
+               }
+       }
+
+       if (busy_flag) {
+               printk (KERN_INFO
+                       "PPP: device busy, remove delayed\n");
+               return;
+       }
+/*
+ * Release the tty registration of the line dicipline so that no new entries
+ * may be created.
+ */
+       status = tty_register_ldisc (N_PPP, NULL);
+       if (status != 0)
+               printk (KERN_INFO
+                       "PPP: Unable to unregister ppp line discipline "
+                       "(err = %d)\n", status);
+       else
+               printk (KERN_INFO
+                       "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);
+               unregister_netdev (dev);
+/*
+ * Release the storage occupied by the control structures
+ */
+               next = ctl->next;
+               kfree (ctl);
        }
-       set_fs (old_fs);
 }
+#endif
index 32b228fe80a4bbed62f21a3de3a0065ada50b69e..2d550094632f45ca41ffef28464d98622e83fcb1 100644 (file)
@@ -1,6 +1,6 @@
 #
 # pppd makefile for Linux
-# $Id: Makefile.linux,v 1.6 1995/04/28 04:32:20 paulus Exp $
+# $Id: Makefile.linux,v 1.7 1995/06/12 11:37:02 paulus Exp $
 #
 
 BINDIR = /usr/etc
@@ -25,7 +25,7 @@ endif
 
 # CC = gcc
 # DEBUG_FLAGS = -DDEBUGALL
-COMPILE_FLAGS = -D_linux_=1 -DHAVE_PATHS_H -I..
+COMPILE_FLAGS = -D_linux_=1 -DHAVE_PATHS_H
 COPTS = -g # -O2
 VER = 0.2.8
 LIBS = -lbsd