Drivers, libraries, services, and tools providing Point-to-Point Protocol support on Fuchsia. PPP provides a direct link-layer (L2) over a serial connection. It supports IPv4 and IPv6 network layers.
PPP Server to open and close connections. Does not maintain any state about the connection. Exits after sending one command.
BUILD.gn defines the main build targets.
:ppp builds all drivers, services, and tools.
:tests builds all tests.
% fx run-test ppp-tests: Runs Serial PPP tests, and HDLC tests.
% fx run-test ppp-packet-tests: Runs PPP Packet tests.
% fx run-test ppp-protocol-tests: Runs PPP Protocol tests.
Host commands begin with
%. Client commands begin with
$. QEMU monitor commands begin with
% fx qemu -N -- -serial mon:stdio -serial pty.
kernel.serial=none to allow PPP access to serial port 0.
(qemu) info chardev.
serial1 (referred to as
$ run ppp-cli open -4 IP_ADDRESS -d /dev/class/ppp/000
% sudo /sbin/pppd nodetach debug noauth PTY
nodetach to make ending the connection easier.
debug to get a verbose log of the send and received packets.
noauth because the client does not yet support authentication.
pppd provides a network interface (
ppp0) and the negotiated IP addresses.
ppp#. To bring it up for use with the netstack, run
ifconfig ppp# add IP_ADDRESS/MASK followed by
ifconfig ppp# up.
Device protocol focuses on a simple
Rx interface. It relies on the caller to provide a protocol with each message.
Rx follow a hanging get pattern, blocking until the driver has sent or received the data. This allows natural backpressure and avoids signalling clients.
Enable controls whether the driver has exclusive access to the serial port.
GetStatus control the allowed network protocols for the current PPP connection.
The driver reads and writes PPP frames according to the HDLC-like framing in RFC-1662. It also muxes the different protocols between driver clients. The driver communicates with clients using the
The HDLC framing, and Frame Check Sequence calculation are in a library for reuse.
To read frames and respond to FIDL messages, the driver maintains two threads. One thread runs an async loop, and binds to each incoming client. It loops and reads FIDL messages, dispatching them to the driver. The other thread is the reader thread. It reads data from the serial port and responds to callbacks when packets are available.
The driver maintains a fixed-size queue and a callback for each protocol a client can request. When the driver receives an
Rx call, it registers a callback to reply for the specified protocol.
The reader loop checks if there are any registered callbacks it has packets for. If it has a packet and a callback, it pops the packet from its queue, replies, and deregisters the callback. Once the loop has finished trying each callback, it attempts to read one packet from the serial port. The loop will read bytes one-by-one, scanning for the end of frame byte. (The serial port is far too slow for this to cause a bottleneck.) It will read up to the max frame size, and will time out if reading the next byte takes too long. In either case, it discards the malformed packet. In case it read a full packet but had invalid format or frame check sequence, it discards the packet.
If the driver has a valid packet, it will inspect the packet protocol and push it into the correct queue. Each queue drops its oldest packets to maintain a fixed max size.
On a call to
Tx, the driver will block the reply until it has framed and written all data to the serial port.
The driver is thread-safe and can handle more than one in-flight FIDL message at the same time.
The packet library allows encoding PPP packet formats in the type system. It also provides convenient serialization of packets. It depends on the
packet crate and the
zerocopy crate, which manipulate buffers. The library provides a high level interface to specify packet structure.
The library supports serializing and parsing the configuration options for each protocol. Control protocols encode options as Type-Length-Value elements. You can add new LCP-like protocols by defining the options and any extra packet formats.
The protocol library is the heart of the PPP implementation. It contains a generic implementation of an LCP-like control protocol. It also specializes and extends this to support LCP, IPCP and IPv6CP. It manipulates packets based on events given to the control protocol state machine. The state machine uses the typestate pattern. This allows the compiler to verify correctness.
The protocol library allows extension without duplication of the core protocol logic. You can add a new control protocol by defining options and how to interact with them.
The library supports user-defined asynchronous methods for sending and receiving packets. It also supports configurable timeout logic.
The architecture of the state machine follows the one specified in RFC-1661. It combines the closed/ closing/down/stopped/stopping states into one closed state. Transitions handle the missing states. As a first implementation, some features of PPP are not implemented. Frame compression, authentication, non-default MRU, and link quality monitoring are not implemented. The architecture of the library supports adding these in the future if necessary.
The CLI is a thin wrapper around
Close. It parses the command line to build up a call. It then executes the call with the PPP server and exits when it receives a reply. It does not keep running while the connection is open.
The server is a long-lived process that manages one open PPP connection at a time. Changes to the server could allow more than one simultaneous PPP connections.
The server asynchronously processes commands, packets, and timeouts. The server flattens each client into a single stream of commands. (The server has no need to distinguish between clients, as the CLI exits after one command). When no connection is open, the server listens for commands from clients.
Open, the server takes options from the message. It begins giving timeout and packets events to the state machine. When a network protocol opens, it signals the driver. The server stays in a loop waiting on more commands, packets, or timeouts. On any command, the server closes the connection. The server resumes the command processing loop.