> ## 12. PPP Driver

> The PPP packet driver is a set of libraries in Dynamic C that allows the user to establish a PPP (Point-to-Point Protocol) link over a full-duplex serial line between a Rabbit-based controller and another system that supports PPP.

> A common use of the PPP protocol is the transfer of IP packets between a remote host and an Internet Service Provider (ISP) over a modem connection. The PPP packet driver supports the transfer of Internet Protocol (IP) data and is compatible with all TCP/IP libraries for the Rabbit.

> The PPP packet driver was derived from source code originally written by Darby Corporate Solutions (DCS).

> ### 12.1 PPP Libraries

> The PPP driver is in two library files.

> `PPPLINK.LIB` contains:

> - The interrupt service routine for transmitting and receiving characters over the serial link. It also handles the insertion and detection of escape characters and CRC generation and checking.
> - `PPPflowcontrolOn()`, `PPPflowcontrolOff()`, and `PPPclose()`

> `PPP.LIB` contains:

> - Routines for setting up and running the PPP connection.

> A third library, `MODEM.LIB`, contains functions for controlling an external modem through a full RS232 link.

> ### 12.2 Operation Details

> The first step is to configure whatever transport medium will be used for the PPP connection. For directly connecting a serial line to the peer, the two serial data lines TX and RX may be adequate. The most common situation, however, will be some sort of modem.

> #### 12.2.1 The Modem Interface

> The interface between a modem and a controller is either a true RS232 interface or a variation on RS232 that uses TTL voltage levels for all of the signals. The latter are used by board-mounted modem modules. If an external modem is used, an RS232 transceiver chip is needed to convert RS232 voltages to logic signals and vice versa. A full RS232 connection has 3 outputs and 5 inputs from the controllers point of view. In RS232 terminology, the controller is referred to as the DTE (Data Terminal Equipment). Modems and other peripherals are referred to as DCE's (Data Communications Equipment).

> The specifics of a dial-up PPP connection are dependant on the modem hardware and the ISP.

> #### 12.2.1.1 Rabbit Pin Connections to Modem

> The modem control library, `MODEM.LIB`, defines default connections to the Rabbit as follows:

> RS232 Signal | Rabbit Pin | Direction
> DTR | PB6 | out
> RTS | PB7 | out
> CTS | PB0 | in
> DCD | PB2 | in
> RI | PB3 | in
> DSR | PB4 | in
> TD | PC2 | out
> RD | PC3 | in

> #### 12.2.2 Flow Control

> Hardware flow control is implemented for the Rabbit PPP system. It follows the RS232 convention of using Ready To Send (RTS) and Clear To Send (CTS) lines. Flow control is usually required for baud rates above 9600. Flow control can be enabled or disabled by `PPPflowcontrolOn()`and `PPPflowcontrolOff()`, respectively. Flow control is off by default.

> #### 12.2.3 Serial Port C

> By default the PPP link is established using serial port C. It can be changed, but it requires some `#define` changes near the top of `PPPLINK.LIB` in the section starting with `PPP_SERDR`. If a modem is used, some rewriting of `MODEM.LIB` is also required.

> ### 12.3 Software Implementation Overview

> The first stage in dial-up PPP is to establish a modem connection with the ISP. The function `ModemInit()` opens the serial port, then detects if there is a modem connected and ready. It does this by sending "AT" to the modem a set number of times until it receives an "OK" response. This should work with any Hayes-compatible modem, which is the standard today. At this point the modem is ready and commands can be sent to it using `ModemSend()`. Remember to include a carriage return "\r" at the end of each command sent.

> The function `ModemExpect()` is used to wait for a character sequence to occur. Normally the first use of this in a program is to determine that the modem has connected. When a connection occurs, the modem will send a string along the lines of "CONNECT AT x" or something similar. `ModemExpect()` can be set to listen for this. Once connected, the ISP may either attempt PPP negotiation immediately, or request a user name and password first. In the latter case, a sequence of `ModemSend()` and `ModemExpect()` calls are used to handle this (see See "Authentication Sequence" on page 304).

