杰理 SDK 文档中心
首页
首页
  • SDK 概述与快速开始

    • SDK 概览与 AC791N 芯片平台
    • 环境搭建与编译指南
    • 烧录与固件升级
    • 工程结构导览
  • 产品方案应用

    • WiFi 摄像头方案
    • WiFi IPC 可视对讲方案
    • WiFi 故事机方案
    • 扫码枪 HID 方案
    • 开发板示例工程
  • 公共应用组件

    • 语音识别 ASR 引擎
    • LLM 与 AI 语音助手接入
    • 摄像头传感器驱动
    • UI 显示框架与驱动
    • USB 主机与设备栈
    • 文件系统与存储管理
    • 系统服务与外设管理
    • 生产测试与射频工具
  • 蓝牙协议栈

    • 经典蓝牙 BR/EDR
    • BLE 低功耗蓝牙
    • 蓝牙 Mesh 网络
    • 蓝牙扩展协议(RCSP/广播/无线麦克风)
  • WiFi 与网络协议栈

    • WiFi 驱动与网络模式
    • lwIP TCP/IP 协议栈
    • 网络安全与加密库
    • 应用层网络协议
    • 流媒体与音视频传输
    • 云平台接入 SDK
    • P2P 远程访问与设备互联
  • 芯片平台与驱动

    • wl82 平台与硬件加速
    • 外设驱动框架
    • 平台配置与固件打包工具
  • 媒体与音频引擎

    • 音频编解码与音源
    • 音效处理引擎
    • 视频与图像处理
  • 操作系统与运行时

    • 实时操作系统与 POSIX 层
    • C/C++ 运行时库
  • 开发资源与文档

    • 文档与规格书
    • 公共示例工程
    • UI 资源工程与打包
    • SDK 辅助工具与脚本

lwIP TCP/IP 协议栈

杰理 AC79 系列 AIoT SDK 基于 lwIP 2.2.0 构建的 TCP/IP 协议栈移植层,封装了多网络接口(Wi-Fi / 有线以太网 / 蓝牙 / LTE / 扩展无线)的初始化、DHCP、事件回调与 BSD Socket 编程接口,为上层应用提供统一的联网能力。

Purpose and Scope

本页面向 SDK 中的 lwIP TCP/IP 协议栈移植与集成层,涵盖:

  • lwIP 2.2.0 在 AC79 平台上的源码与头文件布局(lib/net/lwip_2_2_0 与 include_lib/net/lwip_2_2_0);
  • 移植层核心文件 LwIP.c 的多 netif 管理与初始化逻辑;
  • 各网络接口驱动(wireless_ethernetif、wired_ethernetif、bt_ethernetif、lte_ethernetif、ext_wireless_ethernetif、wireless_raw_ethernetif);
  • lwipopts.h 的裁剪配置、LWIP_EVENT 事件机制、Socket API 及上层应用模块(NTP、DHCP Server、mSSDP 等)。

不属于本页范围(由同级页面覆盖):Wi-Fi 连接管理、蓝牙协议栈、LTE 模组 AT 指令、HTTP/curl 应用层等,本页仅在其调用 lwIP 接口时提及。

概述(Overview)

lwIP(lightweight IP)是专为嵌入式系统设计的开源 TCP/IP 协议栈,以"小内存占用 + 完整 TCP/IP 功能"为目标。本 SDK 选用 lwIP 2.2.0,并将其移植到 AC79 芯片平台,形成如下关键设计:

  • 多网络接口抽象:同一套协议栈可同时挂载 Wi-Fi、有线以太网(ETH)、蓝牙(BT)、LTE、扩展无线(EXT_WIFI)、无线 RAW 共 6 种 netif,每种接口由 lwip.h 中的宏编号唯一标识(ETH_NETIF=0 … WIFI_RAW_NETIF=5);
  • 静态局域网配置表:每种 netif 对应一份 struct lan_setting,内含 IP、掩码、网关、DHCP 服务器地址与客户端起始地址等参数,编译期即可裁剪(HAVE_*_NETIF 宏);
  • DHCP 超时与事件回调:LwIP.c 内以 100ms 定时器驱动 DHCP 流程,绑定成功/超时通过 LWIP_EVENT 枚举通知上层,应用通过覆盖 weak 符号 xxx_lwip_event_cb 感知网络状态;
  • BSD Socket API:LWIP_SOCKET=1 且 LWIP_COMPAT_SOCKETS=1,应用可直接使用 socket/connect/send/recv 等标准接口;curl 等库通过 USE_LWIPSOCK 直接调用 lwip_init()。

