一些接口函数:
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(最大包长)值
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 sk_buff *netdev_alloc_skb(struct net_device *dev,
unsigned int length)
void kfree_skb(struct sk_buff *skb);
void dev_kfree_skb_any(struct sk_buff *skb);
unsigned char *skb_put(struct sk_buff *skb, unsigned int len);
unsigned char *skb_push(struct sk_buff *skb, unsigned int len);
void skb_reserve(struct sk_buff *skb, int len)
数据传送相关:
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,
.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();
mynetp = alloc_netdev(0, "sn%d", mynet_setup);
if(!mynetp){
return -ENOMEM;
}
mynetp->netdev_ops = &netops;
eth_hw_addr_random(mynetp);
mynetp->watchdog_timeo = msecs_to_jiffies(5000);
return register_netdev(mynetp);
}
static void __exit mynet_exit(void)
{
unregister_netdev(mynetp);
free_netdev(mynetp);
TRACE();
}
module_init(mynet_init);
module_exit(mynet_exit);
MODULE_LICENSE("GPL");