最简网卡驱动

在内核注册自定义的网卡驱动,并通过打印用户空间和内核的交互数据,可以更深层次的理解网络协议。

驱动代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct net_device *mydev;

static int test_start_xmit(struct sk_buff *skb, struct net_device *dev) {
        print_hex_dump(KERN_NOTICE,"",0,16,1,(void*)skb->data,skb->len,false);
        kfree_skb(skb);
        return NETDEV_TX_OK;
}
static int start(struct net_device *dev) {
        return 0;
}

static int stop (struct net_device *dev) {
        return 0;
}
static void stats(struct net_device *dev, struct rtnl_link_stats64 *storage) {
        printk(KERN_ALERT "get stats\n");
        u64 packets, bytes;

        dev_lstats_read(dev, &packets, &bytes);

        storage->rx_packets = packets;
        storage->tx_packets = packets;
        storage->rx_bytes   = bytes;
        storage->tx_bytes   = bytes;
}
static struct net_device_ops net_dev_ops = {
        .ndo_start_xmit = test_start_xmit,
        .ndo_open = start,
        .ndo_stop = stop,
        .ndo_get_stats64 = stats,
};
void add_myself_netdev(void) {
        int ret;
        mydev = alloc_netdev(0, "pan%d", NET_NAME_UNKNOWN, ether_setup);
        if (!mydev) {
                goto out;
        }
        mydev->netdev_ops = &net_dev_ops;
        ret = register_netdev(mydev);
        if (ret) {
                printk(KERN_ALERT "register failed\n");
                free_netdev(mydev);
        }
out:
        printk(KERN_ALERT "add myself net dev failed\n");
}
EXPORT_SYMBOL(add_myself_netdev);


static int hello_init(void) {
        printk(KERN_ALERT "init fishing\n");
        add_myself_netdev();
        //dump_stack();
        return 0;
}

static void hello_exit(void) {
        unregister_netdev(mydev);
        free_netdev(mydev);
        printk(KERN_ALERT "exit fishing\n");
}
//subsys_initcall(hello_init);
module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("shakespeare");

Makefile文件:

ifneq ($(KERNELRELEASE),)
$(info "2nd")

obj-m := fishing.o

else
#kdir := /lib/modules/$(shell uname -r)/build
kdir := /usr/src/linux-headers-$(shell uname -r)
pwd := $(shell pwd)

all:
        $(info "1st")
        make -C $(kdir) M=$(pwd) modules

clean:
        rm *.ko *.o *.order *.mod.c *.symvers *.mod
endif

安装系统头文件,即可进行编译,然后加载到内核

其中,需要配置ip地址

sudo ip link set pan0 up
sudo ip addr add 192.168.90.1/24 dev pan0

使用该网卡发送数据包

nc -u 192.168.90.12 8080

使用tcpdump抓包

sudo tcpdum -i pan0 -nneX

最简网卡驱动_第1张图片

因为192.168.90.12地址的mac不在arp缓存,所以内核会发送arp广播请求。

通过对比内核打印的skb->data内容和tcpdump抓取的报文可知,skb->data的前12个字节是mac地址,接着的0806是arp协议。

你可能感兴趣的:(arp,netdev,网卡驱动,kernel,网络协议)