Linux网络子系统
系统调用接口层:
为应用程序提供访问网络子系统的统一方法。
协议无关层:
提供通用的方法来使用传输层协议,对不同的协议有统一的接口。
协议栈的实现:
实现具体的网络协议。
设备无关层:
协议与设备驱动之前通信的通用接口,对于不同的网络通信设备有统一的接口。
重要的数据结构
网卡描述结构:
在Linux内核中,每个网卡都由一个 net_device结构 来描述,其中的一些重要成员有:
网卡操作集合:
类似于字符设备驱动中的file_operations结构, net_device_ops结构 记录了网卡所支持的操作。
static const struct net_device_ops dm9000_netdev_ops =
{
.ndo_open = dm9000_open,
.ndo_stop = dm9000_stop,
.ndo_start_xmit = dm9000_start_xmit,
.ndo_do_ioctl = dm9000_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
};
网络数据包:
Linux内核中的每个网络数据包都由一个套接字缓冲区结构 struct sk_buff 描述,即一个 sk _ buff 结构就是一个网络包,指向sk_buff 的指针通常被称做skb 。
网卡驱动模型
网卡初始化:
数据发送:
数据接收:
回环网卡驱动设计
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_ether.h> /* For the statistics structure. */
unsigned long bytes = 0;
unsigned long packets = 0;
static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
//数据发送函数,skb是数据包
{
//对于回环网卡,不需要暂停和重启协议栈发送数据,也不需要写入和释放skb
skb->protocol = eth_type_trans(skb,dev);//标明协议
bytes += skb->len;//数据量
packets++; //包的数目
netif_rx(skb); //将包发走
return 0;
}
static struct net_device_stats *loopback_get_stats(struct net_device *dev)
//获取网卡状态信息
{
struct net_device_stats *stats = &dev->stats;
stats->rx_packets = packets;
stats->tx_packets = packets;
stats->rx_bytes = bytes;
stats->tx_bytes = bytes;
return stats;
}
//定义ops结构
static const struct net_device_ops loopback_ops = {
.ndo_start_xmit= loopback_xmit, //发送函数
.ndo_get_stats = loopback_get_stats, //获取网卡状态
};
static void loopback_setup(struct net_device *dev)
//2、初始化net_device结构
{
dev->mtu = (16 * 1024) + 20 + 20 + 12; //网卡能接受的包的最大尺寸,16K数据+tcp头+ip头+以太网头
dev->flags = IFF_LOOPBACK; //回环网卡专有标志
dev->header_ops = ð_header_ops; //构造头的函数,系统已经提供
dev->netdev_ops = &loopback_ops; //回环网卡的操作集
}
/* Setup and register the loopback device. */
static __net_init int loopback_net_init(struct net *net) //入口函数
{
struct net_device *dev;
//1、分配 net_device 结构 2、初始化 net_device 结构
dev = alloc_netdev(0, "lo", loopback_setup);
//3、回环网卡没有硬件结构,不需要初始化硬件
//4、注册网卡驱动
register_netdev(dev);
net->loopback_dev = dev;
return 0;
}
static __net_exit void loopback_net_exit(struct net *net)//出口函数
{
struct net_device *dev = net->loopback_dev;
unregister_netdev(dev); //注销 dev 结构
}
/* Registered in net/core/dev.c */
struct pernet_operations __net_initdata loopback_net_ops =
{
.init = loopback_net_init,
.exit = loopback_net_exit,
};
DM9000网卡驱动设计
参考内核源代码:linux-ok6410\drivers\net\dm9000.c
和 linux-ok6410\drivers\net\dm9000.h
DM9000网卡 数据发送 代码:
//dm9000芯片的发送数据代码
static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
//1、通知协议栈,暂停向驱动发送数据
netif_stop_queue(dev);
//2、将skb中的数据写入寄存器
iow(db, DM9000_TXPLL, skb -> len);
iow(db, DM9000_TXPLH, skb -> len >> 8);
writeb(DM9000_MWCMD, db->io_addr);
(db->outblk)(db->io_data, skb->data, skb->len);
iow(db, DM9000_TCR, TCR_TXREQ);
//3、释放skb
dev_kfree_skb(skb);
//4、通知协议栈继续发送数据,在中断处理函数中写,不在这个函数中
return 0;
}