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 Edit
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 Edit
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 Edit
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 topppOverSerialOpen
, which can point to user defined data.
With no Task Support Edit
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 Edit
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);
int main(void) {
int connected = 0;
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 Edit
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 lwIPEdit
HEAD | Unspecified. |
1.2 | Unspecified. |
External referencesEdit
- RFC 1661 The Point-to-Point Protocol (PPP)
今天的文章lwip分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/4577.html