首页 | 邮件资讯 | 技术教程 | 解决方案 | 产品评测 | 邮件人才 | 邮件博客 | 邮件系统论坛 | 软件下载 | 邮件周刊 | 热点专题 | 工具
网络技术 | 操作系统 | 邮件系统 | 客户端 | 电子邮箱 | 反垃圾邮件 | 邮件安全 | 邮件营销 | 移动电邮 | 邮件软件下载 | 电子书下载

操作系统

Windows 9X | Linux&Uinx | Windows Server | 其它操作系统 | Vista | FreeBSD | Windows 7 |
首页 > 操作系统 > Linux&Uinx > Linux系统内核接收以太帧的处理程序 > 正文

Linux系统内核接收以太帧的处理程序

出处:5DMail.Net收集整理 作者:请作者联系 时间:2007-2-14 14:29:35

1. 前言

以太头中除了6字节目的MAC地址、6字节源MAC地址外,还有两字节的以太帧类型值,如IPv4为0x0800,ARP为0x0806等,网卡驱动收到以太帧后通过接口函数netif_receive_skb()(netif_rx实际最后也是调用netif_receive_skb)交到上层,而这个接口函数就完成对以太帧类型的区分,交到不同的协议处理程序。如果想自己编写某一以太类型帧的处理程序,需要自己添加相应的代码。以下为Linux内核2.6代码。

2. 数据结构

每种协议都要定义一个packet_type结构,引导进入相关的协议数据处理函数,所有节点组成一个链表(HASH链表)。


/* include/linux/netdevice.h */
struct packet_type {
__be16 type; /* This is really htons(ether_type). */
struct net_device *dev; /* NULL is wildcarded here */
int (*func) (struct sk_buff *,
struct net_device *,
struct packet_type *,
struct net_device *);
void *af_packet_priv;
struct list_head list;
            };

参数说明:

type:以太帧类型,16位。

dev:所附着的网卡设备,如果为NULL则匹配全部网卡。

func:协议入口接收处理函数。

af_packet_priv:协议私有数据。

list:链表扣。

一般各协议的packet_type结构都是静态存在,初始化时只提供type和func两个参数就可以了,每个协议在初始化时都要将此结构加入到系统类型链表中。

3. 处理函数

3.1 添加节点

/* net/core/dev.c */
/**
* dev_add_pack - add packet handler
* @pt: packet type declaration
*
* Add a protocol handler to the networking stack. The passed &packet_type
* is linked into kernel lists and may not be freed until it has been
* removed from the kernel lists.
*
* This call does not sleep therefore it can not 
* guarantee all CPU's that are in middle of receiving packets
* will see the new packet type (until the next received packet).
*/
void dev_add_pack(struct packet_type *pt)
{
int hash;
spin_lock_bh(&ptype_lock);
// 如果类型是全部以太类型,则节点链接到ptype_all链
if (pt->type == htons(ETH_P_ALL)) {
netdev_nit++;
list_add_rcu(&pt->list, &ptype_all);
} else {
// 根据协议类型取个HASH,共15个HASH链表
hash = ntohs(pt->type) & 15;
// 将节点链接到HASH链表中,list_add_rcu是加了smp_wmb()保护的list_add链表操作
list_add_rcu(&pt->list, &ptype_base[hash]);
}
spin_unlock_bh(&ptype_lock);
            }

3.2 删除节点


