tcp_recv.c

Go to the documentation of this file.
00001 /*
00002 tcp_recv.c
00003 
00004 Copyright 1995 Philip Homburg
00005 */
00006 
00007 #include "inet.h"
00008 #include "buf.h"
00009 #include "clock.h"
00010 #include "event.h"
00011 #include "type.h"
00012 #include "sr.h"
00013 
00014 #include "io.h"
00015 #include "tcp_int.h"
00016 #include "tcp.h"
00017 #include "assert.h"
00018 
00019 THIS_FILE
00020 
00021 FORWARD void create_RST ARGS(( tcp_conn_t *tcp_conn,
00022         ip_hdr_t *ip_hdr, tcp_hdr_t *tcp_hdr, int data_len ));
00023 FORWARD void process_data ARGS(( tcp_conn_t *tcp_conn,
00024         tcp_hdr_t *tcp_hdr, acc_t *tcp_data, int data_len ));
00025 FORWARD void process_advanced_data ARGS(( tcp_conn_t *tcp_conn,
00026         tcp_hdr_t *tcp_hdr, acc_t *tcp_data, int data_len ));
00027 
00028 PUBLIC void tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data, data_len)
00029 tcp_conn_t *tcp_conn;
00030 ip_hdr_t *ip_hdr;
00031 tcp_hdr_t *tcp_hdr;
00032 acc_t *tcp_data;
00033 size_t data_len;
00034 {
00035         tcp_fd_t *connuser;
00036         int tcp_hdr_flags;
00037         int ip_hdr_len, tcp_hdr_len;
00038         u32_t seg_ack, seg_seq, rcv_hi, snd_una, snd_nxt;
00039         u16_t seg_wnd, mtu;
00040         size_t mss;
00041         int acceptable_ACK, segm_acceptable, send_rst, close_connection;
00042 
00043         ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
00044         tcp_hdr_len= (tcp_hdr->th_data_off & TH_DO_MASK) >> 2;
00045 
00046         tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK;
00047         seg_ack= ntohl(tcp_hdr->th_ack_nr);
00048         seg_seq= ntohl(tcp_hdr->th_seq_nr);
00049         seg_wnd= ntohs(tcp_hdr->th_window);
00050 
00051 #if 0
00052  { where(); tcp_print_conn(tcp_conn); printf("\n");
00053         tcp_print_pack(ip_hdr, tcp_hdr); printf("\n"); }
00054 #endif
00055 
00056         switch (tcp_conn->tc_state)
00057         {
00058         case TCS_CLOSED:
00059 /*
00060 CLOSED:
00061         discard all data.
00062         !RST ?
00063                 ACK ?
00064                         <SEQ=SEG.ACK><CTL=RST>
00065                         exit
00066                 :
00067                         <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
00068                         exit
00069         :
00070                 discard packet
00071                 exit
00072 */
00073 
00074                 if (!(tcp_hdr_flags & THF_RST))
00075                 {
00076                         create_RST(tcp_conn, ip_hdr, tcp_hdr, data_len);
00077                         tcp_conn_write(tcp_conn, 1);
00078                 }
00079                 break;
00080         case TCS_LISTEN:
00081 /*
00082 LISTEN:
00083         RST ?
00084                 discard packet
00085                 exit
00086         ACK ?
00087                 <SEQ=SEG.ACK><CTL=RST>
00088                 exit
00089         SYN ?
00090                 BUG: no security check
00091                 RCV.NXT= SEG.SEQ+1
00092                 IRS= SEG.SEQ
00093                 ISS should already be selected
00094                 <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
00095                 SND.NXT=ISS+1
00096                 SND.UNA=ISS
00097                 state= SYN-RECEIVED
00098                 exit
00099         :
00100                 shouldnot occur
00101                 discard packet
00102                 exit
00103 */
00104                 if (tcp_hdr_flags & THF_RST)
00105                         break;
00106                 if (tcp_hdr_flags & THF_ACK)
00107                 {
00108                         create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len);
00109                         tcp_conn_write(tcp_conn, 1);
00110                         break;
00111                 }
00112                 if (tcp_hdr_flags & THF_SYN)
00113                 {
00114                         tcp_extract_ipopt(tcp_conn, ip_hdr);
00115                         tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss);
00116                         mtu= mss+IP_TCP_MIN_HDR_SIZE;
00117                         if (mtu < IP_MIN_MTU)
00118                         {
00119                                 /* No or unrealistic mss, use default MTU */
00120                                 mtu= IP_DEF_MTU;
00121                         }
00122                         if (mtu < tcp_conn->tc_max_mtu)
00123                         {
00124                                 tcp_conn->tc_max_mtu= mtu;
00125                                 tcp_conn->tc_mtu= mtu;
00126                                 DBLOCK(1, printf(
00127                                         "tcp[%d]: conn[%d]: mtu = %d\n",
00128                                         tcp_conn->tc_port-tcp_port_table,
00129                                         tcp_conn-tcp_conn_table, 
00130                                         mtu););
00131                         }
00132 
00133                         tcp_conn->tc_RCV_LO= seg_seq+1;
00134                         tcp_conn->tc_RCV_NXT= seg_seq+1;
00135                         tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO+
00136                                 tcp_conn->tc_rcv_wnd;
00137                         tcp_conn->tc_RCV_UP= seg_seq;
00138                         tcp_conn->tc_IRS= seg_seq;
00139                         tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;
00140                         tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
00141                         tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS+1;
00142                         tcp_conn->tc_SND_UP= tcp_conn->tc_ISS-1;
00143                         tcp_conn->tc_SND_PSH= tcp_conn->tc_ISS-1;
00144                         tcp_conn->tc_state= TCS_SYN_RECEIVED;
00145                         tcp_conn->tc_stt= 0;
00146                         assert (tcp_check_conn(tcp_conn));
00147                         tcp_conn->tc_locaddr= ip_hdr->ih_dst;
00148                         tcp_conn->tc_locport= tcp_hdr->th_dstport;
00149                         tcp_conn->tc_remaddr= ip_hdr->ih_src;
00150                         tcp_conn->tc_remport= tcp_hdr->th_srcport;
00151                         tcp_conn_write(tcp_conn, 1);
00152 
00153                         DIFBLOCK(0x10, seg_seq == 0,
00154                                 printf("warning got 0 IRS from ");
00155                                 writeIpAddr(tcp_conn->tc_remaddr);
00156                                 printf("\n"));
00157 
00158                         /* Start the timer (if necessary) */
00159                         tcp_set_send_timer(tcp_conn);
00160 
00161                         break;
00162                 }
00163                 /* do nothing */
00164                 break;
00165         case TCS_SYN_SENT:
00166 /*
00167 SYN-SENT:
00168         ACK ?
00169                 SEG.ACK <= ISS || SEG.ACK > SND.NXT ?
00170                         RST ?
00171                                 discard packet
00172                                 exit
00173                         :
00174                                 <SEQ=SEG.ACK><CTL=RST>
00175                                 exit
00176                 SND.UNA <= SEG.ACK && SEG.ACK <= SND.NXT ?
00177                         ACK is acceptable
00178                 :
00179                         ACK is !acceptable
00180         :
00181                 ACK is !acceptable
00182         RST ?
00183                 ACK acceptable ?
00184                         discard segment
00185                         state= CLOSED
00186                         error "connection refused"
00187                         exit
00188                 :
00189                         discard packet
00190                         exit
00191         BUG: no security check
00192         SYN ?
00193                 IRS= SEG.SEQ
00194                 RCV.NXT= IRS+1
00195                 ACK ?
00196                         SND.UNA= SEG.ACK
00197                 SND.UNA > ISS ?
00198                         state= ESTABLISHED
00199                         <SEQ=SND.NXT><ACK= RCV.NXT><CTL=ACK>
00200                         process ev. URG and text
00201                         exit
00202                 :
00203                         state= SYN-RECEIVED
00204                         SND.WND= SEG.WND
00205                         SND.WL1= SEG.SEQ
00206                         SND.WL2= SEG.ACK
00207                         <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
00208                         exit
00209         :
00210                 discard segment
00211                 exit
00212 */
00213                 if (tcp_hdr_flags & THF_ACK)
00214                 {
00215                         if (tcp_LEmod4G(seg_ack, tcp_conn->tc_ISS) ||
00216                                 tcp_Gmod4G(seg_ack, tcp_conn->tc_SND_NXT))
00217                                 if (tcp_hdr_flags & THF_RST)
00218                                         break;
00219                                 else
00220                                 {
00221                                         /* HACK: force sending a RST,
00222                                          * normally, RSTs are not send
00223                                          * if the segment is an ACK.
00224                                          */
00225                                         create_RST (tcp_conn, ip_hdr,
00226                                                 tcp_hdr, data_len+1);
00227                                         tcp_conn_write(tcp_conn, 1);
00228                                         break;
00229                                 }
00230                         acceptable_ACK= (tcp_LEmod4G(tcp_conn->tc_SND_UNA,
00231                                 seg_ack) && tcp_LEmod4G(seg_ack,
00232                                 tcp_conn->tc_SND_NXT));
00233                 }
00234                 else
00235                         acceptable_ACK= FALSE;
00236                 if (tcp_hdr_flags & THF_RST)
00237                 {
00238                         if (acceptable_ACK)
00239                         {
00240                                 DBLOCK(1, printf(
00241                                         "calling tcp_close_connection\n"));
00242 
00243                                 tcp_close_connection(tcp_conn,
00244                                         ECONNREFUSED);
00245                         }
00246                         break;
00247                 }
00248                 if (tcp_hdr_flags & THF_SYN)
00249                 {
00250                         tcp_extract_ipopt(tcp_conn, ip_hdr);
00251                         tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss);
00252                         mtu= mss+IP_TCP_MIN_HDR_SIZE;
00253                         if (mtu < IP_MIN_MTU)
00254                         {
00255                                 /* No or unrealistic mss, use default MTU */
00256                                 mtu= IP_DEF_MTU;
00257                         }
00258                         if (mtu < tcp_conn->tc_max_mtu)
00259                         {
00260                                 tcp_conn->tc_max_mtu= mtu;
00261                                 tcp_conn->tc_mtu= mtu;
00262                                 DBLOCK(1, printf(
00263                                         "tcp[%d]: conn[%d]: mtu = %d\n",
00264                                         tcp_conn->tc_port-tcp_port_table,
00265                                         tcp_conn-tcp_conn_table, 
00266                                         mtu););
00267                         }
00268                         tcp_conn->tc_RCV_LO= seg_seq+1;
00269                         tcp_conn->tc_RCV_NXT= seg_seq+1;
00270                         tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO +
00271                                 tcp_conn->tc_rcv_wnd;
00272                         tcp_conn->tc_RCV_UP= seg_seq;
00273                         tcp_conn->tc_IRS= seg_seq;
00274                         if (tcp_hdr_flags & THF_ACK)
00275                                 tcp_conn->tc_SND_UNA= seg_ack;
00276                         if (tcp_Gmod4G(tcp_conn->tc_SND_UNA,
00277                                 tcp_conn->tc_ISS))
00278                         {
00279                                 tcp_conn->tc_state= TCS_ESTABLISHED;
00280                                 tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
00281 
00282                                 assert (tcp_check_conn(tcp_conn));
00283                                 assert(tcp_conn->tc_connInprogress);
00284 
00285                                 tcp_restart_connect(tcp_conn);
00286 
00287                                 tcp_conn->tc_flags |= TCF_SEND_ACK;
00288                                 tcp_conn_write(tcp_conn, 1);
00289                                 if (data_len != 0)
00290                                 {
00291                                         tcp_frag2conn(tcp_conn, ip_hdr,
00292                                                 tcp_hdr, tcp_data, data_len);
00293                                         /* tcp_data is already freed */
00294                                         return;
00295                                 }
00296                                 break;
00297                         }
00298                         tcp_conn->tc_state= TCS_SYN_RECEIVED;
00299 
00300                         assert (tcp_check_conn(tcp_conn));
00301 
00302                         tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
00303                         tcp_conn_write(tcp_conn, 1);
00304                 }
00305                 break;
00306 
00307         case TCS_SYN_RECEIVED:
00308 /*
00309 SYN-RECEIVED:
00310         test if segment is acceptable:
00311 
00312         Segment Receive Test
00313         Length  Window
00314         0       0       SEG.SEQ == RCV.NXT
00315         0       >0      RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
00316         >0      0       not acceptable
00317         >0      >0      (RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND)
00318                         || (RCV.NXT <= SEG.SEQ+SEG.LEN-1 &&
00319                         SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND)
00320         for urgent data: use RCV.WND+1 for RCV.WND
00321 
00322         Special: Send RST if SEG.SEQ < IRS or SEG.SEQ > RCV.NXT+64K (and
00323                  the packet is not a RST packet itself).
00324 */
00325                 rcv_hi= tcp_conn->tc_RCV_HI;
00326                 if (tcp_hdr_flags & THF_URG)
00327                         rcv_hi++;
00328                 send_rst= tcp_Lmod4G(seg_seq, tcp_conn->tc_IRS) ||
00329                         tcp_Gmod4G(seg_seq, tcp_conn->tc_RCV_NXT+0x10000);
00330                 close_connection= 0;
00331 
00332                 if (!data_len)
00333                 {
00334                         if (rcv_hi == tcp_conn->tc_RCV_NXT)
00335                                 segm_acceptable= (seg_seq == rcv_hi);
00336                         else
00337                         {
00338                                 assert (tcp_Gmod4G(rcv_hi,
00339                                         tcp_conn->tc_RCV_NXT));
00340                                 segm_acceptable= (tcp_LEmod4G(tcp_conn->
00341                                         tc_RCV_NXT, seg_seq) &&
00342                                         tcp_Lmod4G(seg_seq, rcv_hi));
00343                         }
00344                 }
00345                 else
00346                 {
00347                         if (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT))
00348                         {
00349                                 segm_acceptable= (tcp_LEmod4G(tcp_conn->
00350                                         tc_RCV_NXT, seg_seq) &&
00351                                         tcp_Lmod4G(seg_seq, rcv_hi)) ||
00352                                         (tcp_LEmod4G(tcp_conn->tc_RCV_NXT,
00353                                         seg_seq+data_len-1) &&
00354                                         tcp_Lmod4G(seg_seq+data_len-1,
00355                                         rcv_hi));
00356                         }
00357                         else
00358                         {
00359                                 segm_acceptable= FALSE;
00360                         }
00361                 }
00362 /*
00363         !segment acceptable ?
00364                 RST ?
00365                         discard packet
00366                         exit
00367                 :
00368                         <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
00369                         exit
00370 */
00371                 if (!segm_acceptable)
00372                 {
00373                         if (tcp_hdr_flags & THF_RST)
00374                                 ; /* do nothing */
00375                         else if (send_rst)
00376                         {
00377                                 create_RST(tcp_conn, ip_hdr, tcp_hdr,
00378                                         data_len);
00379                                 tcp_conn_write(tcp_conn, 1);
00380                         }
00381                         else
00382                         {
00383                                 tcp_conn->tc_flags |= TCF_SEND_ACK;
00384                                 tcp_conn_write(tcp_conn, 1);
00385                         }
00386                         break;
00387                 }
00388 /*
00389         RST ?
00390                 initiated by a LISTEN ?
00391                         state= LISTEN
00392                         exit
00393                 :
00394                         state= CLOSED
00395                         error "connection refused"
00396                         exit
00397 */
00398 
00399                 if (tcp_hdr_flags & THF_RST)
00400                         close_connection= 1;
00401 
00402 /*
00403         SYN in window ?
00404                 initiated by a LISTEN ?
00405                         state= LISTEN
00406                         exit
00407                 :
00408                         state= CLOSED
00409                         error "connection reset"
00410                         exit
00411 */
00412                 if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,
00413                         tcp_conn->tc_RCV_NXT))
00414                 {
00415                         close_connection= 1;
00416                 }
00417 
00418                 if (close_connection)
00419                 {
00420                         if (!tcp_conn->tc_orglisten)
00421                         {
00422                                 tcp_close_connection(tcp_conn, ECONNREFUSED);
00423                                 break;
00424                         }
00425 
00426                         connuser= tcp_conn->tc_fd;
00427                         assert(connuser);
00428                         if (connuser->tf_flags & TFF_LISTENQ)
00429                         {
00430                                 tcp_close_connection (tcp_conn,
00431                                         ECONNREFUSED);
00432                         }
00433                         else
00434                         {
00435                                 tcp_conn->tc_connInprogress= 0;
00436                                 tcp_conn->tc_fd= NULL;
00437 
00438                                 tcp_close_connection (tcp_conn,
00439                                         ECONNREFUSED);
00440 
00441                                 /* Pick a new ISS next time */
00442                                 tcp_conn->tc_ISS= 0;
00443 
00444                                 (void)tcp_su4listen(connuser, tcp_conn,
00445                                         0 /* !do_listenq */);
00446                         }
00447                         break;
00448                 }
00449 /*
00450         !ACK ?
00451                 discard packet
00452                 exit
00453 */
00454                 if (!(tcp_hdr_flags & THF_ACK))
00455                         break;
00456 /*
00457         SND.UNA < SEG.ACK <= SND.NXT ?
00458                 state= ESTABLISHED
00459         :
00460                 <SEG=SEG.ACK><CTL=RST>
00461                 exit
00462 */
00463                 if (tcp_Lmod4G(tcp_conn->tc_SND_UNA, seg_ack) &&
00464                         tcp_LEmod4G(seg_ack, tcp_conn->tc_SND_NXT))
00465                 {
00466                         tcp_conn->tc_state= TCS_ESTABLISHED;
00467                         tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
00468 
00469                         tcp_release_retrans(tcp_conn, seg_ack, seg_wnd);
00470 
00471                         assert (tcp_check_conn(tcp_conn));
00472                         assert(tcp_conn->tc_connInprogress);
00473 
00474                         tcp_restart_connect(tcp_conn);
00475                         tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data,
00476                                 data_len);
00477                         /* tcp_data is already freed */
00478                         return;
00479                 }
00480                 else
00481                 {
00482                         create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len);
00483                         tcp_conn_write(tcp_conn, 1);
00484                         break;
00485                 }
00486                 break;
00487 
00488         case TCS_ESTABLISHED:
00489         case TCS_CLOSING:
00490 /*
00491 ESTABLISHED:
00492 FIN-WAIT-1:
00493 FIN-WAIT-2:
00494 CLOSE-WAIT:
00495 CLOSING:
00496 LAST-ACK:
00497 TIME-WAIT:
00498         test if segment is acceptable:
00499         Segment Receive Test
00500         Length  Window
00501         0       0       SEG.SEQ == RCV.NXT
00502         0       >0      RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
00503         >0      0       not acceptable
00504         >0      >0      (RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND)
00505                         || (RCV.NXT <= SEG.SEQ+SEG.LEN-1 &&
00506                         SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND)
00507         for urgent data: use RCV.WND+1 for RCV.WND
00508 */
00509                 rcv_hi= tcp_conn->tc_RCV_HI;
00510                 if (tcp_hdr_flags & THF_URG)
00511                         rcv_hi++;
00512                 if (!data_len)
00513                 {
00514                         if (rcv_hi == tcp_conn->tc_RCV_NXT)
00515                                 segm_acceptable= (seg_seq == rcv_hi);
00516                         else
00517                         {
00518                                 assert (tcp_Gmod4G(rcv_hi,
00519                                         tcp_conn->tc_RCV_NXT));
00520                                 segm_acceptable= (tcp_LEmod4G(tcp_conn->
00521                                         tc_RCV_NXT, seg_seq) &&
00522                                         tcp_Lmod4G(seg_seq, rcv_hi));
00523                         }
00524                 }
00525                 else
00526                 {
00527                         if (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT))
00528                         {
00529                                 segm_acceptable= (tcp_LEmod4G(tcp_conn->
00530                                         tc_RCV_NXT, seg_seq) &&
00531                                         tcp_Lmod4G(seg_seq, rcv_hi)) ||
00532                                         (tcp_LEmod4G(tcp_conn->tc_RCV_NXT,
00533                                         seg_seq+data_len-1) &&
00534                                         tcp_Lmod4G(seg_seq+data_len-1,
00535                                         rcv_hi));
00536                         }
00537                         else
00538                         {
00539                                 segm_acceptable= FALSE;
00540                         }
00541                 }
00542 /*
00543         !segment acceptable ?
00544                 RST ?
00545                         discard packet
00546                         exit
00547                 :
00548                         <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
00549                         exit
00550 */
00551                 if (!segm_acceptable)
00552                 {
00553                         if (!(tcp_hdr_flags & THF_RST))
00554                         {
00555                                 DBLOCK(0x20,
00556                                         printf("segment is not acceptable\n");
00557                                         printf("\t");
00558                                         tcp_print_pack(ip_hdr, tcp_hdr);
00559                                         printf("\n\t");
00560                                         tcp_print_conn(tcp_conn);
00561                                         printf("\n"));
00562                                 tcp_conn->tc_flags |= TCF_SEND_ACK;
00563                                 tcp_conn_write(tcp_conn, 1);
00564 
00565                                 /* Sometimes, a retransmission sets the PSH
00566                                  * flag (Solaris 2.4)
00567                                  */
00568                                 if (tcp_conn->tc_rcvd_data != NULL &&
00569                                         (tcp_hdr_flags & THF_PSH))
00570                                 {
00571                                         tcp_conn->tc_flags |= TCF_RCV_PUSH;
00572                                         if (tcp_conn->tc_fd &&
00573                                                 (tcp_conn->tc_fd->tf_flags &
00574                                                 TFF_READ_IP))
00575                                         {
00576                                                 tcp_fd_read(tcp_conn, 1);
00577                                         }
00578                                         if (tcp_conn->tc_fd &&
00579                                                 (tcp_conn->tc_fd->tf_flags &
00580                                                 TFF_SEL_READ))
00581                                         {
00582                                                 tcp_rsel_read(tcp_conn);
00583                                         }
00584                                 }
00585                         }
00586                         break;
00587                 }
00588 /*
00589         RST ?
00590                 state == CLOSING || state == LAST-ACK ||
00591                         state == TIME-WAIT ?
00592                         state= CLOSED
00593                         exit
00594                 :
00595                         state= CLOSED
00596                         error "connection reset"
00597                         exit
00598 */
00599                 if (tcp_hdr_flags & THF_RST)
00600                 {
00601                         if ((tcp_conn->tc_flags &
00602                                 (TCF_FIN_SENT|TCF_FIN_RECV)) ==
00603                                 (TCF_FIN_SENT|TCF_FIN_RECV) &&
00604                                 tcp_conn->tc_send_data == NULL)
00605                         {
00606                                 /* Clean shutdown, but the other side
00607                                  * doesn't want to ACK our FIN.
00608                                  */
00609                                 tcp_close_connection (tcp_conn, 0);
00610                         }
00611                         else
00612                                 tcp_close_connection(tcp_conn, ECONNRESET);
00613                         break;
00614                 }
00615 /*
00616         SYN in window ?
00617                 state= CLOSED
00618                 error "connection reset"
00619                 exit
00620 */
00621                 if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,
00622                         tcp_conn->tc_RCV_NXT))
00623                 {
00624                         tcp_close_connection(tcp_conn, ECONNRESET);
00625                         break;
00626                 }
00627 /*
00628         !ACK ?
00629                 discard packet
00630                 exit
00631 */
00632                 if (!(tcp_hdr_flags & THF_ACK))
00633                         break;
00634 
00635 /*
00636         SND.UNA < SEG.ACK <= SND.NXT ?
00637                 SND.UNA= SEG.ACK
00638                 reply "send ok"
00639                 SND.WL1 < SEG.SEQ || (SND.WL1 == SEG.SEQ &&
00640                         SND.WL2 <= SEG.ACK ?
00641                         SND.WND= SEG.WND
00642                         SND.Wl1= SEG.SEQ
00643                         SND.WL2= SEG.ACK
00644         SEG.ACK <= SND.UNA ?
00645                 ignore ACK
00646         SEG.ACK > SND.NXT ?
00647                 <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
00648                 discard packet
00649                 exit
00650 */
00651 
00652                 /* Always reset the send timer after a valid ack is
00653                  * received. The assumption is that either the ack really
00654                  * acknowledges some data (normal case), contains a zero
00655                  * window, or the remote host has another reason not
00656                  * to accept any data. In all cases, the remote host is
00657                  * alive, so the connection should stay alive too.
00658                  * Do not reset stt if the state is CLOSING, i.e. if
00659                  * the user closed the connection and we still have
00660                  * some data to deliver. We don't want a zero window
00661                  * to keep us from closing the connection.
00662                  */
00663                 if (tcp_conn->tc_state != TCS_CLOSING)
00664                         tcp_conn->tc_stt= 0;
00665 
00666                 snd_una= tcp_conn->tc_SND_UNA;
00667                 snd_nxt= tcp_conn->tc_SND_NXT;
00668                 if (seg_ack == snd_una)
00669                 {
00670                         
00671                         if (tcp_Gmod4G(snd_nxt, snd_una))
00672                         {
00673                                 /* Duplicate ACK */
00674                                 if (++tcp_conn->tc_snd_dack ==
00675                                         TCP_DACK_RETRANS)
00676                                 {
00677                                         tcp_fast_retrans(tcp_conn);
00678                                 }
00679                         }
00680 
00681                         /* This ACK doesn't acknowledge any new data, this
00682                          * is a likely situation if we are only receiving
00683                          * data. We only update the window if we are
00684                          * actually sending or if we currently have a
00685                          * zero window.
00686                          */
00687                         if (tcp_conn->tc_snd_cwnd == snd_una &&
00688                                 seg_wnd != 0)
00689                         {
00690                                 DBLOCK(2, printf("zero window opened\n"));
00691                                 /* The other side opened up its receive
00692                                  * window. */
00693                                 mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;
00694                                 if (seg_wnd > 2*mss)
00695                                         seg_wnd= 2*mss;
00696                                 tcp_conn->tc_snd_cwnd= snd_una+seg_wnd;
00697                                 tcp_conn_write(tcp_conn, 1);
00698                         }
00699                         if (seg_wnd == 0)
00700                         {
00701                                 tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_TRM=
00702                                         snd_una;
00703                         }
00704                 }
00705                 else if (tcp_Lmod4G(snd_una, seg_ack) &&
00706                         tcp_LEmod4G(seg_ack, snd_nxt))
00707                 {
00708                         tcp_release_retrans(tcp_conn, seg_ack, seg_wnd);
00709                         if (tcp_conn->tc_state == TCS_CLOSED)
00710                                 break;
00711                 }
00712                 else if (tcp_Gmod4G(seg_ack,
00713                         snd_nxt))
00714                 {
00715                         tcp_conn->tc_flags |= TCF_SEND_ACK;
00716                         tcp_conn_write(tcp_conn, 1);
00717                         DBLOCK(1, printf(
00718                         "got an ack of something I haven't send\n");
00719                                 printf( "seg_ack= %lu, SND_NXT= %lu\n",
00720                                 seg_ack, snd_nxt));
00721                         break;
00722                 }
00723 
00724 /*
00725         process data...
00726 */
00727                 tcp_extract_ipopt(tcp_conn, ip_hdr);
00728                 tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss);
00729 
00730                 if (data_len)
00731                 {
00732                         if (tcp_LEmod4G(seg_seq, tcp_conn->tc_RCV_NXT))
00733                         {
00734                                 process_data (tcp_conn, tcp_hdr,
00735                                         tcp_data, data_len);
00736                         }
00737                         else
00738                         {
00739                                 process_advanced_data (tcp_conn,
00740                                         tcp_hdr, tcp_data, data_len);
00741                         }
00742                         tcp_conn->tc_flags |= TCF_SEND_ACK;
00743                         tcp_conn_write(tcp_conn, 1);
00744 
00745                         /* Don't process a FIN if we got new data */
00746                         break;
00747                 }
00748 /*
00749         FIN ?
00750                 reply pending receives
00751                 advace RCV.NXT over the FIN
00752                 <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
00753 
00754                 state == ESTABLISHED ?
00755                         state= CLOSE-WAIT
00756                 state == FIN-WAIT-1 ?
00757                         state= CLOSING
00758                 state == FIN-WAIT-2 ?
00759                         state= TIME-WAIT
00760                 state == TIME-WAIT ?
00761                         restart the TIME-WAIT timer
00762         exit
00763 */
00764                 if ((tcp_hdr_flags & THF_FIN) && tcp_LEmod4G(seg_seq,
00765                         tcp_conn->tc_RCV_NXT))
00766                 {
00767                         if (!(tcp_conn->tc_flags & TCF_FIN_RECV) &&
00768                                 tcp_Lmod4G(tcp_conn->tc_RCV_NXT,
00769                                 tcp_conn->tc_RCV_HI))
00770                         {
00771                                 tcp_conn->tc_RCV_NXT++;
00772                                 tcp_conn->tc_flags |= TCF_FIN_RECV;
00773                         }
00774                         tcp_conn->tc_flags |= TCF_SEND_ACK;
00775                         tcp_conn_write(tcp_conn, 1);
00776                         if (tcp_conn->tc_fd &&
00777                                 (tcp_conn->tc_fd->tf_flags & TFF_READ_IP))
00778                         {
00779                                 tcp_fd_read(tcp_conn, 1);
00780                         }
00781                         if (tcp_conn->tc_fd &&
00782                                 (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ))
00783                         {
00784                                 tcp_rsel_read(tcp_conn);
00785                         }
00786                 }
00787                 break;
00788         default:
00789                 printf("tcp_frag2conn: unknown state ");
00790                 tcp_print_state(tcp_conn);
00791                 break;
00792         }
00793         if (tcp_data != NULL)
00794                 bf_afree(tcp_data);
00795 }
00796 
00797 
00798 PRIVATE void
00799 process_data(tcp_conn, tcp_hdr, tcp_data, data_len)
00800 tcp_conn_t *tcp_conn;
00801 tcp_hdr_t *tcp_hdr;
00802 acc_t *tcp_data;
00803 int data_len;
00804 {
00805         u32_t lo_seq, hi_seq, urg_seq, seq_nr, adv_seq, nxt;
00806         u32_t urgptr;
00807         int tcp_hdr_flags;
00808         unsigned int offset;
00809         acc_t *tmp_data, *rcvd_data, *adv_data;
00810         int len_diff;
00811 
00812         assert(tcp_conn->tc_busy);
00813 
00814         /* Note, tcp_data will be freed by the caller. */
00815         assert (!(tcp_hdr->th_flags & THF_SYN));
00816 
00817         seq_nr= ntohl(tcp_hdr->th_seq_nr);
00818         urgptr= ntohs(tcp_hdr->th_urgptr);
00819 
00820         tcp_data->acc_linkC++;
00821 
00822         lo_seq= seq_nr;
00823         tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK;
00824 
00825         if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT))
00826         {
00827                 DBLOCK(0x10,
00828                         printf("segment is a retransmission\n"));
00829                 offset= tcp_conn->tc_RCV_NXT-lo_seq;
00830                 tcp_data= bf_delhead(tcp_data, offset);
00831                 lo_seq += offset;
00832                 data_len -= offset;
00833                 if (tcp_hdr_flags & THF_URG)
00834                 {
00835                         printf("process_data: updating urgent pointer\n");
00836                         if (urgptr >= offset)
00837                                 urgptr -= offset;
00838                         else
00839                                 tcp_hdr_flags &= ~THF_URG;
00840                 }
00841         }
00842         assert (lo_seq == tcp_conn->tc_RCV_NXT);
00843 
00844         if (tcp_hdr_flags & THF_URG)
00845         {
00846                 if (!(tcp_conn->tc_flags & TCF_BSD_URG))
00847                 {
00848                         /* Update urgent pointer to point past the urgent
00849                          * data
00850                          */
00851                         urgptr++;
00852                 }
00853                 if (urgptr == 0)
00854                         tcp_hdr_flags &= ~THF_URG;
00855         }
00856 
00857         if (tcp_hdr_flags & THF_URG)
00858         {
00859                 if (urgptr > data_len)
00860                         urgptr= data_len;
00861                 urg_seq= lo_seq+urgptr;
00862 
00863                 if (tcp_GEmod4G(urg_seq, tcp_conn->tc_RCV_HI))
00864                         urg_seq= tcp_conn->tc_RCV_HI;
00865                 if (tcp_conn->tc_flags & TCF_BSD_URG)
00866                 {
00867                         if (tcp_Gmod4G(tcp_conn->tc_RCV_NXT,
00868                                 tcp_conn->tc_RCV_LO))
00869                         {
00870                                 DBLOCK(1, printf(
00871                                         "ignoring urgent data\n"));
00872 
00873                                 bf_afree(tcp_data);
00874                                 /* Should set advertised window to
00875                                  * zero */
00876 
00877                                 /* Flush */
00878                                 tcp_conn->tc_flags |= TCF_RCV_PUSH;
00879                                 if (tcp_conn->tc_fd &&
00880                                         (tcp_conn->tc_fd->tf_flags &
00881                                         TFF_READ_IP))
00882                                 {
00883                                         tcp_fd_read(tcp_conn, 1);
00884                                 }
00885                                 if (tcp_conn->tc_fd &&
00886                                         (tcp_conn->tc_fd->tf_flags &
00887                                         TFF_SEL_READ))
00888                                 {
00889                                         tcp_rsel_read(tcp_conn);
00890                                 }
00891                                 return;
00892                         }
00893                 }
00894                 if (tcp_Gmod4G(urg_seq, tcp_conn->tc_RCV_UP))
00895                         tcp_conn->tc_RCV_UP= urg_seq;
00896 #if 0
00897                 if (urgptr < data_len)
00898                 {
00899                         data_len= urgptr;
00900                         tmp_data= bf_cut(tcp_data, 0, data_len);
00901                         bf_afree(tcp_data);
00902                         tcp_data= tmp_data;
00903                         tcp_hdr_flags &= ~THF_FIN;
00904                 }
00905 #endif
00906                 tcp_conn->tc_flags |= TCF_RCV_PUSH;
00907         }
00908         else
00909         {
00910                 /* Normal data. */
00911         }
00912 
00913         if (tcp_hdr_flags & THF_PSH)
00914         {
00915                 tcp_conn->tc_flags |= TCF_RCV_PUSH;
00916         }
00917 
00918         hi_seq= lo_seq+data_len;
00919         if (tcp_Gmod4G(hi_seq, tcp_conn->tc_RCV_HI))
00920         {
00921                 data_len= tcp_conn->tc_RCV_HI-lo_seq;
00922                 tmp_data= bf_cut(tcp_data, 0, data_len);
00923                 bf_afree(tcp_data);
00924                 tcp_data= tmp_data;
00925                 hi_seq= lo_seq+data_len;
00926                 tcp_hdr_flags &= ~THF_FIN;
00927         }
00928         assert (tcp_LEmod4G (hi_seq, tcp_conn->tc_RCV_HI));
00929 
00930         rcvd_data= tcp_conn->tc_rcvd_data;
00931         tcp_conn->tc_rcvd_data= 0;
00932         tmp_data= bf_append(rcvd_data, tcp_data);
00933         tcp_conn->tc_rcvd_data= tmp_data;
00934         tcp_conn->tc_RCV_NXT= hi_seq;
00935 
00936         if ((tcp_hdr_flags & THF_FIN) && 
00937                 tcp_Lmod4G(tcp_conn->tc_RCV_NXT, tcp_conn->tc_RCV_HI) &&
00938                 !(tcp_conn->tc_flags & TCF_FIN_RECV))
00939         {
00940                 tcp_conn->tc_RCV_NXT++;
00941                 tcp_conn->tc_flags |= TCF_FIN_RECV;
00942         }
00943 
00944         if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_READ_IP))
00945                 tcp_fd_read(tcp_conn, 1);
00946         if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ))
00947                 tcp_rsel_read(tcp_conn);
00948 
00949         DIFBLOCK(2, (tcp_conn->tc_RCV_NXT == tcp_conn->tc_RCV_HI),
00950                 printf("conn[[%d] full receive buffer\n", 
00951                 tcp_conn-tcp_conn_table));
00952 
00953         if (tcp_conn->tc_adv_data == NULL)
00954                 return;
00955         if (tcp_hdr_flags & THF_FIN)
00956         {
00957                 printf("conn[%d]: advanced data after FIN\n",
00958                         tcp_conn-tcp_conn_table);
00959                 tcp_data= tcp_conn->tc_adv_data;
00960                 tcp_conn->tc_adv_data= NULL;
00961                 bf_afree(tcp_data);
00962                 return;
00963         }
00964 
00965         lo_seq= tcp_conn->tc_adv_seq;
00966         if (tcp_Gmod4G(lo_seq, tcp_conn->tc_RCV_NXT))
00967                 return;         /* Not yet */
00968 
00969         tcp_data= tcp_conn->tc_adv_data;
00970         tcp_conn->tc_adv_data= NULL;
00971 
00972         data_len= bf_bufsize(tcp_data);
00973         if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT))
00974         {
00975                 offset= tcp_conn->tc_RCV_NXT-lo_seq;
00976                 if (offset >= data_len)
00977                 {
00978                         bf_afree(tcp_data);
00979                         return;
00980                 }
00981                 tcp_data= bf_delhead(tcp_data, offset);
00982                 lo_seq += offset;
00983                 data_len -= offset;
00984         }
00985         assert (lo_seq == tcp_conn->tc_RCV_NXT);
00986 
00987         hi_seq= lo_seq+data_len;
00988         assert (tcp_LEmod4G (hi_seq, tcp_conn->tc_RCV_HI));
00989 
00990         rcvd_data= tcp_conn->tc_rcvd_data;
00991         tcp_conn->tc_rcvd_data= 0;
00992         tmp_data= bf_append(rcvd_data, tcp_data);
00993         tcp_conn->tc_rcvd_data= tmp_data;
00994         tcp_conn->tc_RCV_NXT= hi_seq;
00995 
00996         assert (tcp_conn->tc_RCV_LO + bf_bufsize(tcp_conn->tc_rcvd_data) ==
00997                 tcp_conn->tc_RCV_NXT ||
00998                 (tcp_print_conn(tcp_conn), printf("\n"), 0));
00999 
01000         if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_READ_IP))
01001                 tcp_fd_read(tcp_conn, 1);
01002         if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ))
01003                 tcp_rsel_read(tcp_conn);
01004 
01005         adv_data= tcp_conn->tc_adv_data;
01006         if (adv_data != NULL)
01007         {
01008                 /* Try to use advanced data. */
01009                 adv_seq= tcp_conn->tc_adv_seq;
01010                 nxt= tcp_conn->tc_RCV_NXT;
01011 
01012                 if (tcp_Gmod4G(adv_seq, nxt))
01013                         return;         /* not yet */
01014 
01015                 tcp_conn->tc_adv_data= NULL;
01016                 data_len= bf_bufsize(adv_data);
01017 
01018                 if (tcp_Lmod4G(adv_seq, nxt))
01019                 {
01020                         if (tcp_LEmod4G(adv_seq+data_len, nxt))
01021                         {
01022                                 /* Data is not needed anymore. */
01023                                 bf_afree(adv_data);
01024                                 return;
01025                         }
01026 
01027                         len_diff= nxt-adv_seq;
01028                         adv_data= bf_delhead(adv_data, len_diff);
01029                         data_len -= len_diff;
01030                 }
01031 
01032                 DBLOCK(1, printf("using advanced data\n"));
01033 
01034                 /* Append data to the input buffer */
01035                 if (tcp_conn->tc_rcvd_data == NULL)
01036                 {
01037                         tcp_conn->tc_rcvd_data= adv_data;
01038                 }
01039                 else
01040                 {
01041                         tcp_conn->tc_rcvd_data=
01042                                 bf_append(tcp_conn->tc_rcvd_data, adv_data);
01043                 }
01044                 tcp_conn->tc_SND_NXT += data_len;
01045                 assert(tcp_check_conn(tcp_conn));
01046 
01047                 if (tcp_conn->tc_fd &&
01048                         (tcp_conn->tc_fd->tf_flags & TFF_READ_IP))
01049                 {
01050                         tcp_fd_read(tcp_conn, 1);
01051                 }
01052                 if (tcp_conn->tc_fd &&
01053                         (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ))
01054                 {
01055                         tcp_rsel_read(tcp_conn);
01056                 }
01057         }
01058 }
01059 
01060 PRIVATE void process_advanced_data(tcp_conn, tcp_hdr, tcp_data, data_len)
01061 tcp_conn_t *tcp_conn;
01062 tcp_hdr_t *tcp_hdr;
01063 acc_t *tcp_data;
01064 int data_len;
01065 {
01066         u32_t seq, adv_seq;
01067         acc_t *adv_data;
01068 
01069         assert(tcp_conn->tc_busy);
01070 
01071         /* Note, tcp_data will be freed by the caller. */
01072 
01073         /* Always send an ACK, this allows the sender to do a fast
01074          * retransmit.
01075          */
01076         tcp_conn->tc_flags |= TCF_SEND_ACK;
01077         tcp_conn_write(tcp_conn, 1);
01078 
01079         if (tcp_hdr->th_flags & THF_URG)
01080                 return; /* Urgent data is to complicated */
01081 
01082         if (tcp_hdr->th_flags & THF_PSH)
01083                 tcp_conn->tc_flags |= TCF_RCV_PUSH;
01084         seq= ntohl(tcp_hdr->th_seq_nr);
01085 
01086         /* Make sure that the packet doesn't fall outside of the window
01087          * we offered.
01088          */
01089         if (tcp_Gmod4G(seq+data_len, tcp_conn->tc_RCV_HI))
01090                 return;
01091 
01092         adv_data= tcp_conn->tc_adv_data;
01093         adv_seq= tcp_conn->tc_adv_seq;
01094         tcp_conn->tc_adv_data= NULL;
01095 
01096         tcp_data->acc_linkC++;
01097         if (adv_data == NULL)
01098         {
01099                 adv_seq= seq;
01100                 adv_data= tcp_data;
01101         }
01102         else if (seq + data_len == adv_seq)
01103         {
01104                 /* New data fits right before exiting data. */
01105                 adv_data= bf_append(tcp_data, adv_data);
01106                 adv_seq= seq;
01107         }
01108         else if (adv_seq + bf_bufsize(adv_data) == seq)
01109         {
01110                 /* New data fits right after exiting data. */
01111                 adv_data= bf_append(adv_data, tcp_data);
01112         }
01113         else
01114         {
01115                 /* New data doesn't fit. */
01116                 bf_afree(tcp_data);
01117         }
01118         tcp_conn->tc_adv_data= adv_data;
01119         tcp_conn->tc_adv_seq= adv_seq;
01120 }
01121                                 
01122 PRIVATE void create_RST(tcp_conn, ip_hdr, tcp_hdr, data_len)
01123 tcp_conn_t *tcp_conn;
01124 ip_hdr_t *ip_hdr;
01125 tcp_hdr_t *tcp_hdr;
01126 int data_len;
01127 {
01128         acc_t *tmp_ipopt, *tmp_tcpopt, *tcp_pack;
01129         acc_t *RST_acc;
01130         ip_hdr_t *RST_ip_hdr;
01131         tcp_hdr_t *RST_tcp_hdr;
01132         size_t pack_size, ip_hdr_len, mss;
01133 
01134         DBLOCK(0x10, printf("in create_RST, bad pack is:\n"); 
01135                 tcp_print_pack(ip_hdr, tcp_hdr); tcp_print_state(tcp_conn);
01136                 printf("\n"));
01137 
01138         assert(tcp_conn->tc_busy);
01139 
01140         /* Only send RST packets in reponse to actual data (or SYN, FIN)
01141          * this solves a problem during connection shutdown. The problem
01142          * is the follow senario: a senders closes the connection instead
01143          * of doing a shutdown and waiting for the receiver to shutdown.
01144          * The receiver is slow in processing the last data. After the
01145          * sender has completely closed the connection, the receiver
01146          * sends a window update which triggers the sender to send a
01147          * RST. The receiver closes the connection in reponse to the RST.
01148          */
01149         if ((tcp_hdr->th_flags & (THF_FIN|THF_SYN)) == 0 &&
01150                 data_len == 0)
01151         {
01152 #if DEBUG
01153  { printf("tcp_recv`create_RST: no data, no RST\n"); }
01154 #endif
01155                 return;
01156         }
01157 
01158         tmp_ipopt= tcp_conn->tc_remipopt;
01159         if (tmp_ipopt)
01160                 tmp_ipopt->acc_linkC++;
01161         tmp_tcpopt= tcp_conn->tc_tcpopt;
01162         if (tmp_tcpopt)
01163                 tmp_tcpopt->acc_linkC++;
01164 
01165         tcp_extract_ipopt (tcp_conn, ip_hdr);
01166         tcp_extract_tcpopt (tcp_conn, tcp_hdr, &mss);
01167 
01168         RST_acc= tcp_make_header (tcp_conn, &RST_ip_hdr, &RST_tcp_hdr,
01169                 (acc_t *)0);
01170 
01171         if (tcp_conn->tc_remipopt)
01172                 bf_afree(tcp_conn->tc_remipopt);
01173         tcp_conn->tc_remipopt= tmp_ipopt;
01174         if (tcp_conn->tc_tcpopt)
01175                 bf_afree(tcp_conn->tc_tcpopt);
01176         tcp_conn->tc_tcpopt= tmp_tcpopt;
01177 
01178         RST_ip_hdr->ih_src= ip_hdr->ih_dst;
01179         RST_ip_hdr->ih_dst= ip_hdr->ih_src;
01180 
01181         RST_tcp_hdr->th_srcport= tcp_hdr->th_dstport;
01182         RST_tcp_hdr->th_dstport= tcp_hdr->th_srcport;
01183         if (tcp_hdr->th_flags & THF_ACK)
01184         {
01185                 RST_tcp_hdr->th_seq_nr= tcp_hdr->th_ack_nr;
01186                 RST_tcp_hdr->th_flags= THF_RST;
01187         }
01188         else
01189         {
01190                 RST_tcp_hdr->th_seq_nr= 0;
01191                 RST_tcp_hdr->th_ack_nr=
01192                         htonl(
01193                                 ntohl(tcp_hdr->th_seq_nr)+
01194                                 data_len +
01195                                 (tcp_hdr->th_flags & THF_SYN ? 1 : 0) +
01196                                 (tcp_hdr->th_flags & THF_FIN ? 1 : 0));
01197                 RST_tcp_hdr->th_flags= THF_RST|THF_ACK;
01198         }
01199 
01200         pack_size= bf_bufsize(RST_acc);
01201         RST_ip_hdr->ih_length= htons(pack_size);
01202         RST_tcp_hdr->th_window= htons(tcp_conn->tc_rcv_wnd);
01203         RST_tcp_hdr->th_chksum= 0;
01204 
01205         RST_acc->acc_linkC++;
01206         ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
01207         tcp_pack= bf_delhead(RST_acc, ip_hdr_len);
01208         RST_tcp_hdr->th_chksum= ~tcp_pack_oneCsum (RST_ip_hdr, tcp_pack);
01209         bf_afree(tcp_pack);
01210         
01211         DBLOCK(2, tcp_print_pack(ip_hdr, tcp_hdr); printf("\n");
01212                 tcp_print_pack(RST_ip_hdr, RST_tcp_hdr); printf("\n"));
01213 
01214         if (tcp_conn->tc_frag2send)
01215                 bf_afree(tcp_conn->tc_frag2send);
01216         tcp_conn->tc_frag2send= RST_acc;
01217         tcp_conn_write(tcp_conn, 1);
01218 }
01219 
01220 PUBLIC void
01221 tcp_fd_read(tcp_conn, enq)
01222 tcp_conn_t *tcp_conn;
01223 int enq;                                        /* Enqueue writes. */
01224 {
01225         tcp_fd_t *tcp_fd;
01226         size_t data_size, read_size;
01227         acc_t *data;
01228         int fin_recv, urg, push, result;
01229         i32_t old_window, new_window;
01230         u16_t mss;
01231 
01232         assert(tcp_conn->tc_busy);
01233 
01234         tcp_fd= tcp_conn->tc_fd;
01235 
01236         assert (tcp_fd->tf_flags & TFF_READ_IP);
01237         if (tcp_conn->tc_state == TCS_CLOSED)
01238         {
01239                 if (tcp_fd->tf_read_offset)
01240                         tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset);
01241                 else
01242                         tcp_reply_read (tcp_fd, tcp_conn->tc_error);
01243                 return;
01244         }
01245 
01246         urg= tcp_Gmod4G(tcp_conn->tc_RCV_UP, tcp_conn->tc_RCV_LO);
01247         push= (tcp_conn->tc_flags & TCF_RCV_PUSH);
01248         fin_recv= (tcp_conn->tc_flags & TCF_FIN_RECV);
01249 
01250         data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO;
01251         if (fin_recv)
01252                 data_size--;
01253         if (urg)
01254         {
01255 #if DEBUG
01256                 printf("tcp_fd_read: RCV_UP = 0x%x, RCV_LO = 0x%x\n",
01257                         tcp_conn->tc_RCV_UP, tcp_conn->tc_RCV_LO);
01258 #endif
01259                 read_size= tcp_conn->tc_RCV_UP-tcp_conn->tc_RCV_LO;
01260         }
01261         else
01262                 read_size= data_size;
01263 
01264         if (read_size >= tcp_fd->tf_read_count)
01265                 read_size= tcp_fd->tf_read_count;
01266         else if (!push && !fin_recv && !urg &&
01267                 data_size < TCP_MIN_RCV_WND_SIZE)
01268         {
01269                 /* Defer the copy out until later. */
01270                 return;
01271         }
01272         else if (data_size == 0 && !fin_recv)
01273         {
01274                 /* No data, and no end of file. */
01275                 return;
01276         }
01277 
01278         if (read_size)
01279         {
01280                 if (urg && !(tcp_fd->tf_flags & TFF_RECV_URG))
01281                 {
01282                         if (tcp_fd->tf_read_offset)
01283                         {
01284                                 tcp_reply_read (tcp_fd,
01285                                         tcp_fd->tf_read_offset);
01286                         }
01287                         else
01288                         {
01289                                 tcp_reply_read (tcp_fd, EURG);
01290                         }
01291                         return;
01292                 }
01293                 else if (!urg && (tcp_fd->tf_flags & TFF_RECV_URG))
01294                 {
01295                         if (tcp_fd->tf_read_offset)
01296                         {
01297                                 tcp_reply_read (tcp_fd,
01298                                         tcp_fd->tf_read_offset);
01299                         }
01300                         else
01301                         {
01302                                 tcp_reply_read(tcp_fd, ENOURG);
01303                         }
01304                         return;
01305                 }
01306 
01307                 if (read_size == data_size)
01308                 {
01309                         data= tcp_conn->tc_rcvd_data;
01310                         data->acc_linkC++;
01311                 }
01312                 else
01313                 {
01314                         data= bf_cut(tcp_conn->tc_rcvd_data, 0, read_size);
01315                 }
01316                 result= (*tcp_fd->tf_put_userdata) (tcp_fd->tf_srfd,
01317                         tcp_fd->tf_read_offset, data, FALSE);
01318                 if (result<0)
01319                 {
01320                         if (tcp_fd->tf_read_offset)
01321                                 tcp_reply_read(tcp_fd, tcp_fd->
01322                                         tf_read_offset);
01323                         else
01324                                 tcp_reply_read(tcp_fd, result);
01325                         return;
01326                 }
01327                 tcp_fd->tf_read_offset += read_size;
01328                 tcp_fd->tf_read_count -= read_size;
01329 
01330                 if (data_size == read_size)
01331                 {
01332                         bf_afree(tcp_conn->tc_rcvd_data);
01333                         tcp_conn->tc_rcvd_data= 0;
01334                 }
01335                 else
01336                 {
01337                         tcp_conn->tc_rcvd_data=
01338                                 bf_delhead(tcp_conn->tc_rcvd_data,
01339                                 read_size);
01340                 }
01341                 tcp_conn->tc_RCV_LO += read_size;
01342                 data_size -= read_size;
01343         }
01344 
01345         /* Update IRS and often RCV_UP every 0.5GB */
01346         if (tcp_conn->tc_RCV_LO - tcp_conn->tc_IRS > 0x40000000)
01347         {
01348                 tcp_conn->tc_IRS += 0x20000000;
01349                 DBLOCK(1, printf("tcp_fd_read: updating IRS to 0x%lx\n",
01350                         (unsigned long)tcp_conn->tc_IRS););
01351                 if (tcp_Lmod4G(tcp_conn->tc_RCV_UP, tcp_conn->tc_IRS))
01352                 {
01353                         tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS;
01354                         DBLOCK(1, printf(
01355                                 "tcp_fd_read: updating RCV_UP to 0x%lx\n",
01356                                 (unsigned long)tcp_conn->tc_RCV_UP););
01357                 }
01358                 DBLOCK(1, printf("tcp_fd_read: RCP_LO = 0x%lx\n",
01359                         (unsigned long)tcp_conn->tc_RCV_LO););
01360         }
01361 
01362         mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;
01363         if (tcp_conn->tc_RCV_HI-tcp_conn->tc_RCV_LO <=
01364                 tcp_conn->tc_rcv_wnd-mss)
01365         {
01366                 old_window= tcp_conn->tc_RCV_HI-tcp_conn->tc_RCV_NXT;
01367                 tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO + 
01368                         tcp_conn->tc_rcv_wnd;
01369                 new_window= tcp_conn->tc_RCV_HI-tcp_conn->tc_RCV_NXT;
01370                 assert(old_window >=0 && new_window >= old_window);
01371                 if (old_window < mss && new_window >= mss)
01372                 {
01373                         tcp_conn->tc_flags |= TCF_SEND_ACK;
01374                         DBLOCK(2, printf("opening window\n"));
01375                         tcp_conn_write(tcp_conn, 1);
01376                 }
01377         }
01378         if (tcp_conn->tc_rcvd_data == NULL &&
01379                 tcp_conn->tc_adv_data == NULL)
01380         {
01381                 /* Out of data, clear PUSH flag and reply to a read. */
01382                 tcp_conn->tc_flags &= ~TCF_RCV_PUSH;
01383         }
01384         if (fin_recv || urg || tcp_fd->tf_read_offset ||
01385                 !tcp_fd->tf_read_count)
01386         {
01387                 tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset);
01388                 return;
01389         }
01390 }
01391 
01392 PUBLIC unsigned
01393 tcp_sel_read(tcp_conn)
01394 tcp_conn_t *tcp_conn;
01395 {
01396         tcp_fd_t *tcp_fd;
01397         size_t data_size;
01398         int fin_recv, urg, push;
01399 
01400         tcp_fd= tcp_conn->tc_fd;
01401 
01402         if (tcp_conn->tc_state == TCS_CLOSED)
01403                 return 1;
01404 
01405         fin_recv= (tcp_conn->tc_flags & TCF_FIN_RECV);
01406         if (fin_recv)
01407                 return 1;
01408 
01409         data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO;
01410         if (data_size == 0)
01411         {
01412                 /* No data, and no end of file. */
01413                 return 0;
01414         }
01415 
01416         urg= tcp_Gmod4G(tcp_conn->tc_RCV_UP, tcp_conn->tc_RCV_LO);
01417         push= (tcp_conn->tc_flags & TCF_RCV_PUSH);
01418 
01419         if (!push && !urg && data_size < TCP_MIN_RCV_WND_SIZE)
01420         {
01421                 /* Defer until later. */
01422                 return 0;
01423         }
01424 
01425         return 1;
01426 }
01427 
01428 PUBLIC void
01429 tcp_rsel_read(tcp_conn)
01430 tcp_conn_t *tcp_conn;
01431 {
01432         tcp_fd_t *tcp_fd;
01433 
01434         if (tcp_sel_read(tcp_conn) == 0)
01435                 return;
01436 
01437         tcp_fd= tcp_conn->tc_fd;
01438         tcp_fd->tf_flags &= ~TFF_SEL_READ;
01439         if (tcp_fd->tf_select_res)
01440                 tcp_fd->tf_select_res(tcp_fd->tf_srfd, SR_SELECT_READ);
01441         else
01442                 printf("tcp_rsel_read: no select_res\n");
01443 }
01444 
01445 PUBLIC void tcp_bytesavailable(tcp_fd, bytesp)
01446 tcp_fd_t *tcp_fd;
01447 int *bytesp;
01448 {
01449         tcp_conn_t *tcp_conn;
01450         size_t data_size, read_size;
01451         acc_t *data;
01452         int fin_recv, urg, push, result;
01453         i32_t old_window, new_window;
01454         u16_t mss;
01455 
01456         *bytesp= 0;     /* The default is that nothing is available */
01457 
01458         if (!(tcp_fd->tf_flags & TFF_CONNECTED))
01459                 return;
01460         tcp_conn= tcp_fd->tf_conn;
01461 
01462         if (tcp_conn->tc_state == TCS_CLOSED)
01463                 return;
01464 
01465         urg= tcp_Gmod4G(tcp_conn->tc_RCV_UP, tcp_conn->tc_RCV_LO);
01466         push= (tcp_conn->tc_flags & TCF_RCV_PUSH);
01467         fin_recv= (tcp_conn->tc_flags & TCF_FIN_RECV);
01468 
01469         data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO;
01470         if (fin_recv)
01471                 data_size--;
01472         if (urg)
01473                 data_size= tcp_conn->tc_RCV_UP-tcp_conn->tc_RCV_LO;
01474 
01475         if (urg && !(tcp_fd->tf_flags & TFF_RECV_URG))
01476                 return;
01477         else if (!urg && (tcp_fd->tf_flags & TFF_RECV_URG))
01478                 return;
01479 
01480         *bytesp= data_size;
01481 }
01482 
01483 /*
01484  * $PchId: tcp_recv.c,v 1.30 2005/06/28 14:21:35 philip Exp $
01485  */

Generated on Fri Apr 14 22:57:31 2006 for minix by  doxygen 1.4.6