典型使用场景:Wi-Fi 连上 AP 后调用 Init_LwIP(WIFI_NETIF) 获取 IP,再基于 Socket 发起 HTTP/MQTT 连接;BT 网络接口用于手机共享网络;LTE 接口用于蜂窝数据上网。

架构(Architecture)

flowchart TD
    subgraph sg_App["应用层"]
        App["应用任务 (socket 调用)"]
        Curl["curl (USE_LWIPSOCK)"]
    end

    subgraph sg_API["API 层"]
        SockAPI["BSD Socket API<br/>(sockets.c)"]
        NetDB["DNS / netdb"]
    end

    subgraph sg_Core["lwIP 核心"]
        Core["TCP / UDP / IP / ICMP / ARP"]
        NetifCore["netif 抽象层"]
        DHCP["DHCP 客户端"]
        IP6["IPv6 / DHCPv6"]
    end

    subgraph sg_Port["AC79 移植层 (port)"]
        LWIPC["LwIP.c 多 netif 管理"]
        WNetif["wireless_ethernetif"]
        ENetif["wired_ethernetif"]
        BNetif["bt_ethernetif"]
        LNetif["lte_ethernetif"]
        XNetif["ext_wireless_ethernetif"]
        RNetif["wireless_raw_ethernetif"]
        Opts["lwipopts.h / sys_arch.h"]
    end

    subgraph sg_Drv["硬件/驱动层"]
        WiFiDrv["Wi-Fi 驱动"]
        EthDrv["ETH PHY"]
        BtDrv["蓝牙驱动"]
        LteDrv["LTE 模组"]
    end

    App --> SockAPI
    Curl --> SockAPI
    SockAPI --> Core
    NetDB --> Core
    Core --> NetifCore
    NetifCore --> LWIPC
    DHCP --> NetifCore
    IP6 --> NetifCore
    LWIPC --> WNetif
    LWIPC --> ENetif
    LWIPC --> BNetif
    LWIPC --> LNetif
    LWIPC --> XNetif
    LWIPC --> RNetif
    Opts -.->|"编译期裁剪"| Core
    WNetif --> WiFiDrv
    ENetif --> EthDrv
    BNetif --> BtDrv
    LNetif --> LteDrv
    XNetif --> WiFiDrv

架构说明:上层应用(含 curl)只面对 BSD Socket API;协议栈核心(TCP/UDP/IP/ARP)之上由 netif 抽象层屏蔽具体物理介质差异。AC79 移植层 LwIP.c 负责创建并注册 6 种 netif,每种 netif 的 init 函数(如 wireless_ethernetif_init)完成驱动绑定与 MAC/主机名设置。lwipopts.h 在编译期裁剪协议栈功能(如是否启用 Socket、IPv6、窗口缩放),这是嵌入式内存优化的关键手段。sys_arch.h 提供 OS 抽象(信号量、邮箱、线程),使 lwIP 能运行在 RTOS 之上。

核心实现分析

1. 移植层入口:lib/net/lwip_2_2_0/port/LwIP.c

LwIP.c 是整条移植链的枢纽,职责包括:声明 6 种 netif 的 init 函数、维护每接口独立的 struct lan_setting 静态配置、提供 Init_LwIP / lwip_netif_set_up / lwip_netif_set_down / lwip_renew 等对外 API,并以 100ms 周期推进 DHCP 超时检测。

文件顶部通过宏开关决定编译哪些 netif:

#define HAVE_ETH_WIRE_NETIF
#define HAVE_LTE_NETIF
#define HAVE_BT_NETIF
#define HAVE_EXT_WIRELESS_NETIF
#define HAVE_WRIELESS_RAW_NETIF

extern err_t wireless_ethernetif_init(struct netif *netif);
extern err_t ext_wireless_ethernetif_init(struct netif *netif);
extern err_t wired_ethernetif_init(struct netif *netif);
extern err_t bt_ethernetif_init(struct netif *netif);
extern err_t lte_ethernetif_init(struct netif *netif);
extern err_t wireless_raw_ethernetif_init(struct netif *netif);

Source: LwIP.c

这些 err_t xxx_ethernetif_init(struct netif *) 是 lwIP 标准的 netif 初始化回调,分别实现在 port/ 目录下各自的 xxx_ethernetif.c 文件中。LwIP.c 通过 extern 声明引用它们,在运行时把它们注册进 netif_add()。

2. 静态局域网配置表 struct lan_setting

每种网络接口在编译期内置一份默认 IP 配置。结构体定义在 lwip.h:

