lwip双网卡移植的问题,以及特殊解决方法。

本文档详细介绍了在产品中移植LWIP轻量级TCP/IP协议栈,从单网卡到双网卡的过程中遇到的问题,包括MAC地址设置、数据包处理、路由选择等,并提供了解决方案,如修改ip_route()函数来适应同一网段的双网卡配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 我公司产品是双网口,原来的程序是自己写的TCP/IP协议栈,因为只是简单实现了ARP和TCP、UDP的最简单情况,所以有时候在公网上会遇到问题。

后来在单网口的产品中移植了LWIP,轻量级TCP/IP协议栈,觉得一定程度上解决了问题,所以双网卡的产品也要用LWIP这个协议栈来实现。这个工作就落到了我的头上。

单网卡的移植我不赘述,只描述从单网卡向双网卡移植过程中遇到的问题以及解决方法。

首先,我看了下单网卡移植中所作的改动。

  • 硬件启动时初始化硬件,调用my_lwip_init(),这个函数中创建任务,添加网卡配置。
  • low_level_init()函数中设置本网卡初始化时MAC地址的设置。
  • low_level_output()函数处理输出信息。
  • low_level_input()函数处理输入信息。
  • ethernetif_input()函数是区分接受到的数据包怎么处理。

由此,可以知道我所需要做的主要改动就是针对这几个函数,及其相关的函数。

  1. 多创建一个netif块,硬件初始化时在mylwip_init()函数中多添加一个netif_add,并调用netif_set_up().
  2. 在low_level_init()中,区分两个网卡的MAC地址并且填充到netif块中。[由此代码可见,硬件mac地址修改后程序必须重新设置netif链表才能正确执行。]
  3. 在low_level_output()中,判断返回的数据是要发送到哪个网卡,将数据拷贝到网卡发送缓冲区,然后发送。
  4. 在low_level_input()中,判断是哪个网卡接受到了数据,并将网卡接受缓冲区中的数据拷贝到netif块的payload数据处。

在进行完这几步骤以后,ping程序已经可以通了,但是出现了一些奇怪的现象,同一个网口竟然能通讯两个Ip地址的内容[在一个网口ping两个网卡都能通],所以又在ethernetif_input()函数中判断加入目标地址是本网卡再进入TCP/IP

