`
thecloud
  • 浏览: 882192 次
文章分类
社区版块
存档分类
最新评论

Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)

 
阅读更多

本文分析基于Linux Kernel 1.2.13

原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7549340

更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html

作者:闫明

注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。


上篇分析了应用层经过BSD socket层到INET socket层的函数调用关系和数据的处理流程,INET层会调用具体的传输层协议,还是以UDP协议为例

udp_write()函数

static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
	  unsigned flags)
{
	return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
}

在分析udp_sendto()函数之前,先了解一下sockaddr_in结构,这是标准的网络接口地址结构的定义

struct sockaddr_in {
  short int		sin_family;	/* Address family	地址族	*/
  unsigned short int	sin_port;	/* Port number	端口号		*/
  struct in_addr	sin_addr;	/* Internet address	网络地址	*/

  /* Pad to size of `struct sockaddr'. */
  unsigned char		__pad[__SOCK_SIZE__ - sizeof(short int) -
			sizeof(unsigned short int) - sizeof(struct in_addr)];
};
#define sin_zero	__pad		/* for BSD UNIX comp. -FvK	*/

udp_sentdto()函数

static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
	   unsigned flags, struct sockaddr_in *usin, int addr_len)
{
	struct sockaddr_in sin;
	int tmp;

	/* 
	 *	Check the flags. We support no flags for UDP sending
	 */
	if (flags&~MSG_DONTROUTE) 
	  	return(-EINVAL);
	/*
	 *	Get and verify the address. 
	 */
	 
	if (usin) //如果usin不是空
	{
		if (addr_len < sizeof(sin)) 
			return(-EINVAL);
		memcpy(&sin,usin,sizeof(sin));
		if (sin.sin_family && sin.sin_family != AF_INET)
			return(-EINVAL);
		if (sin.sin_port == 0) 
			return(-EINVAL);
	} 
	else //usin为空
	{
		if (sk->state != TCP_ESTABLISHED) 
			return(-EINVAL);
		sin.sin_family = AF_INET;//协议族
		sin.sin_port = sk->dummy_th.dest;//目的端口
		sin.sin_addr.s_addr = sk->daddr;//目的地址
  	}
  
  	/*
  	 *	BSD socket semantics. You must set SO_BROADCAST to permit
  	 *	broadcasting of data.
  	 */
  	 
  	if(sin.sin_addr.s_addr==INADDR_ANY)//目的地址是全0地址,对应当前主机
  		sin.sin_addr.s_addr=ip_my_addr();//将目的地址设为当前主机的网络地址
  		
  	if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
	    	return -EACCES;			/* Must turn broadcast on first */

	sk->inuse = 1;

	/* Send the packet. */
	tmp = udp_send(sk, &sin, from, len, flags);//调用udp_send()真正的发送数据

	/* The datagram has been sent off.  Release the socket. */
	release_sock(sk);
	return(tmp);
}

udp_send()函数