struct lan_setting {
    u8_t WIRELESS_IP_ADDR0;//无线IP地址
    u8_t WIRELESS_IP_ADDR1;
    u8_t WIRELESS_IP_ADDR2;
    u8_t WIRELESS_IP_ADDR3;

    u8_t WIRELESS_NETMASK0;//无线掩码
    u8_t WIRELESS_NETMASK1;
    u8_t WIRELESS_NETMASK2;
    u8_t WIRELESS_NETMASK3;

    u8_t WIRELESS_GATEWAY0;//无线网关
    u8_t WIRELESS_GATEWAY1;
    u8_t WIRELESS_GATEWAY2;
    u8_t WIRELESS_GATEWAY3;

    u8_t SERVER_IPADDR1;//DHCP服务器地址
    u8_t SERVER_IPADDR2;
    u8_t SERVER_IPADDR3;
    u8_t SERVER_IPADDR4;

    u8_t CLIENT_IPADDR1;//起始IP地址
    u8_t CLIENT_IPADDR2;
    u8_t CLIENT_IPADDR3;
    u8_t CLIENT_IPADDR4;

    u8_t SUB_NET_MASK1;//子网掩码
    u8_t SUB_NET_MASK2;
    u8_t SUB_NET_MASK3;
    u8_t SUB_NET_MASK4;
};

Source: lwip.h

设计意图:字段名虽以 WIRELESS_ 开头,但被所有接口复用——各接口以不同初值填充同一结构。Wi-Fi 与蓝牙默认 192.168.1.1 / 192.168.0.1 网段,有线以太网默认 172.16.109.152,保证多接口共存时网段不冲突;SERVER_IPADDR 与 CLIENT_IPADDR 用于内置 DHCP Server(app/dhcp_srv)的地址池分配。每个接口的实例定义于 LwIP.c,例如:

static struct lan_setting wireless_lan_setting_info = {
    .WIRELESS_IP_ADDR0  = 192,
    .WIRELESS_IP_ADDR1  = 168,
    .WIRELESS_IP_ADDR2  = 1,
    .WIRELESS_IP_ADDR3  = 1,
    .WIRELESS_NETMASK0  = 255,
    .WIRELESS_NETMASK1  = 255,
    .WIRELESS_NETMASK2  = 255,
    .WIRELESS_NETMASK3  = 0,
    .WIRELESS_GATEWAY0  = 192,
    .WIRELESS_GATEWAY1  = 168,
    .WIRELESS_GATEWAY2  = 1,
    .WIRELESS_GATEWAY3  = 1,
    .SERVER_IPADDR1  = 192,
    .SERVER_IPADDR2  = 168,
    .SERVER_IPADDR3  = 1,
    .SERVER_IPADDR4  = 1,
    .CLIENT_IPADDR1  = 192,
    .CLIENT_IPADDR2  = 168,
    .CLIENT_IPADDR3  = 1,
    .CLIENT_IPADDR4  = 101,
    .SUB_NET_MASK1   = 255,
    .SUB_NET_MASK2   = 255,
    .SUB_NET_MASK3   = 255,
    .SUB_NET_MASK4   = 0,
};

Source: LwIP.c

net_get_lan_info(u8_t lwip_netif) 按 netif 编号返回对应配置表,供初始化与 DHCP Server 查询;net_get_netif_handle(u8_t lwip_netif) 返回对应 struct netif * 句柄。

3. 网络接口编号与事件枚举(lwip.h)

#define  ETH_NETIF      (0)
#define  WIFI_NETIF     (1)
#define  BT_NETIF       (2)
#define  LTE_NETIF      (3)
#define  EXT_WIFI_NETIF (4)
#define  WIFI_RAW_NETIF (5)
#define  MAX_NETIF_NUM  (6)

enum LWIP_EVENT {
    LWIP_WIRELESS_DHCP_BOUND_TIMEOUT,
    LWIP_WIRELESS_DHCP_BOUND_SUCC,
    LWIP_WIRE_DHCP_BOUND_TIMEOUT,
    LWIP_WIRE_DHCP_BOUND_SUCC,
    LWIP_LTE_DHCP_BOUND_TIMEOUT,
    LWIP_LTE_DHCP_BOUND_SUCC,
    LWIP_EXT_WIRELESS_DHCP_BOUND_TIMEOUT,
    LWIP_EXT_WIRELESS_DHCP_BOUND_SUCC,
    LWIP_BT_DHCP_BOUND_TIMEOUT,
    LWIP_BT_DHCP_BOUND_SUCC,
    LWIP_IP_GOT_IPV6_SUCC,
};

