Post by Paul Mackerra » Fri, 08 Feb 2002 13:00:08

I have written down the details of the interface between the PPP
generic code and the PPP channels, and the interface between the PPP
generic code and userland.  Here it is, as a patch to create

I hope this will help to encourage people to convert the other PPP
implementations in the kernel to use the generic PPP layer. :-)

Dave, assuming it looks OK to you, could you send it on to Linus and
Marcelo?  Thanks.


diff -urN /dev/null linux/Documentation/networking/ppp_generic.txt
--- /dev/null   Thu Jan 01 10:00:00 1970
+++ linux/Documentation/networking/ppp_generic.txt      Thu Feb 07 14:43:18 2002
@@ -0,0 +1,432 @@
+               PPP Generic Driver and Channel Interface
+               ----------------------------------------
+                           Paul Mackerras
+                             7 Feb 2002
+The generic PPP driver in linux-2.4 provides an implementation of the
+functionality which is of use in any PPP implementation, including:
+* the network interface unit (ppp0 etc.)
+* the interface to the networking code
+* PPP multilink: splitting datagrams between multiple links, and
+  ordering and combining received fragments
+* the interface to pppd, via a /dev/ppp character device
+* packet compression and decompression
+* TCP/IP header compression and decompression
+* detecting network traffic for demand dialling and for idle timeouts
+* simple packet filtering
+For sending and receiving PPP frames, the generic PPP driver calls on
+the services of PPP `channels'.  A PPP channel encapsulates a
+mechanism for transporting PPP frames from one machine to another.  A
+PPP channel implementation can be arbitrarily complex internally but
+has a very simple interface with the generic PPP code: it merely has
+to be able to send PPP frames, receive PPP frames, and optionally
+handle ioctl requests.  Currently there are PPP channel
+implementations for asynchronous serial ports, synchronous serial
+ports, and for PPP over ethernet.
+This architecture makes it possible to implement PPP multilink in a
+natural and straightforward way, by allowing more than one channel to
+be linked to each ppp network interface unit.  The generic layer is
+responsible for splitting datagrams on transmit and recombining them
+on receive.
+PPP channel API
+See include/linux/ppp_channel.h for the declaration of the types and
+functions used to communicate between the generic PPP layer and PPP
+Each channel has to provide two functions to the generic PPP layer,
+via the ppp_channel.ops pointer:
+* start_xmit() is called by the generic layer when it has a frame to
+  send.  The channel has the option of rejecting the frame for
+  flow-control reasons.  In this case, start_xmit() should return 0
+  and the channel should call the ppp_output_wakeup() function at a
+  later time when it can accept frames again, and the generic layer
+  will then attempt to retransmit the rejected frame(s).  If the frame
+  is accepted, the start_xmit() function should return 1.
+* ioctl() provides an interface which can be used by a user-space
+  program to control aspects of the channel's behaviour.  This
+  procedure will be called when a user-space program does an ioctl
+  system call on an instance of /dev/ppp which is bound to the
+  channel.  (Usually it would only be pppd which would do this.)
+The generic PPP layer provides seven functions to channels:
+* ppp_register_channel() is called when a channel has been created, to
+  notify the PPP generic layer of its presence.  For example, setting
+  a serial port to the PPPDISC line discipline causes the ppp_async
+  channel code to call this function.
+* ppp_unregister_channel() is called when a channel is to be
+  destroyed.  For example, the ppp_async channel code calls this when
+  a hangup is detected on the serial port.
+* ppp_output_wakeup() is called by a channel when it has previously
+  rejected a call to its start_xmit function, and can now accept more
+  packets.
+* ppp_input() is called by a channel when it has received a complete
+  PPP frame.
+* ppp_input_error() is called by a channel when it has detected that a
+  frame has been lost or dropped (for example, because of a FCS (frame
+  check sequence) error).
+* ppp_channel_index() returns the channel index assigned by the PPP
+  generic layer to this channel.  The channel should provide some way
+  (e.g. an ioctl) to transmit this back to user-space, as user-space
+  will need it to attach an instance of /dev/ppp to this channel.
+* ppp_unit_number() returns the unit number of the ppp network
+  interface to which this channel is connected, or -1 if the channel
+  is not connected.
+Connecting a channel to the ppp generic layer is initiated from the
+channel code, rather than from the generic layer.  The channel is
+expected to have some way for a user-level process to control it
+independently of the ppp generic layer.  For example, with the
+ppp_async channel, this is provided by the file descriptor to the
+serial port.
+Generally a user-level process will initialize the underlying
+communications medium and prepare it to do PPP.  For example, with an
+async tty, this can involve setting the tty speed and modes, issuing
+modem commands, and then going through some sort of dialog with the
+remote system to invoke PPP service there.  We refer to this process
+as `discovery'.  Then the user-level process tells the medium to
+become a PPP channel and register itself with the generic PPP layer.
+The channel then has to report the channel number assigned to it back
+to the user-level process.  From that point, the PPP negotiation code
+in the PPP daemon (pppd) can take over and perform the PPP
+negotiation, accessing the channel through the /dev/ppp interface.
+At the interface to the PPP generic layer, PPP frames are stored in
+skbuff structures and start with the two-byte PPP protocol number.
+The frame does *not* include the 0xff `address' byte or the 0x03
+`control' byte that are optionally used in async PPP.  Nor is there
+any escaping of control characters, nor are there any FCS or framing
+characters included.  That is all the responsibility of the channel
+code, if it is needed for the particular medium.  That is, the skbuffs
+presented to the start_xmit() function contain only the 2-byte
+protocol number and the data, and the skbuffs presented to ppp_input()
+must be in the same format.
+The channel must provide an instance of a ppp_channel struct to
+represent the channel.  The channel is free to use the `private' field
+however it wishes.  The channel should initialize the `mtu' and
+`hdrlen' fields before calling ppp_register_channel() and not change
+them until after ppp_unregister_channel() returns.  The `mtu' field
+represents the maximum size of the data part of the PPP frames, that
+is, it does not include the 2-byte protocol number.
+If the channel needs some headroom in the skbuffs presented to it for
+transmission (i.e., some space free in the skbuff data area before the
+start of the PPP frame), it should set the `hdrlen' field of the
+ppp_channel struct to the amount of headroom required.  The generic
+PPP layer will attempt to provide that much headroom but the channel
+should still check if there is sufficient headroom and copy the skbuff
+if there isn't.
+On the input side, channels should ideally provide at least 2 bytes of
+headroom in the skbuffs presented to ppp_input().  The generic PPP
+code does not require this but will be more efficient if this is done.
+Buffering and flow control
+The generic PPP layer has been designed to minimize the amount of data
+that it buffers in the transmit direction.  It maintains a queue of
+transmit packets for the PPP unit (network interface device) plus a
+queue of transmit packets for each attached channel.  Normally the
+transmit queue for the unit will contain at most one packet; the
+exceptions are when pppd sends packets by writing to /dev/ppp, and
+when the core networking code calls the generic layer's start_xmit()
+function with the queue stopped, i.e. when the generic layer has
+called netif_stop_queue(), which only happens on a transmit timeout.
+The start_xmit function always accepts and queues the packet which it
+is asked to transmit.
+Transmit packets are dequeued from the PPP unit transmit queue and
+then subjected to TCP/IP header compression and packet compression
+(Deflate or BSD-Compress compression), as appropriate.  After this
+point the packets can no longer be reordered, as the decompression
+algorithms rely on receiving compressed packets in the same order that
+they were generated.
+If multilink is not in use, this packet is then passed to the attached
+channel's start_xmit() function.  If the channel refuses to take
+the packet, the generic layer saves it for later transmission.  The
+generic layer will call the channel's start_xmit() function again
+when the channel calls  ppp_output_wakeup() or when the core
+networking code calls the generic layer's start_xmit() function
+again.  The generic layer contains no timeout and retransmission
+logic; it relies on the core networking code for that.
+If multilink is in use, the generic layer divides the packet into one
+or more fragments and puts a multilink header on each fragment.  It
+decides how many fragments to use based on the length of the packet
+and the number of channels which are potentially able to accept a
+fragment at the moment.  A channel is potentially able to accept a
+fragment if it doesn't have any fragments currently queued up for it
+to transmit.  The channel may still refuse a fragment; in this case
+the fragment is queued up for the channel to transmit later.  This
+scheme has the effect that more fragments are given to higher-
+bandwidth channels.  It also means that under light load, the generic
+layer will tend to fragment large packets across all the ...

read more »



Post by David S. Mille » Fri, 08 Feb 2002 13:50:09

   Date: Thu, 7 Feb 2002 14:50:58 +1100 (EST)

   Dave, assuming it looks OK to you, could you send it on to Linus and
   Marcelo?  Thanks.

How critical is this and the other PPP patches for 2.4.x?  Could it
wait for 2.4.19-pre1?  I don't want to pressure Marcelo for 2.4.18
final unless absolutely necessary.

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in

More majordomo info at
Please read the FAQ at



Post by Paul Mackerra » Fri, 08 Feb 2002 14:40:12

Quote:David S. Miller writes:
> How critical is this and the other PPP patches for 2.4.x?  Could it
> wait for 2.4.19-pre1?  I don't want to pressure Marcelo for 2.4.18
> final unless absolutely necessary.

Not critical at all.  I have forwarded Marcelo a patch which fixes one
of the problems in ppp_generic.c by changing all_ppp_lock into a
semaphore.  I agree that the rest of the fixes can wait for the
2.4.19-pre series.  The problems tend to show up mainly on SMP boxes
handling multiple PPP connections.  I posted the patch so that the
people who were having problems could try it and let me know if it
fixed their problems.

I would appreciate it though if you had time to look over the patch
and see if you think I have missed any potential races.

As for the documentation patch, it's not going to affect any code
behaviour, so it can go in whenever you and Marcelo think is
appropriate. :)

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in

More majordomo info at
Please read the FAQ at