Ethernut Home Hardware Firmware Tools Download Community
 
 
Search | Legals | Deutsch

Setting up PPP


This paper provides helpful information about how to get started with Ethernut's PPP.

PPP, the Point to Point Protocol can be used to encapsulate IP and other packets on a serial link. As its name implies, the link is established between two points only. The initiator is called the PPP client, which connects to the PPP server on the other end of the line. The current Ethernut implementation supports the client mode only. Thus, Ethernut can actively call another party, but is not able to answer incoming calls. However, as soon as a PPP session has been established, either party may run TCP or UDP servers or clients.

PPP is a complex protocol with many parameters. Unlike Ethernet connections, several steps are required to establish a session.

Hardware


Device Initialization

First of all the serial interface has to be initialized. On Nut/OS an UART is used and must be registered.

  NutRegisterDevice(&devAhdlc0, 0, 0);
At the time of this writing devUsartAvr is the most advanced UART driver for the AVR platform. However, PPP runs at optimum performance, when the HDLC part is integrated into the driver. The bad news is, that devAhdlc, which provides this feature, is based on the old devUart driver. If this is all Greek to you, don't worry. Register devAhdlc0 for the first and devAhdlc1 for the second UART.

Nut/OS implements PPP itself as a device. Thus, the application has to register it as well.

  NutRegisterDevice(&devPpp, 0, 0);
Now, as the PPP device is registered, we can open it. The name of the device is ppp. Note the lower case letters. Similar to most other operating systems, devices are opened in Nut/OS, by their names. In addition, Nut/OS allows to add a colon to the device name, followed by a path. This is similar to DOS and Windows, when specifying a path of a file or directory on a certain device or drive. However, we do not really specify a path, but pass a number of parameters. And, like Linux, Nut/OS uses slashes, not backslashes, to separate the parts of a path.
  pppcom = _open("ppp:uart0/user/passwd", _O_RDWR | _O_BINARY);
The first parameter is the name of the UART device, which PPP should use. We registered devAhdlc0 for this purpose, the name of this device is uart0. Actually, all devices using the first AVR UART do have the same symbolic name uart0. If there is a new driver at any later time, you only need to change the line containing NutRegisterDevice().

The next part must contain the user's name, followed by the corresponding password. If your provider doesn't require authentication, you can simply leave them out. Remember, that PPP can be used for dialing into remote hosts over a public telephone network. That's why some login information is typically required. Do not mixup login with PPP authentication. User logins, which are rarely required, can be handled by NutChat() before PPP is actually activated. We will soon discuss this function. PPP authentication on the other hand is part of the negotiation between the PPP client (Ethernut) and the PPP server (ISP). This negotiation will later run automatically in the background and is out of our control. Thus we need to provide this information before the negotiation actually starts.

If the open call for the PPP device succeeds, it returns a handle for this device, which can be used to set the baudrate. For this kind of special device functions, Nut/OS offers the ioctl() routine.

  u_long lctl = 38400;
  _ioctl(pppcom, UART_SETSPEED, &lctl);

Up to this point, nothing has been transmitted. Both, the UART and the PPP device just sit there, waiting for data to be transmitted or received.


Dialing Out

PPP can be used with many different serial hardware. The most simple is a direct serial cable. However, most systems will use a modem connected to a telephone line or a GPRS modem. Let's try a simple modem first.

We use the US Robotics Courier Dual Standard V34+, a quite old part, but still useful. You can use almost any model, preferable one with Hayes compatible command set.

After initialization ur PPP interface is still inactive and the UART device can be used in a normal fashion, sending and receiving single characters. This way we can talk to the modem, sending Hayes commands and receiving responses.

Fortunately Nut/OS offers the NutChat() routine, which executes a simple chat script and returns its result. In general, chat scripts are made of one or more pairs of strings. The first part of such a pair is the string, that is expected and the second part is the one to be sent. A simple chat script looks like this

      "'' AT OK ATD555 CONNECT"