Source: lwip.h 与 lwip.h

LWIP_EVENT 是移植层向上层广播网络状态的事件集合:每个接口的 DHCP 绑定成功/超时各占两个枚举值,另有一个 IPv6 获取成功事件。事件通过 weak 回调(见下文)分发,应用可选择性覆盖其中任意一个而不影响其它接口。

4. Weak 符号回调:应用层的扩展点

LwIP.c 定义了 5 个 __attribute__((weak)) 回调,默认实现为空函数(返回 0),应用层可定义同名强符号覆盖:

int __attribute__((weak)) lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event)
{
    return 0;
}
int __attribute__((weak)) lte_lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event)
{
    return 0;
}
int __attribute__((weak)) ext_lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event)
{
    return 0;
}
int __attribute__((weak)) eth_lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event)
{
    return 0;
}
int __attribute__((weak)) bt_lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event)
{
    return 0;
}

Source: LwIP.c

同一文件还提供两个 weak 扩展钩子:dns_set_server(unsigned int *dnsserver)(默认填 0x23415679 占位)与 socket_send_but_netif_busy_hook(int s, char type_udp)(网络忙时的发送拦截钩子)。这种"weak 默认 + 强符号覆盖"模式在嵌入式 SDK 中非常常见:既保证链接期无未定义符号,又免去了虚函数表开销。

5. DHCP 驱动与超时机制

LwIP.c 定义了 DHCP_TMR_INTERVAL 100(毫秒)与 dhcp_timeout_msec = 15 * 1000(15 秒),并为 Wi-Fi/ETH/LTE/EXT/BT 各维护一个 xxx_dhcp_timeout_cnt 计数器与 static u8 lwip_static_ip_renew[MAX_NETIF_NUM] 静态 IP 续租标志数组。核心思路是:

  • 调用 lwip_renew(lwip_netif, dhcp) 启动 DHCP(dhcp==1)或静态 IP(dhcp==0);
  • 周期定时(100ms)检查是否超时;超时后若开启 IPV4_ADDR_CONFLICT_DETECT 则进行 IP 冲突检测,并向上层派发 LWIP_*_DHCP_BOUND_TIMEOUT 事件;
  • 绑定成功则派发 LWIP_*_DHCP_BOUND_SUCC,同时 lwip_etharp_cleanup_netif() 清理 ARP 表,防止旧邻居缓存污染新网络。