> Eventually the ISP will begin PPP negotiation. At this stage `ModemClose()` should be called to shutdown normal serial operation. After calling `sock_init()` and doing any other necessary TCP/IP initialization, `PPPinit()` is called, followed by any necessary PPP option initialization, and finally a call to `PPPstart()`.

> Once the PPP connection is established through a successful call to `PPPstart()`, the user can send packets to the peer using the TCP/IP libraries.

> #### 12.3.1 Defining Network Parameters

> The following parameters must be defined at compile time:

>     // Sets the TCP/IP stack to use PPP. This should be "pppoe.lib" when using PPP over Ethernet.
>     #define PKTDRV "ppp.lib"

>     // In the most common case, the Rabbit will be dialing into an ISP. The ISP will usually wish to
>     // assign the IP address. Setting the IP address to 0.0.0.0 indicates that the Rabbit does not have a
>     // valid address when started. If the Rabbit has a permanent address or will be dialed into,
>     // MY_IP_ADDRESS should be set to a proper IP address.
>     #define MY_IP_ADDRESS "0.0.0.0"

>     // This is a parameter intended for Ethernet and other shared network schemes. Since PPP is a
>     // single point-to-point link, all traffic must be routed through a peer. There is no such thing as
>     // "local" traffic. A netmask of 255.255.255.255 causes all addresses to be routed to.
>     #define MY_NETMASK "255.255.255.255"

>     // This is the address of the host that will perform routing for the Rabbit. (With PPP this is always
>     // the peer.) If the ISP assigns a gateway machine to use, then define MY_GATEWAY to that. If the
>     // gateway is not known, defining PPP_PEERROUTE will make a gateway out of whatever
>     // machine you connect to, i.e. the Rabbit will use whatever address the peer uses when identifying
>     // itself during PPP negotiation. PPP_PEERROUTE will work under most circumstances, but a
>     // static gateway address may be needed for special cases.
>     #define MY_GATEWAY "10.1.1.1"

>     // This works the same as with Ethernet: it defines a host that will resolve names into IP addresses.
>     #define MY_NAMESERVER "10.1.1.2"

> #### 12.3.1.1 IP Addresses

> When the Rabbit and the peer are establishing a connection, they negotiate what their IP addresses will be. When the Rabbit is connecting to an ISP, an IP address will be assigned to it by the ISP. In some cases, such as the Rabbit acting as a dial-in ISP, IP addresses for the Rabbit and the peer should be set by the Rabbit. This is done using `PPPnegotiateIP()`.

> #### 12.3.2 Configuration Options

> The following configuration options are supported by the Rabbit PPP system:

> Table 3. Configuration Options
> LCP Configuration Option Type Field | Meaning of Option Type
> 01 | MRU (Maximum-Receive-Unit)
> 02 | ACCM (Async-Control-Character-Map)
> 03 | Auth (Authentication-Type): PAP only
> 05 | Magic Number
> 07 | PFC (Protocol-Field-Compression)
> 08 | ACFC (Address-and-Control-Field-Compression)

> For more information on these options, refer to RFC 1661: The Point-to-Point Protocol (PPP) at:

>      http://rfc.asuka.net/rfc/rfc1661.html

> #### 12.3.3 Authentication

> The PPP library supports an optional authentication phase. Both the authentication of a peer and being authenticated by a peer are done using Password Authentication Protocol (PAP). This is a simple two-way handshake only done upon initial link establishment.

> The most common case is when the Rabbit must authenticate itself to the ISP it is connecting to. This is configured using `PPPsetAuthenticatee()`, which sets the username and password the Rabbit will use.

> A different situation arises when the Rabbit needs to authenticate a connecting peer. This is necessary when the Rabbit is being dialed into. `PPPsetAuthenticator()` sets a name and password that will be required from the peer before a connection will be established.

> #### 12.3.3.1 Authentication Sequence

