source: trunk/minix/servers/inet/generic/tcp_recv.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 32.3 KB
Line 
1/*
2tcp_recv.c
3
4Copyright 1995 Philip Homburg
5*/
6
7#include "inet.h"
8#include "buf.h"
9#include "clock.h"
10#include "event.h"
11#include "type.h"
12#include "sr.h"
13
14#include "io.h"
15#include "tcp_int.h"
16#include "tcp.h"
17#include "assert.h"
18
19THIS_FILE
20
21FORWARD void create_RST ARGS(( tcp_conn_t *tcp_conn,
22 ip_hdr_t *ip_hdr, tcp_hdr_t *tcp_hdr, int data_len ));
23FORWARD void process_data ARGS(( tcp_conn_t *tcp_conn,
24 tcp_hdr_t *tcp_hdr, acc_t *tcp_data, int data_len ));
25FORWARD void process_advanced_data ARGS(( tcp_conn_t *tcp_conn,
26 tcp_hdr_t *tcp_hdr, acc_t *tcp_data, int data_len ));
27
28PUBLIC void tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data, data_len)
29tcp_conn_t *tcp_conn;
30ip_hdr_t *ip_hdr;
31tcp_hdr_t *tcp_hdr;
32acc_t *tcp_data;
33size_t data_len;
34{
35 tcp_fd_t *connuser;
36 int tcp_hdr_flags;
37 int ip_hdr_len, tcp_hdr_len;
38 u32_t seg_ack, seg_seq, rcv_hi, snd_una, snd_nxt;
39 u16_t seg_wnd, mtu;
40 size_t mss;
41 int acceptable_ACK, segm_acceptable, send_rst, close_connection;
42
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;
45
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);
50
51#if 0
52 { where(); tcp_print_conn(tcp_conn); printf("\n");
53 tcp_print_pack(ip_hdr, tcp_hdr); printf("\n"); }
54#endif
55
56 switch (tcp_conn->tc_state)
57 {
58 case TCS_CLOSED:
59/*
60CLOSED:
61 discard all data.
62 !RST ?
63 ACK ?
64 <SEQ=SEG.ACK><CTL=RST>
65 exit
66 :
67 <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
68 exit
69 :
70 discard packet
71 exit
72*/
73
74 if (!(tcp_hdr_flags & THF_RST))
75 {
76 create_RST(tcp_conn, ip_hdr, tcp_hdr, data_len);
77 tcp_conn_write(tcp_conn, 1);
78 }
79 break;
80 case TCS_LISTEN:
81/*
82LISTEN:
83 RST ?
84 discard packet
85 exit
86 ACK ?
87 <SEQ=SEG.ACK><CTL=RST>
88 exit
89 SYN ?
90 BUG: no security check
91 RCV.NXT= SEG.SEQ+1
92 IRS= SEG.SEQ
93 ISS should already be selected
94 <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
95 SND.NXT=ISS+1
96 SND.UNA=ISS
97 state= SYN-RECEIVED
98 exit
99 :
100 shouldnot occur
101 discard packet
102 exit
103*/
104 if (tcp_hdr_flags & THF_RST)
105 break;
106 if (tcp_hdr_flags & THF_ACK)
107 {
108 create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len);
109 tcp_conn_write(tcp_conn, 1);
110 break;
111 }
112 if (tcp_hdr_flags & THF_SYN)
113 {
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)
118 {
119 /* No or unrealistic mss, use default MTU */
120 mtu= IP_DEF_MTU;
121 }
122 if (mtu < tcp_conn->tc_max_mtu)
123 {
124 tcp_conn->tc_max_mtu= mtu;
125 tcp_conn->tc_mtu= mtu;
126 DBLOCK(1, printf(
127 "tcp[%d]: conn[%d]: mtu = %d\n",
128 tcp_conn->tc_port-tcp_port_table,
129 tcp_conn-tcp_conn_table,
130 mtu););
131 }
132
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;
145 tcp_conn->tc_stt= 0;
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);
152
153 DIFBLOCK(0x10, seg_seq == 0,
154 printf("warning got 0 IRS from ");
155 writeIpAddr(tcp_conn->tc_remaddr);
156 printf("\n"));
157
158 /* Start the timer (if necessary) */
159 tcp_set_send_timer(tcp_conn);
160
161 break;
162 }
163 /* do nothing */
164 break;
165 case TCS_SYN_SENT:
166/*
167SYN-SENT:
168 ACK ?
169 SEG.ACK <= ISS || SEG.ACK > SND.NXT ?
170 RST ?
171 discard packet
172 exit
173 :
174 <SEQ=SEG.ACK><CTL=RST>
175 exit
176 SND.UNA <= SEG.ACK && SEG.ACK <= SND.NXT ?
177 ACK is acceptable
178 :
179 ACK is !acceptable
180 :
181 ACK is !acceptable
182 RST ?
183 ACK acceptable ?
184 discard segment
185 state= CLOSED
186 error "connection refused"
187 exit
188 :
189 discard packet
190 exit
191 BUG: no security check
192 SYN ?
193 IRS= SEG.SEQ
194 RCV.NXT= IRS+1
195 ACK ?
196 SND.UNA= SEG.ACK
197 SND.UNA > ISS ?
198 state= ESTABLISHED
199 <SEQ=SND.NXT><ACK= RCV.NXT><CTL=ACK>
200 process ev. URG and text
201 exit
202 :
203 state= SYN-RECEIVED
204 SND.WND= SEG.WND
205 SND.WL1= SEG.SEQ
206 SND.WL2= SEG.ACK
207 <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
208 exit
209 :
210 discard segment
211 exit
212*/
213 if (tcp_hdr_flags & THF_ACK)
214 {
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)
218 break;
219 else
220 {
221 /* HACK: force sending a RST,
222 * normally, RSTs are not send
223 * if the segment is an ACK.
224 */
225 create_RST (tcp_conn, ip_hdr,
226 tcp_hdr, data_len+1);
227 tcp_conn_write(tcp_conn, 1);
228 break;
229 }
230 acceptable_ACK= (tcp_LEmod4G(tcp_conn->tc_SND_UNA,
231 seg_ack) && tcp_LEmod4G(seg_ack,
232 tcp_conn->tc_SND_NXT));
233 }
234 else
235 acceptable_ACK= FALSE;
236 if (tcp_hdr_flags & THF_RST)
237 {
238 if (acceptable_ACK)
239 {
240 DBLOCK(1, printf(
241 "calling tcp_close_connection\n"));
242
243 tcp_close_connection(tcp_conn,
244 ECONNREFUSED);
245 }
246 break;
247 }
248 if (tcp_hdr_flags & THF_SYN)
249 {
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)
254 {
255 /* No or unrealistic mss, use default MTU */
256 mtu= IP_DEF_MTU;
257 }
258 if (mtu < tcp_conn->tc_max_mtu)
259 {
260 tcp_conn->tc_max_mtu= mtu;
261 tcp_conn->tc_mtu= mtu;
262 DBLOCK(1, printf(
263 "tcp[%d]: conn[%d]: mtu = %d\n",
264 tcp_conn->tc_port-tcp_port_table,
265 tcp_conn-tcp_conn_table,
266 mtu););
267 }
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,
277 tcp_conn->tc_ISS))
278 {
279 tcp_conn->tc_state= TCS_ESTABLISHED;
280 tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
281
282 assert (tcp_check_conn(tcp_conn));
283 assert(tcp_conn->tc_connInprogress);
284
285 tcp_restart_connect(tcp_conn);
286
287 tcp_conn->tc_flags |= TCF_SEND_ACK;
288 tcp_conn_write(tcp_conn, 1);
289 if (data_len != 0)
290 {
291 tcp_frag2conn(tcp_conn, ip_hdr,
292 tcp_hdr, tcp_data, data_len);
293 /* tcp_data is already freed */
294 return;
295 }
296 break;
297 }
298 tcp_conn->tc_state= TCS_SYN_RECEIVED;
299
300 assert (tcp_check_conn(tcp_conn));
301
302 tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
303 tcp_conn_write(tcp_conn, 1);
304 }
305 break;
306
307 case TCS_SYN_RECEIVED:
308/*
309SYN-RECEIVED:
310 test if segment is acceptable:
311
312 Segment Receive Test
313 Length Window
314 0 0 SEG.SEQ == RCV.NXT
315 0 >0 RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
316 >0 0 not acceptable
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
321
322 Special: Send RST if SEG.SEQ < IRS or SEG.SEQ > RCV.NXT+64K (and
323 the packet is not a RST packet itself).
324*/
325 rcv_hi= tcp_conn->tc_RCV_HI;
326 if (tcp_hdr_flags & THF_URG)
327 rcv_hi++;
328 send_rst= tcp_Lmod4G(seg_seq, tcp_conn->tc_IRS) ||
329 tcp_Gmod4G(seg_seq, tcp_conn->tc_RCV_NXT+0x10000);
330 close_connection= 0;
331
332 if (!data_len)
333 {
334 if (rcv_hi == tcp_conn->tc_RCV_NXT)
335 segm_acceptable= (seg_seq == rcv_hi);
336 else
337 {
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));
343 }
344 }
345 else
346 {
347 if (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT))
348 {
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,
355 rcv_hi));
356 }
357 else
358 {
359 segm_acceptable= FALSE;
360 }
361 }
362/*
363 !segment acceptable ?
364 RST ?
365 discard packet
366 exit
367 :
368 <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
369 exit
370*/
371 if (!segm_acceptable)
372 {
373 if (tcp_hdr_flags & THF_RST)
374 ; /* do nothing */
375 else if (send_rst)
376 {
377 create_RST(tcp_conn, ip_hdr, tcp_hdr,
378 data_len);
379 tcp_conn_write(tcp_conn, 1);
380 }
381 else
382 {
383 tcp_conn->tc_flags |= TCF_SEND_ACK;
384 tcp_conn_write(tcp_conn, 1);
385 }
386 break;
387 }
388/*
389 RST ?
390 initiated by a LISTEN ?
391 state= LISTEN
392 exit
393 :
394 state= CLOSED
395 error "connection refused"
396 exit
397*/
398
399 if (tcp_hdr_flags & THF_RST)
400 close_connection= 1;
401
402/*
403 SYN in window ?
404 initiated by a LISTEN ?
405 state= LISTEN
406 exit
407 :
408 state= CLOSED
409 error "connection reset"
410 exit
411*/
412 if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,
413 tcp_conn->tc_RCV_NXT))
414 {
415 close_connection= 1;
416 }
417
418 if (close_connection)
419 {
420 if (!tcp_conn->tc_orglisten)
421 {
422 tcp_close_connection(tcp_conn, ECONNREFUSED);
423 break;
424 }
425
426 connuser= tcp_conn->tc_fd;
427 assert(connuser);
428 if (connuser->tf_flags & TFF_LISTENQ)
429 {
430 tcp_close_connection (tcp_conn,
431 ECONNREFUSED);
432 }
433 else
434 {
435 tcp_conn->tc_connInprogress= 0;
436 tcp_conn->tc_fd= NULL;
437
438 tcp_close_connection (tcp_conn,
439 ECONNREFUSED);
440
441 /* Pick a new ISS next time */
442 tcp_conn->tc_ISS= 0;
443
444 (void)tcp_su4listen(connuser, tcp_conn,
445 0 /* !do_listenq */);
446 }
447 break;
448 }
449/*
450 !ACK ?
451 discard packet
452 exit
453*/
454 if (!(tcp_hdr_flags & THF_ACK))
455 break;
456/*
457 SND.UNA < SEG.ACK <= SND.NXT ?
458 state= ESTABLISHED
459 :
460 <SEG=SEG.ACK><CTL=RST>
461 exit
462*/
463 if (tcp_Lmod4G(tcp_conn->tc_SND_UNA, seg_ack) &&
464 tcp_LEmod4G(seg_ack, tcp_conn->tc_SND_NXT))
465 {
466 tcp_conn->tc_state= TCS_ESTABLISHED;
467 tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
468
469 tcp_release_retrans(tcp_conn, seg_ack, seg_wnd);
470
471 assert (tcp_check_conn(tcp_conn));
472 assert(tcp_conn->tc_connInprogress);
473
474 tcp_restart_connect(tcp_conn);
475 tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data,
476 data_len);
477 /* tcp_data is already freed */
478 return;
479 }
480 else
481 {
482 create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len);
483 tcp_conn_write(tcp_conn, 1);
484 break;
485 }
486 break;
487
488 case TCS_ESTABLISHED:
489 case TCS_CLOSING:
490/*
491ESTABLISHED:
492FIN-WAIT-1:
493FIN-WAIT-2:
494CLOSE-WAIT:
495CLOSING:
496LAST-ACK:
497TIME-WAIT:
498 test if segment is acceptable:
499 Segment Receive Test
500 Length Window
501 0 0 SEG.SEQ == RCV.NXT
502 0 >0 RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
503 >0 0 not acceptable
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
508*/
509 rcv_hi= tcp_conn->tc_RCV_HI;
510 if (tcp_hdr_flags & THF_URG)
511 rcv_hi++;
512 if (!data_len)
513 {
514 if (rcv_hi == tcp_conn->tc_RCV_NXT)
515 segm_acceptable= (seg_seq == rcv_hi);
516 else
517 {
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));
523 }
524 }
525 else
526 {
527 if (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT))
528 {
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,
535 rcv_hi));
536 }
537 else
538 {
539 segm_acceptable= FALSE;
540 }
541 }
542/*
543 !segment acceptable ?
544 RST ?
545 discard packet
546 exit
547 :
548 <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
549 exit
550*/
551 if (!segm_acceptable)
552 {
553 if (!(tcp_hdr_flags & THF_RST))
554 {
555 DBLOCK(0x20,
556 printf("segment is not acceptable\n");
557 printf("\t");
558 tcp_print_pack(ip_hdr, tcp_hdr);
559 printf("\n\t");
560 tcp_print_conn(tcp_conn);
561 printf("\n"));
562 tcp_conn->tc_flags |= TCF_SEND_ACK;
563 tcp_conn_write(tcp_conn, 1);
564
565 /* Sometimes, a retransmission sets the PSH
566 * flag (Solaris 2.4)
567 */
568 if (tcp_conn->tc_rcvd_data != NULL &&
569 (tcp_hdr_flags & THF_PSH))
570 {
571 tcp_conn->tc_flags |= TCF_RCV_PUSH;
572 if (tcp_conn->tc_fd &&
573 (tcp_conn->tc_fd->tf_flags &
574 TFF_READ_IP))
575 {
576 tcp_fd_read(tcp_conn, 1);
577 }
578 if (tcp_conn->tc_fd &&
579 (tcp_conn->tc_fd->tf_flags &
580 TFF_SEL_READ))
581 {
582 tcp_rsel_read(tcp_conn);
583 }
584 }
585 }
586 break;
587 }
588/*
589 RST ?
590 state == CLOSING || state == LAST-ACK ||
591 state == TIME-WAIT ?
592 state= CLOSED
593 exit
594 :
595 state= CLOSED
596 error "connection reset"
597 exit
598*/
599 if (tcp_hdr_flags & THF_RST)
600 {
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)
605 {
606 /* Clean shutdown, but the other side
607 * doesn't want to ACK our FIN.
608 */
609 tcp_close_connection (tcp_conn, 0);
610 }
611 else
612 tcp_close_connection(tcp_conn, ECONNRESET);
613 break;
614 }
615/*
616 SYN in window ?
617 state= CLOSED
618 error "connection reset"
619 exit
620*/
621 if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,
622 tcp_conn->tc_RCV_NXT))
623 {
624 tcp_close_connection(tcp_conn, ECONNRESET);
625 break;
626 }
627/*
628 !ACK ?
629 discard packet
630 exit
631*/
632 if (!(tcp_hdr_flags & THF_ACK))
633 break;
634
635/*
636 SND.UNA < SEG.ACK <= SND.NXT ?
637 SND.UNA= SEG.ACK
638 reply "send ok"
639 SND.WL1 < SEG.SEQ || (SND.WL1 == SEG.SEQ &&
640 SND.WL2 <= SEG.ACK ?
641 SND.WND= SEG.WND
642 SND.Wl1= SEG.SEQ
643 SND.WL2= SEG.ACK
644 SEG.ACK <= SND.UNA ?
645 ignore ACK
646 SEG.ACK > SND.NXT ?
647 <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
648 discard packet
649 exit
650*/
651
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.
662 */
663 if (tcp_conn->tc_state != TCS_CLOSING)
664 tcp_conn->tc_stt= 0;
665
666 snd_una= tcp_conn->tc_SND_UNA;
667 snd_nxt= tcp_conn->tc_SND_NXT;
668 if (seg_ack == snd_una)
669 {
670
671 if (tcp_Gmod4G(snd_nxt, snd_una))
672 {
673 /* Duplicate ACK */
674 if (++tcp_conn->tc_snd_dack ==
675 TCP_DACK_RETRANS)
676 {
677 tcp_fast_retrans(tcp_conn);
678 }
679 }
680
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
685 * zero window.
686 */
687 if (tcp_conn->tc_snd_cwnd == snd_una &&
688 seg_wnd != 0)
689 {
690 DBLOCK(2, printf("zero window opened\n"));
691 /* The other side opened up its receive
692 * window. */
693 mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;
694 if (seg_wnd > 2*mss)
695 seg_wnd= 2*mss;
696 tcp_conn->tc_snd_cwnd= snd_una+seg_wnd;
697 tcp_conn_write(tcp_conn, 1);
698 }
699 if (seg_wnd == 0)
700 {
701 tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_TRM=
702 snd_una;
703 }
704 }
705 else if (tcp_Lmod4G(snd_una, seg_ack) &&
706 tcp_LEmod4G(seg_ack, snd_nxt))
707 {
708 tcp_release_retrans(tcp_conn, seg_ack, seg_wnd);
709 if (tcp_conn->tc_state == TCS_CLOSED)
710 break;
711 }
712 else if (tcp_Gmod4G(seg_ack,
713 snd_nxt))
714 {
715 tcp_conn->tc_flags |= TCF_SEND_ACK;
716 tcp_conn_write(tcp_conn, 1);
717 DBLOCK(1, printf(
718 "got an ack of something I haven't send\n");
719 printf( "seg_ack= %lu, SND_NXT= %lu\n",
720 seg_ack, snd_nxt));
721 break;
722 }
723
724/*
725 process data...
726*/
727 tcp_extract_ipopt(tcp_conn, ip_hdr);
728 tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss);
729
730 if (data_len)
731 {
732 if (tcp_LEmod4G(seg_seq, tcp_conn->tc_RCV_NXT))
733 {
734 process_data (tcp_conn, tcp_hdr,
735 tcp_data, data_len);
736 }
737 else
738 {
739 process_advanced_data (tcp_conn,
740 tcp_hdr, tcp_data, data_len);
741 }
742 tcp_conn->tc_flags |= TCF_SEND_ACK;
743 tcp_conn_write(tcp_conn, 1);
744
745 /* Don't process a FIN if we got new data */
746 break;
747 }
748/*
749 FIN ?
750 reply pending receives
751 advace RCV.NXT over the FIN
752 <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
753
754 state == ESTABLISHED ?
755 state= CLOSE-WAIT
756 state == FIN-WAIT-1 ?
757 state= CLOSING
758 state == FIN-WAIT-2 ?
759 state= TIME-WAIT
760 state == TIME-WAIT ?
761 restart the TIME-WAIT timer
762 exit
763*/
764 if ((tcp_hdr_flags & THF_FIN) && tcp_LEmod4G(seg_seq,
765 tcp_conn->tc_RCV_NXT))
766 {
767 if (!(tcp_conn->tc_flags & TCF_FIN_RECV) &&
768 tcp_Lmod4G(tcp_conn->tc_RCV_NXT,
769 tcp_conn->tc_RCV_HI))
770 {
771 tcp_conn->tc_RCV_NXT++;
772 tcp_conn->tc_flags |= TCF_FIN_RECV;
773 }
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))
778 {
779 tcp_fd_read(tcp_conn, 1);
780 }
781 if (tcp_conn->tc_fd &&
782 (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ))
783 {
784 tcp_rsel_read(tcp_conn);
785 }
786 }
787 break;
788 default:
789 printf("tcp_frag2conn: unknown state ");
790 tcp_print_state(tcp_conn);
791 break;
792 }
793 if (tcp_data != NULL)
794 bf_afree(tcp_data);
795}
796
797
798PRIVATE void
799process_data(tcp_conn, tcp_hdr, tcp_data, data_len)
800tcp_conn_t *tcp_conn;
801tcp_hdr_t *tcp_hdr;
802acc_t *tcp_data;
803int data_len;
804{
805 u32_t lo_seq, hi_seq, urg_seq, seq_nr, adv_seq, nxt;
806 u32_t urgptr;
807 int tcp_hdr_flags;
808 unsigned int offset;
809 acc_t *tmp_data, *rcvd_data, *adv_data;
810 int len_diff;
811
812 assert(tcp_conn->tc_busy);
813
814 /* Note, tcp_data will be freed by the caller. */
815 assert (!(tcp_hdr->th_flags & THF_SYN));
816
817 seq_nr= ntohl(tcp_hdr->th_seq_nr);
818 urgptr= ntohs(tcp_hdr->th_urgptr);
819
820 tcp_data->acc_linkC++;
821
822 lo_seq= seq_nr;
823 tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK;
824
825 if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT))
826 {
827 DBLOCK(0x10,
828 printf("segment is a retransmission\n"));
829 offset= tcp_conn->tc_RCV_NXT-lo_seq;
830 tcp_data= bf_delhead(tcp_data, offset);
831 lo_seq += offset;
832 data_len -= offset;
833 if (tcp_hdr_flags & THF_URG)
834 {
835 printf("process_data: updating urgent pointer\n");
836 if (urgptr >= offset)
837 urgptr -= offset;
838 else
839 tcp_hdr_flags &= ~THF_URG;
840 }
841 }
842 assert (lo_seq == tcp_conn->tc_RCV_NXT);
843
844 if (tcp_hdr_flags & THF_URG)
845 {
846 if (!(tcp_conn->tc_flags & TCF_BSD_URG))
847 {
848 /* Update urgent pointer to point past the urgent
849 * data
850 */
851 urgptr++;
852 }
853 if (urgptr == 0)
854 tcp_hdr_flags &= ~THF_URG;
855 }
856
857 if (tcp_hdr_flags & THF_URG)
858 {
859 if (urgptr > data_len)
860 urgptr= data_len;
861 urg_seq= lo_seq+urgptr;
862
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)
866 {
867 if (tcp_Gmod4G(tcp_conn->tc_RCV_NXT,
868 tcp_conn->tc_RCV_LO))
869 {
870 DBLOCK(1, printf(
871 "ignoring urgent data\n"));
872
873 bf_afree(tcp_data);
874 /* Should set advertised window to
875 * zero */
876
877 /* Flush */
878 tcp_conn->tc_flags |= TCF_RCV_PUSH;
879 if (tcp_conn->tc_fd &&
880 (tcp_conn->tc_fd->tf_flags &
881 TFF_READ_IP))
882 {
883 tcp_fd_read(tcp_conn, 1);
884 }
885 if (tcp_conn->tc_fd &&
886 (tcp_conn->tc_fd->tf_flags &
887 TFF_SEL_READ))
888 {
889 tcp_rsel_read(tcp_conn);
890 }
891 return;
892 }
893 }
894 if (tcp_Gmod4G(urg_seq, tcp_conn->tc_RCV_UP))
895 tcp_conn->tc_RCV_UP= urg_seq;
896#if 0
897 if (urgptr < data_len)
898 {
899 data_len= urgptr;
900 tmp_data= bf_cut(tcp_data, 0, data_len);
901 bf_afree(tcp_data);
902 tcp_data= tmp_data;
903 tcp_hdr_flags &= ~THF_FIN;
904 }
905#endif
906 tcp_conn->tc_flags |= TCF_RCV_PUSH;
907 }
908 else
909 {
910 /* Normal data. */
911 }
912
913 if (tcp_hdr_flags & THF_PSH)
914 {
915 tcp_conn->tc_flags |= TCF_RCV_PUSH;
916 }
917
918 hi_seq= lo_seq+data_len;
919 if (tcp_Gmod4G(hi_seq, tcp_conn->tc_RCV_HI))
920 {
921 data_len= tcp_conn->tc_RCV_HI-lo_seq;
922 tmp_data= bf_cut(tcp_data, 0, data_len);
923 bf_afree(tcp_data);
924 tcp_data= tmp_data;
925 hi_seq= lo_seq+data_len;
926 tcp_hdr_flags &= ~THF_FIN;
927 }
928 assert (tcp_LEmod4G (hi_seq, tcp_conn->tc_RCV_HI));
929
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;
935
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))
939 {
940 tcp_conn->tc_RCV_NXT++;
941 tcp_conn->tc_flags |= TCF_FIN_RECV;
942 }
943
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);
948
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));
952
953 if (tcp_conn->tc_adv_data == NULL)
954 return;
955 if (tcp_hdr_flags & THF_FIN)
956 {
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;
961 bf_afree(tcp_data);
962 return;
963 }
964
965 lo_seq= tcp_conn->tc_adv_seq;
966 if (tcp_Gmod4G(lo_seq, tcp_conn->tc_RCV_NXT))
967 return; /* Not yet */
968
969 tcp_data= tcp_conn->tc_adv_data;
970 tcp_conn->tc_adv_data= NULL;
971
972 data_len= bf_bufsize(tcp_data);
973 if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT))
974 {
975 offset= tcp_conn->tc_RCV_NXT-lo_seq;
976 if (offset >= data_len)
977 {
978 bf_afree(tcp_data);
979 return;
980 }
981 tcp_data= bf_delhead(tcp_data, offset);
982 lo_seq += offset;
983 data_len -= offset;
984 }
985 assert (lo_seq == tcp_conn->tc_RCV_NXT);
986
987 hi_seq= lo_seq+data_len;
988 assert (tcp_LEmod4G (hi_seq, tcp_conn->tc_RCV_HI));
989
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;
995
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));
999
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);
1004
1005 adv_data= tcp_conn->tc_adv_data;
1006 if (adv_data != NULL)
1007 {
1008 /* Try to use advanced data. */
1009 adv_seq= tcp_conn->tc_adv_seq;
1010 nxt= tcp_conn->tc_RCV_NXT;
1011
1012 if (tcp_Gmod4G(adv_seq, nxt))
1013 return; /* not yet */
1014
1015 tcp_conn->tc_adv_data= NULL;
1016 data_len= bf_bufsize(adv_data);
1017
1018 if (tcp_Lmod4G(adv_seq, nxt))
1019 {
1020 if (tcp_LEmod4G(adv_seq+data_len, nxt))
1021 {
1022 /* Data is not needed anymore. */
1023 bf_afree(adv_data);
1024 return;
1025 }
1026
1027 len_diff= nxt-adv_seq;
1028 adv_data= bf_delhead(adv_data, len_diff);
1029 data_len -= len_diff;
1030 }
1031
1032 DBLOCK(1, printf("using advanced data\n"));
1033
1034 /* Append data to the input buffer */
1035 if (tcp_conn->tc_rcvd_data == NULL)
1036 {
1037 tcp_conn->tc_rcvd_data= adv_data;
1038 }
1039 else
1040 {
1041 tcp_conn->tc_rcvd_data=
1042 bf_append(tcp_conn->tc_rcvd_data, adv_data);
1043 }
1044 tcp_conn->tc_SND_NXT += data_len;
1045 assert(tcp_check_conn(tcp_conn));
1046
1047 if (tcp_conn->tc_fd &&
1048 (tcp_conn->tc_fd->tf_flags & TFF_READ_IP))
1049 {
1050 tcp_fd_read(tcp_conn, 1);
1051 }
1052 if (tcp_conn->tc_fd &&
1053 (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ))
1054 {
1055 tcp_rsel_read(tcp_conn);
1056 }
1057 }
1058}
1059
1060PRIVATE void process_advanced_data(tcp_conn, tcp_hdr, tcp_data, data_len)
1061tcp_conn_t *tcp_conn;
1062tcp_hdr_t *tcp_hdr;
1063acc_t *tcp_data;
1064int data_len;
1065{
1066 u32_t seq, adv_seq;
1067 acc_t *adv_data;
1068
1069 assert(tcp_conn->tc_busy);
1070
1071 /* Note, tcp_data will be freed by the caller. */
1072
1073 /* Always send an ACK, this allows the sender to do a fast
1074 * retransmit.
1075 */
1076 tcp_conn->tc_flags |= TCF_SEND_ACK;
1077 tcp_conn_write(tcp_conn, 1);
1078
1079 if (tcp_hdr->th_flags & THF_URG)
1080 return; /* Urgent data is to complicated */
1081
1082 if (tcp_hdr->th_flags & THF_PSH)
1083 tcp_conn->tc_flags |= TCF_RCV_PUSH;
1084 seq= ntohl(tcp_hdr->th_seq_nr);
1085
1086 /* Make sure that the packet doesn't fall outside of the window
1087 * we offered.
1088 */
1089 if (tcp_Gmod4G(seq+data_len, tcp_conn->tc_RCV_HI))
1090 return;
1091
1092 adv_data= tcp_conn->tc_adv_data;
1093 adv_seq= tcp_conn->tc_adv_seq;
1094 tcp_conn->tc_adv_data= NULL;
1095
1096 tcp_data->acc_linkC++;
1097 if (adv_data == NULL)
1098 {
1099 adv_seq= seq;
1100 adv_data= tcp_data;
1101 }
1102 else if (seq + data_len == adv_seq)
1103 {
1104 /* New data fits right before exiting data. */
1105 adv_data= bf_append(tcp_data, adv_data);
1106 adv_seq= seq;
1107 }
1108 else if (adv_seq + bf_bufsize(adv_data) == seq)
1109 {
1110 /* New data fits right after exiting data. */
1111 adv_data= bf_append(adv_data, tcp_data);
1112 }
1113 else
1114 {
1115 /* New data doesn't fit. */
1116 bf_afree(tcp_data);
1117 }
1118 tcp_conn->tc_adv_data= adv_data;
1119 tcp_conn->tc_adv_seq= adv_seq;
1120}
1121
1122PRIVATE void create_RST(tcp_conn, ip_hdr, tcp_hdr, data_len)
1123tcp_conn_t *tcp_conn;
1124ip_hdr_t *ip_hdr;
1125tcp_hdr_t *tcp_hdr;
1126int data_len;
1127{
1128 acc_t *tmp_ipopt, *tmp_tcpopt, *tcp_pack;
1129 acc_t *RST_acc;
1130 ip_hdr_t *RST_ip_hdr;
1131 tcp_hdr_t *RST_tcp_hdr;
1132 size_t pack_size, ip_hdr_len, mss;
1133
1134 DBLOCK(0x10, printf("in create_RST, bad pack is:\n");
1135 tcp_print_pack(ip_hdr, tcp_hdr); tcp_print_state(tcp_conn);
1136 printf("\n"));
1137
1138 assert(tcp_conn->tc_busy);
1139
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.
1148 */
1149 if ((tcp_hdr->th_flags & (THF_FIN|THF_SYN)) == 0 &&
1150 data_len == 0)
1151 {
1152#if DEBUG
1153 { printf("tcp_recv`create_RST: no data, no RST\n"); }
1154#endif
1155 return;
1156 }
1157
1158 tmp_ipopt= tcp_conn->tc_remipopt;
1159 if (tmp_ipopt)
1160 tmp_ipopt->acc_linkC++;
1161 tmp_tcpopt= tcp_conn->tc_tcpopt;
1162 if (tmp_tcpopt)
1163 tmp_tcpopt->acc_linkC++;
1164
1165 tcp_extract_ipopt (tcp_conn, ip_hdr);
1166 tcp_extract_tcpopt (tcp_conn, tcp_hdr, &mss);
1167
1168 RST_acc= tcp_make_header (tcp_conn, &RST_ip_hdr, &RST_tcp_hdr,
1169 (acc_t *)0);
1170
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;
1177
1178 RST_ip_hdr->ih_src= ip_hdr->ih_dst;
1179 RST_ip_hdr->ih_dst= ip_hdr->ih_src;
1180
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)
1184 {
1185 RST_tcp_hdr->th_seq_nr= tcp_hdr->th_ack_nr;
1186 RST_tcp_hdr->th_flags= THF_RST;
1187 }
1188 else
1189 {
1190 RST_tcp_hdr->th_seq_nr= 0;
1191 RST_tcp_hdr->th_ack_nr=
1192 htonl(
1193 ntohl(tcp_hdr->th_seq_nr)+
1194 data_len +
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;
1198 }
1199
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;
1204
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);
1209 bf_afree(tcp_pack);
1210
1211 DBLOCK(2, tcp_print_pack(ip_hdr, tcp_hdr); printf("\n");
1212 tcp_print_pack(RST_ip_hdr, RST_tcp_hdr); printf("\n"));
1213
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);
1218}
1219
1220PUBLIC void
1221tcp_fd_read(tcp_conn, enq)
1222tcp_conn_t *tcp_conn;
1223int enq; /* Enqueue writes. */
1224{
1225 tcp_fd_t *tcp_fd;
1226 size_t data_size, read_size;
1227 acc_t *data;
1228 int fin_recv, urg, push, result;
1229 i32_t old_window, new_window;
1230 u16_t mss;
1231
1232 assert(tcp_conn->tc_busy);
1233
1234 tcp_fd= tcp_conn->tc_fd;
1235
1236 assert (tcp_fd->tf_flags & TFF_READ_IP);
1237 if (tcp_conn->tc_state == TCS_CLOSED)
1238 {
1239 if (tcp_fd->tf_read_offset)
1240 tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset);
1241 else
1242 tcp_reply_read (tcp_fd, tcp_conn->tc_error);
1243 return;
1244 }
1245
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);
1249
1250 data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO;
1251 if (fin_recv)
1252 data_size--;
1253 if (urg)
1254 {
1255#if DEBUG
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);
1258#endif
1259 read_size= tcp_conn->tc_RCV_UP-tcp_conn->tc_RCV_LO;
1260 }
1261 else
1262 read_size= data_size;
1263
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)
1268 {
1269 /* Defer the copy out until later. */
1270 return;
1271 }
1272 else if (data_size == 0 && !fin_recv)
1273 {
1274 /* No data, and no end of file. */
1275 return;
1276 }
1277
1278 if (read_size)
1279 {
1280 if (urg && !(tcp_fd->tf_flags & TFF_RECV_URG))
1281 {
1282 if (tcp_fd->tf_read_offset)
1283 {
1284 tcp_reply_read (tcp_fd,
1285 tcp_fd->tf_read_offset);
1286 }
1287 else
1288 {
1289 tcp_reply_read (tcp_fd, EURG);
1290 }
1291 return;
1292 }
1293 else if (!urg && (tcp_fd->tf_flags & TFF_RECV_URG))
1294 {
1295 if (tcp_fd->tf_read_offset)
1296 {
1297 tcp_reply_read (tcp_fd,
1298 tcp_fd->tf_read_offset);
1299 }
1300 else
1301 {
1302 tcp_reply_read(tcp_fd, ENOURG);
1303 }
1304 return;
1305 }
1306
1307 if (read_size == data_size)
1308 {
1309 data= tcp_conn->tc_rcvd_data;
1310 data->acc_linkC++;
1311 }
1312 else
1313 {
1314 data= bf_cut(tcp_conn->tc_rcvd_data, 0, read_size);
1315 }
1316 result= (*tcp_fd->tf_put_userdata) (tcp_fd->tf_srfd,
1317 tcp_fd->tf_read_offset, data, FALSE);
1318 if (result<0)
1319 {
1320 if (tcp_fd->tf_read_offset)
1321 tcp_reply_read(tcp_fd, tcp_fd->
1322 tf_read_offset);
1323 else
1324 tcp_reply_read(tcp_fd, result);
1325 return;
1326 }
1327 tcp_fd->tf_read_offset += read_size;
1328 tcp_fd->tf_read_count -= read_size;
1329
1330 if (data_size == read_size)
1331 {
1332 bf_afree(tcp_conn->tc_rcvd_data);
1333 tcp_conn->tc_rcvd_data= 0;
1334 }
1335 else
1336 {
1337 tcp_conn->tc_rcvd_data=
1338 bf_delhead(tcp_conn->tc_rcvd_data,
1339 read_size);
1340 }
1341 tcp_conn->tc_RCV_LO += read_size;
1342 data_size -= read_size;
1343 }
1344
1345 /* Update IRS and often RCV_UP every 0.5GB */
1346 if (tcp_conn->tc_RCV_LO - tcp_conn->tc_IRS > 0x40000000)
1347 {
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))
1352 {
1353 tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS;
1354 DBLOCK(1, printf(
1355 "tcp_fd_read: updating RCV_UP to 0x%lx\n",
1356 (unsigned long)tcp_conn->tc_RCV_UP););
1357 }
1358 DBLOCK(1, printf("tcp_fd_read: RCP_LO = 0x%lx\n",
1359 (unsigned long)tcp_conn->tc_RCV_LO););
1360 }
1361
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)
1365 {
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)
1372 {
1373 tcp_conn->tc_flags |= TCF_SEND_ACK;
1374 DBLOCK(2, printf("opening window\n"));
1375 tcp_conn_write(tcp_conn, 1);
1376 }
1377 }
1378 if (tcp_conn->tc_rcvd_data == NULL &&
1379 tcp_conn->tc_adv_data == NULL)
1380 {
1381 /* Out of data, clear PUSH flag and reply to a read. */
1382 tcp_conn->tc_flags &= ~TCF_RCV_PUSH;
1383 }
1384 if (fin_recv || urg || tcp_fd->tf_read_offset ||
1385 !tcp_fd->tf_read_count)
1386 {
1387 tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset);
1388 return;
1389 }
1390}
1391
1392PUBLIC unsigned
1393tcp_sel_read(tcp_conn)
1394tcp_conn_t *tcp_conn;
1395{
1396 tcp_fd_t *tcp_fd;
1397 size_t data_size;
1398 int fin_recv, urg, push;
1399
1400 tcp_fd= tcp_conn->tc_fd;
1401
1402 if (tcp_conn->tc_state == TCS_CLOSED)
1403 return 1;
1404
1405 fin_recv= (tcp_conn->tc_flags & TCF_FIN_RECV);
1406 if (fin_recv)
1407 return 1;
1408
1409 data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO;
1410 if (data_size == 0)
1411 {
1412 /* No data, and no end of file. */
1413 return 0;
1414 }
1415
1416 urg= tcp_Gmod4G(tcp_conn->tc_RCV_UP, tcp_conn->tc_RCV_LO);
1417 push= (tcp_conn->tc_flags & TCF_RCV_PUSH);
1418
1419 if (!push && !urg && data_size < TCP_MIN_RCV_WND_SIZE)
1420 {
1421 /* Defer until later. */
1422 return 0;
1423 }
1424
1425 return 1;
1426}
1427
1428PUBLIC void
1429tcp_rsel_read(tcp_conn)
1430tcp_conn_t *tcp_conn;
1431{
1432 tcp_fd_t *tcp_fd;
1433
1434 if (tcp_sel_read(tcp_conn) == 0)
1435 return;
1436
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);
1441 else
1442 printf("tcp_rsel_read: no select_res\n");
1443}
1444
1445PUBLIC void tcp_bytesavailable(tcp_fd, bytesp)
1446tcp_fd_t *tcp_fd;
1447int *bytesp;
1448{
1449 tcp_conn_t *tcp_conn;
1450 size_t data_size, read_size;
1451 acc_t *data;
1452 int fin_recv, urg, push, result;
1453 i32_t old_window, new_window;
1454 u16_t mss;
1455
1456 *bytesp= 0; /* The default is that nothing is available */
1457
1458 if (!(tcp_fd->tf_flags & TFF_CONNECTED))
1459 return;
1460 tcp_conn= tcp_fd->tf_conn;
1461
1462 if (tcp_conn->tc_state == TCS_CLOSED)
1463 return;
1464
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);
1468
1469 data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO;
1470 if (fin_recv)
1471 data_size--;
1472 if (urg)
1473 data_size= tcp_conn->tc_RCV_UP-tcp_conn->tc_RCV_LO;
1474
1475 if (urg && !(tcp_fd->tf_flags & TFF_RECV_URG))
1476 return;
1477 else if (!urg && (tcp_fd->tf_flags & TFF_RECV_URG))
1478 return;
1479
1480 *bytesp= data_size;
1481}
1482
1483/*
1484 * $PchId: tcp_recv.c,v 1.30 2005/06/28 14:21:35 philip Exp $
1485 */
Note: See TracBrowser for help on using the repository browser.