| # Point-to-Point Protocol |
| |
| 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. |
| |
| ## Definitions |
| - PPP: Point-to-Point Protocol. |
| - LCP: Link Control Protocol. |
| - IPCP: IPv4 Control Protocol |
| - IPV6CP: IPv6 Control Protocol. |
| |
| ## Source Layout |
| - Drivers |
| - Serial PPP: Reads and writes frames over a bound serial port. Also provides |
| muxing of PPP protocols. |
| - Libraries |
| - Common: Provides common protocol number definitions. |
| - HDLC: Provides frame check sequence calculation and HDLC-like framing |
| functions. |
| - PPP Packet: Provides serialization of packet types, including control |
| protocols and their options. |
| - PPP Protocol: Provides a generic implementation of the PPP control protocol |
| state machine. Also includes implementations of LCP, IPCP and IPV6CP. |
| - Services |
| - PPP Server: Configures and maintains one PPP connection. Provides an |
| interface for local applications to open and close PPP connections. |
| - Tools |
| - PPP CLI: Parses commands and forwards them to `PPP Server` to open and close |
| connections. Does not maintain any state about the connection. Exits after |
| sending one command. |
| |
| ## Build |
| The root `BUILD.gn` defines the main build targets. `:ppp` builds all drivers, |
| services, and tools. `:tests` builds all tests. |
| |
| ## Test |
| - `% fx test ppp-tests`: Runs Serial PPP tests, and HDLC tests. |
| - `% fx test ppp-packet-tests`: Runs PPP Packet tests. |
| - `% fx test ppp-protocol-tests`: Runs PPP Protocol tests. |
| |
| ## Example IPv4 Configuration with QEMU and PPPD on Linux |
| Host commands begin with `%`. Client commands begin with `$`. QEMU monitor |
| commands begin with `(qemu)`. |
| - Ensure you have built with PPP support (see above). |
| - `% fx qemu -N -- -serial mon:stdio -serial pty`. |
| - This tells QEMU to multiplex monitor and serial port 0 (kernel serial log) |
| on stdin/out. |
| - Provide `kernel.serial=none` to allow PPP access to serial port 0. |
| - Switch to monitor mode (default in QEMU is `C-a c`). |
| - `(qemu) info chardev`. |
| - Note the pty for `serial1` (referred to as `PTY` below). |
| - Switch back to console mode. |
| - `$ run ppp-cli open -4 IP_ADDRESS -d /dev/class/ppp/000` |
| - This tells the server to try to bring up IPv4 with some IP address |
| `IP_ADDRESS` on `serial1`. |
| - `% sudo /sbin/pppd nodetach debug noauth PTY` |
| - This brings up a PPP connection with IPv4 on the host with the given pty. |
| - Pass `nodetach` to make ending the connection easier. |
| - Pass `debug` to get a verbose log of the send and received packets. |
| - Pass `noauth` because the client does not yet support authentication. |
| - On success, `pppd` provides a network interface (`ppp0`) and the negotiated IP |
| addresses. |
| - The client will also have a network interface `ppp#`. To bring it up for use |
| with the netstack, run `ip addr add dev ppp# IP_ADDRESS/MASK` followed by |
| `ip link set ppp# up`. |
| - The host and device network interfaces are ready for use. You can verify this |
| by pinging the client's IP from the host. |
| |
| # Design |
| |
| ## `serial-ppp` |
| 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 `fuchsia.hardware.network` FIDL. |
| |
| 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. |
| |
| ## `ppp_packet` |
| 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. |
| |
| ## `ppp_protocol` |
| 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. |
| |
| ## `ppp-cli` |
| The CLI is a thin wrapper around `Ppp` FIDL's `Open` and `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. |
| |
| ## `ppp-server` |
| 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. |
| |
| On `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. |