4 Copyright 1995 Philip Homburg
21 FORWARD
void create_RST
ARGS(( tcp_conn_t
*tcp_conn
,
22 ip_hdr_t
*ip_hdr
, tcp_hdr_t
*tcp_hdr
, int data_len
));
23 FORWARD
void process_data
ARGS(( tcp_conn_t
*tcp_conn
,
24 tcp_hdr_t
*tcp_hdr
, acc_t
*tcp_data
, int data_len
));
25 FORWARD
void process_advanced_data
ARGS(( tcp_conn_t
*tcp_conn
,
26 tcp_hdr_t
*tcp_hdr
, acc_t
*tcp_data
, int data_len
));
28 PUBLIC
void tcp_frag2conn(tcp_conn
, ip_hdr
, tcp_hdr
, tcp_data
, data_len
)
37 int ip_hdr_len
, tcp_hdr_len
;
38 u32_t seg_ack
, seg_seq
, rcv_hi
, snd_una
, snd_nxt
;
41 int acceptable_ACK
, segm_acceptable
, send_rst
, close_connection
;
43 ip_hdr_len
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
) << 2;
44 tcp_hdr_len
= (tcp_hdr
->th_data_off
& TH_DO_MASK
) >> 2;
46 tcp_hdr_flags
= tcp_hdr
->th_flags
& TH_FLAGS_MASK
;
47 seg_ack
= ntohl(tcp_hdr
->th_ack_nr
);
48 seg_seq
= ntohl(tcp_hdr
->th_seq_nr
);
49 seg_wnd
= ntohs(tcp_hdr
->th_window
);
52 { where(); tcp_print_conn(tcp_conn
); printf("\n");
53 tcp_print_pack(ip_hdr
, tcp_hdr
); printf("\n"); }
56 switch (tcp_conn
->tc_state
)
64 <SEQ=SEG.ACK><CTL=RST>
67 <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
74 if (!(tcp_hdr_flags
& THF_RST
))
76 create_RST(tcp_conn
, ip_hdr
, tcp_hdr
, data_len
);
77 tcp_conn_write(tcp_conn
, 1);
87 <SEQ=SEG.ACK><CTL=RST>
90 BUG: no security check
93 ISS should already be selected
94 <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
104 if (tcp_hdr_flags
& THF_RST
)
106 if (tcp_hdr_flags
& THF_ACK
)
108 create_RST (tcp_conn
, ip_hdr
, tcp_hdr
, data_len
);
109 tcp_conn_write(tcp_conn
, 1);
112 if (tcp_hdr_flags
& THF_SYN
)
114 tcp_extract_ipopt(tcp_conn
, ip_hdr
);
115 tcp_extract_tcpopt(tcp_conn
, tcp_hdr
, &mss
);
116 mtu
= mss
+IP_TCP_MIN_HDR_SIZE
;
117 if (mtu
< IP_MIN_MTU
)
119 /* No or unrealistic mss, use default MTU */
122 if (mtu
< tcp_conn
->tc_max_mtu
)
124 tcp_conn
->tc_max_mtu
= mtu
;
125 tcp_conn
->tc_mtu
= mtu
;
127 "tcp[%d]: conn[%d]: mtu = %d\n",
128 tcp_conn
->tc_port
-tcp_port_table
,
129 tcp_conn
-tcp_conn_table
,
133 tcp_conn
->tc_RCV_LO
= seg_seq
+1;
134 tcp_conn
->tc_RCV_NXT
= seg_seq
+1;
135 tcp_conn
->tc_RCV_HI
= tcp_conn
->tc_RCV_LO
+
136 tcp_conn
->tc_rcv_wnd
;
137 tcp_conn
->tc_RCV_UP
= seg_seq
;
138 tcp_conn
->tc_IRS
= seg_seq
;
139 tcp_conn
->tc_SND_UNA
= tcp_conn
->tc_ISS
;
140 tcp_conn
->tc_SND_TRM
= tcp_conn
->tc_ISS
;
141 tcp_conn
->tc_SND_NXT
= tcp_conn
->tc_ISS
+1;
142 tcp_conn
->tc_SND_UP
= tcp_conn
->tc_ISS
-1;
143 tcp_conn
->tc_SND_PSH
= tcp_conn
->tc_ISS
-1;
144 tcp_conn
->tc_state
= TCS_SYN_RECEIVED
;
146 assert (tcp_check_conn(tcp_conn
));
147 tcp_conn
->tc_locaddr
= ip_hdr
->ih_dst
;
148 tcp_conn
->tc_locport
= tcp_hdr
->th_dstport
;
149 tcp_conn
->tc_remaddr
= ip_hdr
->ih_src
;
150 tcp_conn
->tc_remport
= tcp_hdr
->th_srcport
;
151 tcp_conn_write(tcp_conn
, 1);
153 DIFBLOCK(0x10, seg_seq
== 0,
154 printf("warning got 0 IRS from ");
155 writeIpAddr(tcp_conn
->tc_remaddr
);
158 /* Start the timer (if necessary) */
159 tcp_set_send_timer(tcp_conn
);
169 SEG.ACK <= ISS || SEG.ACK > SND.NXT ?
174 <SEQ=SEG.ACK><CTL=RST>
176 SND.UNA <= SEG.ACK && SEG.ACK <= SND.NXT ?
186 error "connection refused"
191 BUG: no security check
199 <SEQ=SND.NXT><ACK= RCV.NXT><CTL=ACK>
200 process ev. URG and text
207 <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
213 if (tcp_hdr_flags
& THF_ACK
)
215 if (tcp_LEmod4G(seg_ack
, tcp_conn
->tc_ISS
) ||
216 tcp_Gmod4G(seg_ack
, tcp_conn
->tc_SND_NXT
))
217 if (tcp_hdr_flags
& THF_RST
)
221 /* HACK: force sending a RST,
222 * normally, RSTs are not send
223 * if the segment is an ACK.
225 create_RST (tcp_conn
, ip_hdr
,
226 tcp_hdr
, data_len
+1);
227 tcp_conn_write(tcp_conn
, 1);
230 acceptable_ACK
= (tcp_LEmod4G(tcp_conn
->tc_SND_UNA
,
231 seg_ack
) && tcp_LEmod4G(seg_ack
,
232 tcp_conn
->tc_SND_NXT
));
235 acceptable_ACK
= FALSE
;
236 if (tcp_hdr_flags
& THF_RST
)
241 "calling tcp_close_connection\n"));
243 tcp_close_connection(tcp_conn
,
248 if (tcp_hdr_flags
& THF_SYN
)
250 tcp_extract_ipopt(tcp_conn
, ip_hdr
);
251 tcp_extract_tcpopt(tcp_conn
, tcp_hdr
, &mss
);
252 mtu
= mss
+IP_TCP_MIN_HDR_SIZE
;
253 if (mtu
< IP_MIN_MTU
)
255 /* No or unrealistic mss, use default MTU */
258 if (mtu
< tcp_conn
->tc_max_mtu
)
260 tcp_conn
->tc_max_mtu
= mtu
;
261 tcp_conn
->tc_mtu
= mtu
;
263 "tcp[%d]: conn[%d]: mtu = %d\n",
264 tcp_conn
->tc_port
-tcp_port_table
,
265 tcp_conn
-tcp_conn_table
,
268 tcp_conn
->tc_RCV_LO
= seg_seq
+1;
269 tcp_conn
->tc_RCV_NXT
= seg_seq
+1;
270 tcp_conn
->tc_RCV_HI
= tcp_conn
->tc_RCV_LO
+
271 tcp_conn
->tc_rcv_wnd
;
272 tcp_conn
->tc_RCV_UP
= seg_seq
;
273 tcp_conn
->tc_IRS
= seg_seq
;
274 if (tcp_hdr_flags
& THF_ACK
)
275 tcp_conn
->tc_SND_UNA
= seg_ack
;
276 if (tcp_Gmod4G(tcp_conn
->tc_SND_UNA
,
279 tcp_conn
->tc_state
= TCS_ESTABLISHED
;
280 tcp_conn
->tc_rt_dead
= TCP_DEF_RT_DEAD
;
282 assert (tcp_check_conn(tcp_conn
));
283 assert(tcp_conn
->tc_connInprogress
);
285 tcp_restart_connect(tcp_conn
);
287 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
288 tcp_conn_write(tcp_conn
, 1);
291 tcp_frag2conn(tcp_conn
, ip_hdr
,
292 tcp_hdr
, tcp_data
, data_len
);
293 /* tcp_data is already freed */
298 tcp_conn
->tc_state
= TCS_SYN_RECEIVED
;
300 assert (tcp_check_conn(tcp_conn
));
302 tcp_conn
->tc_SND_TRM
= tcp_conn
->tc_ISS
;
303 tcp_conn_write(tcp_conn
, 1);
307 case TCS_SYN_RECEIVED
:
310 test if segment is acceptable:
314 0 0 SEG.SEQ == RCV.NXT
315 0 >0 RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
317 >0 >0 (RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND)
318 || (RCV.NXT <= SEG.SEQ+SEG.LEN-1 &&
319 SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND)
320 for urgent data: use RCV.WND+1 for RCV.WND
322 Special: Send RST if SEG.SEQ < IRS or SEG.SEQ > RCV.NXT+64K (and
323 the packet is not a RST packet itself).
325 rcv_hi
= tcp_conn
->tc_RCV_HI
;
326 if (tcp_hdr_flags
& THF_URG
)
328 send_rst
= tcp_Lmod4G(seg_seq
, tcp_conn
->tc_IRS
) ||
329 tcp_Gmod4G(seg_seq
, tcp_conn
->tc_RCV_NXT
+0x10000);
334 if (rcv_hi
== tcp_conn
->tc_RCV_NXT
)
335 segm_acceptable
= (seg_seq
== rcv_hi
);
338 assert (tcp_Gmod4G(rcv_hi
,
339 tcp_conn
->tc_RCV_NXT
));
340 segm_acceptable
= (tcp_LEmod4G(tcp_conn
->
341 tc_RCV_NXT
, seg_seq
) &&
342 tcp_Lmod4G(seg_seq
, rcv_hi
));
347 if (tcp_Gmod4G(rcv_hi
, tcp_conn
->tc_RCV_NXT
))
349 segm_acceptable
= (tcp_LEmod4G(tcp_conn
->
350 tc_RCV_NXT
, seg_seq
) &&
351 tcp_Lmod4G(seg_seq
, rcv_hi
)) ||
352 (tcp_LEmod4G(tcp_conn
->tc_RCV_NXT
,
353 seg_seq
+data_len
-1) &&
354 tcp_Lmod4G(seg_seq
+data_len
-1,
359 segm_acceptable
= FALSE
;
363 !segment acceptable ?
368 <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
371 if (!segm_acceptable
)
373 if (tcp_hdr_flags
& THF_RST
)
377 create_RST(tcp_conn
, ip_hdr
, tcp_hdr
,
379 tcp_conn_write(tcp_conn
, 1);
383 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
384 tcp_conn_write(tcp_conn
, 1);
390 initiated by a LISTEN ?
395 error "connection refused"
399 if (tcp_hdr_flags
& THF_RST
)
404 initiated by a LISTEN ?
409 error "connection reset"
412 if ((tcp_hdr_flags
& THF_SYN
) && tcp_GEmod4G(seg_seq
,
413 tcp_conn
->tc_RCV_NXT
))
418 if (close_connection
)
420 if (!tcp_conn
->tc_orglisten
)
422 tcp_close_connection(tcp_conn
, ECONNREFUSED
);
426 connuser
= tcp_conn
->tc_fd
;
428 if (connuser
->tf_flags
& TFF_LISTENQ
)
430 tcp_close_connection (tcp_conn
,
435 tcp_conn
->tc_connInprogress
= 0;
436 tcp_conn
->tc_fd
= NULL
;
438 tcp_close_connection (tcp_conn
,
441 /* Pick a new ISS next time */
444 (void)tcp_su4listen(connuser
, tcp_conn
,
445 0 /* !do_listenq */);
454 if (!(tcp_hdr_flags
& THF_ACK
))
457 SND.UNA < SEG.ACK <= SND.NXT ?
460 <SEG=SEG.ACK><CTL=RST>
463 if (tcp_Lmod4G(tcp_conn
->tc_SND_UNA
, seg_ack
) &&
464 tcp_LEmod4G(seg_ack
, tcp_conn
->tc_SND_NXT
))
466 tcp_conn
->tc_state
= TCS_ESTABLISHED
;
467 tcp_conn
->tc_rt_dead
= TCP_DEF_RT_DEAD
;
469 tcp_release_retrans(tcp_conn
, seg_ack
, seg_wnd
);
471 assert (tcp_check_conn(tcp_conn
));
472 assert(tcp_conn
->tc_connInprogress
);
474 tcp_restart_connect(tcp_conn
);
475 tcp_frag2conn(tcp_conn
, ip_hdr
, tcp_hdr
, tcp_data
,
477 /* tcp_data is already freed */
482 create_RST (tcp_conn
, ip_hdr
, tcp_hdr
, data_len
);
483 tcp_conn_write(tcp_conn
, 1);
488 case TCS_ESTABLISHED
:
498 test if segment is acceptable:
501 0 0 SEG.SEQ == RCV.NXT
502 0 >0 RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
504 >0 >0 (RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND)
505 || (RCV.NXT <= SEG.SEQ+SEG.LEN-1 &&
506 SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND)
507 for urgent data: use RCV.WND+1 for RCV.WND
509 rcv_hi
= tcp_conn
->tc_RCV_HI
;
510 if (tcp_hdr_flags
& THF_URG
)
514 if (rcv_hi
== tcp_conn
->tc_RCV_NXT
)
515 segm_acceptable
= (seg_seq
== rcv_hi
);
518 assert (tcp_Gmod4G(rcv_hi
,
519 tcp_conn
->tc_RCV_NXT
));
520 segm_acceptable
= (tcp_LEmod4G(tcp_conn
->
521 tc_RCV_NXT
, seg_seq
) &&
522 tcp_Lmod4G(seg_seq
, rcv_hi
));
527 if (tcp_Gmod4G(rcv_hi
, tcp_conn
->tc_RCV_NXT
))
529 segm_acceptable
= (tcp_LEmod4G(tcp_conn
->
530 tc_RCV_NXT
, seg_seq
) &&
531 tcp_Lmod4G(seg_seq
, rcv_hi
)) ||
532 (tcp_LEmod4G(tcp_conn
->tc_RCV_NXT
,
533 seg_seq
+data_len
-1) &&
534 tcp_Lmod4G(seg_seq
+data_len
-1,
539 segm_acceptable
= FALSE
;
543 !segment acceptable ?
548 <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
551 if (!segm_acceptable
)
553 if (!(tcp_hdr_flags
& THF_RST
))
556 printf("segment is not acceptable\n");
558 tcp_print_pack(ip_hdr
, tcp_hdr
);
560 tcp_print_conn(tcp_conn
);
562 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
563 tcp_conn_write(tcp_conn
, 1);
565 /* Sometimes, a retransmission sets the PSH
568 if (tcp_conn
->tc_rcvd_data
!= NULL
&&
569 (tcp_hdr_flags
& THF_PSH
))
571 tcp_conn
->tc_flags
|= TCF_RCV_PUSH
;
572 if (tcp_conn
->tc_fd
&&
573 (tcp_conn
->tc_fd
->tf_flags
&
576 tcp_fd_read(tcp_conn
, 1);
578 if (tcp_conn
->tc_fd
&&
579 (tcp_conn
->tc_fd
->tf_flags
&
582 tcp_rsel_read(tcp_conn
);
590 state == CLOSING || state == LAST-ACK ||
596 error "connection reset"
599 if (tcp_hdr_flags
& THF_RST
)
601 if ((tcp_conn
->tc_flags
&
602 (TCF_FIN_SENT
|TCF_FIN_RECV
)) ==
603 (TCF_FIN_SENT
|TCF_FIN_RECV
) &&
604 tcp_conn
->tc_send_data
== NULL
)
606 /* Clean shutdown, but the other side
607 * doesn't want to ACK our FIN.
609 tcp_close_connection (tcp_conn
, 0);
612 tcp_close_connection(tcp_conn
, ECONNRESET
);
618 error "connection reset"
621 if ((tcp_hdr_flags
& THF_SYN
) && tcp_GEmod4G(seg_seq
,
622 tcp_conn
->tc_RCV_NXT
))
624 tcp_close_connection(tcp_conn
, ECONNRESET
);
632 if (!(tcp_hdr_flags
& THF_ACK
))
636 SND.UNA < SEG.ACK <= SND.NXT ?
639 SND.WL1 < SEG.SEQ || (SND.WL1 == SEG.SEQ &&
647 <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
652 /* Always reset the send timer after a valid ack is
653 * received. The assumption is that either the ack really
654 * acknowledges some data (normal case), contains a zero
655 * window, or the remote host has another reason not
656 * to accept any data. In all cases, the remote host is
657 * alive, so the connection should stay alive too.
658 * Do not reset stt if the state is CLOSING, i.e. if
659 * the user closed the connection and we still have
660 * some data to deliver. We don't want a zero window
661 * to keep us from closing the connection.
663 if (tcp_conn
->tc_state
!= TCS_CLOSING
)
666 snd_una
= tcp_conn
->tc_SND_UNA
;
667 snd_nxt
= tcp_conn
->tc_SND_NXT
;
668 if (seg_ack
== snd_una
)
671 if (tcp_Gmod4G(snd_nxt
, snd_una
))
674 if (++tcp_conn
->tc_snd_dack
==
677 tcp_fast_retrans(tcp_conn
);
681 /* This ACK doesn't acknowledge any new data, this
682 * is a likely situation if we are only receiving
683 * data. We only update the window if we are
684 * actually sending or if we currently have a
687 if (tcp_conn
->tc_snd_cwnd
== snd_una
&&
690 DBLOCK(2, printf("zero window opened\n"));
691 /* The other side opened up its receive
693 mss
= tcp_conn
->tc_mtu
-IP_TCP_MIN_HDR_SIZE
;
696 tcp_conn
->tc_snd_cwnd
= snd_una
+seg_wnd
;
697 tcp_conn_write(tcp_conn
, 1);
701 tcp_conn
->tc_snd_cwnd
= tcp_conn
->tc_SND_TRM
=
705 else if (tcp_Lmod4G(snd_una
, seg_ack
) &&
706 tcp_LEmod4G(seg_ack
, snd_nxt
))
708 tcp_release_retrans(tcp_conn
, seg_ack
, seg_wnd
);
709 if (tcp_conn
->tc_state
== TCS_CLOSED
)
712 else if (tcp_Gmod4G(seg_ack
,
715 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
716 tcp_conn_write(tcp_conn
, 1);
718 "got an ack of something I haven't send\n");
719 printf( "seg_ack= %lu, SND_NXT= %lu\n",
727 tcp_extract_ipopt(tcp_conn
, ip_hdr
);
728 tcp_extract_tcpopt(tcp_conn
, tcp_hdr
, &mss
);
732 if (tcp_LEmod4G(seg_seq
, tcp_conn
->tc_RCV_NXT
))
734 process_data (tcp_conn
, tcp_hdr
,
739 process_advanced_data (tcp_conn
,
740 tcp_hdr
, tcp_data
, data_len
);
742 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
743 tcp_conn_write(tcp_conn
, 1);
745 /* Don't process a FIN if we got new data */
750 reply pending receives
751 advace RCV.NXT over the FIN
752 <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
754 state == ESTABLISHED ?
756 state == FIN-WAIT-1 ?
758 state == FIN-WAIT-2 ?
761 restart the TIME-WAIT timer
764 if ((tcp_hdr_flags
& THF_FIN
) && tcp_LEmod4G(seg_seq
,
765 tcp_conn
->tc_RCV_NXT
))
767 if (!(tcp_conn
->tc_flags
& TCF_FIN_RECV
) &&
768 tcp_Lmod4G(tcp_conn
->tc_RCV_NXT
,
769 tcp_conn
->tc_RCV_HI
))
771 tcp_conn
->tc_RCV_NXT
++;
772 tcp_conn
->tc_flags
|= TCF_FIN_RECV
;
774 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
775 tcp_conn_write(tcp_conn
, 1);
776 if (tcp_conn
->tc_fd
&&
777 (tcp_conn
->tc_fd
->tf_flags
& TFF_READ_IP
))
779 tcp_fd_read(tcp_conn
, 1);
781 if (tcp_conn
->tc_fd
&&
782 (tcp_conn
->tc_fd
->tf_flags
& TFF_SEL_READ
))
784 tcp_rsel_read(tcp_conn
);
789 printf("tcp_frag2conn: unknown state ");
790 tcp_print_state(tcp_conn
);
793 if (tcp_data
!= NULL
)
799 process_data(tcp_conn
, tcp_hdr
, tcp_data
, data_len
)
800 tcp_conn_t
*tcp_conn
;
805 u32_t lo_seq
, hi_seq
, urg_seq
, seq_nr
, adv_seq
, nxt
;
809 acc_t
*tmp_data
, *rcvd_data
, *adv_data
;
812 assert(tcp_conn
->tc_busy
);
814 /* Note, tcp_data will be freed by the caller. */
815 assert (!(tcp_hdr
->th_flags
& THF_SYN
));
817 seq_nr
= ntohl(tcp_hdr
->th_seq_nr
);
818 urgptr
= ntohs(tcp_hdr
->th_urgptr
);
820 tcp_data
->acc_linkC
++;
823 tcp_hdr_flags
= tcp_hdr
->th_flags
& TH_FLAGS_MASK
;
825 if (tcp_Lmod4G(lo_seq
, tcp_conn
->tc_RCV_NXT
))
828 printf("segment is a retransmission\n"));
829 offset
= tcp_conn
->tc_RCV_NXT
-lo_seq
;
830 tcp_data
= bf_delhead(tcp_data
, offset
);
833 if (tcp_hdr_flags
& THF_URG
)
835 printf("process_data: updating urgent pointer\n");
836 if (urgptr
>= offset
)
839 tcp_hdr_flags
&= ~THF_URG
;
842 assert (lo_seq
== tcp_conn
->tc_RCV_NXT
);
844 if (tcp_hdr_flags
& THF_URG
)
846 if (!(tcp_conn
->tc_flags
& TCF_BSD_URG
))
848 /* Update urgent pointer to point past the urgent
854 tcp_hdr_flags
&= ~THF_URG
;
857 if (tcp_hdr_flags
& THF_URG
)
859 if (urgptr
> data_len
)
861 urg_seq
= lo_seq
+urgptr
;
863 if (tcp_GEmod4G(urg_seq
, tcp_conn
->tc_RCV_HI
))
864 urg_seq
= tcp_conn
->tc_RCV_HI
;
865 if (tcp_conn
->tc_flags
& TCF_BSD_URG
)
867 if (tcp_Gmod4G(tcp_conn
->tc_RCV_NXT
,
868 tcp_conn
->tc_RCV_LO
))
871 "ignoring urgent data\n"));
874 /* Should set advertised window to
878 tcp_conn
->tc_flags
|= TCF_RCV_PUSH
;
879 if (tcp_conn
->tc_fd
&&
880 (tcp_conn
->tc_fd
->tf_flags
&
883 tcp_fd_read(tcp_conn
, 1);
885 if (tcp_conn
->tc_fd
&&
886 (tcp_conn
->tc_fd
->tf_flags
&
889 tcp_rsel_read(tcp_conn
);
894 if (tcp_Gmod4G(urg_seq
, tcp_conn
->tc_RCV_UP
))
895 tcp_conn
->tc_RCV_UP
= urg_seq
;
897 if (urgptr
< data_len
)
900 tmp_data
= bf_cut(tcp_data
, 0, data_len
);
903 tcp_hdr_flags
&= ~THF_FIN
;
906 tcp_conn
->tc_flags
|= TCF_RCV_PUSH
;
913 if (tcp_hdr_flags
& THF_PSH
)
915 tcp_conn
->tc_flags
|= TCF_RCV_PUSH
;
918 hi_seq
= lo_seq
+data_len
;
919 if (tcp_Gmod4G(hi_seq
, tcp_conn
->tc_RCV_HI
))
921 data_len
= tcp_conn
->tc_RCV_HI
-lo_seq
;
922 tmp_data
= bf_cut(tcp_data
, 0, data_len
);
925 hi_seq
= lo_seq
+data_len
;
926 tcp_hdr_flags
&= ~THF_FIN
;
928 assert (tcp_LEmod4G (hi_seq
, tcp_conn
->tc_RCV_HI
));
930 rcvd_data
= tcp_conn
->tc_rcvd_data
;
931 tcp_conn
->tc_rcvd_data
= 0;
932 tmp_data
= bf_append(rcvd_data
, tcp_data
);
933 tcp_conn
->tc_rcvd_data
= tmp_data
;
934 tcp_conn
->tc_RCV_NXT
= hi_seq
;
936 if ((tcp_hdr_flags
& THF_FIN
) &&
937 tcp_Lmod4G(tcp_conn
->tc_RCV_NXT
, tcp_conn
->tc_RCV_HI
) &&
938 !(tcp_conn
->tc_flags
& TCF_FIN_RECV
))
940 tcp_conn
->tc_RCV_NXT
++;
941 tcp_conn
->tc_flags
|= TCF_FIN_RECV
;
944 if (tcp_conn
->tc_fd
&& (tcp_conn
->tc_fd
->tf_flags
& TFF_READ_IP
))
945 tcp_fd_read(tcp_conn
, 1);
946 if (tcp_conn
->tc_fd
&& (tcp_conn
->tc_fd
->tf_flags
& TFF_SEL_READ
))
947 tcp_rsel_read(tcp_conn
);
949 DIFBLOCK(2, (tcp_conn
->tc_RCV_NXT
== tcp_conn
->tc_RCV_HI
),
950 printf("conn[[%d] full receive buffer\n",
951 tcp_conn
-tcp_conn_table
));
953 if (tcp_conn
->tc_adv_data
== NULL
)
955 if (tcp_hdr_flags
& THF_FIN
)
957 printf("conn[%d]: advanced data after FIN\n",
958 tcp_conn
-tcp_conn_table
);
959 tcp_data
= tcp_conn
->tc_adv_data
;
960 tcp_conn
->tc_adv_data
= NULL
;
965 lo_seq
= tcp_conn
->tc_adv_seq
;
966 if (tcp_Gmod4G(lo_seq
, tcp_conn
->tc_RCV_NXT
))
967 return; /* Not yet */
969 tcp_data
= tcp_conn
->tc_adv_data
;
970 tcp_conn
->tc_adv_data
= NULL
;
972 data_len
= bf_bufsize(tcp_data
);
973 if (tcp_Lmod4G(lo_seq
, tcp_conn
->tc_RCV_NXT
))
975 offset
= tcp_conn
->tc_RCV_NXT
-lo_seq
;
976 if (offset
>= data_len
)
981 tcp_data
= bf_delhead(tcp_data
, offset
);
985 assert (lo_seq
== tcp_conn
->tc_RCV_NXT
);
987 hi_seq
= lo_seq
+data_len
;
988 assert (tcp_LEmod4G (hi_seq
, tcp_conn
->tc_RCV_HI
));
990 rcvd_data
= tcp_conn
->tc_rcvd_data
;
991 tcp_conn
->tc_rcvd_data
= 0;
992 tmp_data
= bf_append(rcvd_data
, tcp_data
);
993 tcp_conn
->tc_rcvd_data
= tmp_data
;
994 tcp_conn
->tc_RCV_NXT
= hi_seq
;
996 assert (tcp_conn
->tc_RCV_LO
+ bf_bufsize(tcp_conn
->tc_rcvd_data
) ==
997 tcp_conn
->tc_RCV_NXT
||
998 (tcp_print_conn(tcp_conn
), printf("\n"), 0));
1000 if (tcp_conn
->tc_fd
&& (tcp_conn
->tc_fd
->tf_flags
& TFF_READ_IP
))
1001 tcp_fd_read(tcp_conn
, 1);
1002 if (tcp_conn
->tc_fd
&& (tcp_conn
->tc_fd
->tf_flags
& TFF_SEL_READ
))
1003 tcp_rsel_read(tcp_conn
);
1005 adv_data
= tcp_conn
->tc_adv_data
;
1006 if (adv_data
!= NULL
)
1008 /* Try to use advanced data. */
1009 adv_seq
= tcp_conn
->tc_adv_seq
;
1010 nxt
= tcp_conn
->tc_RCV_NXT
;
1012 if (tcp_Gmod4G(adv_seq
, nxt
))
1013 return; /* not yet */
1015 tcp_conn
->tc_adv_data
= NULL
;
1016 data_len
= bf_bufsize(adv_data
);
1018 if (tcp_Lmod4G(adv_seq
, nxt
))
1020 if (tcp_LEmod4G(adv_seq
+data_len
, nxt
))
1022 /* Data is not needed anymore. */
1027 len_diff
= nxt
-adv_seq
;
1028 adv_data
= bf_delhead(adv_data
, len_diff
);
1029 data_len
-= len_diff
;
1032 DBLOCK(1, printf("using advanced data\n"));
1034 /* Append data to the input buffer */
1035 if (tcp_conn
->tc_rcvd_data
== NULL
)
1037 tcp_conn
->tc_rcvd_data
= adv_data
;
1041 tcp_conn
->tc_rcvd_data
=
1042 bf_append(tcp_conn
->tc_rcvd_data
, adv_data
);
1044 tcp_conn
->tc_SND_NXT
+= data_len
;
1045 assert(tcp_check_conn(tcp_conn
));
1047 if (tcp_conn
->tc_fd
&&
1048 (tcp_conn
->tc_fd
->tf_flags
& TFF_READ_IP
))
1050 tcp_fd_read(tcp_conn
, 1);
1052 if (tcp_conn
->tc_fd
&&
1053 (tcp_conn
->tc_fd
->tf_flags
& TFF_SEL_READ
))
1055 tcp_rsel_read(tcp_conn
);
1060 PRIVATE
void process_advanced_data(tcp_conn
, tcp_hdr
, tcp_data
, data_len
)
1061 tcp_conn_t
*tcp_conn
;
1069 assert(tcp_conn
->tc_busy
);
1071 /* Note, tcp_data will be freed by the caller. */
1073 /* Always send an ACK, this allows the sender to do a fast
1076 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
1077 tcp_conn_write(tcp_conn
, 1);
1079 if (tcp_hdr
->th_flags
& THF_URG
)
1080 return; /* Urgent data is to complicated */
1082 if (tcp_hdr
->th_flags
& THF_PSH
)
1083 tcp_conn
->tc_flags
|= TCF_RCV_PUSH
;
1084 seq
= ntohl(tcp_hdr
->th_seq_nr
);
1086 /* Make sure that the packet doesn't fall outside of the window
1089 if (tcp_Gmod4G(seq
+data_len
, tcp_conn
->tc_RCV_HI
))
1092 adv_data
= tcp_conn
->tc_adv_data
;
1093 adv_seq
= tcp_conn
->tc_adv_seq
;
1094 tcp_conn
->tc_adv_data
= NULL
;
1096 tcp_data
->acc_linkC
++;
1097 if (adv_data
== NULL
)
1102 else if (seq
+ data_len
== adv_seq
)
1104 /* New data fits right before exiting data. */
1105 adv_data
= bf_append(tcp_data
, adv_data
);
1108 else if (adv_seq
+ bf_bufsize(adv_data
) == seq
)
1110 /* New data fits right after exiting data. */
1111 adv_data
= bf_append(adv_data
, tcp_data
);
1115 /* New data doesn't fit. */
1118 tcp_conn
->tc_adv_data
= adv_data
;
1119 tcp_conn
->tc_adv_seq
= adv_seq
;
1122 PRIVATE
void create_RST(tcp_conn
, ip_hdr
, tcp_hdr
, data_len
)
1123 tcp_conn_t
*tcp_conn
;
1128 acc_t
*tmp_ipopt
, *tmp_tcpopt
, *tcp_pack
;
1130 ip_hdr_t
*RST_ip_hdr
;
1131 tcp_hdr_t
*RST_tcp_hdr
;
1132 size_t pack_size
, ip_hdr_len
, mss
;
1134 DBLOCK(0x10, printf("in create_RST, bad pack is:\n");
1135 tcp_print_pack(ip_hdr
, tcp_hdr
); tcp_print_state(tcp_conn
);
1138 assert(tcp_conn
->tc_busy
);
1140 /* Only send RST packets in reponse to actual data (or SYN, FIN)
1141 * this solves a problem during connection shutdown. The problem
1142 * is the follow senario: a senders closes the connection instead
1143 * of doing a shutdown and waiting for the receiver to shutdown.
1144 * The receiver is slow in processing the last data. After the
1145 * sender has completely closed the connection, the receiver
1146 * sends a window update which triggers the sender to send a
1147 * RST. The receiver closes the connection in reponse to the RST.
1149 if ((tcp_hdr
->th_flags
& (THF_FIN
|THF_SYN
)) == 0 &&
1153 { printf("tcp_recv`create_RST: no data, no RST\n"); }
1158 tmp_ipopt
= tcp_conn
->tc_remipopt
;
1160 tmp_ipopt
->acc_linkC
++;
1161 tmp_tcpopt
= tcp_conn
->tc_tcpopt
;
1163 tmp_tcpopt
->acc_linkC
++;
1165 tcp_extract_ipopt (tcp_conn
, ip_hdr
);
1166 tcp_extract_tcpopt (tcp_conn
, tcp_hdr
, &mss
);
1168 RST_acc
= tcp_make_header (tcp_conn
, &RST_ip_hdr
, &RST_tcp_hdr
,
1171 if (tcp_conn
->tc_remipopt
)
1172 bf_afree(tcp_conn
->tc_remipopt
);
1173 tcp_conn
->tc_remipopt
= tmp_ipopt
;
1174 if (tcp_conn
->tc_tcpopt
)
1175 bf_afree(tcp_conn
->tc_tcpopt
);
1176 tcp_conn
->tc_tcpopt
= tmp_tcpopt
;
1178 RST_ip_hdr
->ih_src
= ip_hdr
->ih_dst
;
1179 RST_ip_hdr
->ih_dst
= ip_hdr
->ih_src
;
1181 RST_tcp_hdr
->th_srcport
= tcp_hdr
->th_dstport
;
1182 RST_tcp_hdr
->th_dstport
= tcp_hdr
->th_srcport
;
1183 if (tcp_hdr
->th_flags
& THF_ACK
)
1185 RST_tcp_hdr
->th_seq_nr
= tcp_hdr
->th_ack_nr
;
1186 RST_tcp_hdr
->th_flags
= THF_RST
;
1190 RST_tcp_hdr
->th_seq_nr
= 0;
1191 RST_tcp_hdr
->th_ack_nr
=
1193 ntohl(tcp_hdr
->th_seq_nr
)+
1195 (tcp_hdr
->th_flags
& THF_SYN
? 1 : 0) +
1196 (tcp_hdr
->th_flags
& THF_FIN
? 1 : 0));
1197 RST_tcp_hdr
->th_flags
= THF_RST
|THF_ACK
;
1200 pack_size
= bf_bufsize(RST_acc
);
1201 RST_ip_hdr
->ih_length
= htons(pack_size
);
1202 RST_tcp_hdr
->th_window
= htons(tcp_conn
->tc_rcv_wnd
);
1203 RST_tcp_hdr
->th_chksum
= 0;
1205 RST_acc
->acc_linkC
++;
1206 ip_hdr_len
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
) << 2;
1207 tcp_pack
= bf_delhead(RST_acc
, ip_hdr_len
);
1208 RST_tcp_hdr
->th_chksum
= ~tcp_pack_oneCsum (RST_ip_hdr
, tcp_pack
);
1211 DBLOCK(2, tcp_print_pack(ip_hdr
, tcp_hdr
); printf("\n");
1212 tcp_print_pack(RST_ip_hdr
, RST_tcp_hdr
); printf("\n"));
1214 if (tcp_conn
->tc_frag2send
)
1215 bf_afree(tcp_conn
->tc_frag2send
);
1216 tcp_conn
->tc_frag2send
= RST_acc
;
1217 tcp_conn_write(tcp_conn
, 1);
1221 tcp_fd_read(tcp_conn
, enq
)
1222 tcp_conn_t
*tcp_conn
;
1223 int enq
; /* Enqueue writes. */
1226 size_t data_size
, read_size
;
1228 int fin_recv
, urg
, push
, result
;
1229 i32_t old_window
, new_window
;
1232 assert(tcp_conn
->tc_busy
);
1234 tcp_fd
= tcp_conn
->tc_fd
;
1236 assert (tcp_fd
->tf_flags
& TFF_READ_IP
);
1237 if (tcp_conn
->tc_state
== TCS_CLOSED
)
1239 if (tcp_fd
->tf_read_offset
)
1240 tcp_reply_read (tcp_fd
, tcp_fd
->tf_read_offset
);
1242 tcp_reply_read (tcp_fd
, tcp_conn
->tc_error
);
1246 urg
= tcp_Gmod4G(tcp_conn
->tc_RCV_UP
, tcp_conn
->tc_RCV_LO
);
1247 push
= (tcp_conn
->tc_flags
& TCF_RCV_PUSH
);
1248 fin_recv
= (tcp_conn
->tc_flags
& TCF_FIN_RECV
);
1250 data_size
= tcp_conn
->tc_RCV_NXT
-tcp_conn
->tc_RCV_LO
;
1256 printf("tcp_fd_read: RCV_UP = 0x%x, RCV_LO = 0x%x\n",
1257 tcp_conn
->tc_RCV_UP
, tcp_conn
->tc_RCV_LO
);
1259 read_size
= tcp_conn
->tc_RCV_UP
-tcp_conn
->tc_RCV_LO
;
1262 read_size
= data_size
;
1264 if (read_size
>= tcp_fd
->tf_read_count
)
1265 read_size
= tcp_fd
->tf_read_count
;
1266 else if (!push
&& !fin_recv
&& !urg
&&
1267 data_size
< TCP_MIN_RCV_WND_SIZE
)
1269 /* Defer the copy out until later. */
1272 else if (data_size
== 0 && !fin_recv
)
1274 /* No data, and no end of file. */
1280 if (urg
&& !(tcp_fd
->tf_flags
& TFF_RECV_URG
))
1282 if (tcp_fd
->tf_read_offset
)
1284 tcp_reply_read (tcp_fd
,
1285 tcp_fd
->tf_read_offset
);
1289 tcp_reply_read (tcp_fd
, EURG
);
1293 else if (!urg
&& (tcp_fd
->tf_flags
& TFF_RECV_URG
))
1295 if (tcp_fd
->tf_read_offset
)
1297 tcp_reply_read (tcp_fd
,
1298 tcp_fd
->tf_read_offset
);
1302 tcp_reply_read(tcp_fd
, ENOURG
);
1307 if (read_size
== data_size
)
1309 data
= tcp_conn
->tc_rcvd_data
;
1314 data
= bf_cut(tcp_conn
->tc_rcvd_data
, 0, read_size
);
1316 result
= (*tcp_fd
->tf_put_userdata
) (tcp_fd
->tf_srfd
,
1317 tcp_fd
->tf_read_offset
, data
, FALSE
);
1320 if (tcp_fd
->tf_read_offset
)
1321 tcp_reply_read(tcp_fd
, tcp_fd
->
1324 tcp_reply_read(tcp_fd
, result
);
1327 tcp_fd
->tf_read_offset
+= read_size
;
1328 tcp_fd
->tf_read_count
-= read_size
;
1330 if (data_size
== read_size
)
1332 bf_afree(tcp_conn
->tc_rcvd_data
);
1333 tcp_conn
->tc_rcvd_data
= 0;
1337 tcp_conn
->tc_rcvd_data
=
1338 bf_delhead(tcp_conn
->tc_rcvd_data
,
1341 tcp_conn
->tc_RCV_LO
+= read_size
;
1342 data_size
-= read_size
;
1345 /* Update IRS and often RCV_UP every 0.5GB */
1346 if (tcp_conn
->tc_RCV_LO
- tcp_conn
->tc_IRS
> 0x40000000)
1348 tcp_conn
->tc_IRS
+= 0x20000000;
1349 DBLOCK(1, printf("tcp_fd_read: updating IRS to 0x%lx\n",
1350 (unsigned long)tcp_conn
->tc_IRS
););
1351 if (tcp_Lmod4G(tcp_conn
->tc_RCV_UP
, tcp_conn
->tc_IRS
))
1353 tcp_conn
->tc_RCV_UP
= tcp_conn
->tc_IRS
;
1355 "tcp_fd_read: updating RCV_UP to 0x%lx\n",
1356 (unsigned long)tcp_conn
->tc_RCV_UP
););
1358 DBLOCK(1, printf("tcp_fd_read: RCP_LO = 0x%lx\n",
1359 (unsigned long)tcp_conn
->tc_RCV_LO
););
1362 mss
= tcp_conn
->tc_mtu
-IP_TCP_MIN_HDR_SIZE
;
1363 if (tcp_conn
->tc_RCV_HI
-tcp_conn
->tc_RCV_LO
<=
1364 tcp_conn
->tc_rcv_wnd
-mss
)
1366 old_window
= tcp_conn
->tc_RCV_HI
-tcp_conn
->tc_RCV_NXT
;
1367 tcp_conn
->tc_RCV_HI
= tcp_conn
->tc_RCV_LO
+
1368 tcp_conn
->tc_rcv_wnd
;
1369 new_window
= tcp_conn
->tc_RCV_HI
-tcp_conn
->tc_RCV_NXT
;
1370 assert(old_window
>=0 && new_window
>= old_window
);
1371 if (old_window
< mss
&& new_window
>= mss
)
1373 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
1374 DBLOCK(2, printf("opening window\n"));
1375 tcp_conn_write(tcp_conn
, 1);
1378 if (tcp_conn
->tc_rcvd_data
== NULL
&&
1379 tcp_conn
->tc_adv_data
== NULL
)
1381 /* Out of data, clear PUSH flag and reply to a read. */
1382 tcp_conn
->tc_flags
&= ~TCF_RCV_PUSH
;
1384 if (fin_recv
|| urg
|| tcp_fd
->tf_read_offset
||
1385 !tcp_fd
->tf_read_count
)
1387 tcp_reply_read (tcp_fd
, tcp_fd
->tf_read_offset
);
1393 tcp_sel_read(tcp_conn
)
1394 tcp_conn_t
*tcp_conn
;
1398 int fin_recv
, urg
, push
;
1400 tcp_fd
= tcp_conn
->tc_fd
;
1402 if (tcp_conn
->tc_state
== TCS_CLOSED
)
1405 fin_recv
= (tcp_conn
->tc_flags
& TCF_FIN_RECV
);
1409 data_size
= tcp_conn
->tc_RCV_NXT
-tcp_conn
->tc_RCV_LO
;
1412 /* No data, and no end of file. */
1416 urg
= tcp_Gmod4G(tcp_conn
->tc_RCV_UP
, tcp_conn
->tc_RCV_LO
);
1417 push
= (tcp_conn
->tc_flags
& TCF_RCV_PUSH
);
1419 if (!push
&& !urg
&& data_size
< TCP_MIN_RCV_WND_SIZE
)
1421 /* Defer until later. */
1429 tcp_rsel_read(tcp_conn
)
1430 tcp_conn_t
*tcp_conn
;
1434 if (tcp_sel_read(tcp_conn
) == 0)
1437 tcp_fd
= tcp_conn
->tc_fd
;
1438 tcp_fd
->tf_flags
&= ~TFF_SEL_READ
;
1439 if (tcp_fd
->tf_select_res
)
1440 tcp_fd
->tf_select_res(tcp_fd
->tf_srfd
, SR_SELECT_READ
);
1442 printf("tcp_rsel_read: no select_res\n");
1445 PUBLIC
void tcp_bytesavailable(tcp_fd
, bytesp
)
1449 tcp_conn_t
*tcp_conn
;
1450 size_t data_size
, read_size
;
1452 int fin_recv
, urg
, push
, result
;
1453 i32_t old_window
, new_window
;
1456 *bytesp
= 0; /* The default is that nothing is available */
1458 if (!(tcp_fd
->tf_flags
& TFF_CONNECTED
))
1460 tcp_conn
= tcp_fd
->tf_conn
;
1462 if (tcp_conn
->tc_state
== TCS_CLOSED
)
1465 urg
= tcp_Gmod4G(tcp_conn
->tc_RCV_UP
, tcp_conn
->tc_RCV_LO
);
1466 push
= (tcp_conn
->tc_flags
& TCF_RCV_PUSH
);
1467 fin_recv
= (tcp_conn
->tc_flags
& TCF_FIN_RECV
);
1469 data_size
= tcp_conn
->tc_RCV_NXT
-tcp_conn
->tc_RCV_LO
;
1473 data_size
= tcp_conn
->tc_RCV_UP
-tcp_conn
->tc_RCV_LO
;
1475 if (urg
&& !(tcp_fd
->tf_flags
& TFF_RECV_URG
))
1477 else if (!urg
&& (tcp_fd
->tf_flags
& TFF_RECV_URG
))
1484 * $PchId: tcp_recv.c,v 1.30 2005/06/28 14:21:35 philip Exp $