从结构sk_buff中提取数据 [英] Extracting data from struct sk_buff

查看:712
本文介绍了从结构sk_buff中提取数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从结构的sk_buff 中提取数据,但没有收到我期待的输出。所讨论的帧是34字节;一个14字节的以太网首部周围的8个字节(实验协议)报头包

 结构monitoring_hdr {
    U8版本;
    U8型;
    U8保留;
    U8 haddr_len;    U32时钟;
} __packed;

这个头之后,有两种,可变长度的硬件地址(其长度由 haddr_len 字段上方决定)。在这里的例子中,它们都是6个字节长。

以下code提取头(结构体)正确,但不是说跟着两个MAC地址。

发送方:

  ...
    SKB = alloc_skb(MTU,GFP_ATOMIC);
    如果(不太可能(!SKB))
            返回;
    skb_reserve(SKB,ll_hlen);
    skb_reset_network_header(SKB);
    NWP =(结构monitoring_hdr *)skb_put(SKB,hdr_len);
    在结构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 =(结构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 89 C6 04 2F C0 DF 01 03
0010 | 00 06 D0 BA 8C 88 0E 00 89 6 04 00 2F 90 F5 C6
0020 | 44 5B

第14个字节是以太网报头。下面的8个字节(从 01 和结束 88 )应放入<$ C $字节C>结构monitoring_hdr ,它正确执行。然后,我期待下面的MAC地址为:

  SRC = 00 0E 89 C6 04 2F
DST = 00 90 F5 C6 44 5B

实际输出:

但是,我接收移位两个字节左侧的数据:

  SRC = 8C 88 00 0E 89 C6
DST = 04 2F 00 90 F5 C6

有人能看到上面code逻辑缺陷?还是有更好的方式来做到这一点?我也试过 skb_pull skb_network_header 的接收方,但导致内核崩溃。

感谢您事先的任何帮助。

SOLUTION

的指针数据在的sk_buff 没有被指向的src 作为第一个字节它本来应该。我最终使用以下内容:

  ...
   skb_reset_network_header(SKB);
   NWP =(结构monitoring_hdr *)skb_network_header(SKB);
   skb_pull(SKB,offsetof(结构monitoring_hdr,haddrs_begin));   SRC =&是skb- GT;数据;
   DST = skb_pull(SKB,nwp-&GT; haddr_len);
   ...


解决方案

综观的 skbuff.h中头,您使用的是看起来像这样的功能:

 静态内嵌无效skb_reset_network_header(结构的sk_buff * SKB)
{
        &是skb- GT; network_header =&是skb- GT;数据 - - 是skb- GT;头;
}静态内嵌无符号字符* skb_network_header(常量结构的sk_buff * SKB)
{
        返回&是skb- GT;头+&是skb- GT; network_header;
}的extern unsigned char型* skb_pull(结构的sk_buff * SKB,无符号整型LEN);
静态内嵌无符号字符* __ skb_pull(结构的sk_buff * SKB,无符号整型LEN)
{
        &是skb- GT; LEN - = len个;
        BUG_ON(&是skb- GT; LEN&LT;&是skb- GT; DATA_LEN);
        返回&是skb- GT;数据+ = LEN;
}

因此​​,首先,我会试着打印出是skb-&GT;数据是skb-&GT;头制作确保它们在引用您希望他们包的部分。既然你在这里使用的是自定义协议,也许是在头处理code的一个错误,这是造成是skb-方式&gt;数据来设置不正确

另外,在看的定义sky_network_header skb_pull 让我觉得也许你没有正确使用它们。如果不是第6个字节的地址是在所指向的位置是​​的skb_network_header返回值()?这看起来函数添加报头块的长度的缓冲区的头部,这将导致的指针的第一数据值

同样,它看起来像 skb_pull()添加字段的长度你传递和返回指向下一个字节。所以,你可能要像这样的东西更多:

  SRC = skb_network_header(SKB);
DST = skb_pull(SKB,nwp-&GT; haddr_len);

我希望帮助。对不起,这不是一个确切的答案。

I'm attempting to extract data from a struct sk_buff, but have not received the output I am expecting. The frame in question is 34 bytes; a 14-byte Ethernet header wrapped around an 8-byte (experimental protocol) header:

struct monitoring_hdr {
    u8      version;
    u8      type;
    u8      reserved;
    u8      haddr_len;

    u32     clock;
} __packed;

After this header, there are two, variable-length hardware addresses (their lengths are dictated by the haddr_len field above). In the example here, they are both 6 bytes long.

The following code extracts the header (the struct) correctly, but not the two MAC addresses that follow.

Sender side:

    ...
    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);
    ...

Receiver side:

   ...
   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);
   ...

Expected output:

I used tcpdump to capture the packet in question on the wire, and saw this (it was actually padded to 60 bytes by the sender's NIC, which I've omitted):

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

The first 14 bytes is the Ethernet header. The following 8 bytes (starting with 01 and ending with 88) should be the bytes put into the struct monitoring_hdr, which executes correctly. Then, I am expecting the following MAC addresses to be found:

src = 00 0e c6 89 04 2f
dst = 00 90 f5 c6 44 5b

Actual output:

However, the data that I receive is shifted two bytes to the left:

src = 8c 88 00 0e c6 89
dst = 04 2f 00 90 f5 c6

Can anyone see a logical flaw in above code? Or is there a better way to do this? I've also tried skb_pull in place of skb_network_header on the receiving side, but that resulted in a kernel panic.

Thanks in advance for any help.

SOLUTION:

The pointer to the first byte of the data in the sk_buff was not being pointed to by src as it should have been. I ended up using the following:

   ...
   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);
   ...

解决方案

Looking at the skbuff.h header, the functions you are using look like this:

static inline void skb_reset_network_header(struct sk_buff *skb)
{
        skb->network_header = skb->data - skb->head;
}

static inline unsigned char *skb_network_header(const struct sk_buff *skb)
{
        return skb->head + skb->network_header;
}

extern unsigned char *skb_pull(struct sk_buff *skb, unsigned int len);
static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len)
{
        skb->len -= len;
        BUG_ON(skb->len < skb->data_len);
        return skb->data += len;
}

So first, I would try printing out skb->data and skb->head to make sure they are referencing the parts of the packet you expect them to. Since you are using a custom protocol here, perhaps there is a bug in the header processing code which is causing skb->data to be set incorrectly.

Also, looking at the definitions of sky_network_header and skb_pull makes me think perhaps you are using them incorrectly. Shouldn't the first 6-byte addr be at the location pointed to be the return value of skb_network_header()? It looks like that function adds the length of the header block to the head of the buffer, which should result in a pointer to your first data value.

Similarly, it looks like skb_pull() adds the length of the field you pass in and returns the pointer to the next byte. So you probably want something more like this:

src = skb_network_header(skb);
dst = skb_pull(skb, nwp->haddr_len);

I hope that helps. I'm sorry that this is not an exact answer.

这篇关于从结构sk_buff中提取数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