6. 网络接口驱动(port/*_ethernetif.c)

每种物理介质对应一个 netif 驱动,遵循 lwIP 的 netif->linkoutput / output / init 回调模型。以 bt_ethernetif.c 为例,初始化时会设置接口主机名:

#if LWIP_NETIF_HOSTNAME
    /* Initialize interface hostname */
    netif->hostname = LWIP_LOCAL_HOSTNAME;
#endif

Source: bt_ethernetif.c

lte_ethernetif.c 额外在 LWIP_NETIF_REMOVE_CALLBACK 开启时注册 remove_callback = lte_ethernetif_exit,保证 netif 被移除(如 LTE 模组断线)时能正确释放驱动资源——这是多接口热插拔场景的关键清理路径。各驱动的 linkoutput 最终把 lwIP 的 pbuf 链交给对应硬件驱动(Wi-Fi/ETH PHY/蓝牙/LTE 模组)发送。

7. 编译期裁剪:lwipopts.h

include_lib/net/lwip_2_2_0/lwip/port/lwipopts.h 是 lwIP 的选项配置文件,直接决定协议栈的内存占用与功能集合,关键项:

//开启支持IPV6
#define CONFIG_LWIP_IPV6_ENABLE

#define MULTI_NETIF_SUPPORT             0
#define JL_LWIP                         1
#define LWIP_HAVE_LOOPIF                1
#define LWIP_SOCKET                     1
#define LWIP_COMPAT_SOCKETS             1
#define LWIP_NETCONN                    0
#define LWIP_SO_RCVTIMEO                1
#define LWIP_SO_SNDTIMEO                1
#define LWIP_SO_SNDRCVTIMEO_NONSTANDARD 1
#define LWIP_WND_SCALE                  0
#define TCP_RCV_SCALE                   0
#define DHCPS_UNICAST_ENABLE            0
#define ETHARP_SUPPORT_STATIC_ENTRIES   1
#define DEFAULT_ACCEPTMBOX_SIZE   60
#define DEFAULT_RAW_RECVMBOX_SIZE 61

Source: lwipopts.h

设计权衡:Socket API 开启而 Netconn API 关闭(LWIP_SOCKET=1, LWIP_NETCONN=0),因为上层(curl、MQTT 等)只使用 BSD 风格接口,省去 netconn 层的内存与线程开销;LWIP_COMPAT_SOCKETS=1 让 sockets.h 直接提供 socket/connect 等标准名称;SO_RCVTIMEO/SNDTIMEO 以毫秒 int 形式(非标准模式)提供,便于嵌入式应用设置超时;窗口缩放关闭以节省每连接内存;DEFAULT_ACCEPTMBOX_SIZE=60 保证 listen 积压队列容量。另外提供 lwipopts_bt.h、lwipopts_sfc.h 等变体,供不同产品配置复用。

核心流程(Core Flow)

Wi-Fi 接口联网全流程

以最常见的 Wi-Fi 场景为例,展示从协议栈启动到应用拿到 IP 的完整时序:

sequenceDiagram
    participant App as 应用任务
    participant LWIPC as LwIP.c 移植层
    participant CORE as lwIP 核心 (tcpip)
    participant DRV as Wi-Fi 驱动
    participant AP as AP/路由器 (DHCP Server)

    App->>LWIPC: Init_LwIP(WIFI_NETIF)
    activate LWIPC
    LWIPC->>CORE: lwip_init() / netif_add(wireless_ethernetif_init)
    CORE->>DRV: wireless_ethernetif_init(netif)
    DRV-->>CORE: netif 注册成功 (MAC/hostname)
    LWIPC->>CORE: lwip_renew(WIFI_NETIF, dhcp=1)
    CORE->>AP: DHCP Discover
    AP-->>CORE: DHCP Offer
    CORE->>AP: DHCP Request
    AP-->>CORE: DHCP Ack (绑定 IP)
    CORE->>LWIPC: DHCP 绑定成功
    LWIPC->>App: lwip_event_cb(LWIP_WIRELESS_DHCP_BOUND_SUCC)
    deactivate LWIPC
    App->>CORE: socket()/connect()/send() 业务通信

关键点说明:

  1. Init_LwIP(WIFI_NETIF) 是每个接口的入口,内部保证 lwip_init() 只执行一次(static u8 lwip_inited 防重入);
  2. netif_add() 传入 wireless_ethernetif_init,驱动回调里填充 netif->hwaddr(MAC 来自 netdev_get_mac_addr())、hostname 与 linkoutput;
  3. lwip_renew 选择 DHCP(默认 use_dhcp=1)或静态 IP;DHCP 由 lwIP 的 dhcp_start() 驱动,移植层只负责 100ms 超时轮询;
  4. 绑定结果经 LWIP_EVENT 回调上抛,Wi-Fi 事件走 lwip_event_cb,LTE/EXT/BT/ETH 各有独立回调,避免多接口事件互相干扰。

DHCP 状态机与超时分支

flowchart TD
    Start([lwip_renew]) --> IsDhcp{" dhcp 参数?"}
    IsDhcp -->|"dhcp=0 静态IP"| Static["netif_set_addr 静态配置"]
    IsDhcp -->|"dhcp=1"| DhcpStart["dhcp_start()"]
    DhcpStart --> WaitBound{" 绑定成功? "}
    WaitBound -->|"成功"| Succ["派发 LWIP_*_DHCP_BOUND_SUCC"]
    WaitBound -->|"15s 超时 (100ms 轮询)"| Timeout{"IPV4_ADDR_CONFLICT_DETECT?"}
    Timeout -->|"开启"| Detect["IP 冲突检测<br/>lwip_etharp_cleanup_netif"]
    Timeout -->|"关闭"| Evt["派发 LWIP_*_DHCP_BOUND_TIMEOUT"]
    Succ --> Up["netif 置 up,应用可建连"]
    Detect --> Evt
    Evt --> Retry["应用可重新 lwip_renew 或回退静态 IP"]

DHCP 失败后不会死等:15 秒超时即上报 BOUND_TIMEOUT,应用可自行决定重试、回退静态 IP 或提示用户——这是嵌入式联网"永不阻塞"设计原则的体现。

使用示例(Usage Examples)

示例 1:curl 在 lwIP 上的初始化

curl 通过 USE_LWIPSOCK 宏直接使用 lwIP 的 socket 实现,初始化时调用 lwip_init():

#elif defined(USE_LWIPSOCK)
    lwip_init();
#endif

Source: easy.c

这印证了移植层的完整性:lwIP 的 tcpip 核心可直接被第三方库初始化,LwIP.c 的 Init_LwIP 是更上层的多 netif 封装,二者可独立使用。

示例 2:应用侧初始化与事件订阅(典型调用序列)

基于 lwip.h 导出 API 的典型用法(SDK 上层联网任务的标准模式):

#include "lwip.h"

/* 覆盖 weak 回调,感知网络状态 */
int lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event)
{
    switch (event) {
    case LWIP_WIRELESS_DHCP_BOUND_SUCC:
        /* 已获得 IP,可以开始 socket 通信 */
        break;
    case LWIP_WIRELESS_DHCP_BOUND_TIMEOUT:
        /* 超时,可重试 lwip_renew 或使用静态 IP */
        break;
    default:
        break;
    }
    return 0;
}