> A common situation with dial-up PPP is that an ISP will want to authenticate the dialer before PPP negotiation. There are no real standards for doing this, so each ISP is potentially different. The best way to develop a correct sequence of `ModemSend()` and `ModemExpect()` commands is to connect to the ISP using a terminal program on a PC. You can then take note of the necessary sequence to start PPP negotiation.

> Here is a hypothetical session as seen by a terminal program. Characters typed in and sent to the ISP or the modem are displayed in `bold`.

> `AT
> `OK
> `ATDT5554545
> `OK
> CONNECT 28800
> Welcome to someisp.com
> Login?`rabbit
> `Password:`Ilikecarrots
> `Logging in as rabbit
> Start PPP $*($}}}}}$}$#$#${@#>>}}FF}}$}

> From this session we could use `ModemSend()` and `ModemExpect()` to create a dial-up function like this:

>     int myDialUp(){
>        if(ModemOpen(57600) == 0){
>           return 0;
>        }
>        if(ModemInit() == 0){
>           return 0;
>        }
>        ModemSend("ATDT5554545\r");
>        if (ModemExpect("OK", 2000) == 0)){
>           return 0;               //something is wrong with the modem
>        }
>        if(ModemExpect("CONNECT", 30000) == 0){
>           return 0;               //didn't connect to the ISP
>        }
>        if(ModemExpect("Login?", 5000) == 0){
>           return 0;
>        }
>        ModemSend("rabbit\r");
>        if(ModemExpect("word:", 5000) == 0){
>           return 0;
>        }
>        ModemSend("Ilikecarrots\r");
>        if(ModemExpect("PPP", 5000) == 0){
>           return 0;               //probably a failed login
>        }
>        ModemClose();
>        sock_init();
>        PPPinit(57600);
>        PPPflowcontrolOn();
>        return 1; //all done
>     }

> As you can see, `ModemExpect()` will pick up any part of the received string. Clever use of this allows the initialization to be fairly generic, but subtle differences between ISP's will often require customized sequences such as this.

> #### 12.3.4 Link Teardown

> Tearing down the link must also be done in stages. First, a terminate request must be sent to the peer. This is done with `PPPshutdown()`. `PPPshutdown()` will return once an acknowledgement has been sent by the peer, or after a time out period. This is followed by a call to `PPPclose`, which unloads the PPP serial driver. If the connection is via a modem, the modem must then be hung up. First the regular serial driver is reopened with `ModemOpen()`. `ModemHangup()` sends the hang up and reset commands to the modem. Finally, a call to `ModemClose()` shuts down the serial driver.

> ### 12.4 Functions

> This section describes the functions that compose the PPP driver and the functions for modem control.

> #### Using Cofunctions

> Establishing a PPP connection over a modem is time-consuming. Depending on the baud rate negotiated by the modem, the whole process can take 30 seconds or more. Much of this time is spent by the controller waiting for a response from the other end. In a practical application, where the controller has other tasks to perform, this may be unacceptable. For this, there are cofunction versions of all of the functions that wait for responses from the peer. There are still parts of the initialization process that create delays, but the effect is much smaller.

> ## CofModemExpect

>     int CofModemExpect(char *send_string, unsigned long timeout);

> ### Description

> Listens for a specific string to be sent by the modem. Yields to other tasks while waiting for input.

> ### Parameters

> #### send_string

> A `NULL`-terminated string to listen for.

> #### timeout

> Maximum wait in milliseconds for a character.

> ### Return value

> `1`: The expected string was received.
> `0`: A timeout occurred before receiving the string.

> ### Library

> MODEM.LIB

> ## CofModemHangup

>     int CofModemHangup();

> ### Description

> Sends "ATH" and "ATZ" commands. Yields to other tasks while waiting for responses.

> ### Return value

> `1`: Success
> `0`: Modem not responding

> ### Library

> MODEM.LIB

> ## CofModemInit

>     int CofModemInit();

> ### Description

> Resets modem with AT, ATZ commands. Yields to other tasks while waiting for responses.

