からデータを抽出しようとしてstruct sk_buff
いますが、期待する出力が得られません。問題のフレームは 34 バイトです。8 バイト (実験的プロトコル) ヘッダーをラップする 14 バイトのイーサネット ヘッダー:
struct monitoring_hdr {
u8 version;
u8 type;
u8 reserved;
u8 haddr_len;
u32 clock;
} __packed;
このヘッダーの後に、2 つの可変長ハードウェア アドレスがあります (それらの長さはhaddr_len
上記のフィールドによって決まります)。この例では、両方とも 6 バイト長です。
次のコードは、ヘッダー (構造体) を正しく抽出しますが、後続の 2 つの 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
実際の出力:
ただし、受信したデータは 2 バイト左にシフトされます。
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);
...