内核网络模块:Ethernet DIX帧填充sk_buff后被识别为Linux cooked帧的解决方法
问题解决:内核模块构建以太网帧被识别为Linux Cooked Capture的修复
问题原因
你编写的代码未正确初始化sk_buff的以太网头部元数据,内核无法识别这是完整的Ethernet DIX帧,因此默认以Linux cooked capture(SLL格式)解析。
修正后的代码
struct sk_buff* skb = netdev_alloc_skb(dev, len); if (!skb) { // 处理内存分配失败 return; } // 预留IP对齐空间(可选,提升性能) skb_reserve(skb, NET_IP_ALIGN); // 将完整以太网帧数据拷贝到skb,skb_put自动扩展数据区 memcpy(skb_put(skb, len), data, len); // 标记以太网头部在skb中的起始位置 skb_set_mac_header(skb, 0); // 自动识别并设置以太网协议类型,也可直接指定如ETH_P_IP skb->protocol = eth_type_trans(skb, dev); // 提交数据包至网络栈 netif_rx(skb);
关键修正点说明
- 移除错误的
skb_reserve(skb, len):原代码中该操作将数据指针后移len字节,后续skb_push又移回,完全无效且破坏了skb的头部空间布局。netdev_alloc_skb已为硬件头部预留了NET_SKB_PAD字节空间,无需额外按帧长度预留。 - 使用
skb_put替代skb_push:skb_put负责扩展skb的数据区并更新tail/len字段,是向skb写入数据的标准方式。 - 设置
mac_header:通过skb_set_mac_header明确告知内核,skb起始位置就是以太网头部,让内核按标准以太网帧格式解析。 - 设置协议类型:
eth_type_trans从以太网帧的类型字段提取协议并赋值给skb->protocol,确保网络栈能正确处理后续的IP/TCP等上层协议。
内容的提问来源于stack exchange,提问作者Artem Dudich
相关产品推荐
相关产品推荐