/**
* __dev_remove_pack - remove packet handler
* @pt: packet type declaration
*
* Remove a protocol handler that was previously added to the kernel
* protocol handlers by dev_add_pack(). The passed &packet_type is removed
* from the kernel lists and can be freed or reused once this function
* returns. 
*
* The packet type might still be in use by receivers
* and must not be freed until after all the CPU's have gone
* through a quiescent state.
*/
void __dev_remove_pack(struct packet_type *pt)
{
struct list_head *head;
struct packet_type *pt1;
spin_lock_bh(&ptype_lock);
// 根据协议类型找是在ptype_all表还是某一HASH链表中
if (pt->type == htons(ETH_P_ALL)) {
netdev_nit--;
head = &ptype_all;
} else
head = &ptype_base[ntohs(pt->type) & 15];
// 直接用地址比对进行查找,而不是类型,因为同一个类型也可能有多个节点
list_for_each_entry(pt1, head, list) {
if (pt == pt1) {
list_del_rcu(&pt->list);
goto out;
}
}
printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
out:
spin_unlock_bh(&ptype_lock);
}
/**
* dev_remove_pack - remove packet handler
* @pt: packet type declaration
*
* Remove a protocol handler that was previously added to the kernel
* protocol handlers by dev_add_pack(). The passed &packet_type is removed
* from the kernel lists and can be freed or reused once this function
* returns.
*
* This call sleeps to guarantee that no CPU is looking at the packet
* type after return.
*/
// 只是__dev_remove_pack()的包裹函数
void dev_remove_pack(struct packet_type *pt)
{
__dev_remove_pack(pt);
synchronize_net();
            }

4. 实例

4.1 IP

