4 Copyright 1995 Philip Homburg
21 static void create_RST
ARGS(( tcp_conn_t
*tcp_conn
,
22 ip_hdr_t
*ip_hdr
, tcp_hdr_t
*tcp_hdr
, int data_len
));
23 static void process_data
ARGS(( tcp_conn_t
*tcp_conn
,
24 tcp_hdr_t
*tcp_hdr
, acc_t
*tcp_data
, int data_len
));
25 static void process_advanced_data
ARGS(( tcp_conn_t
*tcp_conn
,
26 tcp_hdr_t
*tcp_hdr
, acc_t
*tcp_data
, int data_len
));
28 void tcp_frag2conn(tcp_conn
, ip_hdr
, tcp_hdr
, tcp_data
, data_len
)
37 u32_t seg_ack
, seg_seq
, rcv_hi
, snd_una
, snd_nxt
;
40 int acceptable_ACK
, segm_acceptable
, send_rst
, close_connection
;
42 tcp_hdr_flags
= tcp_hdr
->th_flags
& TH_FLAGS_MASK
;
43 seg_ack
= ntohl(tcp_hdr
->th_ack_nr
);
44 seg_seq
= ntohl(tcp_hdr
->th_seq_nr
);
45 seg_wnd
= ntohs(tcp_hdr
->th_window
);
48 { where(); tcp_print_conn(tcp_conn
); printf("\n");
49 tcp_print_pack(ip_hdr
, tcp_hdr
); printf("\n"); }
52 switch (tcp_conn
->tc_state
)
60 <SEQ=SEG.ACK><CTL=RST>
63 <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
70 if (!(tcp_hdr_flags
& THF_RST
))
72 create_RST(tcp_conn
, ip_hdr
, tcp_hdr
, data_len
);
73 tcp_conn_write(tcp_conn
, 1);
83 <SEQ=SEG.ACK><CTL=RST>
86 BUG: no security check
89 ISS should already be selected
90 <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
100 if (tcp_hdr_flags
& THF_RST
)
102 if (tcp_hdr_flags
& THF_ACK
)
104 create_RST (tcp_conn
, ip_hdr
, tcp_hdr
, data_len
);
105 tcp_conn_write(tcp_conn
, 1);
108 if (tcp_hdr_flags
& THF_SYN
)
110 tcp_extract_ipopt(tcp_conn
, ip_hdr
);
111 tcp_extract_tcpopt(tcp_conn
, tcp_hdr
, &mss
);
112 mtu
= mss
+IP_TCP_MIN_HDR_SIZE
;
113 if (mtu
< IP_MIN_MTU
)
115 /* No or unrealistic mss, use default MTU */
118 if (mtu
< tcp_conn
->tc_max_mtu
)
120 tcp_conn
->tc_max_mtu
= mtu
;
121 tcp_conn
->tc_mtu
= mtu
;
123 "tcp[%d]: conn[%d]: mtu = %d\n",
124 tcp_conn
->tc_port
-tcp_port_table
,
125 tcp_conn
-tcp_conn_table
,
129 tcp_conn
->tc_RCV_LO
= seg_seq
+1;
130 tcp_conn
->tc_RCV_NXT
= seg_seq
+1;
131 tcp_conn
->tc_RCV_HI
= tcp_conn
->tc_RCV_LO
+
132 tcp_conn
->tc_rcv_wnd
;
133 tcp_conn
->tc_RCV_UP
= seg_seq
;
134 tcp_conn
->tc_IRS
= seg_seq
;
135 tcp_conn
->tc_SND_UNA
= tcp_conn
->tc_ISS
;
136 tcp_conn
->tc_SND_TRM
= tcp_conn
->tc_ISS
;
137 tcp_conn
->tc_SND_NXT
= tcp_conn
->tc_ISS
+1;
138 tcp_conn
->tc_SND_UP
= tcp_conn
->tc_ISS
-1;
139 tcp_conn
->tc_SND_PSH
= tcp_conn
->tc_ISS
-1;
140 tcp_conn
->tc_state
= TCS_SYN_RECEIVED
;
142 assert (tcp_check_conn(tcp_conn
));
143 tcp_conn
->tc_locaddr
= ip_hdr
->ih_dst
;
144 tcp_conn
->tc_locport
= tcp_hdr
->th_dstport
;
145 tcp_conn
->tc_remaddr
= ip_hdr
->ih_src
;
146 tcp_conn
->tc_remport
= tcp_hdr
->th_srcport
;
147 tcp_conn_write(tcp_conn
, 1);
149 DIFBLOCK(0x10, seg_seq
== 0,
150 printf("warning got 0 IRS from ");
151 writeIpAddr(tcp_conn
->tc_remaddr
);
154 /* Start the timer (if necessary) */
155 tcp_set_send_timer(tcp_conn
);
165 SEG.ACK <= ISS || SEG.ACK > SND.NXT ?
170 <SEQ=SEG.ACK><CTL=RST>
172 SND.UNA <= SEG.ACK && SEG.ACK <= SND.NXT ?
182 error "connection refused"
187 BUG: no security check
195 <SEQ=SND.NXT><ACK= RCV.NXT><CTL=ACK>
196 process ev. URG and text
203 <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
209 if (tcp_hdr_flags
& THF_ACK
)
211 if (tcp_LEmod4G(seg_ack
, tcp_conn
->tc_ISS
) ||
212 tcp_Gmod4G(seg_ack
, tcp_conn
->tc_SND_NXT
)) {
213 if (tcp_hdr_flags
& THF_RST
)
217 /* HACK: force sending a RST,
218 * normally, RSTs are not send
219 * if the segment is an ACK.
221 create_RST (tcp_conn
, ip_hdr
,
222 tcp_hdr
, data_len
+1);
223 tcp_conn_write(tcp_conn
, 1);
227 acceptable_ACK
= (tcp_LEmod4G(tcp_conn
->tc_SND_UNA
,
228 seg_ack
) && tcp_LEmod4G(seg_ack
,
229 tcp_conn
->tc_SND_NXT
));
232 acceptable_ACK
= FALSE
;
233 if (tcp_hdr_flags
& THF_RST
)
238 "calling tcp_close_connection\n"));
240 tcp_close_connection(tcp_conn
,
245 if (tcp_hdr_flags
& THF_SYN
)
247 tcp_extract_ipopt(tcp_conn
, ip_hdr
);
248 tcp_extract_tcpopt(tcp_conn
, tcp_hdr
, &mss
);
249 mtu
= mss
+IP_TCP_MIN_HDR_SIZE
;
250 if (mtu
< IP_MIN_MTU
)
252 /* No or unrealistic mss, use default MTU */
255 if (mtu
< tcp_conn
->tc_max_mtu
)
257 tcp_conn
->tc_max_mtu
= mtu
;
258 tcp_conn
->tc_mtu
= mtu
;
260 "tcp[%d]: conn[%d]: mtu = %d\n",
261 tcp_conn
->tc_port
-tcp_port_table
,
262 tcp_conn
-tcp_conn_table
,
265 tcp_conn
->tc_RCV_LO
= seg_seq
+1;
266 tcp_conn
->tc_RCV_NXT
= seg_seq
+1;
267 tcp_conn
->tc_RCV_HI
= tcp_conn
->tc_RCV_LO
+
268 tcp_conn
->tc_rcv_wnd
;
269 tcp_conn
->tc_RCV_UP
= seg_seq
;
270 tcp_conn
->tc_IRS
= seg_seq
;
271 if (tcp_hdr_flags
& THF_ACK
)
272 tcp_conn
->tc_SND_UNA
= seg_ack
;
273 if (tcp_Gmod4G(tcp_conn
->tc_SND_UNA
,
276 tcp_conn
->tc_state
= TCS_ESTABLISHED
;
277 tcp_conn
->tc_rt_dead
= TCP_DEF_RT_DEAD
;
279 assert (tcp_check_conn(tcp_conn
));
280 assert(tcp_conn
->tc_connInprogress
);
282 tcp_restart_connect(tcp_conn
);
284 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
285 tcp_conn_write(tcp_conn
, 1);
288 tcp_frag2conn(tcp_conn
, ip_hdr
,
289 tcp_hdr
, tcp_data
, data_len
);
290 /* tcp_data is already freed */
295 tcp_conn
->tc_state
= TCS_SYN_RECEIVED
;
297 assert (tcp_check_conn(tcp_conn
));
299 tcp_conn
->tc_SND_TRM
= tcp_conn
->tc_ISS
;
300 tcp_conn_write(tcp_conn
, 1);
304 case TCS_SYN_RECEIVED
:
307 test if segment is acceptable:
311 0 0 SEG.SEQ == RCV.NXT
312 0 >0 RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
314 >0 >0 (RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND)
315 || (RCV.NXT <= SEG.SEQ+SEG.LEN-1 &&
316 SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND)
317 for urgent data: use RCV.WND+1 for RCV.WND
319 Special: Send RST if SEG.SEQ < IRS or SEG.SEQ > RCV.NXT+64K (and
320 the packet is not a RST packet itself).
322 rcv_hi
= tcp_conn
->tc_RCV_HI
;
323 if (tcp_hdr_flags
& THF_URG
)
325 send_rst
= tcp_Lmod4G(seg_seq
, tcp_conn
->tc_IRS
) ||
326 tcp_Gmod4G(seg_seq
, tcp_conn
->tc_RCV_NXT
+0x10000);
331 if (rcv_hi
== tcp_conn
->tc_RCV_NXT
)
332 segm_acceptable
= (seg_seq
== rcv_hi
);
335 assert (tcp_Gmod4G(rcv_hi
,
336 tcp_conn
->tc_RCV_NXT
));
337 segm_acceptable
= (tcp_LEmod4G(tcp_conn
->
338 tc_RCV_NXT
, seg_seq
) &&
339 tcp_Lmod4G(seg_seq
, rcv_hi
));
344 if (tcp_Gmod4G(rcv_hi
, tcp_conn
->tc_RCV_NXT
))
346 segm_acceptable
= (tcp_LEmod4G(tcp_conn
->
347 tc_RCV_NXT
, seg_seq
) &&
348 tcp_Lmod4G(seg_seq
, rcv_hi
)) ||
349 (tcp_LEmod4G(tcp_conn
->tc_RCV_NXT
,
350 seg_seq
+data_len
-1) &&
351 tcp_Lmod4G(seg_seq
+data_len
-1,
356 segm_acceptable
= FALSE
;
360 !segment acceptable ?
365 <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
368 if (!segm_acceptable
)
370 if (tcp_hdr_flags
& THF_RST
)
374 create_RST(tcp_conn
, ip_hdr
, tcp_hdr
,
376 tcp_conn_write(tcp_conn
, 1);
380 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
381 tcp_conn_write(tcp_conn
, 1);
387 initiated by a LISTEN ?
392 error "connection refused"
396 if (tcp_hdr_flags
& THF_RST
)
401 initiated by a LISTEN ?
406 error "connection reset"
409 if ((tcp_hdr_flags
& THF_SYN
) && tcp_GEmod4G(seg_seq
,
410 tcp_conn
->tc_RCV_NXT
))
415 if (close_connection
)
417 if (!tcp_conn
->tc_orglisten
)
419 tcp_close_connection(tcp_conn
, ECONNREFUSED
);
423 connuser
= tcp_conn
->tc_fd
;
425 if (connuser
->tf_flags
& TFF_LISTENQ
)
427 tcp_close_connection (tcp_conn
,
432 tcp_conn
->tc_connInprogress
= 0;
433 tcp_conn
->tc_fd
= NULL
;
435 tcp_close_connection (tcp_conn
,
438 /* Pick a new ISS next time */
441 (void)tcp_su4listen(connuser
, tcp_conn
,
442 0 /* !do_listenq */);
451 if (!(tcp_hdr_flags
& THF_ACK
))
454 SND.UNA < SEG.ACK <= SND.NXT ?
457 <SEG=SEG.ACK><CTL=RST>
460 if (tcp_Lmod4G(tcp_conn
->tc_SND_UNA
, seg_ack
) &&
461 tcp_LEmod4G(seg_ack
, tcp_conn
->tc_SND_NXT
))
463 tcp_conn
->tc_state
= TCS_ESTABLISHED
;
464 tcp_conn
->tc_rt_dead
= TCP_DEF_RT_DEAD
;
466 tcp_release_retrans(tcp_conn
, seg_ack
, seg_wnd
);
468 assert (tcp_check_conn(tcp_conn
));
469 assert(tcp_conn
->tc_connInprogress
);
471 tcp_restart_connect(tcp_conn
);
472 tcp_frag2conn(tcp_conn
, ip_hdr
, tcp_hdr
, tcp_data
,
474 /* tcp_data is already freed */
479 create_RST (tcp_conn
, ip_hdr
, tcp_hdr
, data_len
);
480 tcp_conn_write(tcp_conn
, 1);
485 case TCS_ESTABLISHED
:
495 test if segment is acceptable:
498 0 0 SEG.SEQ == RCV.NXT
499 0 >0 RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
501 >0 >0 (RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND)
502 || (RCV.NXT <= SEG.SEQ+SEG.LEN-1 &&
503 SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND)
504 for urgent data: use RCV.WND+1 for RCV.WND
506 rcv_hi
= tcp_conn
->tc_RCV_HI
;
507 if (tcp_hdr_flags
& THF_URG
)
511 if (rcv_hi
== tcp_conn
->tc_RCV_NXT
)
512 segm_acceptable
= (seg_seq
== rcv_hi
);
515 assert (tcp_Gmod4G(rcv_hi
,
516 tcp_conn
->tc_RCV_NXT
));
517 segm_acceptable
= (tcp_LEmod4G(tcp_conn
->
518 tc_RCV_NXT
, seg_seq
) &&
519 tcp_Lmod4G(seg_seq
, rcv_hi
));
524 if (tcp_Gmod4G(rcv_hi
, tcp_conn
->tc_RCV_NXT
))
526 segm_acceptable
= (tcp_LEmod4G(tcp_conn
->
527 tc_RCV_NXT
, seg_seq
) &&
528 tcp_Lmod4G(seg_seq
, rcv_hi
)) ||
529 (tcp_LEmod4G(tcp_conn
->tc_RCV_NXT
,
530 seg_seq
+data_len
-1) &&
531 tcp_Lmod4G(seg_seq
+data_len
-1,
536 segm_acceptable
= FALSE
;
540 !segment acceptable ?
545 <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
548 if (!segm_acceptable
)
550 if (!(tcp_hdr_flags
& THF_RST
))
553 printf("segment is not acceptable\n");
555 tcp_print_pack(ip_hdr
, tcp_hdr
);
557 tcp_print_conn(tcp_conn
);
559 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
560 tcp_conn_write(tcp_conn
, 1);
562 /* Sometimes, a retransmission sets the PSH
565 if (tcp_conn
->tc_rcvd_data
!= NULL
&&
566 (tcp_hdr_flags
& THF_PSH
))
568 tcp_conn
->tc_flags
|= TCF_RCV_PUSH
;
569 if (tcp_conn
->tc_fd
&&
570 (tcp_conn
->tc_fd
->tf_flags
&
573 tcp_fd_read(tcp_conn
, 1);
575 if (tcp_conn
->tc_fd
&&
576 (tcp_conn
->tc_fd
->tf_flags
&
579 tcp_rsel_read(tcp_conn
);
587 state == CLOSING || state == LAST-ACK ||
593 error "connection reset"
596 if (tcp_hdr_flags
& THF_RST
)
598 if ((tcp_conn
->tc_flags
&
599 (TCF_FIN_SENT
|TCF_FIN_RECV
)) ==
600 (TCF_FIN_SENT
|TCF_FIN_RECV
) &&
601 tcp_conn
->tc_send_data
== NULL
)
603 /* Clean shutdown, but the other side
604 * doesn't want to ACK our FIN.
606 tcp_close_connection (tcp_conn
, 0);
609 tcp_close_connection(tcp_conn
, ECONNRESET
);
615 error "connection reset"
618 if ((tcp_hdr_flags
& THF_SYN
) && tcp_GEmod4G(seg_seq
,
619 tcp_conn
->tc_RCV_NXT
))
621 tcp_close_connection(tcp_conn
, ECONNRESET
);
629 if (!(tcp_hdr_flags
& THF_ACK
))
633 SND.UNA < SEG.ACK <= SND.NXT ?
636 SND.WL1 < SEG.SEQ || (SND.WL1 == SEG.SEQ &&
644 <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
649 /* Always reset the send timer after a valid ack is
650 * received. The assumption is that either the ack really
651 * acknowledges some data (normal case), contains a zero
652 * window, or the remote host has another reason not
653 * to accept any data. In all cases, the remote host is
654 * alive, so the connection should stay alive too.
655 * Do not reset stt if the state is CLOSING, i.e. if
656 * the user closed the connection and we still have
657 * some data to deliver. We don't want a zero window
658 * to keep us from closing the connection.
660 if (tcp_conn
->tc_state
!= TCS_CLOSING
)
663 snd_una
= tcp_conn
->tc_SND_UNA
;
664 snd_nxt
= tcp_conn
->tc_SND_NXT
;
665 if (seg_ack
== snd_una
)
668 if (tcp_Gmod4G(snd_nxt
, snd_una
))
671 if (++tcp_conn
->tc_snd_dack
==
674 tcp_fast_retrans(tcp_conn
);
678 /* This ACK doesn't acknowledge any new data, this
679 * is a likely situation if we are only receiving
680 * data. We only update the window if we are
681 * actually sending or if we currently have a
684 if (tcp_conn
->tc_snd_cwnd
== snd_una
&&
687 DBLOCK(2, printf("zero window opened\n"));
688 /* The other side opened up its receive
690 mss
= tcp_conn
->tc_mtu
-IP_TCP_MIN_HDR_SIZE
;
693 tcp_conn
->tc_snd_cwnd
= snd_una
+seg_wnd
;
694 tcp_conn_write(tcp_conn
, 1);
698 tcp_conn
->tc_snd_cwnd
= tcp_conn
->tc_SND_TRM
=
702 else if (tcp_Lmod4G(snd_una
, seg_ack
) &&
703 tcp_LEmod4G(seg_ack
, snd_nxt
))
705 tcp_release_retrans(tcp_conn
, seg_ack
, seg_wnd
);
706 if (tcp_conn
->tc_state
== TCS_CLOSED
)
709 else if (tcp_Gmod4G(seg_ack
,
712 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
713 tcp_conn_write(tcp_conn
, 1);
715 "got an ack of something I haven't send\n");
716 printf( "seg_ack= %u, SND_NXT= %u\n",
724 tcp_extract_ipopt(tcp_conn
, ip_hdr
);
725 tcp_extract_tcpopt(tcp_conn
, tcp_hdr
, &mss
);
729 if (tcp_LEmod4G(seg_seq
, tcp_conn
->tc_RCV_NXT
))
731 process_data (tcp_conn
, tcp_hdr
,
736 process_advanced_data (tcp_conn
,
737 tcp_hdr
, tcp_data
, data_len
);
739 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
740 tcp_conn_write(tcp_conn
, 1);
742 /* Don't process a FIN if we got new data */
747 reply pending receives
748 advace RCV.NXT over the FIN
749 <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
751 state == ESTABLISHED ?
753 state == FIN-WAIT-1 ?
755 state == FIN-WAIT-2 ?
758 restart the TIME-WAIT timer
761 if ((tcp_hdr_flags
& THF_FIN
) && tcp_LEmod4G(seg_seq
,
762 tcp_conn
->tc_RCV_NXT
))
764 if (!(tcp_conn
->tc_flags
& TCF_FIN_RECV
) &&
765 tcp_Lmod4G(tcp_conn
->tc_RCV_NXT
,
766 tcp_conn
->tc_RCV_HI
))
768 tcp_conn
->tc_RCV_NXT
++;
769 tcp_conn
->tc_flags
|= TCF_FIN_RECV
;
771 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
772 tcp_conn_write(tcp_conn
, 1);
773 if (tcp_conn
->tc_fd
&&
774 (tcp_conn
->tc_fd
->tf_flags
& TFF_READ_IP
))
776 tcp_fd_read(tcp_conn
, 1);
778 if (tcp_conn
->tc_fd
&&
779 (tcp_conn
->tc_fd
->tf_flags
& TFF_SEL_READ
))
781 tcp_rsel_read(tcp_conn
);
786 printf("tcp_frag2conn: unknown state ");
787 tcp_print_state(tcp_conn
);
790 if (tcp_data
!= NULL
)
796 process_data(tcp_conn
, tcp_hdr
, tcp_data
, data_len
)
797 tcp_conn_t
*tcp_conn
;
802 u32_t lo_seq
, hi_seq
, urg_seq
, seq_nr
, adv_seq
, nxt
;
806 acc_t
*tmp_data
, *rcvd_data
, *adv_data
;
809 assert(tcp_conn
->tc_busy
);
811 /* Note, tcp_data will be freed by the caller. */
812 assert (!(tcp_hdr
->th_flags
& THF_SYN
));
814 seq_nr
= ntohl(tcp_hdr
->th_seq_nr
);
815 urgptr
= ntohs(tcp_hdr
->th_urgptr
);
817 tcp_data
->acc_linkC
++;
820 tcp_hdr_flags
= tcp_hdr
->th_flags
& TH_FLAGS_MASK
;
822 if (tcp_Lmod4G(lo_seq
, tcp_conn
->tc_RCV_NXT
))
825 printf("segment is a retransmission\n"));
826 offset
= tcp_conn
->tc_RCV_NXT
-lo_seq
;
827 tcp_data
= bf_delhead(tcp_data
, offset
);
830 if (tcp_hdr_flags
& THF_URG
)
832 printf("process_data: updating urgent pointer\n");
833 if (urgptr
>= offset
)
836 tcp_hdr_flags
&= ~THF_URG
;
839 assert (lo_seq
== tcp_conn
->tc_RCV_NXT
);
841 if (tcp_hdr_flags
& THF_URG
)
843 if (!(tcp_conn
->tc_flags
& TCF_BSD_URG
))
845 /* Update urgent pointer to point past the urgent
851 tcp_hdr_flags
&= ~THF_URG
;
854 if (tcp_hdr_flags
& THF_URG
)
856 if (urgptr
> data_len
)
858 urg_seq
= lo_seq
+urgptr
;
860 if (tcp_GEmod4G(urg_seq
, tcp_conn
->tc_RCV_HI
))
861 urg_seq
= tcp_conn
->tc_RCV_HI
;
862 if (tcp_conn
->tc_flags
& TCF_BSD_URG
)
864 if (tcp_Gmod4G(tcp_conn
->tc_RCV_NXT
,
865 tcp_conn
->tc_RCV_LO
))
868 "ignoring urgent data\n"));
871 /* Should set advertised window to
875 tcp_conn
->tc_flags
|= TCF_RCV_PUSH
;
876 if (tcp_conn
->tc_fd
&&
877 (tcp_conn
->tc_fd
->tf_flags
&
880 tcp_fd_read(tcp_conn
, 1);
882 if (tcp_conn
->tc_fd
&&
883 (tcp_conn
->tc_fd
->tf_flags
&
886 tcp_rsel_read(tcp_conn
);
891 if (tcp_Gmod4G(urg_seq
, tcp_conn
->tc_RCV_UP
))
892 tcp_conn
->tc_RCV_UP
= urg_seq
;
894 if (urgptr
< data_len
)
897 tmp_data
= bf_cut(tcp_data
, 0, data_len
);
900 tcp_hdr_flags
&= ~THF_FIN
;
903 tcp_conn
->tc_flags
|= TCF_RCV_PUSH
;
910 if (tcp_hdr_flags
& THF_PSH
)
912 tcp_conn
->tc_flags
|= TCF_RCV_PUSH
;
915 hi_seq
= lo_seq
+data_len
;
916 if (tcp_Gmod4G(hi_seq
, tcp_conn
->tc_RCV_HI
))
918 data_len
= tcp_conn
->tc_RCV_HI
-lo_seq
;
919 tmp_data
= bf_cut(tcp_data
, 0, data_len
);
922 hi_seq
= lo_seq
+data_len
;
923 tcp_hdr_flags
&= ~THF_FIN
;
925 assert (tcp_LEmod4G (hi_seq
, tcp_conn
->tc_RCV_HI
));
927 rcvd_data
= tcp_conn
->tc_rcvd_data
;
928 tcp_conn
->tc_rcvd_data
= 0;
929 tmp_data
= bf_append(rcvd_data
, tcp_data
);
930 tcp_conn
->tc_rcvd_data
= tmp_data
;
931 tcp_conn
->tc_RCV_NXT
= hi_seq
;
933 if ((tcp_hdr_flags
& THF_FIN
) &&
934 tcp_Lmod4G(tcp_conn
->tc_RCV_NXT
, tcp_conn
->tc_RCV_HI
) &&
935 !(tcp_conn
->tc_flags
& TCF_FIN_RECV
))
937 tcp_conn
->tc_RCV_NXT
++;
938 tcp_conn
->tc_flags
|= TCF_FIN_RECV
;
941 if (tcp_conn
->tc_fd
&& (tcp_conn
->tc_fd
->tf_flags
& TFF_READ_IP
))
942 tcp_fd_read(tcp_conn
, 1);
943 if (tcp_conn
->tc_fd
&& (tcp_conn
->tc_fd
->tf_flags
& TFF_SEL_READ
))
944 tcp_rsel_read(tcp_conn
);
946 DIFBLOCK(2, (tcp_conn
->tc_RCV_NXT
== tcp_conn
->tc_RCV_HI
),
947 printf("conn[[%d] full receive buffer\n",
948 tcp_conn
-tcp_conn_table
));
950 if (tcp_conn
->tc_adv_data
== NULL
)
952 if (tcp_hdr_flags
& THF_FIN
)
954 printf("conn[%d]: advanced data after FIN\n",
955 tcp_conn
-tcp_conn_table
);
956 tcp_data
= tcp_conn
->tc_adv_data
;
957 tcp_conn
->tc_adv_data
= NULL
;
962 lo_seq
= tcp_conn
->tc_adv_seq
;
963 if (tcp_Gmod4G(lo_seq
, tcp_conn
->tc_RCV_NXT
))
964 return; /* Not yet */
966 tcp_data
= tcp_conn
->tc_adv_data
;
967 tcp_conn
->tc_adv_data
= NULL
;
969 data_len
= bf_bufsize(tcp_data
);
970 if (tcp_Lmod4G(lo_seq
, tcp_conn
->tc_RCV_NXT
))
972 offset
= tcp_conn
->tc_RCV_NXT
-lo_seq
;
973 if (offset
>= data_len
)
978 tcp_data
= bf_delhead(tcp_data
, offset
);
982 assert (lo_seq
== tcp_conn
->tc_RCV_NXT
);
984 hi_seq
= lo_seq
+data_len
;
985 assert (tcp_LEmod4G (hi_seq
, tcp_conn
->tc_RCV_HI
));
987 rcvd_data
= tcp_conn
->tc_rcvd_data
;
988 tcp_conn
->tc_rcvd_data
= 0;
989 tmp_data
= bf_append(rcvd_data
, tcp_data
);
990 tcp_conn
->tc_rcvd_data
= tmp_data
;
991 tcp_conn
->tc_RCV_NXT
= hi_seq
;
993 assert (tcp_conn
->tc_RCV_LO
+ bf_bufsize(tcp_conn
->tc_rcvd_data
) ==
994 tcp_conn
->tc_RCV_NXT
||
995 (tcp_print_conn(tcp_conn
), printf("\n"), 0));
997 if (tcp_conn
->tc_fd
&& (tcp_conn
->tc_fd
->tf_flags
& TFF_READ_IP
))
998 tcp_fd_read(tcp_conn
, 1);
999 if (tcp_conn
->tc_fd
&& (tcp_conn
->tc_fd
->tf_flags
& TFF_SEL_READ
))
1000 tcp_rsel_read(tcp_conn
);
1002 adv_data
= tcp_conn
->tc_adv_data
;
1003 if (adv_data
!= NULL
)
1005 /* Try to use advanced data. */
1006 adv_seq
= tcp_conn
->tc_adv_seq
;
1007 nxt
= tcp_conn
->tc_RCV_NXT
;
1009 if (tcp_Gmod4G(adv_seq
, nxt
))
1010 return; /* not yet */
1012 tcp_conn
->tc_adv_data
= NULL
;
1013 data_len
= bf_bufsize(adv_data
);
1015 if (tcp_Lmod4G(adv_seq
, nxt
))
1017 if (tcp_LEmod4G(adv_seq
+data_len
, nxt
))
1019 /* Data is not needed anymore. */
1024 len_diff
= nxt
-adv_seq
;
1025 adv_data
= bf_delhead(adv_data
, len_diff
);
1026 data_len
-= len_diff
;
1029 DBLOCK(1, printf("using advanced data\n"));
1031 /* Append data to the input buffer */
1032 if (tcp_conn
->tc_rcvd_data
== NULL
)
1034 tcp_conn
->tc_rcvd_data
= adv_data
;
1038 tcp_conn
->tc_rcvd_data
=
1039 bf_append(tcp_conn
->tc_rcvd_data
, adv_data
);
1041 tcp_conn
->tc_SND_NXT
+= data_len
;
1042 assert(tcp_check_conn(tcp_conn
));
1044 if (tcp_conn
->tc_fd
&&
1045 (tcp_conn
->tc_fd
->tf_flags
& TFF_READ_IP
))
1047 tcp_fd_read(tcp_conn
, 1);
1049 if (tcp_conn
->tc_fd
&&
1050 (tcp_conn
->tc_fd
->tf_flags
& TFF_SEL_READ
))
1052 tcp_rsel_read(tcp_conn
);
1057 static void process_advanced_data(tcp_conn
, tcp_hdr
, tcp_data
, data_len
)
1058 tcp_conn_t
*tcp_conn
;
1066 assert(tcp_conn
->tc_busy
);
1068 /* Note, tcp_data will be freed by the caller. */
1070 /* Always send an ACK, this allows the sender to do a fast
1073 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
1074 tcp_conn_write(tcp_conn
, 1);
1076 if (tcp_hdr
->th_flags
& THF_URG
)
1077 return; /* Urgent data is to complicated */
1079 if (tcp_hdr
->th_flags
& THF_PSH
)
1080 tcp_conn
->tc_flags
|= TCF_RCV_PUSH
;
1081 seq
= ntohl(tcp_hdr
->th_seq_nr
);
1083 /* Make sure that the packet doesn't fall outside of the window
1086 if (tcp_Gmod4G(seq
+data_len
, tcp_conn
->tc_RCV_HI
))
1089 adv_data
= tcp_conn
->tc_adv_data
;
1090 adv_seq
= tcp_conn
->tc_adv_seq
;
1091 tcp_conn
->tc_adv_data
= NULL
;
1093 tcp_data
->acc_linkC
++;
1094 if (adv_data
== NULL
)
1099 else if (seq
+ data_len
== adv_seq
)
1101 /* New data fits right before exiting data. */
1102 adv_data
= bf_append(tcp_data
, adv_data
);
1105 else if (adv_seq
+ bf_bufsize(adv_data
) == seq
)
1107 /* New data fits right after exiting data. */
1108 adv_data
= bf_append(adv_data
, tcp_data
);
1112 /* New data doesn't fit. */
1115 tcp_conn
->tc_adv_data
= adv_data
;
1116 tcp_conn
->tc_adv_seq
= adv_seq
;
1119 static void create_RST(tcp_conn
, ip_hdr
, tcp_hdr
, data_len
)
1120 tcp_conn_t
*tcp_conn
;
1125 acc_t
*tmp_ipopt
, *tmp_tcpopt
, *tcp_pack
;
1127 ip_hdr_t
*RST_ip_hdr
;
1128 tcp_hdr_t
*RST_tcp_hdr
;
1129 size_t pack_size
, ip_hdr_len
, mss
;
1131 DBLOCK(0x10, printf("in create_RST, bad pack is:\n");
1132 tcp_print_pack(ip_hdr
, tcp_hdr
); tcp_print_state(tcp_conn
);
1135 assert(tcp_conn
->tc_busy
);
1137 /* Only send RST packets in reponse to actual data (or SYN, FIN)
1138 * this solves a problem during connection shutdown. The problem
1139 * is the follow senario: a senders closes the connection instead
1140 * of doing a shutdown and waiting for the receiver to shutdown.
1141 * The receiver is slow in processing the last data. After the
1142 * sender has completely closed the connection, the receiver
1143 * sends a window update which triggers the sender to send a
1144 * RST. The receiver closes the connection in reponse to the RST.
1146 if ((tcp_hdr
->th_flags
& (THF_FIN
|THF_SYN
)) == 0 &&
1150 { printf("tcp_recv`create_RST: no data, no RST\n"); }
1155 tmp_ipopt
= tcp_conn
->tc_remipopt
;
1157 tmp_ipopt
->acc_linkC
++;
1158 tmp_tcpopt
= tcp_conn
->tc_tcpopt
;
1160 tmp_tcpopt
->acc_linkC
++;
1162 tcp_extract_ipopt (tcp_conn
, ip_hdr
);
1163 tcp_extract_tcpopt (tcp_conn
, tcp_hdr
, &mss
);
1165 RST_acc
= tcp_make_header (tcp_conn
, &RST_ip_hdr
, &RST_tcp_hdr
,
1168 if (tcp_conn
->tc_remipopt
)
1169 bf_afree(tcp_conn
->tc_remipopt
);
1170 tcp_conn
->tc_remipopt
= tmp_ipopt
;
1171 if (tcp_conn
->tc_tcpopt
)
1172 bf_afree(tcp_conn
->tc_tcpopt
);
1173 tcp_conn
->tc_tcpopt
= tmp_tcpopt
;
1175 RST_ip_hdr
->ih_src
= ip_hdr
->ih_dst
;
1176 RST_ip_hdr
->ih_dst
= ip_hdr
->ih_src
;
1178 RST_tcp_hdr
->th_srcport
= tcp_hdr
->th_dstport
;
1179 RST_tcp_hdr
->th_dstport
= tcp_hdr
->th_srcport
;
1180 if (tcp_hdr
->th_flags
& THF_ACK
)
1182 RST_tcp_hdr
->th_seq_nr
= tcp_hdr
->th_ack_nr
;
1183 RST_tcp_hdr
->th_flags
= THF_RST
;
1187 RST_tcp_hdr
->th_seq_nr
= 0;
1188 RST_tcp_hdr
->th_ack_nr
=
1190 ntohl(tcp_hdr
->th_seq_nr
)+
1192 (tcp_hdr
->th_flags
& THF_SYN
? 1 : 0) +
1193 (tcp_hdr
->th_flags
& THF_FIN
? 1 : 0));
1194 RST_tcp_hdr
->th_flags
= THF_RST
|THF_ACK
;
1197 pack_size
= bf_bufsize(RST_acc
);
1198 RST_ip_hdr
->ih_length
= htons(pack_size
);
1199 RST_tcp_hdr
->th_window
= htons(tcp_conn
->tc_rcv_wnd
);
1200 RST_tcp_hdr
->th_chksum
= 0;
1202 RST_acc
->acc_linkC
++;
1203 ip_hdr_len
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
) << 2;
1204 tcp_pack
= bf_delhead(RST_acc
, ip_hdr_len
);
1205 RST_tcp_hdr
->th_chksum
= ~tcp_pack_oneCsum (RST_ip_hdr
, tcp_pack
);
1208 DBLOCK(2, tcp_print_pack(ip_hdr
, tcp_hdr
); printf("\n");
1209 tcp_print_pack(RST_ip_hdr
, RST_tcp_hdr
); printf("\n"));
1211 if (tcp_conn
->tc_frag2send
)
1212 bf_afree(tcp_conn
->tc_frag2send
);
1213 tcp_conn
->tc_frag2send
= RST_acc
;
1214 tcp_conn_write(tcp_conn
, 1);
1218 tcp_fd_read(tcp_conn
, enq
)
1219 tcp_conn_t
*tcp_conn
;
1220 int enq
; /* Enqueue writes. */
1223 size_t data_size
, read_size
;
1225 int fin_recv
, urg
, push
, result
;
1226 i32_t old_window
, new_window
;
1229 assert(tcp_conn
->tc_busy
);
1231 tcp_fd
= tcp_conn
->tc_fd
;
1233 assert (tcp_fd
->tf_flags
& TFF_READ_IP
);
1234 if (tcp_conn
->tc_state
== TCS_CLOSED
)
1236 if (tcp_fd
->tf_read_offset
)
1237 tcp_reply_read (tcp_fd
, tcp_fd
->tf_read_offset
);
1239 tcp_reply_read (tcp_fd
, tcp_conn
->tc_error
);
1243 urg
= tcp_Gmod4G(tcp_conn
->tc_RCV_UP
, tcp_conn
->tc_RCV_LO
);
1244 push
= (tcp_conn
->tc_flags
& TCF_RCV_PUSH
);
1245 fin_recv
= (tcp_conn
->tc_flags
& TCF_FIN_RECV
);
1247 data_size
= tcp_conn
->tc_RCV_NXT
-tcp_conn
->tc_RCV_LO
;
1253 printf("tcp_fd_read: RCV_UP = 0x%x, RCV_LO = 0x%x\n",
1254 tcp_conn
->tc_RCV_UP
, tcp_conn
->tc_RCV_LO
);
1256 read_size
= tcp_conn
->tc_RCV_UP
-tcp_conn
->tc_RCV_LO
;
1259 read_size
= data_size
;
1261 if (read_size
>= tcp_fd
->tf_read_count
)
1262 read_size
= tcp_fd
->tf_read_count
;
1263 else if (!push
&& !fin_recv
&& !urg
&&
1264 data_size
< TCP_MIN_RCV_WND_SIZE
)
1266 /* Defer the copy out until later. */
1269 else if (data_size
== 0 && !fin_recv
)
1271 /* No data, and no end of file. */
1277 if (urg
&& !(tcp_fd
->tf_flags
& TFF_RECV_URG
))
1279 if (tcp_fd
->tf_read_offset
)
1281 tcp_reply_read (tcp_fd
,
1282 tcp_fd
->tf_read_offset
);
1286 tcp_reply_read (tcp_fd
, EURG
);
1290 else if (!urg
&& (tcp_fd
->tf_flags
& TFF_RECV_URG
))
1292 if (tcp_fd
->tf_read_offset
)
1294 tcp_reply_read (tcp_fd
,
1295 tcp_fd
->tf_read_offset
);
1299 tcp_reply_read(tcp_fd
, ENOURG
);
1304 if (read_size
== data_size
)
1306 data
= tcp_conn
->tc_rcvd_data
;
1311 data
= bf_cut(tcp_conn
->tc_rcvd_data
, 0, read_size
);
1313 result
= (*tcp_fd
->tf_put_userdata
) (tcp_fd
->tf_srfd
,
1314 tcp_fd
->tf_read_offset
, data
, FALSE
);
1317 if (tcp_fd
->tf_read_offset
)
1318 tcp_reply_read(tcp_fd
, tcp_fd
->
1321 tcp_reply_read(tcp_fd
, result
);
1324 tcp_fd
->tf_read_offset
+= read_size
;
1325 tcp_fd
->tf_read_count
-= read_size
;
1327 if (data_size
== read_size
)
1329 bf_afree(tcp_conn
->tc_rcvd_data
);
1330 tcp_conn
->tc_rcvd_data
= 0;
1334 tcp_conn
->tc_rcvd_data
=
1335 bf_delhead(tcp_conn
->tc_rcvd_data
,
1338 tcp_conn
->tc_RCV_LO
+= read_size
;
1339 data_size
-= read_size
;
1342 /* Update IRS and often RCV_UP every 0.5GB */
1343 if (tcp_conn
->tc_RCV_LO
- tcp_conn
->tc_IRS
> 0x40000000)
1345 tcp_conn
->tc_IRS
+= 0x20000000;
1346 DBLOCK(1, printf("tcp_fd_read: updating IRS to 0x%lx\n",
1347 (unsigned long)tcp_conn
->tc_IRS
););
1348 if (tcp_Lmod4G(tcp_conn
->tc_RCV_UP
, tcp_conn
->tc_IRS
))
1350 tcp_conn
->tc_RCV_UP
= tcp_conn
->tc_IRS
;
1352 "tcp_fd_read: updating RCV_UP to 0x%lx\n",
1353 (unsigned long)tcp_conn
->tc_RCV_UP
););
1355 DBLOCK(1, printf("tcp_fd_read: RCP_LO = 0x%lx\n",
1356 (unsigned long)tcp_conn
->tc_RCV_LO
););
1359 mss
= tcp_conn
->tc_mtu
-IP_TCP_MIN_HDR_SIZE
;
1360 if (tcp_conn
->tc_RCV_HI
-tcp_conn
->tc_RCV_LO
<=
1361 tcp_conn
->tc_rcv_wnd
-mss
)
1363 old_window
= tcp_conn
->tc_RCV_HI
-tcp_conn
->tc_RCV_NXT
;
1364 tcp_conn
->tc_RCV_HI
= tcp_conn
->tc_RCV_LO
+
1365 tcp_conn
->tc_rcv_wnd
;
1366 new_window
= tcp_conn
->tc_RCV_HI
-tcp_conn
->tc_RCV_NXT
;
1367 assert(old_window
>=0 && new_window
>= old_window
);
1368 if (old_window
< mss
&& new_window
>= mss
)
1370 tcp_conn
->tc_flags
|= TCF_SEND_ACK
;
1371 DBLOCK(2, printf("opening window\n"));
1372 tcp_conn_write(tcp_conn
, 1);
1375 if (tcp_conn
->tc_rcvd_data
== NULL
&&
1376 tcp_conn
->tc_adv_data
== NULL
)
1378 /* Out of data, clear PUSH flag and reply to a read. */
1379 tcp_conn
->tc_flags
&= ~TCF_RCV_PUSH
;
1381 if (fin_recv
|| urg
|| tcp_fd
->tf_read_offset
||
1382 !tcp_fd
->tf_read_count
)
1384 tcp_reply_read (tcp_fd
, tcp_fd
->tf_read_offset
);
1390 tcp_sel_read(tcp_conn
)
1391 tcp_conn_t
*tcp_conn
;
1394 int fin_recv
, urg
, push
;
1396 if (tcp_conn
->tc_state
== TCS_CLOSED
)
1399 fin_recv
= (tcp_conn
->tc_flags
& TCF_FIN_RECV
);
1403 data_size
= tcp_conn
->tc_RCV_NXT
-tcp_conn
->tc_RCV_LO
;
1406 /* No data, and no end of file. */
1410 urg
= tcp_Gmod4G(tcp_conn
->tc_RCV_UP
, tcp_conn
->tc_RCV_LO
);
1411 push
= (tcp_conn
->tc_flags
& TCF_RCV_PUSH
);
1413 if (!push
&& !urg
&& data_size
< TCP_MIN_RCV_WND_SIZE
)
1415 /* Defer until later. */
1423 tcp_rsel_read(tcp_conn
)
1424 tcp_conn_t
*tcp_conn
;
1428 if (tcp_sel_read(tcp_conn
) == 0)
1431 tcp_fd
= tcp_conn
->tc_fd
;
1432 tcp_fd
->tf_flags
&= ~TFF_SEL_READ
;
1433 if (tcp_fd
->tf_select_res
)
1434 tcp_fd
->tf_select_res(tcp_fd
->tf_srfd
, SR_SELECT_READ
);
1436 printf("tcp_rsel_read: no select_res\n");
1439 void tcp_bytesavailable(tcp_fd
, bytesp
)
1443 tcp_conn_t
*tcp_conn
;
1447 *bytesp
= 0; /* The default is that nothing is available */
1449 if (!(tcp_fd
->tf_flags
& TFF_CONNECTED
))
1451 tcp_conn
= tcp_fd
->tf_conn
;
1453 if (tcp_conn
->tc_state
== TCS_CLOSED
)
1456 urg
= tcp_Gmod4G(tcp_conn
->tc_RCV_UP
, tcp_conn
->tc_RCV_LO
);
1457 fin_recv
= (tcp_conn
->tc_flags
& TCF_FIN_RECV
);
1459 data_size
= tcp_conn
->tc_RCV_NXT
-tcp_conn
->tc_RCV_LO
;
1463 data_size
= tcp_conn
->tc_RCV_UP
-tcp_conn
->tc_RCV_LO
;
1465 if (urg
&& !(tcp_fd
->tf_flags
& TFF_RECV_URG
))
1467 else if (!urg
&& (tcp_fd
->tf_flags
& TFF_RECV_URG
))
1474 * $PchId: tcp_recv.c,v 1.30 2005/06/28 14:21:35 philip Exp $