It consists of two and a half pair. The first pair is an empty string '' followed by the string AT. When executed, NutChat() expects nothing and send out AT followed by a carriage return. The carriage return need not to be specified in the script, it is automatically appended to the output string. If the modem understands the Hayes command set, it will respond to the AT command with a simple OK followed by a carriage return. This is where the second pair jumps in. It expects the string OK and, as soon as this is received, responds with ATD555, which is the Hayes command to dial 555. The last pair is not complete. It just specifies the expected string, but doesn't define the response. Thus the response is assumed to be empty. As soon as the modem establishes a connection, it sends sends out something like
      CONNECT 38400/ARQ
or similar. As soon as NutChat() detects the string CONNECT, it will return with result zero. The application is now informed, that the modem connection has been successfully established.

It is not unusual, that the modem will respond with a different string, like BUSY if it detects, that the dialed number is occupied. NutChat() offers a variety of functions to handle such situations. Here is a more advanced example

      "TIMEOUT 10 ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ATDT555 CONNECT"
The first pair starts with the special keyword TIMEOUT. NutChat() will not expect this string, but interprets the pair as an internal command. TIMEOUT 10 will set the timeout to 10 seconds. A timeout pair may be specified multiple times in order to change its value while the script is executed. If any of the expected strings couldn't be received within the specified number of seconds, then NutChat() will return an error value of 3. ABORT is another special keyword. Whenever the string, which follows the ABORT keyword, is send by the modem, NutChat() will abort the script processing and return an error value to the caller. The value returned is 4 plus the index of the specified abort string. In our given example, BUSY will return 4, 'NO CARRIER' will return 5. This way the application is able to determine, what causes the failure.

You may have noted the hyphens with 'NO CARRIER'. These are required to make this a single string within the script.

Finally the keyword REPORT may be used to store the last modem response in a buffer, which can be accessed through the global u_char pointer chat_report after NutChat() returned. This is quite useful to check the complete connection string returned by the modem.

Modems are picky devices and NutChat() allows to use special characters to further control them.

      \b  Backspace character
      \c  Suppresses carriage return at the end of a send string
      \d  Delay 1 second
      \n  Line feed character
      \N  Null character
      \p  Delay 100 milliseconds
      \r  Carriage return character
      \s  Space character
      \t  Tab character
      \\  Backslash character
      \DDD Character DDD, where DDD are up to three octal digits
When using these characters be aware, that the compiler will translate backslashes within string literals. Using \r will be replaced by a carriage return, which is not what we want. In order to add a backslash plus character r we must write \\r within string literals. Using these characters. the "ABORT 'NO CARRIER'" may also have been written as "ABORT NO\\sCARRIER", which saves us one character. You do not agree? Then remember, that the compiler replaces the backslashed backslash with a single backslash.

It's likely, that you need to consult your modem's manual to find out more. It is also a good idea to try the modem commands with your PC and a terminal emulator first.


Network Interface Setup

PPP Layers As soon as the modem connection is active, the application needs to configure the PPP network device.

      rc = NutNetIfConfig("ppp", 0, 0, 0);
This simple call does it all, but under the hood, this is the most complicated part. In any case, check its return value. If anything goes wrong, this is the place to check and we will look into it in more detail. Note, that the parameters, which usually specify the IP address and the network mask are set to zero. This is because the PPP server on the remote side will typically provide these parameters.

PPP adds four layers to the Ethernut TCP/IP stack.

      HDLC  PPP in HDLC-like Framing (RFC 1662)
      LCP   PPP LCP Extensions (RFC 1570)
      PAP   PPP Authentication Protocols (RFC 1334)
      IPCP  Internet Protocol Control Protocol (RFC 1332)

As stated above, the PPP interface is still inactive after its initialization and even after the PPP device has been opened. However, opening the PPP device initialized the states of all PPP layers. Opening the PPP device puts both, the IPCP and the LCP layer in the STARTING mode. In this mode, the layers will neither accept any input nor generate any output.

When the application calls NutNetIfConfig(), the RS232 interface will be handed over to the HDLC layer. When this happens, all transmitted data is packed into HDLC frames and all received data is expected to be packed in HDLC frames. In addition, the HDLC layer will report to the LCP layer, that it is up and running.

As soon as the LCP layer is informed, that the lower layer is up, it will send out a request through the HDLC layer. Assuming, that the modem is still connected, this request will be packed into a HDLC frame and send via modem to the remote. The remote's stack works in the same way and consequently sends out an LCP request. In simple words, more or less at the same time both sides will receive a LCP request.