/* net/ipv4/af_inet.c */
static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),
.func = ip_rcv, // IP接收数据的入口点
};
static int __init inet_init(void)
{
......
dev_add_pack(&ip_packet_type);
            ......

由于IP协议部分不能作为内核模块,所以是没有卸载函数的,没必要调用dev_remove_pack()函数。

 

4.2 8021q vlan


/* net/8021q/vlan.c */
static struct packet_type vlan_packet_type = {
.type = __constant_htons(ETH_P_8021Q),
.func = vlan_skb_recv, /* VLAN receive method */
};
......
static int __init vlan_proto_init(void)
{
......
dev_add_pack(&vlan_packet_type);
......
static void __exit vlan_cleanup_module(void)
{
......
dev_remove_pack(&vlan_packet_type);
      ......

由于VLAN可为模块方式存在,所以在模块清除函数中要调用dev_remove_pack()。

5. 网络接收

网卡驱动收到数据包构造出skb后,通过接口函数netif_receive_skb()传递到上层进行协议处理分配。

/* net/core/dev.c */
int netif_receive_skb(struct sk_buff *skb)
{
......
// 先查处理所有以太类型的链表各节点
list_for_each_entry_rcu(ptype, &ptype_all, list) {
if (!ptype->dev || ptype->dev == skb->dev) {
if (pt_prev) 
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
......
// 再查指定协议的HASH链表
list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
if (ptype->type == type &&
(!ptype->dev || ptype->dev == skb->dev)) {
if (pt_prev) 
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
......
// 该函数就是调用个协议的接收函数处理该skb包,进入第三层网络层处理
static __inline__ int deliver_skb(struct sk_buff *skb,
struct packet_type *pt_prev,
struct net_device *orig_dev)
{
atomic_inc(&skb->users);
return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
      }

6. 结论

通过链表挂接方式,Linux内核可以很容易的添加各种协议的接收处理函数。

数据流程:

网卡驱动--->netif_rx()--->netif_receive_skb()->deliver_skb()->packet_type.func

相关文章 热门文章
  • 如何在Android系统中使用QQ邮箱Exchange移动终端同步服务?
  • 如何在塞班S60系统中使用QQ邮箱Exchange移动终端同步服务?
  • IMF系统遭黑客攻击 部分电子邮件和文档丢失
  • Powercfg 从命令行控制系统的电源管理
  • 实现微软AD与Domino OA系统的互连互用
  • 邮件系统双雄PK: TurboMail vs Exchange
  • 利用Transporter Suite实现从第3方邮件系统迁移到Exchange 2007
  • 使用远程桌面连接的10大技巧 从Windows XP客户端连接和管理远程系统
  • 监视Windows 7中的系统启动性能
  • TurboMail邮件系统双机热备方案
  • TurboMail免费打造企业级别邮件系统
  • 现代通信系统的革命:Email死了?
  • linux的基本操作(上)
  • Linux系统下应用知识大荟萃
  • GNU GRUB启动管理器
  • 制作基于软盘的Linux系统
  • 网络配置文件快速解读
  • linux的基本操作(下)
  • 剖析Linux系统启动过程
  • DameWare让局域网管理不再繁琐
  • 在Redhat 9下实现双机热备和集群功能
  • LINUX守护进程介绍
  • Redhat advance server 2.1集群的安装与管理
  • Linux必须学会的60个命令-文件处理
  • 自由广告区
     
    最新软件下载
  • SharePoint Server 2010 部署文档
  • Exchange 2010 RTM升级至SP1 教程
  • Exchange 2010 OWA下RBAC实现的组功能...
  • Lync Server 2010 Standard Edition 标..
  • Lync Server 2010 Enterprise Edition...
  • Forefront Endpoint Protection 2010 ...
  • Lync Server 2010 Edge 服务器部署文档
  • 《Exchange 2003专家指南》
  • Mastering Hyper-V Deployment
  • Windows Server 2008 R2 Hyper-V
  • Microsoft Lync Server 2010 Unleashed
  • Windows Server 2008 R2 Unleashed
  • 今日邮件技术文章
  • 腾讯,在创新中演绎互联网“进化论”
  • 华科人 张小龙 (中国第二代程序员 QQ...
  • 微软推出新功能 提高Hotmail密码安全性
  • 快压技巧分享:秒传邮件超大附件
  • 不容忽视的邮件营销数据分析过程中的算..
  • 国内手机邮箱的现状与未来发展——访尚..
  • 易观数据:2011Q2中国手机邮箱市场收入..
  • 穿越时空的爱恋 QQ邮箱音视频及贺卡邮件
  • Hotmail新功能:“我的朋友可能被黑了”
  • 入侵邻居网络发骚扰邮件 美国男子被重..
  • 网易邮箱莫子睿:《非你莫属》招聘多过..
  • 中国电信推广189邮箱绿色账单
  • 最新专题
  • 鸟哥的Linux私房菜之Mail服务器
  • Exchange Server 2010技术专题
  • Windows 7 技术专题
  • Sendmail 邮件系统配置
  • 组建Exchange 2003邮件系统
  • Windows Server 2008 专题
  • ORF 反垃圾邮件系统
  • Exchange Server 2007 专题
  • ISA Server 2006 教程专题
  • Windows Vista 技术专题
  • “黑莓”(BlackBerry)专题
  • Apache James 专题
  • 分类导航
    邮件新闻资讯:
    IT业界 | 邮件服务器 | 邮件趣闻 | 移动电邮
    电子邮箱 | 反垃圾邮件|邮件客户端|网络安全
    行业数据 | 邮件人物 | 网站公告 | 行业法规
    网络技术:
    邮件原理 | 网络协议 | 网络管理 | 传输介质
    线路接入 | 路由接口 | 邮件存储 | 华为3Com
    CISCO技术 | 网络与服务器硬件
    操作系统:
    Windows 9X | Linux&Uinx | Windows NT
    Windows Vista | FreeBSD | 其它操作系统
    邮件服务器:
    程序与开发 | Exchange | Qmail | Postfix
    Sendmail | MDaemon | Domino | Foxmail
    KerioMail | JavaMail | Winwebmail |James
    Merak&VisNetic | CMailServer | WinMail
    金笛邮件系统 | 其它 |
    反垃圾邮件:
    综述| 客户端反垃圾邮件|服务器端反垃圾邮件
    邮件客户端软件:
    Outlook | Foxmail | DreamMail| KooMail
    The bat | 雷鸟 | Eudora |Becky! |Pegasus
    IncrediMail |其它
    电子邮箱: 个人邮箱 | 企业邮箱 |Gmail
    移动电子邮件:服务器 | 客户端 | 技术前沿
    邮件网络安全:
    软件漏洞 | 安全知识 | 病毒公告 |防火墙
    攻防技术 | 病毒查杀| ISA | 数字签名
    邮件营销:
    Email营销 | 网络营销 | 营销技巧 |营销案例
    邮件人才:招聘 | 职场 | 培训 | 指南 | 职场
    解决方案:
    邮件系统|反垃圾邮件 |安全 |移动电邮 |招标
    产品评测:
    邮件系统 |反垃圾邮件 |邮箱 |安全 |客户端
    广告联系 | 合作联系 | 关于我们 | 联系我们 | 繁體中文
    版权所有:邮件技术资讯网©2003-2010 www.5dmail.net, All Rights Reserved
    www.5Dmail.net Web Team   粤ICP备05009143号