static int udp_send(struct sock *sk, //要发送的数据包使用的协议对用的sock结构
					   struct sockaddr_in *sin,//目的端的标准的网络接口地址
	 				   unsigned char *from,//要发送的数据所在地址
	 				   int len,//发送数据的长度
	 				   int rt)
{
	struct sk_buff *skb;
	struct device *dev;
	struct udphdr *uh;
	unsigned char *buff;
	unsigned long saddr;
	int size, tmp;
	int ttl;
  
	/* 
	 *	Allocate an sk_buff copy of the packet.
	 */
	 
	size = sk->prot->max_header + len;//计算大小为UDP最长表头+ 数据长度
	skb = sock_alloc_send_skb(sk, size, 0, &tmp);//根据要发送的数据分配sk_buff结构空间并对当前套接字状态检查


	if (skb == NULL) 
		return tmp;

	skb->sk       = NULL;	/* to avoid changing sk->saddr */
	skb->free     = 1;
	skb->localroute = sk->localroute|(rt&MSG_DONTROUTE);

	/*
	 *	Now build the IP and MAC header. 
	 */
	 
	buff = skb->data;//将skb中的数据指针赋值给buff指针
	saddr = sk->saddr;//本地地址
	dev = NULL;
	ttl = sk->ip_ttl;//生存时间
#ifdef CONFIG_IP_MULTICAST
	if (MULTICAST(sin->sin_addr.s_addr))
		ttl = sk->ip_mc_ttl;
#endif
	tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
			&dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,ttl);//调用ip_build_header()创建IP报头和调用ip_send()创建MAC首部

	skb->sk=sk;	/* So memory is freed correctly */
	
	/*
	 *	Unable to put a header on the packet.
	 */
	 		    
	if (tmp < 0 ) 
	{
		sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
		return(tmp);
  	}
  	
	buff += tmp;
	saddr = skb->saddr; /*dev->pa_addr;*/
	skb->len = tmp + sizeof(struct udphdr) + len;	/* len + UDP + IP + MAC */
	skb->dev = dev;
	
	/*
	 *	Fill in the UDP header. 填写UDP的报头
	 */
	 
	uh = (struct udphdr *) buff;
	uh->len = htons(len + sizeof(struct udphdr));//数据包长度
	uh->source = sk->dummy_th.source;//本地端口
	uh->dest = sin->sin_port;//远端端口
	buff = (unsigned char *) (uh + 1);

	/*
	 *	Copy the user data. 
	 */
	 
	memcpy_fromfs(buff, from, len);//复制用户数据

  	/*
  	 *	Set up the UDP checksum. 
  	 */
  	 
	udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);//计算UDP报头的校验和

	/* 
	 *	Send the datagram to the interface. 
	 */
	 
	udp_statistics.UdpOutDatagrams++;
	 
	sk->prot->queue_xmit(sk, dev, skb, 1);//调用IP层函数发送数据
	return(len);
}

这样要发送的数据填充的sk_buff结构中之后再对UDP数据包添加IP数据报头和MAC帧的首部。最后调用IP层的发送函数发送数据包。


分享到:
评论

