⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp_recv.c

📁 minux的源代码,一个非常小的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
tcp_recv.c
*/

#include "inet.h"
#include "buf.h"
#include "clock.h"
#include "type.h"

#include "tcp_int.h"
#include "tcp.h"
#include "assert.h"

INIT_PANIC();

FORWARD void create_RST ARGS(( tcp_conn_t *tcp_conn,
	ip_hdr_t *ip_hdr, tcp_hdr_t *tcp_hdr ));
FORWARD void process_data ARGS(( tcp_conn_t *tcp_conn,
	tcp_hdr_t *tcp_hdr, int tcp_hdr_len, acc_t *tcp_data,
	int data_len ));
FORWARD void process_advanced_data ARGS(( tcp_conn_t *tcp_conn,
	tcp_hdr_t *tcp_hdr, int tcp_hdr_len, acc_t *tcp_data,
	int data_len ));
FORWARD acc_t *merge_packs ARGS(( acc_t *first, acc_t *next ));
FORWARD void fd_read ARGS(( tcp_fd_t *tcp_fd ));
FORWARD void switch_read_fd ARGS(( tcp_conn_t *tcp_conn,
	tcp_fd_t *tcp_fd, tcp_fd_t **ref_urg_fd,
	tcp_fd_t **ref_norm_fd ));

