lwIP Wiki
No edit summary
Tag: Visual edit
 
(13 intermediate revisions by 5 users not shown)
Line 1: Line 1:
===PPP from an application perspective===
+
=PPP from an application perspective=
   
There are two ways to use lwIP with PPP support. Either PPPoE (PPP over Ethernet) or PPP-over-serial.
+
There are two ways to use lwIP with PPP support. Either PPPoE (PPP over Ethernet) or PPP-over-serial.
lwIP supports being run in a threaded environment, where ppp is a separate task that runs alongside the main
+
lwIP supports being run in a threaded environment, where ppp is a separate task that runs alongside the main
 
lwIP thread. lwIP also supports being run from a main loop, with lwIP functions being called from the main loop.
 
lwIP thread. lwIP also supports being run from a main loop, with lwIP functions being called from the main loop.
   
Line 23: Line 23:
   
   
= With Task Support =
+
=== With Task Support ===
In addition to sio_write(), sio_read() and sio_read_abort() are required.
+
In addition to sio_write(), sio_read(), sio_read_abort() and the linkStatusCB are required to be implemented by you. The first 2 functions are statically linked, while the last function is defined through a function pointer (so the name can be different, and could be dynamically created as well).
  +
  +
The function sio_read() is called from the pppInputThread, repeatedly. It blocks until it fills the requested buffer size or times-out, reading data from the serial device. It must abort itself if there is
  +
a call to sio_read_abort(). The soft link between sio_read and sio_read_abort must be implemented by you, either
  +
via a global variable, RTOS event, etc. The timeout should be relatively small, just large enough so that data is actually buffered in more than 1 byte chunks but small enough to make the ppp stack responsive. A timeout of about 2 ms is reasonable.
   
 
/**
 
/**
Line 34: Line 38:
 
* @return number of bytes actually received - may be 0 if aborted by sio_read_abort
 
* @return number of bytes actually received - may be 0 if aborted by sio_read_abort
 
*
 
*
* @note This function will block until data can be received. The blocking
 
* can be cancelled by calling sio_read_abort().
 
 
*/
 
*/
 
u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
 
u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
  +
 
  +
The sio_read_abort() function must cause the sio_read command to exit immediately. This command is called by the tcpip_thread, mostly when ending a PPP session (terminated, link down or explicit close).
  +
 
/**
 
/**
 
* Aborts a blocking sio_read() call.
 
* Aborts a blocking sio_read() call.
Line 46: Line 50:
 
void sio_read_abort(sio_fd_t fd);
 
void sio_read_abort(sio_fd_t fd);
   
  +
=== Required callback function ===
   
  +
The callback
   
  +
void (*linkStatusCB)(void *ctx, int errCode, void *arg)
= With no Task Support =
 
  +
  +
is called under the following events:
  +
*Link Terminated. <code>errCode</code> is nonzero, arg is null.
  +
*sifup (Interface Up).<code>errCode</code> is PPPERR_NONE, and <code>arg</code> is pointer to <code>ppp_addrs</code> structure, which contains IP address.
  +
*sifdown (Interace Down). <code>errCode</code> is PPPERR_CONNECT, and arg is null.
  +
  +
The <code>errCode</code> can be one of the following
  +
  +
#define PPPERR_NONE 0 /* No error. */
  +
#define PPPERR_PARAM -1 /* Invalid parameter. */
  +
#define PPPERR_OPEN -2 /* Unable to open PPP session. */
  +
#define PPPERR_DEVICE -3 /* Invalid I/O device for PPP. */
  +
#define PPPERR_ALLOC -4 /* Unable to allocate resources. */
  +
#define PPPERR_USER -5 /* User interrupt. */
  +
#define PPPERR_CONNECT -6 /* Connection lost. */
  +
#define PPPERR_AUTHFAIL -7 /* Failed authentication challenge. */
  +
#define PPPERR_PROTOCOL -8 /* Failed to meet protocol. */
  +
  +
The <code>ctx</code> pointer is an optional user defined pointer that is defined as an argument in the call to <code>pppOverSerialOpen</code>, which can point to user defined data.
  +
 
=== With no Task Support ===
 
You need to receive the serial data in your main thread, then from your main thread call
 
You need to receive the serial data in your main thread, then from your main thread call
 
pppos_input(int pd, u_char* data, int len);
 
pppos_input(int pd, u_char* data, int len);
   
   
= Example Task Application code =
+
=== Example Task Application code ===
   
  +
This example shows the initialization of the TCP and PPP threads. It assumes that you will do your socket handling
  +
in the context of the main() function.
   
<code>#define PPP_SERIAL_PORT 0
+
<code>
  +
#include "ppp/ppp.h"
 
  +