/* 联网任务 */
void net_task(void)
{
    Init_LwIP(WIFI_NETIF);          /* 初始化协议栈与 Wi-Fi netif */
    lwip_netif_set_up(WIFI_NETIF);  /* 置 up 接口 */
    lwip_renew(WIFI_NETIF, 1);      /* 启动 DHCP */
    lwip_set_default_netif(WIFI_NETIF); /* 设为默认路由接口 */
}

Sources: lwip.h、LwIP.c

示例 3:查询接口配置

net_get_lan_info() 按接口编号返回配置表,net_get_netif_handle() 返回 netif 句柄,供上层读取 IP/网关:

struct lan_setting *net_get_lan_info(u8_t lwip_netif)
{
    if (lwip_netif == WIFI_NETIF) {
        return &wireless_lan_setting_info;
    }
#ifdef HAVE_WRIELESS_RAW_NETIF
    if (lwip_netif == WIFI_RAW_NETIF) {
        return &wireless_raw_lan_setting_info;
    }
#endif
#ifdef HAVE_EXT_WIRELESS_NETIF
    else if (lwip_netif == EXT_WIFI_NETIF) {
        return &ext_wireless_lan_setting_info;
    }
#endif
    /* ... LTE / ETH / BT 分支同理 ... */
    return NULL;
}

Source: LwIP.c

设计意图:该查询函数把所有配置集中管理,上层拿到 lan_setting 后即可用 IP4_ADDR(&ip, ...) 组装 ip_addr_t,用于静态 IP 回退或 DHCP Server 配置,避免各模块各自维护 IP 常量。

配置选项(Configuration Options)

lwipopts.h 关键宏

选项类型默认值说明
LWIP_SOCKETint1启用 BSD Socket API(sockets.c)
LWIP_COMPAT_SOCKETSint1提供 socket/connect 等标准名称的兼容层
LWIP_NETCONNint0关闭 Netconn API,省内存
LWIP_SO_RCVTIMEO / LWIP_SO_SNDTIMEOint1启用收发超时设置
LWIP_SO_SNDRCVTIMEO_NONSTANDARDint1超时参数用毫秒 int(winsock 风格)而非 timeval
CONFIG_LWIP_IPV6_ENABLE宏开启支持 IPv6(含 DHCPv6)
LWIP_HAVE_LOOPIFint1启用 loopback 接口
MULTI_NETIF_SUPPORTint0多 netif 高级路由支持(默认关)
JL_LWIPint1杰理平台定制标志
LWIP_WND_SCALE / TCP_RCV_SCALEint0 / 0关闭 TCP 窗口缩放
ETHARP_SUPPORT_STATIC_ENTRIESint1ARP 静态表项支持
DHCPS_UNICAST_ENABLEint0DHCP Server 单播应答(默认关)
DEFAULT_ACCEPTMBOX_SIZEint60listen 连接积压邮箱容量
DEFAULT_RAW_RECVMBOX_SIZEint61RAW socket 收包邮箱容量
LWIP_NETIF_HOSTNAMEint1netif 主机名支持(驱动中设置)
LWIP_NETIF_REMOVE_CALLBACKint1netif 移除回调(LTE 驱动使用)

LwIP.c 运行期常量

常量类型默认值说明
DHCP_TMR_INTERVAL宏100 msDHCP 超时轮询周期
dhcp_timeout_msecstatic u3215000 msDHCP 绑定超时阈值
use_dhcpstatic u81以太网接口默认走 DHCP
IPV4_ADDR_CONFLICT_DETECTextern const u8外部定义是否开启 IPv4 地址冲突检测

API 参考(API Reference)

以下 API 由 lwip.h 导出、LwIP.c 实现,是上层与协议栈移植层的主要交互接口。

void Init_LwIP(u8_t lwip_netif)