PUBLIC void tcp_frag2conn(tcp_conn, ip_pack, tcp_pack)
tcp_conn_t *tcp_conn;
acc_t *ip_pack;
acc_t *tcp_pack;
{
	tcp_fd_t *connuser;
	int tcp_hdr_flags;
	ip_hdr_t *ip_hdr;
	tcp_hdr_t *tcp_hdr;
	int ip_hdr_len, tcp_hdr_len;
	u32_t seg_ack, seg_seq, rcv_hi;
	u16_t data_length, seg_wnd;
	int acceptable_ACK, segm_acceptable;

#if DEBUG & 256
 { where(); printf("tcp_frag2conn(&tcp_conn_table[%d],..) called\n",
	tcp_conn-tcp_conn_table); }
#endif
#if DEBUG & 256
 { where(); printf("tc_connuser= 0x%x\n", tcp_conn->tc_connuser); }
#endif

	ip_pack= bf_packIffLess(ip_pack, IP_MIN_HDR_SIZE);
	ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_pack);
	ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
	if (ip_hdr_len>IP_MIN_HDR_SIZE)
	{
		ip_pack= bf_packIffLess(ip_pack, ip_hdr_len);
		ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_pack);
	}

	tcp_pack= bf_packIffLess(tcp_pack, TCP_MIN_HDR_SIZE);
	tcp_hdr= (tcp_hdr_t *)ptr2acc_data(tcp_pack);
	tcp_hdr_len= (tcp_hdr->th_data_off & TH_DO_MASK) >> 2;
		/* actualy (>> 4) << 2 */
	if (tcp_hdr_len>TCP_MIN_HDR_SIZE)
	{
		tcp_pack= bf_packIffLess(tcp_pack, tcp_hdr_len);
		tcp_hdr= (tcp_hdr_t *)ptr2acc_data(tcp_pack);
	}
	data_length= tcp_hdr->th_chksum-tcp_hdr_len;
		/* th_chksum is used for packet size internally */
	tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK;
	seg_ack= ntohl(tcp_hdr->th_ack_nr);
	seg_seq= ntohl(tcp_hdr->th_seq_nr);
	seg_wnd= ntohs(tcp_hdr->th_window);

	switch (tcp_conn->tc_state)
	{
	case TCS_CLOSED:
/*
CLOSED:
	discard all data.
	!RST ?
		ACK ?
			<SEQ=SEG.ACK><CTL=RST>
			exit
		:
			<SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
			exit
	:
		discard packet
		exit
*/

		if (!(tcp_hdr_flags & THF_RST))
		{
			create_RST (tcp_conn, ip_hdr, tcp_hdr);
			tcp_restart_write(tcp_conn);
		}
		break;
	case TCS_LISTEN:
/*
LISTEN:
	RST ?
		discard packet
		exit
	ACK ?
		<SEQ=SEG.ACK><CTL=RST>
		exit
	SYN ?
		BUG: no security check
		RCV.NXT= SEG.SEQ+1
		IRS= SEG.SEQ
		ISS should already be selected
		<SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
		SND.NXT=ISS+1
		SND.UNA=ISS
		state= SYN-RECEIVED
		exit
	:
		shouldnot occur
		discard packet
		exit
*/
#if DEBUG & 256
 { where(); printf("\n"); }
#endif
		if (tcp_hdr_flags & THF_RST)
			break;
		if (tcp_hdr_flags & THF_ACK)
		{
			create_RST (tcp_conn, ip_hdr, tcp_hdr);
			tcp_restart_write(tcp_conn);
			break;
		}
		if (tcp_hdr_flags & THF_SYN)
		{
			tcp_extract_ipopt(tcp_conn, ip_hdr);
			tcp_extract_tcpopt(tcp_conn, tcp_hdr);
			tcp_conn->tc_RCV_LO= seg_seq+1;
			tcp_conn->tc_RCV_NXT= seg_seq+1;
			tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO+
				tcp_conn->tc_rcv_wnd;
			tcp_conn->tc_RCV_UP= seg_seq;
			tcp_conn->tc_IRS= seg_seq;
			tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;
			tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
			tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS+1;
			tcp_conn->tc_SND_UP= tcp_conn->tc_ISS-1;
			tcp_conn->tc_SND_PSH= tcp_conn->tc_ISS-1;
			tcp_conn->tc_SND_WL1= seg_seq;
			tcp_conn->tc_state= TCS_SYN_RECEIVED;
			tcp_conn->tc_no_retrans= 0;
assert (tcp_check_conn(tcp_conn));
#if DEBUG & 2
 { where(); tcp_write_state(tcp_conn); }
#endif
			tcp_conn->tc_locaddr= ip_hdr->ih_dst;
			tcp_conn->tc_locport= tcp_hdr->th_dstport;
			tcp_conn->tc_remaddr= ip_hdr->ih_src;
			tcp_conn->tc_remport= tcp_hdr->th_srcport;
#if DEBUG & 256
 { where(); printf("calling tcp_restart_write(&tcp_conn_table[%d])\n",
	tcp_conn-tcp_conn_table); }
#endif
			tcp_restart_write(tcp_conn);
			break;
		}
#if DEBUG
 { where(); printf("this shouldn't happen\n"); }
#endif
		break;
	case TCS_SYN_SENT:
/*
SYN-SENT:
	ACK ?
		SEG.ACK <= ISS || SEG.ACK > SND.NXT ?
			RST ?
				discard packet
				exit
			:
				<SEQ=SEG.ACK><CTL=RST>
				exit
		SND.UNA <= SEG.ACK && SEG.ACK <= SND.NXT ?
			ACK is acceptable
		:
			ACK is !acceptable
	:
		ACK is !acceptable
	RST ?
		ACK acceptable ?
			discard segment
			state= CLOSED
			error "connection refused"
			exit
		:
			discard packet
			exit
	BUG: no security check
	SYN ?
		IRS= SEG.SEQ
		RCV.NXT= IRS+1
		ACK ?
			SND.UNA= SEG.ACK
		SND.UNA > ISS ?
			state= ESTABLISHED
			<SEQ=SND.NXT><ACK= RCV.NXT><CTL=ACK>
			process ev. URG and text
			exit
		:
			state= SYN-RECEIVED
			SND.WND= SEG.WND
			SND.WL1= SEG.SEQ
			SND.WL2= SEG.ACK
			<SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
			exit
	:
		discard segment
		exit
*/
		if (tcp_hdr_flags & THF_ACK)
		{
			if (tcp_LEmod4G(seg_ack, tcp_conn->tc_ISS) ||
				tcp_Gmod4G(seg_ack, tcp_conn->tc_SND_NXT))
				if (tcp_hdr_flags & THF_RST)
					break;
				else
				{
					create_RST (tcp_conn, ip_hdr,
						tcp_hdr);
					tcp_restart_write(tcp_conn);
					break;
				}
			acceptable_ACK= (tcp_LEmod4G(tcp_conn->tc_SND_UNA,
				seg_ack) && tcp_LEmod4G(seg_ack,
				tcp_conn->tc_SND_NXT));
		}
		else
			acceptable_ACK= FALSE;
		if (tcp_hdr_flags & THF_RST)
		{
			if (acceptable_ACK)
			{
#if DEBUG & 256
 { where(); printf("calling tcp_close_connection\n"); }
#endif
				tcp_close_connection(tcp_conn,
					ECONNREFUSED);
			}
			break;
		}
		if (tcp_hdr_flags & THF_SYN)
		{
			tcp_conn->tc_RCV_LO= seg_seq+1;
			tcp_conn->tc_RCV_NXT= seg_seq+1;
			tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO +
				tcp_conn->tc_rcv_wnd;
			tcp_conn->tc_RCV_UP= seg_seq;
			tcp_conn->tc_IRS= seg_seq;
			if (tcp_hdr_flags & THF_ACK)
				tcp_conn->tc_SND_UNA= seg_ack;
			if (tcp_Gmod4G(tcp_conn->tc_SND_UNA,
				tcp_conn->tc_ISS))
			{
				tcp_conn->tc_state= TCS_ESTABLISHED;
assert (tcp_check_conn(tcp_conn));
#if DEBUG & 2
 { where(); tcp_write_state(tcp_conn); }
#endif
#if DEBUG & 256
 { where(); printf("ISS= 0x%lx\n", tcp_conn->tc_ISS); }
#endif
assert(tcp_conn->tc_connuser);
				tcp_restart_connect(tcp_conn-> tc_connuser);
				if (tcp_conn->tc_state == TCS_CLOSED)
				{
 { where(); printf("connection closed while inuse\n"); }
					break;
				}
				tcp_conn->tc_flags &= ~TCF_ACK_TIMER_SET;
#if DEBUG & 256
 { where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n", 
	tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
				tcp_conn->tc_flags |= TCF_SEND_ACK;
#if DEBUG & 256
 { where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n", 
	tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
				tcp_restart_write (tcp_conn);
				tcp_frag2conn(tcp_conn, ip_pack, tcp_pack);
				return;
				/* ip_pack and tcp_pack are already
					freed */
			}
			tcp_conn->tc_state= TCS_SYN_RECEIVED;
assert (tcp_check_conn(tcp_conn));
#if DEBUG
 { where(); tcp_write_state(tcp_conn); }
#endif
			tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
			tcp_restart_write(tcp_conn);
		}
		break;
	case TCS_SYN_RECEIVED:
	case TCS_ESTABLISHED:
	case TCS_FIN_WAIT_1:
	case TCS_FIN_WAIT_2:
	case TCS_CLOSE_WAIT:
	case TCS_CLOSING:
	case TCS_LAST_ACK:
	case TCS_TIME_WAIT:
/*
SYN-RECEIVED:
ESTABLISHED:
FIN-WAIT-1:
FIN-WAIT-2:
CLOSE-WAIT:
CLOSING:
LAST-ACK:
TIME-WAIT:
	test if segment is acceptable:
	Segment	Receive	Test
	Length	Window
	0	0	SEG.SEQ == RCV.NXT
	0	>0	RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
	>0	0	not acceptable
	>0	>0	(RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND)
			|| (RCV.NXT <= SEG.SEQ+SEG.LEN-1 &&
			SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND)
	for urgent data: use RCV.WND+URG.WND for RCV.WND
*/
#if DEBUG & 256
 { where(); printf("\n"); }
#endif
		rcv_hi= tcp_conn->tc_RCV_HI;
		if (tcp_hdr_flags & THF_URG)
			rcv_hi= tcp_conn->tc_RCV_LO + tcp_conn->tc_rcv_wnd +
				tcp_conn->tc_urg_wnd;
		if (!data_length)
		{
			if (rcv_hi == tcp_conn->tc_RCV_NXT)
			{
#if DEBUG & 256
 { where(); printf("\n"); }
#endif
				segm_acceptable= (seg_seq == rcv_hi);
#if DEBUG
 if (!segm_acceptable)
 { where(); printf("!segm_acceptable\n"); }
#endif
			}
			else
			{
#if DEBUG & 256
 { where(); printf("\n"); }
#endif
assert (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT));
				segm_acceptable= (tcp_LEmod4G(tcp_conn->
					tc_RCV_NXT, seg_seq) &&
					tcp_Lmod4G(seg_seq, rcv_hi));
#if DEBUG & 256
 if (!segm_acceptable)
 { where(); printf("RCV_NXT= 0x%lx, seg_seq= 0x%lx, rcv_hi= 0x%lx\n",
	tcp_conn->tc_RCV_NXT, seg_seq, rcv_hi); }
#endif
			}
		}
		else
		{
			if (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT))
			{
#if DEBUG & 256
 { where(); printf("RCV_NXT= %lu, rcv_hi= %lu, seg_seq= %lu, data_length= %u\n",
	tcp_conn->tc_RCV_NXT, rcv_hi, seg_seq, data_length); }
#endif
				segm_acceptable= (tcp_LEmod4G(tcp_conn->
					tc_RCV_NXT, seg_seq) &&
					tcp_Lmod4G(seg_seq, rcv_hi)) ||
					(tcp_LEmod4G(tcp_conn->tc_RCV_NXT,
					seg_seq+data_length-1) &&
					tcp_Lmod4G(seg_seq+data_length-1,
					rcv_hi));
#if DEBUG & 256
 if (!segm_acceptable)
 { where(); printf("!segm_acceptable\n"); }
#endif
			}
			else
			{
#if DEBUG
 { where(); printf("\n"); }
#endif
				segm_acceptable= FALSE;
#if DEBUG
 if (!segm_acceptable)
 { where(); printf("!segm_acceptable\n"); }
#endif
			}
		}
/*
	!segment acceptable ?
		RST ?
			discard packet
			exit
		:
			<SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
			exit
*/
#if DEBUG & 256
 { where(); printf("\n"); }
#endif
		if (!segm_acceptable)
		{
#if DEBUG & 256
 { where(); printf("segment is not acceptable\n"); }
#endif
			if (!(tcp_hdr_flags & THF_RST))
			{
#if DEBUG & 256
 { where(); printf("segment is not acceptable setting ack timer\n"); }
#endif
				tcp_set_ack_timer(tcp_conn);
			}
			break;
		}
/*
	RST ?
		state == SYN-SECEIVED ?
			initiated by a LISTEN ?
				state= LISTEN
				exit
			:
				state= CLOSED
				error "connection refused"
				exit
		state == CLOSING || state == LAST-ACK ||
			state == TIME-WAIT ?
			state= CLOSED
			exit
		:
			state= CLOSED
			error "connection reset"
			exit
*/
#if DEBUG & 256
 { where(); printf("\n"); }
#endif
		if (tcp_hdr_flags & THF_RST)
		{
			if (tcp_conn->tc_state == TCS_SYN_RECEIVED)
			{
				if (tcp_conn->tc_orglisten)
				{
					connuser= tcp_conn->tc_connuser;
					tcp_conn->tc_connuser= 0;
#if DEBUG
 { where(); printf("calling tcp_close_connection\n"); }
#endif
					tcp_close_connection (tcp_conn,
						ECONNREFUSED);
					if (connuser)
						(void)tcp_su4listen(
							connuser);
					break;
				}
				else
				{
#if DEBUG
 { where(); printf("calling tcp_close_connection\n"); }
#endif
					tcp_close_connection(tcp_conn,
						ECONNREFUSED);
					break;
				}
			}
			if (tcp_conn->tc_state == TCS_CLOSING ||
				tcp_conn->tc_state == TCS_LAST_ACK ||
				tcp_conn->tc_state == TCS_TIME_WAIT)
			{
#if DEBUG
 { where(); printf("calling tcp_close_connection\n"); }
#endif
				tcp_close_connection (tcp_conn,
					ENOCONN);
				break;
			}
#if DEBUG
 { where(); printf("calling tcp_close_connection\n"); }
#endif
			tcp_close_connection(tcp_conn, ECONNRESET);
			break;
		}
/*
	SYN in window ?
		state == SYN-RECEIVED && initiated by a LISTEN ?
			state= LISTEN
			exit
		:
			state= CLOSED
			error "connection reset"
			exit
*/
#if DEBUG  & 256
 { where(); printf("\n"); }
#endif
		if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,
			tcp_conn->tc_RCV_NXT))
		{
			if (tcp_conn->tc_state == TCS_SYN_RECEIVED &&
				tcp_conn->tc_orglisten)
			{
				connuser= tcp_conn->tc_connuser;
				tcp_conn->tc_connuser= 0;
#if DEBUG

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -