------------------------------------------------------------------------------ Pppoa series documentation ------------------------------------------------------------------------------ SUMMARY * GENERAL DESCRIPTION FOR PPPOA2/2M/3 SERIES * DESCRIPTION FOR PPPOA2 SERIES ** Running through a pppoa2 execution ** Read/Write fatal errors handling ** Signals handling ** Difference between pppoa2 and pppoa2m (and birth of pppoa3) * DESCRIPTION OF PPPOA3 ** Changes between pppoa3 and pppoa2 ** Running through a pppoa3 execution ** Signals handling ------------------------------------------------------------------------------ * GENERAL DESCRIPTION FOR PPPOA2/2M/3 SERIES Adsl providers mostly use PPP over ATM. Under Linux and BSD, PPP layer is directly handled by kernel through ppp(d). Unfortunately ppp(d) doesn't know shit about USB or ATM. Thus it is not possible to simply use ppp(d) to communicate with the modem (thus your provider). pppoax series solves this problem by providing a link between ppp(d) and the modem through ppp(d) daemon's pty option. Here's a simple graph showing ppoax's behavior: __________ __________ _______ | |<---------| |<---------------- / ° ° \ | ppp(d) | pty | pppoax | USB bus | Modem | ADSL line<---->ISP |________|--------->|________|----------------> \\ // // ppp packets ^ atm cells \ /____// | \_______/ | encapsulate/expand data in aal5 frames and then send/receive ATM cells through USB *PPPOA2 SERIES DESCRIPTION The first solution we found to handle IO streams was to write a piece of code which splits (by forking) in two parts at run time, one part for reading from USB, and the other one for writing to it. ** Running through a (normal) pppoa2 execution 1 - pppoa2 starts and duplicates its standard file descriptors: 0 (stdin) and 1 (stdout) 2 - opening of the log 3 - duplication of log's descriptor in 0, 1, 2 From that point, nothing displays on the console anymore, all printf output is logged 4 - N_HDLC line discipline set up on descriptors used to communicate with ppp(d) 5 - search for USB modem 6 - Access requests for 0x07 (read) and 0x87 (write) endpoints 7 - Installation of signal handler to manage signals possibly sent by ppp(d) (or even user) 8 - fork +Child goes into infinite loop, doing always the same tasks: read data sent by ppp(d), encapsulate aal5, split into atm cells, send those cells to modem +Parent keeps running 9 - Parent goes into infinite loop and; Receives atm packets from modem, span aal5 frames, send those packets to ppp(d) ** Read/Write fatal error handling In a perfect world, once pppoa is started it would run flawlessly 'ad vitam eternam' (thats 'forever' for those of you who managed to ditch latin 101 in high school ). But life is hard and errors may occur. Here is pppoa2's reaction when shit happens: Child or parent process stops looping and sends TERM signal to the other one.We then release USB devices and so on, in the most proper way possible. Then we exit as cleanly as we can from both processes. Theoretically both process are killed ** signal handling pppoa2 only catches SIGHUP under BSD environment and SIGTERM under Linux. This is due to the fact that ppp(d) uses those signals to announce pty closure to its slave. If a signal is received by one of the two processes it sends it to the other one on its turn. ** difference between pppoa2 and pppoa2m pppoa2 is functional but its design didn't offer any possibility of an easy upgrade or new functionality. The code was not modular enough and any little things that needed to be changed forced a massive code rewrite. pppoa was rewritten in a way that allowed creation of small libraries for crc, atm, aal5 on one side and pppoa using them on the other side. Unfortunately, the design of pppoa2 was so poor that no part of it could be easily re-used. The new version of pppoa, pppoa3, was redesigned from the ground up. Libraries were written but the pppoa3 main code was buggy. We then back ported new code to pppoa2 which was functional and well tested. Then we obtained pppoa2m, a pppoa2 merged with pppoa3. In a few words: pppoa2m = (pppoa2) - (dirty code) + (new aal5/atm/crc libs) pppoa2m is better than pppoa2 because it takes advantage of new library features and also a few things from pppoa3 (log system for example). NB: pppoa2m is a better choice than pppoa2 ------------------------------------------------------------------------------ *PPPOA3 DESCRIPTION It should be fairly obvious to anyone with a positive IQ that pppoa2 is the successor of pppoa3. It takes advantage of the new design. Some variants of BSD don't support threading directly, so we kept both the pppoa2 series and the new pppoa3 series. (Linux can run all of them). Once more, pppoa2m is better than pppoa2. ** Differences between pppoa2 and ppoa3 1 - pppoa3 uses threads instead of forking to allow simultaneous read/write operations. This provides: + Lower latency when switching between read and write + Decreased memory consumption + Better control over scheduling ( finer granularity ) + Improved signal handling 2 - All of the code has been modularized 3 - Better ATM and AAL5 management (CRC added, new checks) 4 - New log system that allows logging to syslogd ** Run through of a normal pppoa3 execution Main thread 1 - Program start 2 - N_HDLC discipline setting 3 - Thread attributes initialization 4 - USB initialization (detection and request of 0x07 and 0x87 endpoints) 5 - Signal handler installation 6 - I/O thread creation 7 - Wait for a semaphore 8 - The semaphore happened this can mean 3 things: + Read fatal error + Write fatal error + A signal was caught by the signal handler 9 - Resources cleanup, threads abortion -> exit I/O thread (created at step 5 in main thread) 1 - Abort validation 2 - Signals blocking (so that only main thread handles them) 3 - Infinite read/write loop: aal5 encapsulation/expanding , atm cells creating/reading 4 - If an error occurs, we commit the semaphore so that main thread will still function 5 - thread exit PS: log system is not started until a message is posted through report function. This is why log creation doesn't appear in this resume. ** Signal handling Signals are handled only by the main thread. When a signal is caught, the signal handler broadcast the error semaphore in order to wake up the main thread. Atomicity of semaphore broadcasting guarantees that the program will terminate at the main thread level.