opendir change: refinement
[minix.git] / servers / inet / generic / tcp_recv.c
blob8178899b88e30df39797b615db84e40fe7361835
1 /*
2 tcp_recv.c
4 Copyright 1995 Philip Homburg
5 */
7 #include "inet.h"
8 #include "buf.h"
9 #include "clock.h"
10 #include "event.h"
11 #include "type.h"
12 #include "sr.h"
14 #include "io.h"
15 #include "tcp_int.h"
16 #include "tcp.h"
17 #include "assert.h"
19 THIS_FILE
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)
29 tcp_conn_t *tcp_conn;
30 ip_hdr_t *ip_hdr;
31 tcp_hdr_t *tcp_hdr;
32 acc_t *tcp_data;
33 size_t data_len;
35 tcp_fd_t *connuser;
36 int tcp_hdr_flags;
37 u32_t seg_ack, seg_seq, rcv_hi, snd_una, snd_nxt;
38 u16_t seg_wnd, mtu;
39 size_t mss;
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);
47 #if 0
48 { where(); tcp_print_conn(tcp_conn); printf("\n");
49 tcp_print_pack(ip_hdr, tcp_hdr); printf("\n"); }
50 #endif
52 switch (tcp_conn->tc_state)
54 case TCS_CLOSED:
56 CLOSED:
57 discard all data.
58 !RST ?
59 ACK ?
60 <SEQ=SEG.ACK><CTL=RST>
61 exit
63 <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
64 exit
66 discard packet
67 exit
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);
75 break;
76 case TCS_LISTEN:
78 LISTEN:
79 RST ?
80 discard packet
81 exit
82 ACK ?
83 <SEQ=SEG.ACK><CTL=RST>
84 exit
85 SYN ?
86 BUG: no security check
87 RCV.NXT= SEG.SEQ+1
88 IRS= SEG.SEQ
89 ISS should already be selected
90 <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
91 SND.NXT=ISS+1
92 SND.UNA=ISS
93 state= SYN-RECEIVED
94 exit
96 shouldnot occur
97 discard packet
98 exit
100 if (tcp_hdr_flags & THF_RST)
101 break;
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);
106 break;
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 */
116 mtu= IP_DEF_MTU;
118 if (mtu < tcp_conn->tc_max_mtu)
120 tcp_conn->tc_max_mtu= mtu;
121 tcp_conn->tc_mtu= mtu;
122 DBLOCK(1, printf(
123 "tcp[%d]: conn[%d]: mtu = %d\n",
124 tcp_conn->tc_port-tcp_port_table,
125 tcp_conn-tcp_conn_table,
126 mtu););
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;
141 tcp_conn->tc_stt= 0;
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);
152 printf("\n"));
154 /* Start the timer (if necessary) */
155 tcp_set_send_timer(tcp_conn);
157 break;
159 /* do nothing */
160 break;
161 case TCS_SYN_SENT:
163 SYN-SENT:
164 ACK ?
165 SEG.ACK <= ISS || SEG.ACK > SND.NXT ?
166 RST ?
167 discard packet
168 exit
170 <SEQ=SEG.ACK><CTL=RST>
171 exit
172 SND.UNA <= SEG.ACK && SEG.ACK <= SND.NXT ?
173 ACK is acceptable
175 ACK is !acceptable
177 ACK is !acceptable
178 RST ?
179 ACK acceptable ?
180 discard segment
181 state= CLOSED
182 error "connection refused"
183 exit
185 discard packet
186 exit
187 BUG: no security check
188 SYN ?
189 IRS= SEG.SEQ
190 RCV.NXT= IRS+1
191 ACK ?
192 SND.UNA= SEG.ACK
193 SND.UNA > ISS ?
194 state= ESTABLISHED
195 <SEQ=SND.NXT><ACK= RCV.NXT><CTL=ACK>
196 process ev. URG and text
197 exit
199 state= SYN-RECEIVED
200 SND.WND= SEG.WND
201 SND.WL1= SEG.SEQ
202 SND.WL2= SEG.ACK
203 <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
204 exit
206 discard segment
207 exit
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)
214 break;
215 else
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);
224 break;
227 acceptable_ACK= (tcp_LEmod4G(tcp_conn->tc_SND_UNA,
228 seg_ack) && tcp_LEmod4G(seg_ack,
229 tcp_conn->tc_SND_NXT));
231 else
232 acceptable_ACK= FALSE;
233 if (tcp_hdr_flags & THF_RST)
235 if (acceptable_ACK)
237 DBLOCK(1, printf(
238 "calling tcp_close_connection\n"));
240 tcp_close_connection(tcp_conn,
241 ECONNREFUSED);
243 break;
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 */
253 mtu= IP_DEF_MTU;
255 if (mtu < tcp_conn->tc_max_mtu)
257 tcp_conn->tc_max_mtu= mtu;
258 tcp_conn->tc_mtu= mtu;
259 DBLOCK(1, printf(
260 "tcp[%d]: conn[%d]: mtu = %d\n",
261 tcp_conn->tc_port-tcp_port_table,
262 tcp_conn-tcp_conn_table,
263 mtu););
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,
274 tcp_conn->tc_ISS))
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);
286 if (data_len != 0)
288 tcp_frag2conn(tcp_conn, ip_hdr,
289 tcp_hdr, tcp_data, data_len);
290 /* tcp_data is already freed */
291 return;
293 break;
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);
302 break;
304 case TCS_SYN_RECEIVED:
306 SYN-RECEIVED:
307 test if segment is acceptable:
309 Segment Receive Test
310 Length Window
311 0 0 SEG.SEQ == RCV.NXT
312 0 >0 RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
313 >0 0 not acceptable
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)
324 rcv_hi++;
325 send_rst= tcp_Lmod4G(seg_seq, tcp_conn->tc_IRS) ||
326 tcp_Gmod4G(seg_seq, tcp_conn->tc_RCV_NXT+0x10000);
327 close_connection= 0;
329 if (!data_len)
331 if (rcv_hi == tcp_conn->tc_RCV_NXT)
332 segm_acceptable= (seg_seq == rcv_hi);
333 else
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));
342 else
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,
352 rcv_hi));
354 else
356 segm_acceptable= FALSE;
360 !segment acceptable ?
361 RST ?
362 discard packet
363 exit
365 <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
366 exit
368 if (!segm_acceptable)
370 if (tcp_hdr_flags & THF_RST)
371 ; /* do nothing */
372 else if (send_rst)
374 create_RST(tcp_conn, ip_hdr, tcp_hdr,
375 data_len);
376 tcp_conn_write(tcp_conn, 1);
378 else
380 tcp_conn->tc_flags |= TCF_SEND_ACK;
381 tcp_conn_write(tcp_conn, 1);
383 break;
386 RST ?
387 initiated by a LISTEN ?
388 state= LISTEN
389 exit
391 state= CLOSED
392 error "connection refused"
393 exit
396 if (tcp_hdr_flags & THF_RST)
397 close_connection= 1;
400 SYN in window ?
401 initiated by a LISTEN ?
402 state= LISTEN
403 exit
405 state= CLOSED
406 error "connection reset"
407 exit
409 if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,
410 tcp_conn->tc_RCV_NXT))
412 close_connection= 1;
415 if (close_connection)
417 if (!tcp_conn->tc_orglisten)
419 tcp_close_connection(tcp_conn, ECONNREFUSED);
420 break;
423 connuser= tcp_conn->tc_fd;
424 assert(connuser);
425 if (connuser->tf_flags & TFF_LISTENQ)
427 tcp_close_connection (tcp_conn,
428 ECONNREFUSED);
430 else
432 tcp_conn->tc_connInprogress= 0;
433 tcp_conn->tc_fd= NULL;
435 tcp_close_connection (tcp_conn,
436 ECONNREFUSED);
438 /* Pick a new ISS next time */
439 tcp_conn->tc_ISS= 0;
441 (void)tcp_su4listen(connuser, tcp_conn,
442 0 /* !do_listenq */);
444 break;
447 !ACK ?
448 discard packet
449 exit
451 if (!(tcp_hdr_flags & THF_ACK))
452 break;
454 SND.UNA < SEG.ACK <= SND.NXT ?
455 state= ESTABLISHED
457 <SEG=SEG.ACK><CTL=RST>
458 exit
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,
473 data_len);
474 /* tcp_data is already freed */
475 return;
477 else
479 create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len);
480 tcp_conn_write(tcp_conn, 1);
481 break;
483 break;
485 case TCS_ESTABLISHED:
486 case TCS_CLOSING:
488 ESTABLISHED:
489 FIN-WAIT-1:
490 FIN-WAIT-2:
491 CLOSE-WAIT:
492 CLOSING:
493 LAST-ACK:
494 TIME-WAIT:
495 test if segment is acceptable:
496 Segment Receive Test
497 Length Window
498 0 0 SEG.SEQ == RCV.NXT
499 0 >0 RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
500 >0 0 not acceptable
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)
508 rcv_hi++;
509 if (!data_len)
511 if (rcv_hi == tcp_conn->tc_RCV_NXT)
512 segm_acceptable= (seg_seq == rcv_hi);
513 else
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));
522 else
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,
532 rcv_hi));
534 else
536 segm_acceptable= FALSE;
540 !segment acceptable ?
541 RST ?
542 discard packet
543 exit
545 <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
546 exit
548 if (!segm_acceptable)
550 if (!(tcp_hdr_flags & THF_RST))
552 DBLOCK(0x20,
553 printf("segment is not acceptable\n");
554 printf("\t");
555 tcp_print_pack(ip_hdr, tcp_hdr);
556 printf("\n\t");
557 tcp_print_conn(tcp_conn);
558 printf("\n"));
559 tcp_conn->tc_flags |= TCF_SEND_ACK;
560 tcp_conn_write(tcp_conn, 1);
562 /* Sometimes, a retransmission sets the PSH
563 * flag (Solaris 2.4)
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 &
571 TFF_READ_IP))
573 tcp_fd_read(tcp_conn, 1);
575 if (tcp_conn->tc_fd &&
576 (tcp_conn->tc_fd->tf_flags &
577 TFF_SEL_READ))
579 tcp_rsel_read(tcp_conn);
583 break;
586 RST ?
587 state == CLOSING || state == LAST-ACK ||
588 state == TIME-WAIT ?
589 state= CLOSED
590 exit
592 state= CLOSED
593 error "connection reset"
594 exit
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);
608 else
609 tcp_close_connection(tcp_conn, ECONNRESET);
610 break;
613 SYN in window ?
614 state= CLOSED
615 error "connection reset"
616 exit
618 if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,
619 tcp_conn->tc_RCV_NXT))
621 tcp_close_connection(tcp_conn, ECONNRESET);
622 break;
625 !ACK ?
626 discard packet
627 exit
629 if (!(tcp_hdr_flags & THF_ACK))
630 break;
633 SND.UNA < SEG.ACK <= SND.NXT ?
634 SND.UNA= SEG.ACK
635 reply "send ok"
636 SND.WL1 < SEG.SEQ || (SND.WL1 == SEG.SEQ &&
637 SND.WL2 <= SEG.ACK ?
638 SND.WND= SEG.WND
639 SND.Wl1= SEG.SEQ
640 SND.WL2= SEG.ACK
641 SEG.ACK <= SND.UNA ?
642 ignore ACK
643 SEG.ACK > SND.NXT ?
644 <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
645 discard packet
646 exit
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)
661 tcp_conn->tc_stt= 0;
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))
670 /* Duplicate ACK */
671 if (++tcp_conn->tc_snd_dack ==
672 TCP_DACK_RETRANS)
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
682 * zero window.
684 if (tcp_conn->tc_snd_cwnd == snd_una &&
685 seg_wnd != 0)
687 DBLOCK(2, printf("zero window opened\n"));
688 /* The other side opened up its receive
689 * window. */
690 mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;
691 if (seg_wnd > 2*mss)
692 seg_wnd= 2*mss;
693 tcp_conn->tc_snd_cwnd= snd_una+seg_wnd;
694 tcp_conn_write(tcp_conn, 1);
696 if (seg_wnd == 0)
698 tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_TRM=
699 snd_una;
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)
707 break;
709 else if (tcp_Gmod4G(seg_ack,
710 snd_nxt))
712 tcp_conn->tc_flags |= TCF_SEND_ACK;
713 tcp_conn_write(tcp_conn, 1);
714 DBLOCK(1, printf(
715 "got an ack of something I haven't send\n");
716 printf( "seg_ack= %u, SND_NXT= %u\n",
717 seg_ack, snd_nxt));
718 break;
722 process data...
724 tcp_extract_ipopt(tcp_conn, ip_hdr);
725 tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss);
727 if (data_len)
729 if (tcp_LEmod4G(seg_seq, tcp_conn->tc_RCV_NXT))
731 process_data (tcp_conn, tcp_hdr,
732 tcp_data, data_len);
734 else
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 */
743 break;
746 FIN ?
747 reply pending receives
748 advace RCV.NXT over the FIN
749 <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
751 state == ESTABLISHED ?
752 state= CLOSE-WAIT
753 state == FIN-WAIT-1 ?
754 state= CLOSING
755 state == FIN-WAIT-2 ?
756 state= TIME-WAIT
757 state == TIME-WAIT ?
758 restart the TIME-WAIT timer
759 exit
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);
784 break;
785 default:
786 printf("tcp_frag2conn: unknown state ");
787 tcp_print_state(tcp_conn);
788 break;
790 if (tcp_data != NULL)
791 bf_afree(tcp_data);
795 static void
796 process_data(tcp_conn, tcp_hdr, tcp_data, data_len)
797 tcp_conn_t *tcp_conn;
798 tcp_hdr_t *tcp_hdr;
799 acc_t *tcp_data;
800 int data_len;
802 u32_t lo_seq, hi_seq, urg_seq, seq_nr, adv_seq, nxt;
803 u32_t urgptr;
804 int tcp_hdr_flags;
805 unsigned int offset;
806 acc_t *tmp_data, *rcvd_data, *adv_data;
807 int len_diff;
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++;
819 lo_seq= seq_nr;
820 tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK;
822 if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT))
824 DBLOCK(0x10,
825 printf("segment is a retransmission\n"));
826 offset= tcp_conn->tc_RCV_NXT-lo_seq;
827 tcp_data= bf_delhead(tcp_data, offset);
828 lo_seq += offset;
829 data_len -= offset;
830 if (tcp_hdr_flags & THF_URG)
832 printf("process_data: updating urgent pointer\n");
833 if (urgptr >= offset)
834 urgptr -= offset;
835 else
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
846 * data
848 urgptr++;
850 if (urgptr == 0)
851 tcp_hdr_flags &= ~THF_URG;
854 if (tcp_hdr_flags & THF_URG)
856 if (urgptr > data_len)
857 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))
867 DBLOCK(1, printf(
868 "ignoring urgent data\n"));
870 bf_afree(tcp_data);
871 /* Should set advertised window to
872 * zero */
874 /* Flush */
875 tcp_conn->tc_flags |= TCF_RCV_PUSH;
876 if (tcp_conn->tc_fd &&
877 (tcp_conn->tc_fd->tf_flags &
878 TFF_READ_IP))
880 tcp_fd_read(tcp_conn, 1);
882 if (tcp_conn->tc_fd &&
883 (tcp_conn->tc_fd->tf_flags &
884 TFF_SEL_READ))
886 tcp_rsel_read(tcp_conn);
888 return;
891 if (tcp_Gmod4G(urg_seq, tcp_conn->tc_RCV_UP))
892 tcp_conn->tc_RCV_UP= urg_seq;
893 #if 0
894 if (urgptr < data_len)
896 data_len= urgptr;
897 tmp_data= bf_cut(tcp_data, 0, data_len);
898 bf_afree(tcp_data);
899 tcp_data= tmp_data;
900 tcp_hdr_flags &= ~THF_FIN;
902 #endif
903 tcp_conn->tc_flags |= TCF_RCV_PUSH;
905 else
907 /* Normal data. */
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);
920 bf_afree(tcp_data);
921 tcp_data= tmp_data;
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)
951 return;
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;
958 bf_afree(tcp_data);
959 return;
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)
975 bf_afree(tcp_data);
976 return;
978 tcp_data= bf_delhead(tcp_data, offset);
979 lo_seq += offset;
980 data_len -= 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. */
1020 bf_afree(adv_data);
1021 return;
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;
1036 else
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;
1059 tcp_hdr_t *tcp_hdr;
1060 acc_t *tcp_data;
1061 int data_len;
1063 u32_t seq, adv_seq;
1064 acc_t *adv_data;
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
1071 * retransmit.
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
1084 * we offered.
1086 if (tcp_Gmod4G(seq+data_len, tcp_conn->tc_RCV_HI))
1087 return;
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)
1096 adv_seq= seq;
1097 adv_data= tcp_data;
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);
1103 adv_seq= seq;
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);
1110 else
1112 /* New data doesn't fit. */
1113 bf_afree(tcp_data);
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;
1121 ip_hdr_t *ip_hdr;
1122 tcp_hdr_t *tcp_hdr;
1123 int data_len;
1125 acc_t *tmp_ipopt, *tmp_tcpopt, *tcp_pack;
1126 acc_t *RST_acc;
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);
1133 printf("\n"));
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 &&
1147 data_len == 0)
1149 #if DEBUG
1150 { printf("tcp_recv`create_RST: no data, no RST\n"); }
1151 #endif
1152 return;
1155 tmp_ipopt= tcp_conn->tc_remipopt;
1156 if (tmp_ipopt)
1157 tmp_ipopt->acc_linkC++;
1158 tmp_tcpopt= tcp_conn->tc_tcpopt;
1159 if (tmp_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,
1166 (acc_t *)0);
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;
1185 else
1187 RST_tcp_hdr->th_seq_nr= 0;
1188 RST_tcp_hdr->th_ack_nr=
1189 htonl(
1190 ntohl(tcp_hdr->th_seq_nr)+
1191 data_len +
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);
1206 bf_afree(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);
1217 void
1218 tcp_fd_read(tcp_conn, enq)
1219 tcp_conn_t *tcp_conn;
1220 int enq; /* Enqueue writes. */
1222 tcp_fd_t *tcp_fd;
1223 size_t data_size, read_size;
1224 acc_t *data;
1225 int fin_recv, urg, push, result;
1226 i32_t old_window, new_window;
1227 u16_t mss;
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);
1238 else
1239 tcp_reply_read (tcp_fd, tcp_conn->tc_error);
1240 return;
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;
1248 if (fin_recv)
1249 data_size--;
1250 if (urg)
1252 #if DEBUG
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);
1255 #endif
1256 read_size= tcp_conn->tc_RCV_UP-tcp_conn->tc_RCV_LO;
1258 else
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. */
1267 return;
1269 else if (data_size == 0 && !fin_recv)
1271 /* No data, and no end of file. */
1272 return;
1275 if (read_size)
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);
1284 else
1286 tcp_reply_read (tcp_fd, EURG);
1288 return;
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);
1297 else
1299 tcp_reply_read(tcp_fd, ENOURG);
1301 return;
1304 if (read_size == data_size)
1306 data= tcp_conn->tc_rcvd_data;
1307 data->acc_linkC++;
1309 else
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);
1315 if (result<0)
1317 if (tcp_fd->tf_read_offset)
1318 tcp_reply_read(tcp_fd, tcp_fd->
1319 tf_read_offset);
1320 else
1321 tcp_reply_read(tcp_fd, result);
1322 return;
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;
1332 else
1334 tcp_conn->tc_rcvd_data=
1335 bf_delhead(tcp_conn->tc_rcvd_data,
1336 read_size);
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;
1351 DBLOCK(1, printf(
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);
1385 return;
1389 unsigned
1390 tcp_sel_read(tcp_conn)
1391 tcp_conn_t *tcp_conn;
1393 size_t data_size;
1394 int fin_recv, urg, push;
1396 if (tcp_conn->tc_state == TCS_CLOSED)
1397 return 1;
1399 fin_recv= (tcp_conn->tc_flags & TCF_FIN_RECV);
1400 if (fin_recv)
1401 return 1;
1403 data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO;
1404 if (data_size == 0)
1406 /* No data, and no end of file. */
1407 return 0;
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. */
1416 return 0;
1419 return 1;
1422 void
1423 tcp_rsel_read(tcp_conn)
1424 tcp_conn_t *tcp_conn;
1426 tcp_fd_t *tcp_fd;
1428 if (tcp_sel_read(tcp_conn) == 0)
1429 return;
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);
1435 else
1436 printf("tcp_rsel_read: no select_res\n");
1439 void tcp_bytesavailable(tcp_fd, bytesp)
1440 tcp_fd_t *tcp_fd;
1441 int *bytesp;
1443 tcp_conn_t *tcp_conn;
1444 size_t data_size;
1445 int fin_recv, urg;
1447 *bytesp= 0; /* The default is that nothing is available */
1449 if (!(tcp_fd->tf_flags & TFF_CONNECTED))
1450 return;
1451 tcp_conn= tcp_fd->tf_conn;
1453 if (tcp_conn->tc_state == TCS_CLOSED)
1454 return;
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;
1460 if (fin_recv)
1461 data_size--;
1462 if (urg)
1463 data_size= tcp_conn->tc_RCV_UP-tcp_conn->tc_RCV_LO;
1465 if (urg && !(tcp_fd->tf_flags & TFF_RECV_URG))
1466 return;
1467 else if (!urg && (tcp_fd->tf_flags & TFF_RECV_URG))
1468 return;
1470 *bytesp= data_size;
1474 * $PchId: tcp_recv.c,v 1.30 2005/06/28 14:21:35 philip Exp $