• 网络设备驱动第二课----框架


    一些接口函数:

    1.创建设备

    /*
    * 功能:创建一个以太网设备对象
    * 输入参数:私有数据大小
    * 返回值:成功:设备句柄     失败:NULL
    */
     struct net_device *alloc_etherdev(sizeof_priv)
    
    /*
    * 功能:创建一个网络设备对象
    * 输入参数:sizeof_priv:私有数据大小
    *          name:网卡名字(名称+%d)
    *          name_assign_type:NET_NAME_UNKNOWN
    *          setup:初始化函数指针(回调函数)
    * 返回值:成功:设备句柄     失败:NULL
    */
    struct net_device *alloc_netdev(sizeof_priv, name,      name_assign_type, setup) ;
    

    2.释放设备对象:

    /*
    * 功能:释放一个网络设备对象
    * 输入参数:设备句柄
    * 返回值:none
    */
    void free_net_devive(struct net_device *dev);

    3.初始化:

    /*
    * 功能:以太网设备初始化
    * 输入参数:设备句柄
    * 返回值:none
    */
    void ether_setup(struct net_device *dev);

    4.注册:

    /*
    * 功能:注册网络设备
    * 输入参数:设备句柄
    * 返回值:成功:0  失败:负数
    */
    int register_netdev(struct net_device *dev);

    5.注销:

    /*
    * 功能:注销网络设备
    * 输入参数:设备句柄
    * 返回值:成功:0  失败:负数
    */
    int unregister_netdevice(struct net_device *dev);

    6.其他通用函数

    提取私有数据

    /*
    * 功能:提取私有数据
    * 输入参数:设备句柄
    * 返回值:成功:私有数据首地址  失败:NULL
    */
    void *netdev_priv(struct net_device *dev)

    设置mac地址

    /*
    * 功能:设置mac地址
    * 输入参数:设备句柄
    *        p:MAC地址所在首地址
    * 返回值:成功:0  失败:负数
    */
    int eth_mac_addr(struct net_device *dev, void *p)
    /*
    * 功能:随机生成mac地址,并将生成的mac地址填充到传入的dev结构体的对应域
    * 输入输出参数:设备句柄
    * 返回值:none
    */
    void eth_hw_addr_random(struct net_device *dev)
    /*
    * 功能:随机生成mac地址
    * 输出参数:addr:将得到的结果放在addr中
    * 返回值:none
    */
    void eth_random_addr(u8 *addr);
    /*
    * 功能:检查mac地址是否有效
    * 输入参数:设备句柄
    * 返回值:有效:1  无效:0
    */
    int eth_validate_addr(struct net_device *dev);

    修改MTU(最大包长)值

    /*
    * 功能:修改MTU值
    * 输入参数:dev:         设备句柄
    *        new_mtu:       新的MTU值(最大包长)
    * 返回值:成功:0  失败:负数
    */
    int eth_change_mtu(struct net_device *dev, int new_mtu);

    开启发送队列

    类比块设备的请求队列记忆,每一个发送请求都是经过调度算法处理后放在发送队列
    中,驱动层的发送回调函数只要从队列中取出任务处理每个发送请求就行。故要响应
    用户层的发送请求就必须开启请求队列。
    
    /*
    * 功能:开启发送队列
    * 输入参数:dev:         设备句柄
    * 返回值:none
    */
    void netif_start_queue(struct net_device *dev)

    关闭发送队列

    /*
    * 功能:关闭发送队列
    * 输入参数:dev:         设备句柄
    * 返回值:none
    */
    void netif_stop_queue(struct net_device *dev)
    

    打开载波调制

    /*
    * 功能:打开载波调制
    * 输入参数:dev:         设备句柄
    * 返回值:none
    */
    void netif_carrier_on(struct net_device *dev)

    关闭载波调制

    /*
    * 功能:关闭载波调制
    * 输入参数:dev:         设备句柄
    * 返回值:none
    */
    void netif_carrier_off(struct net_device *dev)

    套接字缓冲区相关

    至于什么是套接字缓冲区,详见:
    [网络设备中的skbuf](http://blog.csdn.net/u010243305/article/details/53587718)
    
    /*
    * 功能:开辟一块套接字缓冲区
    * 输入参数:unsigned int size:大小
    *         gfp_t priority:   权限
    * 返回值:缓冲区首地址
    */
    struct sk_buff *alloc_skb(unsigned int size, gfp_t priority)
    /*
    * 功能:开辟一块套接字缓冲区
    * 输入参数:  struct net_device dev: 网络设备句柄
    *           unsigned int size:     大小
    * 返回值:缓冲区首地址
    */
    struct sk_buff *netdev_alloc_skb(struct net_device *dev, 
                                     unsigned int length)
    
    /*
    * 功能:释放一块套接字缓冲区
    * 输入参数:  struct sk_buff *skb:缓冲区首地址 
    * 返回值:none
    */
    void kfree_skb(struct sk_buff *skb);
    /*
    * 功能:释放一块套接字缓冲区
    * 输入参数:  struct sk_buff *skb:缓冲区首地址 
    * 返回值:none
    */
    void dev_kfree_skb_any(struct sk_buff *skb);
    /*
    * 功能:tail增大,有效数据区变大
    * 输入参数:  struct sk_buff *skb: 缓冲区首地址 
    *           unsigned int len:    要增大多少
    * 返回值:返回tail指针
    */
    unsigned char *skb_put(struct sk_buff *skb, unsigned int len);
    /*
    * 功能:data下移,有效数据区变小
    * 输入参数:  struct sk_buff *skb: 缓冲区首地址 
    *           unsigned int len:    要下移多少
    * 返回值:返回data指针
    */
    unsigned char *skb_push(struct sk_buff *skb, unsigned int len);
    /*
    * 功能:data下移,tail增大,有效数据区不变
    * 输入参数:  struct sk_buff *skb: 缓冲区首地址 
    *           unsigned int len:    要下移多少
    * 返回值:none
    */
    void skb_reserve(struct sk_buff *skb, int len)

    数据传送相关:

    /*
    * 功能:把sk_buff提交给协议层
    * 输入参数:  struct sk_buff *skb: 缓冲区首地址 
    * 返回值:成功:0(NET_RX_SUCCESS)  失败:1(NET_RX_DROP)
    */
    int netif_rx(struct sk_buff *skb)
    /*
    * 功能:得到协议编号
    * 输入参数:  struct sk_buff *skb:     缓冲区首地址 
    *           struct net_device *dev:  网络设备句柄
    * 返回值:成功:得到的编号  失败:负数
    */
    __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)

    步骤流程:

    1.创建设备对象

    2.初始化

    1.通过回调函数初始化

    2.或者调用内核的函数进行初始化

    3.填充操作方法集并实现其中的函数接口:

    1.打开:

    2.关闭:

    3.发送:

    4.注册

    5.注销

    范例

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    
    #include <linux/netdevice.h>
    #include <linux/etherdevice.h>
    
    #define TRACE() 
        printk(KERN_INFO "%s: %s : %d 
    ", __FILE__, __func__, __LINE__)
    
    static struct net_device *mynetp = NULL;
    //打开设备
    static int mynet_open(struct net_device *dev)
    {
        TRACE();
        /*开启发送队列*/
        netif_start_queue(dev);
        return 0;
    }
    
    //关闭设备
    static int mynet_stop(struct net_device *dev)
    {
        TRACE();
        /*停止发送队列*/
        netif_stop_queue(dev);
        return 0;
    }
    
    //发送数据
    static netdev_tx_t mynet_start_xmit(struct sk_buff *skb, struct net_device *dev)
    {
        TRACE();
        dev->stats.tx_packets++;//已发送的包计数
        return NETDEV_TX_OK;
    }
    
    //超时重发
    static void mynet_tx_timeout(struct net_device *dev)
    {
        TRACE();
    }
    
    struct net_device_stats* mynet_get_stats(struct net_device *dev)
    {
        TRACE();
        return &dev->stats;
    }
    
    
    /*操作方法集*/
    static struct net_device_ops netops = {
        .ndo_open   = mynet_open,
        .ndo_stop   = mynet_stop,
        .ndo_start_xmit = mynet_start_xmit,    //发送
        .ndo_get_stats  = mynet_get_stats,     //状态统计
        .ndo_tx_timeout = mynet_tx_timeout,    //超时重发
        .ndo_change_mtu = eth_change_mtu,      //最大包计数
        .ndo_set_mac_address    = eth_mac_addr,//MAC地址
        .ndo_validate_addr  = eth_validate_addr,//
    };
    
    /*自定义的初始化回调函数*/
    static void mynet_setup(struct net_device *devp)
    {
        TRACE();
        ether_setup(devp);
    }
    
    static int __init mynet_init(void)
    {
        TRACE();
        // 1. alloc net_device
        mynetp = alloc_netdev(0, "sn%d", mynet_setup);   //创建设备对象,并回调初始化函数
        if(!mynetp){
            return -ENOMEM;
        }
    
        // 2. init net_device
        mynetp->netdev_ops = &netops;  //指定操作方法集
        eth_hw_addr_random(mynetp);    //随机分配一个mac地址
        mynetp->watchdog_timeo = msecs_to_jiffies(5000);
    
        // 3. register net_device
        return register_netdev(mynetp);
    }
    
    static void __exit mynet_exit(void)
    {
        // 1. unregister net_device
        unregister_netdev(mynetp);
    
        // 2. free net_device
        free_netdev(mynetp);
        TRACE();
    }
    
    module_init(mynet_init);
    module_exit(mynet_exit);
    
    MODULE_LICENSE("GPL");
    
  • 相关阅读:
    所谓经济现象
    高旻寺德林老和尚开示
    3Delight NSI: A Streamable Render API
    Play vue.js with constant value in SailsJS
    天魔心法之——识人篇
    对国内IoT的展望
    对国内AR产业的预言
    简评某中国工程师嫌疑窃取苹果自动驾驶技术
    评估人类的金三角模型
    Odoo 进销存报表现已开源
  • 原文地址:https://www.cnblogs.com/xxg1992/p/6636405.html
Copyright © 2020-2023  润新知