Linux内核网络设备驱动程序和skb指针

时间:2013-06-13 13:11:51

标签: linux-kernel linux-device-driver ipv6 icmp

我正在编写网络设备驱动程序 内核2.6.35.12
当设备连接到桥接端口时,设备应该正常工作。

我试图拦截从桥接器转发到接口的ICMPv6 RA和NS消息(路由器/邻居请求)。
eth< - > br0< - > mydevice

在设备start_xmit函数中,我正在做以下操作:

检查以太网报头后的协议字段是否为IPV6(0x86dd)

检查ipv6 next标头是否为ICMPv6并检查其类型:

__u8 nexthdr = ipv6_hdr(skb)->nexthdr;
if (nexthdr == htons (IPPROTO_ICMPV6))
{
   struct icmp6hdr *hdr = icmp6_hdr(skb);
   u8 type = hdr->icmp6_type;
   if(type == htons (NDISC_NEIGHBOUR_SOLICITATION) || type == htons (NDISC_ROUTER_SOLICITATION))
       {
        ….Do something here…
       }
   }

当从设备内发送RS / NS时(例如br0),我看到代码正常工作。

问题是当流量从另一个端口通过网桥转发时。

我看到icmp6_hdr(skb)返回错误的标题 调试一些,似乎是 skb-> network_header和skb-> transport_header指向同一个地方。

icmp6_hdr正在使用transport_header来解释它为什么不正确。

转储skb数据时,它看起来所有的标头和有效负载都处于正确的偏移量(也与tcpdump进行比较)

我怀疑它可能与桥接代码有关,然后再潜入它,

我认为也许有人遇到任何类似或有任何其他想法?

1 个答案:

答案 0 :(得分:0)

部分问题在于你假设Netfilter做了什么,而不仅仅是弄清楚下一个标题是什么。根据我的经验(虽然不是很长)你想做这样的事情:

struct icmp6hdr *icmp6;
// Obviously don't do this unless you check to make sure that it's the right protocol
struct ipv6_hdr *ip6hdr = (struct ipv6_hdr*)skb->network_header;
// You need to move the headers around
// Notice the memory address of skb->data and skb->network_header are the same
// that means that the IP header hasn't been "pulled"
skb->transport_header = skb_pull(skb, sizeof(struct ipv6_hdr));
if(ntohs(ip6hdr->nexthdr) == IPPROTO_ICMPV6) {
    icmp6 = (struct icmp6hdr*)skb->transport_header;
    // Doing this is more efficient, since you only are calling the
    // Network to Host function once
    __u8 type = ntohs(hdr->icmp6_type);
    switch(type) {
    case NDISC_NEIGHBOUR_SOLICITATION:
    case NDISC_ROUTER_SOLICITATION:
         // Do your stuff
         break;
    }
}

希望这很有帮助。我刚刚开始编写Netfilter代码,所以我不完全确定100%,但是当我尝试在NF_IP_LOCAL_IN钩子上尝试使用类似IPv4的东西时,我发现了这一点。