#define PPP_SERIAL_PORT 0
 
  +
static void linkStatusCB(void* ctx, int errCode, void* arg);
  +
static void tcpip_init_done(void *arg);
 
 
 
int main(void) {
 
int main(void) {
 
int connected = 0;
 
int connected = 0;
int setup = 0;
+
volatile int setup = 0;
 
int pd;
 
int pd;
const char *username = "myuser"
+
const char *username = "myuser";
const char *password = "mypassword"
+
const char *password = "mypassword";
 
 
/* initialise lwIP */
+
/* initialise lwIP. This creates a new thread, tcpip_thread, that
  +
* communicates with the pppInputThread (see below) */
 
tcpip_init(tcpip_init_done, &setup);
 
tcpip_init(tcpip_init_done, &setup);
 
while (!setup) {
 
while (!setup) {
sleep(1)
+
sleep(1);
 
}
 
}
 
 
/* initialise PPP */
+
/* initialise PPP. This needs to be done only once after boot up, to
  +
* initialize global variables, etc. */
 
pppInit();
 
pppInit();
  +
  +
/* set the method of authentication. Use PPPAUTHTYPE_PAP, or
  +
* PPPAUTHTYPE_CHAP for more security .
  +
* If this is not called, the default is PPPAUTHTYPE_NONE.
 
*/
 
pppSetAuth(PPPAUTHTYPE_ANY, username, password);
 
pppSetAuth(PPPAUTHTYPE_ANY, username, password);
 
 
  +
</code>
  +
  +
<code> /* call the board specific function that will open the specific serial
  +
* port hardware, for example, configuring pins, I/Os, UART, USART,
  +
* clocks, etc. This function is not part of lwip or ppp. You need to
  +
* supply this or find an example for your hardware.
  +
*/
  +
OpenMySerialPortOrUART(PPP_SERIAL_PORT, ...);
  +
  +
</code>
  +
  +
<code> /* call the board specific function that will connect to the modem,
  +
* ie dialing phone numbers, sending configuration AT commands, etc.
  +
* This function is not part of lwip or ppp. You need to supply this
 
if (DialOutMyModem(PPP_SERIAL_PORT, ...) != 0) {
  +
printf("can't dial out");
  +
} else {
  +
 
/** Open a new PPP connection using the given I/O device.
 
/** Open a new PPP connection using the given I/O device.
 
* This initializes the PPP control block but does not
 
* This initializes the PPP control block but does not
* attempt to negotiate the LCP session. If this port
+
* attempt to negotiate the LCP session.
* connects to a modem, the modem connection must be
 
* established before calling this.
 
 
* Return a new PPP connection descriptor on success or
 
* Return a new PPP connection descriptor on success or
* an error code (negative) on failure. */
+
* an error code (negative) on failure.
  +
* This call creates one new thread per call, to service the particular
if (pd = pppOverSerialOpen(PPP_SERIAL_PORT, linkStatusCB, &connected) >= 0) {
 
  +
* serial port, serviced by the pppInputThread function.
while (!done && timeout(60 seconds)) {
 
  +
*/
  +
pd = pppOverSerialOpen(PPP_SERIAL_PORT, linkStatusCB, &connected);
 
if (pd >= 0) {
  +
// the thread was successfully started.
 
while (!connected && timeout(60 seconds)) {
  +
sleep(100 ms);
 
}
 
}
 
 
if (timeout) {
+
if (!timeout) {
pppClose(pd);
+
// We are connected on lwIP over PPP!
  +
  +
while (working) {
 
/* create some socket connections,
  +
* do writes and reads on the sockets, close them, etc */
  +
}
 
}
 
}
  +
/* calling pppClose will end the pppInputThread associated with pd*/
 
pppClose(pd);
 
}
 
}
 
 
  +
// shut down the rest of your hardware.
while (1) {
 
/* We are connected on lwIP over PPP, create some socket connections etc */
 
}
 
 
pppClose(pd);
 
 
}
 
}
 
 
Line 104: Line 171:
 
}
 
}
 
}
 
}
  +
 
 
 