相关推荐

    Linux内核学习资料

    此Linux内核学习资料包中有Linux内核--网络栈实现分析(二)--数据包的...-网络栈实现分析(五)--传输层之UDP协议(上).pdf Linux内核--网络栈实现分析(一)--网络栈初始化.pdf ,希望对正在学习Linux的各位有所帮助

    嵌入式Linux网络体系结构设计与TCP/IP协议栈.part5

    第2~5章在介绍了实现网络体系结构、协议栈、设备驱动程序的两个最重要的数据结构sk_buff和net_device的基础上,展示了Linux内核中为网络设备驱动程序设计和开发而建立的系统构架,最后以两个实例来具体说明如何着手...

    嵌入式Linux网络体系结构设计与TCP/IP协议栈.part3.rar

    第2~5章在介绍了实现网络体系结构、协议栈、设备驱动程序的两个最重要的数据结构sk_buff和net_device的基础上,展示了Linux内核中为网络设备驱动程序设计和开发而建立的系统构架,最后以两个实例来具体说明如何着手...

    嵌入式Linux网络体系结构设计与TCP/IP协议栈.part4.rar

    第2~5章在介绍了实现网络体系结构、协议栈、设备驱动程序的两个最重要的数据结构sk_buff和net_device的基础上,展示了Linux内核中为网络设备驱动程序设计和开发而建立的系统构架,最后以两个实例来具体说明如何着手...

    嵌入式Linux网络体系结构设计与TCP/IP协议栈.part1

    第2~5章在介绍了实现网络体系结构、协议栈、设备驱动程序的两个最重要的数据结构sk_buff和net_device的基础上,展示了Linux内核中为网络设备驱动程序设计和开发而建立的系统构架,最后以两个实例来具体说明如何着手...

    嵌入式Linux网络体系结构设计与TCP/IP协议栈.part2.rar

    第2~5章在介绍了实现网络体系结构、协议栈、设备驱动程序的两个最重要的数据结构sk_buff和net_device的基础上,展示了Linux内核中为网络设备驱动程序设计和开发而建立的系统构架,最后以两个实例来具体说明如何着手...

    Linux内核:从底层向上分析传输层之UDP协议

    这里看看数据包从IP层是如何交给传输层来处理的,为了方便,这里传输层以UDP协议为例来分析。  从ip_rcv()函数中可以看到  /*  * Pass on the datagram to each protocol that wants it,  * based on the ...

    Linux协议栈阅读笔记

    网络协议栈的实现基本采用TCP/IP的四层架构(链路、网络、传输、应用)。不过在实际学习中通常讲到的是5层架构(物理、链路、网络、传输、应用)。  BSD风格 BSD风格就是通常说的 socket、bind、connect、listen、...

    Linux网络编程 视频 教程

    Linux网络编程(总共41集) 讲解Linux网络编程知识,分以下四个篇章。 Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP...

    linux网络编程-宋敬彬-part1

    1.5.1 Linux内核的主要模块 7 1.5.2 Linux的文件结构 9 1.6 GNU通用公共许可证 10 1.6.1 GPL许可证的历史 10 1.6.2 GPL的自由理念 10 1.6.3 GPL的基本条款 11 1.6.4 关于GPL许可证的争议 12 1.7 Linux...

    C++教程网《Linux网络编程》视频百度云地址

    Linux网络编程(总共41集) 讲解Linux网络编程知识,分以下四个篇章。 Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP...

    [免费]2018年C++教程网的linux网络编程视频百度云下载链接.rar

    Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念...

    c++教程网的linux网络编程视频下载

    Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念...

    Linux防火墙.pdf

     2.3.7 Linux内核IGMP攻击 32  2.4 网络层回应 33  2.4.1 网络层过滤回应 33  2.4.2 网络层阈值回应 33  2.4.3 结合多层的回应 34  第3章 传输层的攻击与防御 35  3.1 使用iptables记录传输层首部 35 ...

    C++教程网视频:linux网络编程

    Linux网络编程(总共41集) 讲解Linux网络编程知识,分以下四个篇章。 Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP...

    linux网络编程

    Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念(对等通信、封装、分用、端口) 02TCPIP基础(二) 最大传输单元(MTU)/路径MTU 以太网帧格式 ICMP ARP RARP 03TCPIP基础...

    2018年C++教程网的linux网络编程视频共41集百度云下载链接.rar

    Linux网络编程(总共41集) 讲解Linux网络编程知识,分以下四个篇章。 Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP基础篇...

    lksctp-rs:Rust 的 Linux 内核 SCTP 低级绑定

    SCTP 是一种传输层协议。 它直接位于 IP 之上,与 TCP、UDP 和其他协议并排。 在许多方面,它是 TCP 的新改进版本,最初是为数字电话的需要而设计的。 特别是,它支持 TCP 支持的所有以下功能: 面向连接 可靠的 ...

    入门学习Linux常用必会60个命令实例详解doc/txt

    虚拟控制台的切换可以通过按下Alt键和一个功能键来实现,通常使用F1-F6 。 例如,用户登录后,按一下“Alt+ F2”键,用户就可以看到上面出现的“login:”提示符,说明用户看到了第二个虚拟控制台。然后只需按“Alt+...

    Linux系统故障诊断与排除--James Kirkland

    13.2.3 诊断传输层(TCP和UDP)问题 314 13.2.4 诊断应用程序级的问题:TCP/IP模型的最后一层 329 13.3 小结 329 第14章 登录问题 330 14.1 /etc/password,/etc/shadow和密码时效 331 14.1.1 /etc/...

Global site tag (gtag.js) - Google Analytics