<think>嗯,用户想了解STM32F4上使用LwIP库接收原始以太网帧的方法。根据上下文,用户应该正在做嵌入式网络开发,可能遇到了底层驱动的实现问题。从引用内容看,用户已经基本完成了LwIP移植(能编译通过),但驱动实现和原始帧处理还不清楚。用户引用的两段材料很有价值:[^1]详细说明了LwIP移植需要的核心文件和驱动修改点,[^2]则展示了CubeMX生成的LwIP处理流程。特别注意到[^2]中提到MX_LWIP_Process()函数已经包含网线状态检测,但用户更需要的是原始帧接收而非TCP/UDP应用层开发。原始以太网帧接收的关键在于三点:一是驱动层需要跳过LwIP的ARP/IP过滤(修改ethernetif_input函数);二要注册自定义的RAW回调函数;三要注意内存管理和零拷贝优化。考虑到STM32F4的RAM限制,pbuf内存池配置很重要。用户可能忽略了PHY芯片配置细节。根据经验,LAN8720或DP83848这类常用PHY需要正确初始化自适应模式和双工设置,否则可能接收不到巨帧。在引用中提到的low_level_init()里应该增加PHY特殊寄存器的配置。代码示例部分决定重点展示两个核心修改点:一是驱动层解包时跳过链路层类型检查(避免丢弃非IP帧),二是展示自定义的raw_recv()回调如何从pbuf提取完整MAC帧。另外补充了关键配置宏定义,比如ETH_MAX_PACKET_SIZE必须大于1518字节才能支持VLAN标签帧。潜在问题可能是用户没有启用LwIP的RAWAPI支持(默认关闭),因此特别在配置部分强调要定义LWIP_RAW=1。另外考虑到F4系列有硬件CRC校验,代码中刻意保留了FCS字段,这在实际抓包时很有用。</think> 以下是在 STM32F4xx 上基于 LwIP RAW API 接收原始以太网帧的实现步骤和示例: --- ### **核心步骤** 1. **启用 RAW Socket API** 修改 `lwipopts.h` 文件,添加配置: ```c #define LWIP_RAW 1 // 启用 RAW API #define MEMP_NUM_RAW_PCB 4 // RAW PCB 数量 ``` 2. **修改网卡驱动接收逻辑** (`ethernetif.c`) 在 `ethernetif_input()` 中移除 LwIP 的默认过滤,确保原始帧传递到上层: ```c void ethernetif_input(struct netif *netif) { struct pbuf *p; while ((p = low_level_input(netif)) != NULL) { // 跳过链路层类型检查 (如ETHARP、IP等) // 原代码: if (netif->input(p, netif) != ERR_OK) ... // 替换为直接传递原始 pbuf raw_input(p, netif); // 将原始帧送入 RAW 回调 pbuf_free(p); } } ``` 3. **注册 RAW 接收回调** 在初始化代码中创建 RAW PCB 并绑定回调函数: ```c #include "lwip/raw.h" struct raw_pcb *raw_pcb; // 自定义接收回调函数 static uint8_t raw_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) { if (p != NULL) { // 处理原始以太网帧(包含 MAC 头部) uint8_t *data = p->payload; uint16_t len = p->len; // 此处解析帧内容(例如:data[0-5]=目标MAC, data[6-11]=源MAC...) pbuf_free(p); // 释放 pbuf } return 0; // 返回非0表示不释放pbuf(慎用) } // 初始化 RAW PCB void raw_eth_init() { raw_pcb = raw_new(IP_PROTO_RAW); // 创建RAW协议控制块 if (raw_pcb) { raw_bind(raw_pcb, IP_ADDR_ANY); // 绑定任意IP raw_recv(raw_pcb, raw_recv, NULL); // 注册回调 } } ``` --- ### **关键配置说明** 1. **驱动层修改** - 在 `low_level_input()` 中确保 **不剥离 MAC 头部**,`p->payload` 应指向完整以太网帧(包含源/目的MAC、类型字段等)。 - 若需高性能,可使用 **零拷贝接收**:在 DMA 描述符中直接指向 LwIP 的 `pbuf` 结构(需启用 `PBUF_REF` 或 `PBUF_POOL`)。 2. **LwIP 内存配置** (`lwipopts.h`) ```c #define PBUF_POOL_SIZE 24 // 增加pbuf内存池大小(防止丢帧) #define ETH_PAD_SIZE 0 // 禁止LwIP插入填充字节 ``` --- ### **示例代码片段** ```c // 在 main.c 中初始化 int main(void) { // ... 硬件初始化(ETH、PHY等) netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input); netif_set_up(&gnetif); raw_eth_init(); // 注册RAW回调 while (1) { MX_LWIP_Process(); // 调用LwIP轮询处理 } } ``` --- ### **常见问题排查** 1. **帧被丢弃** - 检查 `MEMP_NUM_RAW_PCB` 和 `PBUF_POOL_SIZE` 是否过小。 - 确认驱动层 `low_level_input()` 返回包含 **完整 MAC 头部** 的 `pbuf`(`len ≥ 14`)。 2. **性能优化** - 使用 **DMA 双缓冲** 减少中断延迟。 - 在 `raw_recv()` 中避免阻塞操作,快速释放 `pbuf`。 --- ### **相关配置宏** | 宏定义 | 作用 | |--------------------------|----------------------------------| | `LWIP_RAW` | 启用 RAW API | | `MEMP_NUM_RAW_PCB` | 同时可用的 RAW Socket 数量 | | `PBUF_POOL_SIZE` | pbuf 内存池大小(决定最大帧缓存数)| | `ETH_PAD_SIZE=0` | 禁用 LwIP 自动填充数据对齐 | > **注**:实际工程需根据硬件(如PHY芯片)修改 `low_level_init()` 和中断配置[^1][^2]。 ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值