我正在尝试从 a 中提取数据struct sk_buff
,但没有收到我期望的输出。有问题的帧是 34 字节;一个 14 字节的以太网报头包裹着一个 8 字节(实验协议)报头:
struct monitoring_hdr {
u8 version;
u8 type;
u8 reserved;
u8 haddr_len;
u32 clock;
} __packed;
在此标头之后,有两个可变长度的硬件地址(它们的长度由haddr_len
上面的字段决定)。在此处的示例中,它们都是 6 个字节长。
以下代码正确提取了标头(结构),但没有提取后面的两个 MAC 地址。
发送方:
...
skb = alloc_skb(mtu, GFP_ATOMIC);
if (unlikely(!skb))
return;
skb_reserve(skb, ll_hlen);
skb_reset_network_header(skb);
nwp = (struct monitoring_hdr *)skb_put(skb, hdr_len);
/* ... Set up fields in struct monitoring_hdr ... */
memcpy(skb_put(skb, dev->addr_len), src, dev->addr_len);
memcpy(skb_put(skb, dev->addr_len), dst, dev->addr_len);
...
接收方:
...
skb_reset_network_header(skb);
nwp = (struct monitoring_hdr *)skb_network_header(skb);
src = skb_pull(skb, nwp->haddr_len);
dst = skb_pull(skb, nwp->haddr_len);
...
预期输出:
我使用 tcpdump 来捕获线路上的相关数据包,并看到了这一点(它实际上被发送者的 NIC 填充到 60 个字节,我已经省略了):
0000 | 00 90 f5 c6 44 5b 00 0e c6 89 04 2f c0 df 01 03
0010 | 00 06 d0 ba 8c 88 00 0e c6 89 04 2f 00 90 f5 c6
0020 | 44 5b
前 14 个字节是以太网报头。以下 8 个字节(以 开头01
和结尾88
)应该是放入 的字节struct monitoring_hdr
,它可以正确执行。然后,我期望找到以下 MAC 地址:
src = 00 0e c6 89 04 2f
dst = 00 90 f5 c6 44 5b
实际输出:
但是,我收到的数据向左移动了两个字节:
src = 8c 88 00 0e c6 89
dst = 04 2f 00 90 f5 c6
任何人都可以在上面的代码中看到逻辑缺陷吗?还是有更好的方法来做到这一点?我也尝试skb_pull
过代替skb_network_header
接收方,但这导致内核恐慌。
提前感谢您的帮助。
解决方案:
指向 中数据的第一个字节的指针没有像它应该sk_buff
指向的那样被指向。src
我最终使用了以下内容:
...
skb_reset_network_header(skb);
nwp = (struct monitoring_hdr *)skb_network_header(skb);
skb_pull(skb, offsetof(struct monitoring_hdr, haddrs_begin));
src = skb->data;
dst = skb_pull(skb, nwp->haddr_len);
...