Linux kernel 将数据包从IP层传递到设备驱动程序
我试图将一个sk_buff数据包从协议栈的IP层传递到我创建并注册的设备驱动程序。设备驱动程序的代码如下所示:Linux kernel 将数据包从IP层传递到设备驱动程序,linux-kernel,Linux Kernel,我试图将一个sk_buff数据包从协议栈的IP层传递到我创建并注册的设备驱动程序。设备驱动程序的代码如下所示: #include<linux/module.h> #include<linux/netdevice.h> #include<linux/kernel.h> #include<linux/skbuff.h> #include<linux/pci.h> #include<lin
#include<linux/module.h>
#include<linux/netdevice.h>
#include<linux/kernel.h>
#include<linux/skbuff.h>
#include<linux/pci.h>
#include<linux/interrupt.h>
struct net_device *my_dev;
static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
{
printk(KERN_INFO "I got a packet");
return NETDEV_TX_OK;
}
static int veth_open(struct net_device *dev)
{
memcpy(dev->dev_addr, "\0ABCD0", ETH_ALEN);
netif_start_queue(dev);
return 0;
}
int veth_close(struct net_device *dev)
{
printk("releasing mydev\n");
netif_stop_queue(dev);
return 0;
}
int veth_dev_init(struct net_device *dev)
{
printk("initialising\n");
return 0;
}
static struct net_device_ops veth_ops = {
.ndo_init = veth_dev_init,
.ndo_open = veth_open,
.ndo_stop = veth_close,
.ndo_start_xmit = veth_xmit,
};
int veth_init()
{
int ret,i;
my_dev = alloc_netdev(sizeof(struct net_device), "my_dev", ether_setup);
if (my_dev == NULL)
return -ENOMEM;
my_dev->netdev_ops = &veth_ops;
register_netdev(my_dev);
return 0;
}
void veth_exit()
{
unregister_netdev(my_dev);
free_netdev(my_dev);
}
module_init(veth_init);
module_exit(veth_exit);
但是数据包没有通过,当我尝试加载此测试模块时,系统显示致命错误并终止进程。您能给我建议一个解决这个问题的好方法吗?因为您的代码显示您只是将skb分配为
struct sk_buff *skb;
void generate_send()
{
skb=alloc_skb(skb,2);
skb->data[0]='m';//just to check
skb->dev="my_dev";
dev_queue_xmit(skb);
}
因此,无法检查alloc_skb()是否成功分配存储。您只需设置这个(skb)结构的dev和data参数。但是如果您在文件/net/core/dev.c中看到函数dev_queue_xmit()的源代码,您将得到返回值为正值但并不意味着数据包已被传输的结果
因此,首先尝试创建整个数据包作为其UDP/TCP报头、IP报头和协议建议的数据。然后将skb的字段设置为整个新创建的数据包。
现在尝试发送它,您将得到结果
如需参考,请尝试->
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb)
return;
skb_put(skb, len);
skb_push(skb, sizeof(*udph));
skb_reset_transport_header(skb);
udph = udp_hdr(skb);
udph->source = htons(....);
udph->dest = htons(...);
udph->len = htons(udp_len);
udph->check = 0;
udph->check = csum_tcpudp_magic(local_ip,
remote_ip,
udp_len, IPPROTO_UDP,
csum_partial(udph, udp_len, 0));
if (udph->check == 0)
udph->check = CSUM_MANGLED_0;
skb_push(skb, sizeof(*iph));
skb_reset_network_header(skb);
iph = ip_hdr(skb);
/* iph->version = 4; iph->ihl = 5; */
put_unaligned(0x45, (unsigned char *)iph);
iph->tos = 0;
put_unaligned(htons(ip_len), &(iph->tot_len));
iph->id = htons(atomic_inc_return(&ip_ident));
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
put_unaligned(local_ip, &(iph->saddr));
put_unaligned(remote_ip, &(iph->daddr));
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
skb->protocol = eth->h_proto = htons(ETH_P_IP);
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, remote_mac, ETH_ALEN);
skb->dev = dev;
dev_queue_xmit(skb);
根据需要更改字段…是否可以添加代码来检查
dev_queue_xmit
的返回值?它将在出错时返回一个否定代码。也许你可以检查它是否真的在排队等待传输或抛出错误。我已经更改了代码,从数据包传输的位置,dev_get_by_name(&init_net,“my_dev”);现在,紧急错误已被删除,但dev_queue_xmit()返回2,这是网络拥塞消息。现在如何摆脱它,从司机那里接过包裹?我不确定dev_queue_xmit
正是因为这个原因以及其他原因才允许丢弃数据包。我在这方面经验不足。这突出了在操作Linux的skbuff例程时使用它们的重要性。如果你不这样做,内部的内务变量就不能保持理智,你会得到奇怪的bug。
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb)
return;
skb_put(skb, len);
skb_push(skb, sizeof(*udph));
skb_reset_transport_header(skb);
udph = udp_hdr(skb);
udph->source = htons(....);
udph->dest = htons(...);
udph->len = htons(udp_len);
udph->check = 0;
udph->check = csum_tcpudp_magic(local_ip,
remote_ip,
udp_len, IPPROTO_UDP,
csum_partial(udph, udp_len, 0));
if (udph->check == 0)
udph->check = CSUM_MANGLED_0;
skb_push(skb, sizeof(*iph));
skb_reset_network_header(skb);
iph = ip_hdr(skb);
/* iph->version = 4; iph->ihl = 5; */
put_unaligned(0x45, (unsigned char *)iph);
iph->tos = 0;
put_unaligned(htons(ip_len), &(iph->tot_len));
iph->id = htons(atomic_inc_return(&ip_ident));
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
put_unaligned(local_ip, &(iph->saddr));
put_unaligned(remote_ip, &(iph->daddr));
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
skb->protocol = eth->h_proto = htons(ETH_P_IP);
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, remote_mac, ETH_ALEN);
skb->dev = dev;
dev_queue_xmit(skb);