No edit summary |
Tag: Visual edit |
||
(13 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
− | + | =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() |
+ | 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) |
||
⚫ | |||
+ | |||
+ | 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. |
||
+ | |||
⚫ | |||
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> |
+ | <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 |
||
⚫ | |||
+ | 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. |
+ | * 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 |
||
⚫ | |||
+ | * serial port, serviced by the pppInputThread function. |
||
⚫ | |||
+ | */ |
||
+ | pd = pppOverSerialOpen(PPP_SERIAL_PORT, linkStatusCB, &connected); |
||
⚫ | |||
+ | // the thread was successfully started. |
||
⚫ | |||
+ | sleep(100 ms); |
||
} |
} |
||
− | if (timeout) { |
+ | if (!timeout) { |
− | + | // We are connected on lwIP over PPP! |
|
+ | |||
+ | while (working) { |
||
⚫ | |||
+ | * do writes and reads on the sockets, close them, etc */ |
||
+ | } |
||
} |
} |
||
+ | /* calling pppClose will end the pppInputThread associated with pd*/ |
||
⚫ | |||
} |
} |
||
+ | // shut down the rest of your hardware. |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
} |
} |
||
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, andarg
is pointer toppp_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 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[]
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.