The HDLC layer passes incoming LCP telegrams to the LCP layer by calling NutLcpInput(). The LCP request telegram contains a list of options, which the other side prefers to use during the upcoming session. Valid options are the maximum number of bytes in a single telegram or the type of authentication. Each side will now make up its mind about this request and either accept, not accept or reject the requested options. The difference between not accepting an option and rejecting it is as follows: A rejected option is not negotiable, which means, that the responding side simply doesn't provide it. An option is not accepted, if the other side is generally able to provide this function, but not in the requested way. As an example, a node may provide authentication, but not the type of authentication requested by the remote. The server may request CHAP authentication, but the client is only able to provide PAP authentication.

If a requested option is declined, the requester will decide, wether it makes sense to further continue. Thus, the requester may not allow any other authentication than CHAP. If the remote doesn't accept this, it will send a LCP termination request to shut down the conversation. As long as unacknowledged options are negotiable, both sides continue to send requests and responses.

When finally all options had been accepted by both sides, LCP will send a LOWER UP report to the IPCP layer, or, if any authentication has been negotiated, initiate the authentication protocol. At the time of this writing, Ethernut supports PAP only. The bad thing about PAP is, that passwords are not encrypted when passed to the remote. Allthough telephone lines are considered safe, some hosts may not accept authentication without encryption.

If authentication fails due to wrong passwords or illegal user names, the authentication layer will inform the IPCP layer, that the lower layer is down. And step by step all layers go down and finally disable the HDLC driver.

If authentication succeeds, the IPCP layer will be informed, that its lower layer is up and IPCP starts negotiating in a similar way as LCP did before. Of course, IPCP negotiates different options, mainly IP addresses. If the application called NutNetIfConfig() with IP address set to zero, Ethernut will accept any local IP address for its PPP network interface.


Hanging Up

Terminating a session is not as easy as it might look first. The host, that wants to terminate a session sends an LCP TERM request, waits a few seconds for a LCP TERM acknowledge and shuts down all layers. If the host receives a LCP TERM request, it responds with a LCP TERM acknowledge and shuts down all layers.

The problem that remains is the modem connection. The modems are not PPP aware. They simply transport any kind of binary data from one end to the other. Assuming that the other side hangs up reilable, we may not bother about the Ethernut modem. If the other side hangs up, our modem will recognize this and hangs up too. But at least this is no fair play.

One solution would be to use the idle timeout, which most modems support. If no traffic is generated within a specified time, the modem will automatically hang up. As you can imagine, this method is not really reliable and additionally causes the connection to stay alive longer than neccessary.

Most Hayes compatible modems offer escape sequence detection. If they receive three consecutive + characters, they will change back to command mode. So we can send the ATH command to hang up. Again, this is unreliable too. Practice shows, that the detection of +++ works quite seldom.

The solution is, using a hardware handshake line. Usually DTR is used for this purpose. The Ethernut Board does not provide DTR, but RTS. Either the modem can be configured to drop the connection on RTS or we need a special adapter cable to route the RTS output on the Ethernut board to the DTR input of the Modem.


PPP Debugging

As stated above, most problems arise during NutNetIfConfig(), when the PPP session is established. Fortunately Nut/OS offers some debug capabilities to track down these problems.

To save code and data space, debugging is not build in by default. It requires to rebuild the libraries with debug code included.

Nut/OS debug output goes to a serial RS232 interface. As we used the standard UART to connect the modem, we need a second one. If your Ethernut is still ATmega103 based, you got a real problem here, because this chip has a single UART only. You need to attach an external UART and rewrite the debug device driver or replace the ATmega103 with an ATmega128. It is clear, that this will be a project of its own.

For Ethernut 1.3 the second UART is available at the expansion port, but you still need some additional hardware, because these signals are TTL level and needs to be shifted to RS232 levels.

As a lucky owner of Ethernut 2.0, you can use jumper JP to route both UARTs to the DB-9 connector.

PPP Layers

You still need a special adapter cable to distribute receive and transmit lines of both UARTs to two separate DB-9 connectors, but this is done in a few minutes and doesn't require more than basic soldering skills.


Using GPRS

Using the mobile telephone network doesn't differ much from using standard telephone lines and modems. In fact, the GPRS devices, that are, for example, build into modern mobile phones, act like Hayes compatible modems. Even better, because the GPRS command set is much more standardized.


