📄 tcp_recv.c
字号:
/*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); }#endifassert(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"); }#endifassert (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 + -