> ### Return value

> `1`: Success
> `0`: Modem not responding

> ### Library

> MODEM.LIB

> ## CofModemSend

>     void CofModemSend(char *send_string);

> ### Description

> Sends a string to the modem. Yields to other tasks while sending.

> ### Parameters

> #### send_string

> A `NULL`-terminated string to be sent to the modem.

> ### Library

> MODEM.LIB

> ## CofPPPshutdown

>     int CofPPPshutdown(unsigned long timeout);

> ### Description

> Sends a Link Terminate Request packet. Waits for the link to be torn down.

> ### Parameters

> #### timeout

> Number of milliseconds to wait before giving up on a response from the peer. Yields to other tasks while waiting.

> ### Return value

> `1`:Shutdown succeeded
> `0`: Shutdown timed out

> ### Library

>     PPP.LIB

> ## CofPPPstart

>     int CofPPPstart(unsigned long timeout, int retry);

> ### Description

> Starts link negotiation process with a connected peer. Yields to other tasks.

> ### Parameters

> #### timeout

> The number of milliseconds to wait between phases of negotiation before starting over.

> #### retry

> Number of times to retry the connection

> ### Return value

> `1`: Negotiation succeeded;
> `0`: A link could not be negotiated.

> ### Library

> PPP.LIB

> ## ModemClose

>     void ModemClose();

> ### Description

> Closes the serial driver down.

> ### Library

> MODEM.LIB

> ## ModemConnected

>     int ModemConnected();

> ### Description

> Returns true if the DCD line is asserted, meaning the modem is connected to a remote carrier.

> ### Return value

> `1`: DCD line is active
> `0`: DCD inactive (nothing connected)

> ### Library

> MODEM.LIB

> ## ModemExpect

>     int ModemExpect(char *send_string, unsigned long timeout);

> ### Description

> Listens for a specific string to be sent by the modem.

> ### Parameters

> #### send_string

> A `NULL`-terminated string to listen for.

> #### timeout

> Maximum wait in milliseconds for a character

> ### Return value

> `1`: The expected string was received
> `0`: A timeout occurred before receiving the string

> ### Library

> MODEM.LIB

> ## ModemHangup

>     int ModemHangup();

> ### Description

> Sends "ATH" and "ATZ" commands

> ### Return value

> `1`: Success
> `0`: Modem not responding

> ### Library

> MODEM.LIB

> ## ModemInit

>     int ModemInit();

> ### Description

> Resets modem with AT, ATZ commands.

> ### Return value

> `1`: Success
> `0`: Modem not responding

> ### Library

> MODEM.LIB

> ## ModemOpen

>     int ModemOpen(unsigned long baud);

> ### Description

> Starts up communication with an external modem.

> ### Parameters

> #### baud

> The baud rate for communicating with the modem.

> ### Return value

> `1`: External modem detected
> `0`: Not connected to external modem

> ### Library

> MODEM.LIB

> ## ModemReady

>     int ModemReady();

> ### Description

> Returns true if the DSR line is asserted.

> ### Return value

> `1`: DSR line is active
> `0`: DSR inactive (nothing connected)

> ### Library

> MODEM.LIB

> ## ModemRinging

>     int ModemRinging();

> ### Description

> Returns true if the RI line is asserted, meaning that the line is ringing.

> ### Return value

> `1`: RI line is active
> `0`: RI inactive (nothing connected)

> ### Library

> MODEM.LIB

> ## ModemSend

>     void ModemSend(char *send_string);

> ### Description

> Sends a string to the modem.

> ### Parameters

> #### send_string

> A `NULL`-terminated string to be sent to the modem.

> ### Library

> MODEM.LIB

> ## ModemStartPPP

>     void ModemStartPPP();

> ### Description

> Hands control of the serial line over to the PPP driver.

> ### Library

> MODEM.LIB

> ## PPPclose

>     void PPPclose();

> ### Description

> Closes the serial port and unloads the PPP interrupt service routine.