Related RFCs

RFC 1332 The PPP Internet Protocol Control Protocol (IPCP)
RFC 1377 The PPP OSI Network Layer Control Protocol (OSINLCP)
RFC 1378 The PPP AppleTalk Control Protocol (ATCP)
RFC 1471 The Definitions of Managed Objects for the Link Control Protocol of the Point-to-Point Protocol
RFC 1472 The Definitions of Managed Objects for the Security Protocols of the Point-to-Point Protocol
RFC 1473 The Definitions of Managed Objects for the IP Network Control Protocol of the Point-to-Point Protocol
RFC 1474 The Definitions of Managed Objects for the Bridge Network Control Protocol of the Point-to-Point Protocol
RFC 1547 Requirements for an Internet Standard Point-to-Point Protocol
RFC 1552 The PPP Internetwork Packet Exchange Control Protocol (IPXCP)
RFC 1553 Compressing IPX Headers Over WAN Media (CIPX)
RFC 1570 PPP LCP Extensions
RFC 1598 PPP in X.25
RFC 1618 PPP over ISDN
RFC 1661 The Point-to-Point Protocol (PPP)
RFC 1662 PPP in HDLC-like Framing
RFC 1663 PPP Reliable Transmission
RFC 1762 The PPP DECnet Phase IV Control Protocol (DNCP)
RFC 1763 The PPP Banyan Vines Control Protocol (BVCP)
RFC 1764 The PPP XNS IDP Control Protocol (XNSCP)
RFC 1962 The PPP Compression Control Protocol (CCP)
RFC 1963 PPP Serial Data Transport Protocol (SDTP)
RFC 1967 PPP LZS-DCP Compression Protocol (LZS-DCP)
RFC 1968 The PPP Encryption Control Protocol (ECP)
RFC 1973 PPP in Frame Relay
RFC 1974 PPP Stac LZS Compression Protocol
RFC 1975 PPP Magnalink Variable Resource Compression
RFC 1976 PPP for Data Compression in Data Circuit-Terminating Equipment (DCE)
RFC 1977 PPP BSD Compression Protocol
RFC 1978 PPP Predictor Compression Protocol
RFC 1979 PPP Deflate Protocol
RFC 1989 PPP Link Quality Monitoring
RFC 1990 The PPP Multilink Protocol (MP)
RFC 1993 PPP Gandalf FZA Compression Protocol
RFC 1994 PPP Challenge Handshake Authentication Protocol (CHAP)
RFC 2043 The PPP SNA Control Protocol (SNACP)
RFC 2097 The PPP NetBIOS Frames Control Protocol (NBFCP)
RFC 2118 Microsoft Point-To-Point Compression (MPPC) Protocol
RFC 2125 The PPP Bandwidth Allocation Protocol (BAP) The PPP Bandwidth Allocation Control Protocol (BACP)
RFC 2153 PPP Vendor Extensions
RFC 2284 PPP Extensible Authentication Protocol (EAP)
RFC 2363 PPP Over FUNI
RFC 2364 PPP over AAL5
RFC 2419 The PPP DES Encryption Protocol, Version 2 (DESE-bis)
RFC 2420 The PPP Triple-DES Encryption Protocol (3DESE)
RFC 2433 Microsoft PPP CHAP Extensions
RFC 2484 PPP LCP Internationalization Configuration Option
RFC 2615 PPP over SONET/SDH
RFC 2661 Layer Two Tunneling Protocol 'L2TP'
RFC 2701 Multi-link Multi-node PPP
RFC 2716 PPP EAP TLS Authentication Protocol
RFC 2759 Microsoft PPP CHAP Extensions, Version 2
RFC 2823 PPP over Simple Data Link (SDL) using SONET/SDH with ATM-like framing
RFC 3078 Microsoft Point-To-Point Encryption (MPPE) Protocol
RFC 3153 PPP Multiplexed
RFC 3255 Extending PPP over SONET/SDH, with virtual concatenation, high order and low order payloads
RFC 3336 PPP over Asynchronous Transfer Mode Adaptation Layer 2
RFC 3518 Point-to-Point Protocol (PPP) Bridging Control Protocol (BCP)