static void linkStatusCB(void *ctx, int errCode, void *arg) {
 
static void linkStatusCB(void *ctx, int errCode, void *arg) {
Line 111: Line 179:
 
struct ppp_addrs *addrs = arg;
 
struct ppp_addrs *addrs = arg;
 
 
struct ppp_addrs {
 
ip_addr_t our_ipaddr, his_ipaddr, netmask, dns1, dns2;
 
};
 
 
 
 
if (errCode == PPPERR_NONE) {
 
if (errCode == PPPERR_NONE) {
Line 127: Line 192:
 
}
 
}
 
</code>
 
</code>
  +
[[Category:LwIP Application Developers Manual]]
  +
[[Category:Page with support notes for version HEAD]]
  +
[[Category:Page with support notes for version 1.2]]
   
  +
== Debug Support ==
   
  +
  +
  +
  +
Add this to lwipopts.h
  +
  +
<code> #define PPP_THREAD_NAME "ppp"
  +
#define PPP_THREAD_STACKSIZE 200
  +
#define PPP_THREAD_PRIO 2
  +
</code>
  +
  +
<code> #define LWIP_DEBUG 1
  +
#define PPP_DEBUG LWIP_DBG_ON
  +
</code>
  +
*PPP packets all start and end with 0x7E. If you don't see these, something is wrong with your low level driver
  +
*Further packet debugging hints are here: http://lists.nongnu.org/archive/html/lwip-users/2011-06/msg00036.html
  +
*If you have trouble with the RTOS crashing on pppClose, look here : http://lists.gnu.org/archive/html/lwip-users/2012-02/msg00124.html
   
 
==PPP support history in lwIP==
 
==PPP support history in lwIP==
Line 141: Line 226:
 
* [http://tools.ietf.org/html/rfc1661 RFC 1661] The Point-to-Point Protocol (PPP)
 
* [http://tools.ietf.org/html/rfc1661 RFC 1661] The Point-to-Point Protocol (PPP)
   
==See also==
+
==See also:==
[[Category:LwIP Application Developers Manual]]
+
This information is not adequate. We would appreciate if someone can add more information regarding implementation of PPP with RTOS.[[Category:LwIP Application Developers Manual]]
 
[[Category:Page with support notes for version HEAD]]
 
[[Category:Page with support notes for version HEAD]]
 
[[Category:Page with support notes for version 1.2]]
 
[[Category:Page with support notes for version 1.2]]

Latest revision as of 17:38, 20 March 2018

PPP from an application perspective[]

There are two ways to use lwIP with PPP support. Either PPPoE (PPP over Ethernet) or PPP-over-serial. lwIP supports being run in a threaded environment, where ppp is a separate task that runs alongside the main lwIP thread. lwIP also supports being run from a main loop, with lwIP functions being called from the main loop.

PPP over serial[]

To setup a PPP connection over a serial link you will need to provide the Serial IO functions.

Both the thread environment and a main loop require implemented sio_write() to be implemented.

/**
 * Writes to the serial device.
 * 
 * @param fd serial device handle
 * @param data pointer to data to send
 * @param len length (in bytes) of data to send
 * @return number of bytes actually sent
 * 
 * @note This function will block until all data can be sent.
 */
u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);


With Task Support[]

In addition to sio_write(), sio_read(), sio_read_abort() and the linkStatusCB are required to be implemented by you. The first 2 functions are statically linked, while the last function is defined through a function pointer (so the name can be different, and could be dynamically created as well).

The function sio_read() is called from the pppInputThread, repeatedly. It blocks until it fills the requested buffer size or times-out, reading data from the serial device. It must abort itself if there is a call to sio_read_abort(). The soft link between sio_read and sio_read_abort must be implemented by you, either via a global variable, RTOS event, etc. The timeout should be relatively small, just large enough so that data is actually buffered in more than 1 byte chunks but small enough to make the ppp stack responsive. A timeout of about 2 ms is reasonable.

/**
 * Reads from the serial device.
 * 
 * @param fd serial device handle
 * @param data pointer to data buffer for receiving
 * @param len maximum length (in bytes) of data to receive
 * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
 * 
 */
u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);

The sio_read_abort() function must cause the sio_read command to exit immediately. This command is called by the tcpip_thread, mostly when ending a PPP session (terminated, link down or explicit close).

/**
 * Aborts a blocking sio_read() call.
 * 
 * @param fd serial device handle
 */
void  sio_read_abort(sio_fd_t fd);

Required callback function[]

The callback

 void (*linkStatusCB)(void *ctx, int errCode, void *arg)

is called under the following events:

  • Link Terminated. errCode is nonzero, arg is null.
  • sifup (Interface Up).errCode is PPPERR_NONE, and arg is pointer to ppp_addrs structure, which contains IP address.
  • sifdown (Interace Down). errCode is PPPERR_CONNECT, and arg is null.

The errCode can be one of the following

#define PPPERR_NONE      0 /* No error. */
#define PPPERR_PARAM    -1 /* Invalid parameter. */
#define PPPERR_OPEN     -2 /* Unable to open PPP session. */
#define PPPERR_DEVICE   -3 /* Invalid I/O device for PPP. */
#define PPPERR_ALLOC    -4 /* Unable to allocate resources. */
#define PPPERR_USER     -5 /* User interrupt. */
#define PPPERR_CONNECT  -6 /* Connection lost. */
#define PPPERR_AUTHFAIL -7 /* Failed authentication challenge. */
#define PPPERR_PROTOCOL -8 /* Failed to meet protocol. */

The ctx pointer is an optional user defined pointer that is defined as an argument in the call to pppOverSerialOpen, which can point to user defined data.

With no Task Support[]

You need to receive the serial data in your main thread, then from your main thread call

pppos_input(int pd, u_char* data, int len);


Example Task Application code[]

This example shows the initialization of the TCP and PPP threads. It assumes that you will do your socket handling in the context of the main() function.


#include "ppp/ppp.h"

#define PPP_SERIAL_PORT 0

static void linkStatusCB(void* ctx, int errCode, void* arg);
static void tcpip_init_done(void *arg);

int main(void) {
    int connected = 0;
    volatile int setup = 0;
    int pd;
    const char *username = "myuser";
    const char *password = "mypassword";
    
    /* initialise lwIP. This creates a new thread, tcpip_thread, that 
     * communicates with the pppInputThread (see below) */
    tcpip_init(tcpip_init_done, &setup);
    while (!setup) {
        sleep(1);
    }

    /* initialise PPP. This needs to be done only once after boot up, to 
     * initialize global variables, etc. */
    pppInit();

    /* set the method of authentication. Use PPPAUTHTYPE_PAP, or
     * PPPAUTHTYPE_CHAP for more security .
     * If this is not called, the default is PPPAUTHTYPE_NONE. 
     */
    pppSetAuth(PPPAUTHTYPE_ANY, username, password);


    /* call the board specific function that will open the specific serial
     * port hardware, for example, configuring pins, I/Os, UART, USART, 
     * clocks, etc. This function is not part of lwip or ppp.  You need to
     * supply this or find an example for your hardware.
     */ 
     OpenMySerialPortOrUART(PPP_SERIAL_PORT, ...);


    /* call the board specific function that will connect to the modem,
     * ie dialing phone numbers, sending configuration AT commands, etc. 
     * This function is not part of lwip or ppp. You need to supply this
    if (DialOutMyModem(PPP_SERIAL_PORT, ...) != 0) {
       printf("can't dial out");
    } else {
         
    /** Open a new PPP connection using the given I/O device.
     * This initializes the PPP control block but does not
     * attempt to negotiate the LCP session.  
     * Return a new PPP connection descriptor on success or
     * an error code (negative) on failure. 
     * This call creates one new thread per call, to service the particular
     * serial port, serviced by the pppInputThread function.
     */
       pd = pppOverSerialOpen(PPP_SERIAL_PORT, linkStatusCB, &connected);
       if (pd >= 0) {
        // the thread was successfully started.
        while (!connected && timeout(60 seconds)) {
          sleep(100 ms);
        }
        
        if (!timeout) {
            // We are connected on lwIP over PPP!
     
            while (working) {
            /* create some socket connections, 
             * do writes and reads on the sockets, close them, etc */
            }
        }
        /* calling pppClose will end the pppInputThread associated with pd*/
        pppClose(pd);
    }

   // shut down the rest of your hardware.
}

static void tcpip_init_done(void *arg)
{
    if (arg) {
        *((bool *)arg) = 1;
    }
}


static void linkStatusCB(void *ctx, int errCode, void *arg) {
   //DTRACE("ctx = 0x%04X, errCode = %d arg = 0x%04X", ctx, errCode, arg);
   int *connected = (int *) ctx;

   struct ppp_addrs *addrs = arg;


   if (errCode == PPPERR_NONE) {
       /* We are connected */
       *connected = 1;
       syslog(LOG_DEBUG, "ip_addr = %s", inet_ntoa(addrs->our_ipaddr));
       syslog(LOG_DEBUG, "netmask = %s", inet_ntoa(addrs->netmask));
       syslog(LOG_DEBUG, "dns1    = %s", inet_ntoa(addrs->dns1));
       syslog(LOG_DEBUG, "dns2    = %s", inet_ntoa(addrs->dns2));
   } else {
       /* We have lost connection */
   }
}

Debug Support[]

Add this to lwipopts.h

 #define PPP_THREAD_NAME             "ppp"
 #define PPP_THREAD_STACKSIZE    200
 #define PPP_THREAD_PRIO               2

 #define LWIP_DEBUG              1
 #define PPP_DEBUG               LWIP_DBG_ON

PPP support history in lwIP[]

HEAD Unspecified.
1.2 Unspecified.

External references[]

  • RFC 1661 The Point-to-Point Protocol (PPP)

See also:[]

This information is not adequate. We would appreciate if someone can add more information regarding implementation of PPP with RTOS.