初始化 lwIP 协议栈并注册指定网络接口。

  • 参数:lwip_netif —— 接口编号,取 ETH_NETIF/WIFI_NETIF/BT_NETIF/LTE_NETIF/EXT_WIFI_NETIF/WIFI_RAW_NETIF。
  • 说明:内部通过 static u8 lwip_inited 保证 lwip_init()(tcpip 核心初始化)全局只执行一次;随后为该接口执行 netif_add() 与默认配置装载(调用 net_get_lan_info 对应表)。
  • 返回:无。重复调用同一接口需先 lwip_netif_set_down 或走 lwip_renew 流程。

void lwip_netif_set_up(u8_t lwip_netif) / void lwip_netif_set_down(u8_t lwip_netif)

置 up / 置 down 指定接口(封装 lwIP 的 netif_set_up / netif_set_down)。

  • 参数:lwip_netif —— 接口编号。
  • 返回:无。置 down 后该接口停止收发;置 up 后恢复,并触发链路状态变化。

void lwip_set_default_netif(u8_t lwip_netif)

将指定接口设为默认路由出口(netif_set_default)。

  • 参数:lwip_netif —— 接口编号。
  • 说明:多接口共存时必须显式指定默认 netif,否则发往外部网络的报文无路由。

void lwip_renew(u8_t lwip_netif, u8_t dhcp)

为接口启动 DHCP(dhcp=1)或应用静态 IP 配置(dhcp=0)。

  • 参数:
    • lwip_netif —— 接口编号;
    • dhcp —— 1 表示 dhcp_start() 动态获取,0 表示用 lan_setting 静态配置(并维护 lwip_static_ip_renew[] 续租标志)。
  • 返回:无。结果通过 LWIP_EVENT 回调异步上报。
  • 相关事件:LWIP_*_DHCP_BOUND_SUCC / LWIP_*_DHCP_BOUND_TIMEOUT。

struct lan_setting *net_get_lan_info(u8_t lwip_netif)

获取指定接口的局域网静态配置表。

  • 参数:lwip_netif —— 接口编号。
  • 返回:指向对应 struct lan_setting 的指针;编号非法或对应 HAVE_*_NETIF 未编译时返回 NULL。

struct netif *net_get_netif_handle(u8_t lwip_netif)

获取指定接口的 lwIP netif 句柄。

  • 参数:lwip_netif —— 接口编号。
  • 返回:struct netif *,可用于直接调用 lwIP 核心 API(如 netif_ip4_addr() 读取 IP)。

事件回调(weak,可覆盖)

int lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event);      /* Wi-Fi / 通用 */
int lte_lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event);  /* LTE */
int ext_lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event);  /* 扩展无线 */
int eth_lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event);  /* 有线以太网 */
int bt_lwip_event_cb(void *lwip_ctx, enum LWIP_EVENT event);   /* 蓝牙 */
int dns_set_server(unsigned int *dnsserver);                   /* DNS 服务器注入 */
int socket_send_but_netif_busy_hook(int s, char type_udp);     /* 忙时发送拦截 */
  • 参数:lwip_ctx —— 协议栈上下文(当前实现传 NULL);event —— LWIP_EVENT 枚举值。
  • 返回:非 0 可被移植层视为已处理(默认实现返回 0)。
  • 设计意图:weak 符号机制让"未覆盖也能链接、覆盖即生效",是嵌入式 C 中零开销的观察者模式。

失败模式、边界情况与并发(Failure Modes, Edge Cases & Concurrency)

DHCP 超时

  • 默认 15 秒未绑定即触发 LWIP_*_DHCP_BOUND_TIMEOUT。上层必须处理该事件(重试 / 静态 IP 回退 / 提示用户),否则设备将长时间无 IP。
  • dhcp_timeout_msec 与 DHCP_TMR_INTERVAL 均为移植层常量,可在不修改 lwIP 核心的前提下调整超时策略。
  • 超时路径会调用 lwip_etharp_cleanup_netif() 清理 ARP 表,避免更换网络后旧邻居表项导致通信失败。

IP 冲突

  • IPV4_ADDR_CONFLICT_DETECT(外部定义,默认在协议栈事件层使能时)在静态 IP / DHCP 场景下做冲突检测,冲突时触发重新获取或上报,防止同一网段内地址重复。