> ### Library

> PPPLINK.LIB

> ## PPPinit

>     void PPPinit(unsigned long baud)

> ### Description

> Initializes the PPP driver, sets parameters. Must be called immediately following a call to `sock_init()`.

> ### Parameters

> #### baud

> The baud rate of the serial port PPP is running on (port C by default).

> ### Library

> PPP.LIB

> ## PPPflowcontrolOff

>     void PPPflowcontrolOff()

> ### Description

> Deactivates hardware flow control for the serial link.

> ### Library

> PPPLINK.LIB

> ## PPPflowcontrolOn

>     void PPPflowcontrolOn()

> ### Description

> Activates hardware flow control for the serial link. The pins used for flow control are defined in `PPPLINK.LIB` as follows:

> `PPP_CTSPORT`: the port address for the CTS input line.
> `PPP_CTSPIN`: the pin number of the CTS input line.
> `PPP_RTSPORT`: the port address of the RTS output line.
> `PPP_RTSSHADOW`: the name of the port's shadow register.
> `PPP_RTSPIN`: the pin number of the RTS output line.

> ### Library

> PPPLINK.LIB

> ## PPPstart

>     int PPPstart(unsigned long timeout, int retry);

> ### Description

> Starts link negotiation process with a connected peer.

> ### Parameters

> #### timeout

> Number of milliseconds to wait between phases of negotiation before starting over.

> #### retry

> Number of times to retry the connection.

> ### Return value

> `1`: Negotiation succeeded;
> `0`: A link could not be negotiated.

> ### Library

> PPP.LIB

> ## PPPnegotiateIP

>     void PPPnegotiateIP(unsigned long local_ip, unsigned long remote_ip);

> ### Description

> Sets PPP driver to negotiate IP addresses for itself and the remote peer. Otherwise, the system will rely on the remote peer to set addresses.

> ### Parameters

> #### local_ip

> IP number to use for this PPP connection.

> #### remote_ip

> IP number that the remote peer should be set to.

> ### Library

> PPP.LIB

> ## PPPnegotiateDNS

>     void PPPnegotiateDNS(unsigned long dns_ip);

> ### Description

> Sets PPP driver to configure a DNS address for the remote peer.

> ### Parameters

> #### dns_ip

> IP number for the DNS server

> ### Library

> PPP.LIB

> ## PPPsetAuthenticatee

>     void PPPsetAuthenticatee(char *username, char *password);

> ### Description

> Sets the driver up to send a PAP authentication message to a peer when requested.

> ### Parameters

> #### username

> The username to send to the peer. The argument string is not copied, so the argument string must stay constant.

> #### password

> The password to send to the peer. The argument string is not copied, so the argument string must stay constant

> ### Library

> PPP.LIB

> ## PPPsetAuthenticator

>     void PPPsetAuthenticator(char *username, char *password);

> ### Description

> Sets the driver up to require a PAP authentication message from a peer. Negotiation will fail unless the peer sends the specified username/password pair. This function is generally used when the Rabbit is acting as a dial-in server.

> ### Parameters

> #### username

> The user name that the peer must match for the link to proceed.

> #### password

> The password that the peer must match for the link to proceed.

> ### Library

> PPP.LIB

> ## PPPshutdown

>     int PPPshutdown(unsigned long timeout);

> ### Description

> Sends a Link Terminate Request packet. Waits for link to be torn down.

> ### Parameters

> #### timeout

> Number of milliseconds to wait before giving up on a response from the peer.

> ### Return value

> `1`: Shutdown succeeded
> `0`: Shutdown timed out

> ### Library

> PPP.LIB

> ## ResetPPP

>     void ResetPPP( );

> ### Description

> Under normal operations, this function will not be needed; the modem control functions make it unnecessary. There are, however, conditions that may make it useful.

> ### Library

> PPP.LIB

Z-World http://www.zworld.com Voice: 530.757.3737 Fax: 530.757.3792 or 530.753.5141 sales@zworld.com