本文分析基于Linux Kernel 1.2.13
原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7555870
更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html
作者:闫明
注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。
在博文Linux内核--网络栈实现分析(三)--驱动程序层(链路层)(上)中对网络设备结构,网络设备初始化等函数有了初步认识,并列出了设备的发送和接收函数。
设备接口层会调用函数设备驱动层ei_start_xmit()函数发送数据,这里没有详细分析。
static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
{
int e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv;//取出网卡设备的私有数据,和具体的网卡型号有关,在ethdev_init()函数中已经分配空间
int length, send_length;
unsigned long flags;
/*
* We normally shouldn't be called if dev->tbusy is set, but the
* existing code does anyway. If it has been too long since the
* last Tx, we assume the board has died and kick it.
*/
if (dev->tbusy) { /* Do timeouts, just like the 8003 driver. */
........................................
........................................
}
/* Sending a NULL skb means some higher layer thinks we've missed an
tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
itself. */
if (skb == NULL) {//该条件似乎不会发生,这用于处理内核中的BUG
dev_tint(dev);//发送设备中的所有缓存的数据包
return 0;
}
length = skb->len;
if (skb->len <= 0)
return 0;
save_flags(flags);
cli();
/* Block a timer-based transmit from overlapping. */
if ((set_bit(0, (void*)&dev->tbusy) != 0) || ei_local->irqlock) {
printk("%s: Tx access conflict. irq=%d lock=%d tx1=%d tx2=%d last=%d\n",
dev->name, dev->interrupt, ei_local->irqlock, ei_local->tx1,
ei_local->tx2, ei_local->lasttx);
restore_flags(flags);
return 1;
}
/* Mask interrupts from the ethercard. */
outb(0x00, e8390_base + EN0_IMR);
ei_local->irqlock = 1;
restore_flags(flags);
send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
if (ei_local->pingpong) {
int output_page;
if (ei_local->tx1 == 0) {
output_page = ei_local->tx_start_page;
ei_local->tx1 = send_length;
if (ei_debug && ei_local->tx2 > 0)
printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
dev->name, ei_local->tx2, ei_local->lasttx,
ei_local->txing);
} else if (ei_local->tx2 == 0) {
output_page = ei_local->tx_start_page + 6;
ei_local->tx2 = send_length;
if (ei_debug && ei_local->tx1 > 0)
printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
dev->name, ei_local->tx1, ei_local->lasttx,
ei_local->txing);
} else { /* We should never get here. */
if (ei_debug)
printk("%s: No Tx buffers free. irq=%d tx1=%d tx2=%d last=%d\n",
dev->name, dev->interrupt, ei_local->tx1,
ei_local->tx2, ei_local->lasttx);
ei_local->irqlock = 0;
dev->tbusy = 1;
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
return 1;
}
ei_block_output(dev, length, skb->data, output_page);
if (! ei_local->txing) {
ei_local->txing = 1;
NS8390_trigger_send(dev, send_length, output_page);
dev->trans_start = jiffies;
if (output_page == ei_local->tx_start_page)
ei_local->tx1 = -1, ei_local->lasttx = -1;
else
ei_local->tx2 = -1, ei_local->lasttx = -2;
} else
ei_local->txqueue++;
dev->tbusy = (ei_local->tx1 && ei_local->tx2);
} else { /* No pingpong, just a single Tx buffer. */
ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
ei_local->txing = 1;
NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
dev->trans_start = jiffies;
dev->tbusy = 1;
}
/* Turn 8390 interrupts back on. */
ei_local->irqlock = 0;
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
dev_kfree_skb (skb, FREE_WRITE);
return 0;
其中的dev_tint()函数是将设备的所有缓存队列中的数据全部调用dev_queue_xmit()发送全部数据包。
/*
* This routine is called when an device driver (i.e. an
* interface) is ready to transmit a packet.
*/
//该函数功能:遍历设备的缓冲队列,对所有的数据包调用dev_queue_xmit()函数发送数据
void dev_tint(struct device *dev)
{
int i;
struct sk_buff *skb;
unsigned long flags;
save_flags(flags);
/*
* Work the queues in priority order
*/
for(i = 0;i < DEV_NUMBUFFS; i++)
{
/*
* Pull packets from the queue
*/
cli();
while((skb=skb_dequeue(&dev->buffs[i]))!=NULL)
{
/*
* Stop anyone freeing the buffer while we retransmit it
*/
skb_device_lock(skb);
restore_flags(flags);
/*
* Feed them to the output stage and if it fails
* indicate they re-queue at the front.
*/
dev_queue_xmit(skb,dev,-i - 1);//注意优先级的计算方式,在函数dev_queue_xmit()中优先级若<0则计算pri=-pri-1=-(-i-1)-1=i,
//这样做的目的就是为了得到正确的where值,函数(dev_queue_xmit())中
/*
* If we can take no more then stop here.
*/
if (dev->tbusy)
return;
cli();
}
}
restore_flags(flags);
}
驱动层严格的说不属于内核网络栈的内容,和硬件关系密切,何况这种网卡硬件设备可能已经不用了,这里就没有详细分析,如果对网卡驱动有兴趣可以看一下之前的分析的ARM-Linux下的DM9000网卡驱动的分析,链接如下:
- ARM-Linux驱动--DM9000网卡驱动分析(一)
- ARM-Linux驱动--DM9000网卡驱动分析(二)
- ARM-Linux驱动--DM9000网卡驱动分析(三)
- ARM-Linux驱动--DM9000网卡驱动分析(四)
分享到:
相关推荐
此Linux内核学习资料包中有Linux内核--网络栈实现分析(二)--数据包的传递过程(上).pdf Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上).pdf Linux内核--网络栈实现分析(四)--网络层之IP协议(上)....
具体内容包括网络栈总体架构分析、网络协议头文件分析、BSD socket层实现分析、INET socket层实现分析、网络层实现分析、链路层实现分析、网络设备驱动程序分析、系统网络栈初始化等内容。 本书适合Linux网络开发...
具体内容包括网络栈总体架构分析、网络协议头文件分析、BSD socket 层实现分析、INET socket 层实现分析、网络层实现分析、链路层实现分析、网络设备驱动程序分析、系统网络栈初始化等内容。 本书适合 Linux 网络...
具体内容包括网络栈总体架构分析、网络协议头文件分析、BSDsocket层实现分析、INETsocket层实现分析、网络层实现分析、链路层实现分析、网络设备驱动程序分析、系统网络栈初始化等内容。, 《Linux内核网络栈源代码...
这里我们开始从底层开始详细分析Linux内核网络栈的实现。由于这是早期版本,代码的层次隔离做的还不是很好,这里说是从底层分析,但是不免会牵扯上层或下层的函数,许多关键代码都在驱动的文件夹下。 我们首先有...
Linux内核使用了设备驱动程序来管理设备,提供了灵活的设备管理机制。 安全管理: 安全管理是Linux内核中负责管理系统安全的组件,包括身份验证、访问控制和加密机制。Linux内核使用了各种安全机制来保护系统免受...
Linux内核网络子系统由多个模块组成,包括网络接口卡驱动程序、网络协议栈、套接字接口等。 二、Ping命令的原理和实现 Ping命令是Linux操作系统中的一条基本命令,用于测试网络连接是否正常。Ping命令的原理是...
摘 要:基于对Linux 下蓝牙协议栈BlueZ 源代码的分析,给出BlueZ的组织结构和特点。分析蓝牙USB 传输驱动机制和数据处理过程, 给出实现蓝牙设备驱动的重要数据结构和流程,并总结Linux 下开发蓝牙USB 设备驱动的...
设备驱动程序:分析和理解Linux内核中的设备驱动程序,包括字符设备驱动、块设备驱动、网络设备驱动等。 系统调度:研究Linux内核的进程调度算法和策略,了解进程优先级、调度器运行队列、上下文切换等相关概念。 ...
Linux内核由多个组件组成,包括进程调度器、内存管理单元、文件系统、网络协议栈和设备驱动程序。每个组件都负责特定的任务,共同实现了Linux内核的功能。 Linux内核实现 Linux内核的实现基于C语言,使用了多种...
Linux 网络驱动程序是 Linux 操作系统内核的重要组成部分,对其的掌握有助于理解网络链路层的工作原理。本文将对 Linux 网络驱动程序进行分析,重点介绍其结构、工作原理和关键技术。 1. Linux 网络设备驱动程序的...
深入分析Linux内核源码 前言 第一章 走进linux 1.1 GNU与Linux的成长 1.2 Linux的开发模式和运作机制 1.3走进Linux内核 1.3.1 Linux内核的特征 1.3.2 Linux内核版本的变化 1.4 分析Linux内核的意义 ...
第2~5章在介绍了实现网络体系结构、协议栈、设备驱动程序的两个最重要的数据结构sk_buff和net_device的基础上,展示了Linux内核中为网络设备驱动程序设计和开发而建立的系统构架,最后以两个实例来具体说明如何着手...
第2~5章在介绍了实现网络体系结构、协议栈、设备驱动程序的两个最重要的数据结构sk_buff和net_device的基础上,展示了Linux内核中为网络设备驱动程序设计和开发而建立的系统构架,最后以两个实例来具体说明如何着手...
第2~5章在介绍了实现网络体系结构、协议栈、设备驱动程序的两个最重要的数据结构sk_buff和net_device的基础上,展示了Linux内核中为网络设备驱动程序设计和开发而建立的系统构架,最后以两个实例来具体说明如何着手...
这些驱动程序需要实现网络协议栈、数据传输等功能。 知识点6: Linux 设备管理 Linux 设备管理是和文件系统紧密结合的,各种设备名称都以文件的形式存放在/dev 目录下,称为设备文件,为了管理这些设备,系统为设备...
第2~5章在介绍了实现网络体系结构、协议栈、设备驱动程序的两个最重要的数据结构sk_buff和net_device的基础上,展示了Linux内核中为网络设备驱动程序设计和开发而建立的系统构架,最后以两个实例来具体说明如何着手...
4. HDLC协议栈:HDLC协议栈是指HDLC协议在操作系统中的实现,包括HDLC通信模块和HDLC驱动程序。 本文主要介绍了在Linux操作系统下设计HDLC通道网络设备驱动的方法和过程,并详细介绍了HDLC通信模块的开发和系统优化...
《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关专业学生深入学 习操作系统的参考书。 引用: 目录 第1章 Linux内核学习基础 1 1.1 为什么...
如果CPU接到一个中断,它就会停止一切工作(除非它正在处理一个更重要的中断,在这种情况下要等到更重要的中断处理结束后才会处理这个中断),把相关的参数存储到栈里,然后调用中断处理程序。这意味着在中断处理程序...