lwip

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, 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 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 support history in lwIPEdit

HEADUnspecified.
1.2Unspecified.

External referencesEdit

  • RFC 1661 The Point-to-Point Protocol (PPP)
03-08
### LWIP 网络协议栈概述 LWIP是一种轻量级的TCP/IP协议栈实现,特别适合于资源受限的嵌入式系统环境[^1]。该协议栈不仅体积小巧而且功能完备,支持多种网络通信需求。 #### 主要特点 - **低内存占用**:通过优化设计减少RAM和ROM的需求。 - **可配置性强**:允许开发者根据具体应用场景调整性能参数。 - **模块化架构**:便于集成到不同的操作系统平台之上。 ```c #include "lwip/opt.h" #include "lwip/sys.h" void init_lwip() { lwip_init(); } ``` 这段简单的初始化函数展示了如何启动LWIP协议栈[^4]。 ### 功能组件解析 按照标准四层模型划分: | 层次 | 描述 | |------------|--------------------------------------------------------------| | 应用层 | 提供API给应用程序调用 | | 传输层 | 实现了可靠的(TCP)以及不可靠(UDP)的数据传输服务 | | 网络层 | 处理数据包路由选择 | | 链路层 | 物理连接的具体细节交给了底层硬件处理 | 值得注意的是,在实际部署过程中,链路层通常依赖特定芯片组的支持而不在软件层面直接体现出来[^3]。 ### 使用指南 对于初次接触的人来说,《uC/OS-II 平台下的 LwIP 移植笔记》是一份非常有价值的参考资料,其中包含了详细的理论解释和技术实践案例分析[^2]。这份文档可以帮助理解如何将LWIP适配至不同类型的微控制器上运行。 另外,“野火”的LWIP教程也提供了一系列易于跟随的学习材料,帮助读者快速掌握必要的知识点并完成初步项目构建。 ### 获取源码 官方GitHub仓库地址为[https://github.com/lwip-tcpip/lwip](https://github.com/lwip-tcpip/lwip),这里可以找到最新版本的下载链接以及其他社区贡献者的扩展插件和支持工具集。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值