多接口并发与默认路由

  • 最多 6 个 netif 可同时存在,但 MULTI_NETIF_SUPPORT=0,即不启用 lwIP 的多路由表,同一时刻只有 lwip_set_default_netif 指定的接口承载对外路由;应用切换上网通道(如 Wi-Fi → LTE)时必须先 set_down 旧接口再 set_up + set_default 新接口,并重新 lwip_renew。
  • 各接口的 DHCP 超时计数器相互独立,事件回调也按接口拆分(lte_lwip_event_cb 等),避免跨接口事件串扰。

线程与重入

  • lwIP 采用 tcpip 线程 + 邮箱模型,sys_arch.h 提供信号量/邮箱抽象;Socket 调用在应用线程执行,内部经 tcpip_api_call 或锁同步到 tcpip 线程。
  • lwip_init() 由 lwip_inited 标志保护,多任务同时调用 Init_LwIP 时不会重复初始化核心(但接口注册仍需应用侧保证时序)。
  • weak 回调默认实现为纯函数(返回 0),应用覆盖时应注意回调运行在哪个上下文(DHCP 轮询定时器 / 事件线程),避免在回调中做阻塞操作或直接调用 lwIP 非线程安全接口。

资源边界

  • DEFAULT_ACCEPTMBOX_SIZE=60 意味着 listen 积压队列最多约 60 个待 accept 连接,超出后新连接会被拒绝——高并发服务器应用需注意;
  • LWIP_WND_SCALE=0 时 TCP 窗口上限受限(典型 64KB),大带宽传输需评估;
  • 每连接 PCB/pbuf 内存来自 lwIP 内存池,连接数过多会触发 MEMP 分配失败,表现为 connect 返回 ENOMEM,应用应限制并发 socket 数。

性能与运维考量(Performance & Operational Notes)

  • 内存优先的裁剪策略:LWIP_NETCONN=0、窗口缩放关闭、LWIP_COMPAT_SOCKETS=1,在保证 BSD API 兼容性的同时把协议栈 RAM 占用压到最低,适配 AC79 这类资源受限的 SoC。
  • DHCP 轮询开销:100ms 定时器只做计数与超时判断,不阻塞 tcpip 线程,开销可忽略。
  • 默认接口切换是运维热点:切换上网通道时建议先 set_down 再 set_up,并调用 lwip_etharp_cleanup_netif()(移植层已在相关路径处理),否则新链路的首包可能被旧 ARP 缓存拖累。
  • 调试入口:printf.h 已在 LwIP.c 引入,可结合 lwIP 的 LWIP_DEBUG 系列宏(TCP_DEBUG、DHCP_DEBUG 等)输出协议栈内部日志,快速定位丢包/超时问题。

扩展点(Extension Points)

  1. 新增网络接口:在 lwip.h 的 netif 编号表追加宏(MAX_NETIF_NUM 同步 +1),在 LwIP.c 中仿照 HAVE_*_NETIF 增加编译开关、lan_setting 实例与 net_get_lan_info 分支,并实现 xxx_ethernetif_init() 驱动(参考 bt_ethernetif.c / lte_ethernetif.c 模板)。
  2. 自定义事件:在 enum LWIP_EVENT 末尾追加枚举值,在移植层触发点调用对应 weak 回调即可,向后兼容既有事件处理代码。
  3. 协议栈功能裁剪:通过 lwipopts.h 宏按产品需求开关(IPv6、Socket、窗口缩放、DHCP Server 单播等);另有 lwipopts_bt.h、lwipopts_sfc.h 变体可按产品线分别配置。
  4. 应用层协议模块:include_lib/net/lwip_2_2_0/lwip/app/ 提供 NTP 客户端(ntp.h)、DHCP Server(dhcp_srv.h)、mSSDP(mssdp.h)及杰理私有协议 cdp/ctp/dtp,可直接复用;sock_api.h 提供面向业务的任务化 Socket 封装。
  5. 驱动钩子:socket_send_but_netif_busy_hook 允许在 netif 忙时拦截发送,可用于背压控制或缓存策略。

相关链接(Related Links)

  • 源码目录:lib/net/lwip_2_2_0 与 include_lib/net/lwip_2_2_0
  • 移植层主文件:LwIP.c
  • 移植层头文件:lwip.h
  • 协议栈配置:lwipopts.h
  • 应用协议模块:lwip/app/sock_api/sock_api.h、lwip/app/ntp/ntp.h、lwip/app/dhcp_srv/dhcp_srv.h
  • curl 的 lwIP 集成:easy.c
  • 相关同级页面:Wi-Fi 连接管理、蓝牙协议栈、LTE 模组、HTTP/curl 应用层(详见网络目录 5-networking 下其它条目)
Prev
WiFi 驱动与网络模式
Next
网络安全与加密库