饭宝 发表于 2024-8-13 20:11:44

Linux 网络装备驱动

一.网络装备驱动框架 

接收
将报文从装备驱动接受并送入协议栈
https://i-blog.csdnimg.cn/direct/2019142ecdee4103a979d55f0e362f9a.png
老API netif_if
编写网络装备驱动
步调
1.注册一个网络装备
2.填充net_device_ops布局体
3.编写接收发送函数
// SPDX-License-Identifier: GPL-2.0-only
/*
* This module emits "Hello, world" on printk when loaded.
*
* It is designed to be used for basic evaluation of the module loading
* subsystem (for example when validating module signing/verification). It
* lacks any extra dependencies, and will not normally be loaded by the
* system unless explicitly requested by name.
*/


#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>

#include <linux/uaccess.h>
#include <linux/io.h>

#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <linux/if_ether.h>        /* For the statistics structure. */
#include <linux/if_arp.h>        /* For ARPHRD_ETHER */
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/percpu.h>
#include <linux/net_tstamp.h>
#include <net/net_namespace.h>
#include <linux/u64_stats_sync.h>
#include <linux/printk.h>
#include <linux/icmp.h>

#define DEBUG_TEST_NETDEV

#define TEST_NETDEV_NAME "test%d"
#define MAX_JUMBO_FRAME_SIZE         0x3F00

static struct net_device *test_netdev;
#ifdef DEBUG_TEST_NETDEV
static void dump_skb (struct sk_buff * skb)
{
print_hex_dump(KERN_ERR, "data: ", DUMP_PREFIX_OFFSET,
                       16, 1, skb->data, skb->len, true);
return;
}
#endif
static int test_open(struct net_device *dev)
{
        printk("<%s:%d>\n", __FUNCTION__,__LINE__);
        return 0;
}
static int test_close(struct net_device *dev)
{
        printk("<%s:%d>\n", __FUNCTION__,__LINE__);
        return 0;
}
netdev_tx_t        test_xmit_frame(struct sk_buff *skb, struct net_device *dev)
{
        int len;
        struct ethhdr *ethh = eth_hdr(skb);
        struct iphdr *iph = ip_hdr(skb);
        struct icmphdr *icmph = icmp_hdr(skb);
        char mac_tmp;
        __be32 addr_tmp;
        printk("<%s:%d>\n", __FUNCTION__,__LINE__);
       
#ifdef DEBUG_TEST_NETDEV
        dump_skb(skb);
#endif
        memcpy(mac_tmp, ethh->h_source, 6);
        memcpy(ethh->h_source, ethh->h_dest, 6);
        memcpy(ethh->h_dest, mac_tmp, 6);
        addr_tmp = iph->saddr;
        iph->saddr = iph->daddr;
        iph->daddr = addr_tmp;
        icmph->type = 0;
        icmph->checksum = 0;
        icmph->checksum = ip_compute_csum(icmph, iph->tot_len - iph->ihl);
        iph->check = 0;
        iph->check = ip_compute_csum(iph, iph->tot_len);
       
#ifdef DEBUG_TEST_NETDEV
        dump_skb(skb);
#endif
        skb_tx_timestamp(skb);

        /* do not fool net_timestamp_check() with various clock bases */
        skb->tstamp = 0;

        skb_orphan(skb);

        /* Before queueing this packet to netif_rx(),
       * make sure dst is refcounted.
       */
        skb_dst_force(skb);
       
        skb->protocol = eth_type_trans(skb, dev);



        len = skb->len;
       
        if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
                test_netdev->stats.rx_bytes += len;
                test_netdev->stats.tx_bytes += len;
                test_netdev->stats.rx_packets++;
                test_netdev->stats.tx_packets++;
        }
       
        return NETDEV_TX_OK;
}

static void        test_set_rx_mode(struct net_device *dev)
{
        printk("<%s:%d>\n", __FUNCTION__,__LINE__);
        return;
}

static int test_set_mac(struct net_device *dev, void *addr)
{
        struct sockaddr *saddr = addr;
        printk("<%s:%d> mac: %02x:%02x:%02x:%02x:%02x:%02x\n",__FUNCTION__,__LINE__,
                saddr->sa_data,saddr->sa_data,saddr->sa_data,saddr->sa_data,saddr->sa_data,saddr->sa_data);
        memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);
        return 0;
}

static void test_tx_timeout (struct net_device *dev)
{
        printk("<%s:%d>\n", __FUNCTION__,__LINE__);
        return;
}
static int test_change_mtu(struct net_device *dev, int new_mtu)
{
        printk("<%s:%d>: mtu: %d\n", __FUNCTION__,__LINE__, new_mtu);
        return 0;
}
static int test_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{

        printk("<%s:%d> cmd %d\n", __FUNCTION__,__LINE__, cmd);
        return 0;

}
static void test_netpoll(struct net_device *dev)
{
        printk("<%s:%d>\n", __FUNCTION__,__LINE__);
        return;
}
static netdev_features_t test_fix_features(struct net_device *dev, netdev_features_t features)
{
       
        printk("<%s:%d> features %llx\n", __FUNCTION__,__LINE__, dev->features);
        return features;
}
static int test_set_features(struct net_device *dev, netdev_features_t features)
{
        printk("<%s:%d> features %llx\n", __FUNCTION__,__LINE__, features);
        dev->features = features;
        return 1;
}
static void test_change_rx_flags(struct net_device *dev, int flags)
{
        printk("<%s:%d> flags %d\n", __FUNCTION__,__LINE__, flags);
}

static const struct net_device_ops test_netdev_ops = {
        .ndo_open                        = test_open,
        .ndo_stop                        = test_close,
        .ndo_start_xmit                = test_xmit_frame,
        .ndo_set_rx_mode        = test_set_rx_mode,
        .ndo_set_mac_address        = test_set_mac,
        .ndo_tx_timeout                = test_tx_timeout,
        .ndo_change_mtu                = test_change_mtu,
        .ndo_do_ioctl                = test_ioctl,
        .ndo_validate_addr        = eth_validate_addr,

#ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller        = test_netpoll,
#endif
        .ndo_fix_features                = test_fix_features,
        .ndo_set_features                = test_set_features,
           .ndo_change_rx_flags         = test_change_rx_flags,


};


static int __init test_netdev_init(void)
{

       
        int ret = 0;
        pr_warn("init test netdev\n");
        test_netdev = alloc_etherdev(sizeof(struct net_device));
        if (!test_netdev)
                goto out;
        test_netdev->netdev_ops = &test_netdev_ops;
        strcpy(test_netdev->name, TEST_NETDEV_NAME);
        ret = register_netdev(test_netdev);
        if(ret)
                goto failed;
        test_netdev->min_mtu = ETH_ZLEN - ETH_HLEN;
        test_netdev->max_mtu = MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN);
        memset(test_netdev->dev_addr, 0x60, test_netdev->addr_len);
        return 0;
failed:
        free_netdev(test_netdev);
out:
        return 0;
}

module_init(test_netdev_init);

static void __exit test_netdev_exit(void)
{
        pr_warn("exit test netdev\n");
        unregister_netdev(test_netdev);
        free_netdev(test_netdev);

}

module_exit(test_netdev_exit);

MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
MODULE_LICENSE("GPL");
 test0就是我们的驱动
https://i-blog.csdnimg.cn/direct/e56e3a5ffddf46fba170716e08c88a8c.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Linux 网络装备驱动