linux网络协议栈分析(五)
2010-07-29 08:48
447 查看
/*#######################################
*
*author Andy Yixin Deng
*Nankai University
*email: andy.yx.deng@gmail.com
*
/*#######################################
本贴为原创,如转载请标明出处!
上回写到了linux发送syn请求的过程,今天以及侦听端收到了syn请求的处理,今天我们写一写连接端收到syn——ack的处理和侦听端口收到了ack的处理过程。
首先开tcp_rcv这个函数中的这样一段代码
这段代码是针对本端是tcp-syn-sent的状态写的。
if(sk->state==TCP_SYN_SENT)
{
/* Crossed SYN or previous junk segment */
if(th->ack)
{
/* We got an ack, but it's not a good ack */
if(!tcp_ack(sk,th,saddr,len))
{
/* Reset the ack - its an ack from a
different connection [ th->rst is checked in tcp_reset()] */
tcp_statistics.TcpAttemptFails++;
tcp_reset(daddr, saddr, th,
sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
if(th->rst)
return tcp_std_reset(sk,skb);
if(!th->syn)
{
/* A valid ack from a different connection
start. Shouldn't happen but cover it */
kfree_skb(skb, FREE_READ);
release_sock(sk);
return 0;
}
/*
* Ok.. it's good. Set up sequence numbers and
* move to established.
*/
syn_ok=1; /* Don't reset this connection for the syn */
sk->acked_seq=th->seq+1;
sk->fin_seq=th->seq;
tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,th,sk->daddr);
tcp_set_state(sk, TCP_ESTABLISHED);//状态变为了建立状态!
tcp_options(sk,th);
sk->dummy_th.dest=th->source;
sk->copied_seq = sk->acked_seq;
if(!sk->dead)
{
sk->state_change(sk);//唤醒睡眠等待的进程
sock_wake_async(sk->socket, 0);
}
if(sk->max_window==0)
{
sk->max_window = 32;
sk->mss = min(sk->max_window, sk->mtu);
}
}
else
{
//如果走进了这个分支说明这个报文是个单纯的syn报文,也就是两段同时建立连接
/* See if SYN's cross. Drop if boring */
if(th->syn && !th->rst)
{
/* Crossed SYN's are fine - but talking to
yourself is right out... */
if(sk->saddr==saddr && sk->daddr==daddr &&
sk->dummy_th.source==th->source &&
sk->dummy_th.dest==th->dest)
{
tcp_statistics.TcpAttemptFails++;
return tcp_std_reset(sk,skb);
}
tcp_set_state(sk,TCP_SYN_RECV);
/*
* FIXME:
* Must send SYN|ACK here
*/
}
/* Discard junk segment */
kfree_skb(skb, FREE_READ);
release_sock(sk);
return 0;
}
/*
* SYN_RECV with data maybe.. drop through
*/
goto rfc_step6;
}
对于tcp-syn-sent状态的socket连接它有两种状态的改变分支
一个分支就是收到了syn-ack,也就是连接建立成功,
一种分支是收到了单纯的syn报文,状态将转移到tcp-syn-recv状态去。
那么上面的分析主要是针对的连接发起方收到了侦听方的两种可能报文的处理,这样我们只要分析连接侦听方收到了ack回应后的处理就可以了
看tcp_rcv这个函数中的一个代码片段
if(th->ack && !tcp_ack(sk,th,saddr,len))
{
/*
* Our three way handshake failed.
*/
if(sk->state==TCP_SYN_RECV)
{
tcp_reset(daddr, saddr, th,sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
return 0;
}
在tcp_ack这个函数中,如果socket的状态是syn-rcv状态的,则将状态转变为tcp-established状态就可以了唤醒睡眠的进程。
*
*author Andy Yixin Deng
*Nankai University
*email: andy.yx.deng@gmail.com
*
/*#######################################
本贴为原创,如转载请标明出处!
上回写到了linux发送syn请求的过程,今天以及侦听端收到了syn请求的处理,今天我们写一写连接端收到syn——ack的处理和侦听端口收到了ack的处理过程。
首先开tcp_rcv这个函数中的这样一段代码
这段代码是针对本端是tcp-syn-sent的状态写的。
if(sk->state==TCP_SYN_SENT)
{
/* Crossed SYN or previous junk segment */
if(th->ack)
{
/* We got an ack, but it's not a good ack */
if(!tcp_ack(sk,th,saddr,len))
{
/* Reset the ack - its an ack from a
different connection [ th->rst is checked in tcp_reset()] */
tcp_statistics.TcpAttemptFails++;
tcp_reset(daddr, saddr, th,
sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
if(th->rst)
return tcp_std_reset(sk,skb);
if(!th->syn)
{
/* A valid ack from a different connection
start. Shouldn't happen but cover it */
kfree_skb(skb, FREE_READ);
release_sock(sk);
return 0;
}
/*
* Ok.. it's good. Set up sequence numbers and
* move to established.
*/
syn_ok=1; /* Don't reset this connection for the syn */
sk->acked_seq=th->seq+1;
sk->fin_seq=th->seq;
tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,th,sk->daddr);
tcp_set_state(sk, TCP_ESTABLISHED);//状态变为了建立状态!
tcp_options(sk,th);
sk->dummy_th.dest=th->source;
sk->copied_seq = sk->acked_seq;
if(!sk->dead)
{
sk->state_change(sk);//唤醒睡眠等待的进程
sock_wake_async(sk->socket, 0);
}
if(sk->max_window==0)
{
sk->max_window = 32;
sk->mss = min(sk->max_window, sk->mtu);
}
}
else
{
//如果走进了这个分支说明这个报文是个单纯的syn报文,也就是两段同时建立连接
/* See if SYN's cross. Drop if boring */
if(th->syn && !th->rst)
{
/* Crossed SYN's are fine - but talking to
yourself is right out... */
if(sk->saddr==saddr && sk->daddr==daddr &&
sk->dummy_th.source==th->source &&
sk->dummy_th.dest==th->dest)
{
tcp_statistics.TcpAttemptFails++;
return tcp_std_reset(sk,skb);
}
tcp_set_state(sk,TCP_SYN_RECV);
/*
* FIXME:
* Must send SYN|ACK here
*/
}
/* Discard junk segment */
kfree_skb(skb, FREE_READ);
release_sock(sk);
return 0;
}
/*
* SYN_RECV with data maybe.. drop through
*/
goto rfc_step6;
}
对于tcp-syn-sent状态的socket连接它有两种状态的改变分支
一个分支就是收到了syn-ack,也就是连接建立成功,
一种分支是收到了单纯的syn报文,状态将转移到tcp-syn-recv状态去。
那么上面的分析主要是针对的连接发起方收到了侦听方的两种可能报文的处理,这样我们只要分析连接侦听方收到了ack回应后的处理就可以了
看tcp_rcv这个函数中的一个代码片段
if(th->ack && !tcp_ack(sk,th,saddr,len))
{
/*
* Our three way handshake failed.
*/
if(sk->state==TCP_SYN_RECV)
{
tcp_reset(daddr, saddr, th,sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
return 0;
}
在tcp_ack这个函数中,如果socket的状态是syn-rcv状态的,则将状态转变为tcp-established状态就可以了唤醒睡眠的进程。
相关文章推荐
- linux网络协议栈分析笔记1-接入部分
- linux网络协议栈内核分析
- linux网络协议栈分析(一)
- Linux网络协议栈分析——从设备驱动到链路层
- [转]Linux网络协议栈分析——从设备驱动到链路层
- 网络配置过程分析(linux网络协议栈笔记)
- linux网络协议栈分析(八)
- linux网络协议栈分析——net_families、inetsw、inetsw_array、inet_protos
- linux网络协议栈分析笔记11-路由1-路由缓存
- LINUX 网络协议栈实现分析-SKBUFF 的实现
- Linux网络协议栈--ip_append_data函数分析
- Linux 网络协议栈开发代码分析篇之VLAN(一)—— vlan 功能模块分析
- linux网络协议栈分析——ioctl的调用流程
- LINUX 网络协议栈实现分析-SKBUFF 的实现
- linux网络协议栈分析笔记3-网桥2
- Linux 网络协议栈开发代码分析篇之VLAN(二)—— Linux下VLAN功能的实现概述
- linux网络协议栈分析——重要数据结构及其关系(socket、sock、sk_buff)
- linux网络协议栈分析笔记12-路由2-FIB1
- linux网络协议栈分析笔记4-网桥3
- Linux 网络协议栈开发代码分析篇之VLAN(三)—— VLAN收发处理