Please wait until the page is fully downloaded and then press the "Expand" button or the blue line numbers.

0056001 /*
0056002 tcp_recv.c
0056003 
0056004 Copyright 1995 Philip Homburg
0056005 */
0056006 
0056007 #include "inet.h"
0056008 #include "buf.h"
0056009 #include "clock.h"
0056010 #include "event.h"
0056011 #include "type.h"
0056012 
0056013 #include "io.h"
0056014 #include "tcp_int.h"
0056015 #include "tcp.h"
0056016 #include "assert.h"
0056017 
0056018 THIS_FILE
0056019 
0056020 FORWARD void create_RST ARGS(( tcp_conn_t *tcp_conn,
0056021          ip_hdr_t *ip_hdr, tcp_hdr_t *tcp_hdr, int data_len ));
0056022 FORWARD void process_data ARGS(( tcp_conn_t *tcp_conn,
0056023          tcp_hdr_t *tcp_hdr, acc_t *tcp_data, int data_len ));
0056024 FORWARD void process_advanced_data ARGS(( tcp_conn_t *tcp_conn,
0056025          tcp_hdr_t *tcp_hdr, acc_t *tcp_data, int data_len ));
0056026 
0056027 PUBLIC void tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data, data_len)
0056028 tcp_conn_t *tcp_conn;
0056029 ip_hdr_t *ip_hdr;
0056030 tcp_hdr_t *tcp_hdr;
0056031 acc_t *tcp_data;
0056032 size_t data_len;
tcp_frag2conn()




0056033 {
0056034          tcp_fd_t *connuser;
0056035          int tcp_hdr_flags;
0056036          int ip_hdr_len, tcp_hdr_len;
0056037          u32_t seg_ack, seg_seq, rcv_hi;
0056038          u16_t seg_wnd;
0056039          int acceptable_ACK, segm_acceptable;
0056040 
0056041          ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
0056042          tcp_hdr_len= (tcp_hdr->th_data_off & TH_DO_MASK) >> 2;
0056043 
0056044          tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK;
0056045          seg_ack= ntohl(tcp_hdr->th_ack_nr);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0056046          seg_seq= ntohl(tcp_hdr->th_seq_nr);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0056047          seg_wnd= ntohs(tcp_hdr->th_window);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0056048 
0056049          switch (tcp_conn->tc_state)
0056050          {
0056051          case TCS_CLOSED:
0056052 /*
0056053 CLOSED:
0056054          discard all data.
0056055          !RST ?
0056056                   ACK ?
0056057                            <SEQ=SEG.ACK><CTL=RST>
0056058                            exit
0056059                   :
0056060                            <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
0056061                            exit
0056062          :
0056063                   discard packet
0056064                   exit
0056065 */
0056066 
0056067                   if (!(tcp_hdr_flags & THF_RST))
0056068                   {
0056069                            create_RST(tcp_conn, ip_hdr, tcp_hdr, data_len);
create_RST()




0056070                            tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056071                   }
0056072                   break;
0056073          case TCS_LISTEN:
0056074 /*
0056075 LISTEN:
0056076          RST ?
0056077                   discard packet
0056078                   exit
0056079          ACK ?
0056080                   <SEQ=SEG.ACK><CTL=RST>
0056081                   exit
0056082          SYN ?
0056083                   BUG: no security check
0056084                   RCV.NXT= SEG.SEQ+1
0056085                   IRS= SEG.SEQ
0056086                   ISS should already be selected
0056087                   <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
0056088                   SND.NXT=ISS+1
0056089                   SND.UNA=ISS
0056090                   state= SYN-RECEIVED
0056091                   exit
0056092          :
0056093                   shouldnot occur
0056094                   discard packet
0056095                   exit
0056096 */
0056097                   if (tcp_hdr_flags & THF_RST)
0056098                            break;
0056099                   if (tcp_hdr_flags & THF_ACK)
0056100                   {
0056101                            create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len);
create_RST()




0056102                            tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056103                            break;
0056104                   }
0056105                   if (tcp_hdr_flags & THF_SYN)
0056106                   {
0056107                            tcp_extract_ipopt(tcp_conn, ip_hdr);
0056108                            tcp_extract_tcpopt(tcp_conn, tcp_hdr);
0056109                            tcp_conn->tc_RCV_LO= seg_seq+1;
0056110                            tcp_conn->tc_RCV_NXT= seg_seq+1;
0056111                            tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO+
0056112                                     tcp_conn->tc_rcv_wnd;
0056113                            tcp_conn->tc_RCV_UP= seg_seq;
0056114                            tcp_conn->tc_IRS= seg_seq;
0056115                            tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;
0056116                            tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
0056117                            tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS+1;
0056118                            tcp_conn->tc_SND_UP= tcp_conn->tc_ISS-1;
0056119                            tcp_conn->tc_SND_PSH= tcp_conn->tc_ISS-1;
0056120                            tcp_conn->tc_state= TCS_SYN_RECEIVED;
0056121                            tcp_conn->tc_stt= 0;
0056122                            assert (tcp_check_conn(tcp_conn));
0056123                            tcp_conn->tc_locaddr= ip_hdr->ih_dst;
0056124                            tcp_conn->tc_locport= tcp_hdr->th_dstport;
0056125                            tcp_conn->tc_remaddr= ip_hdr->ih_src;
0056126                            tcp_conn->tc_remport= tcp_hdr->th_srcport;
0056127                            tcp_conn_write(tcp_conn, 1);
0056128 
0056129                            DIFBLOCK(0x10, seg_seq == 0,
0056130                                     printf("warning got 0 IRS from ");
0056131                                     writeIpAddr(tcp_conn->tc_remaddr);
0056132                                     printf("\n"));
0056133 
0056134                            /* Start the timer (if necessary) */
0056135                            tcp_set_send_timer(tcp_conn);
tcp_set_send_timer()




0056136 
0056137                            break;
0056138                   }
0056139                   /* do nothing */
0056140                   break;
0056141          case TCS_SYN_SENT:
0056142 /*
0056143 SYN-SENT:
0056144          ACK ?
0056145                   SEG.ACK <= ISS || SEG.ACK > SND.NXT ?
0056146                            RST ?
0056147                                     discard packet
0056148                                     exit
0056149                            :
0056150                                     <SEQ=SEG.ACK><CTL=RST>
0056151                                     exit
0056152                   SND.UNA <= SEG.ACK && SEG.ACK <= SND.NXT ?
0056153                            ACK is acceptable
0056154                   :
0056155                            ACK is !acceptable
0056156          :
0056157                   ACK is !acceptable
0056158          RST ?
0056159                   ACK acceptable ?
0056160                            discard segment
0056161                            state= CLOSED
0056162                            error "connection refused"
0056163                            exit
0056164                   :
0056165                            discard packet
0056166                            exit
0056167          BUG: no security check
0056168          SYN ?
0056169                   IRS= SEG.SEQ
0056170                   RCV.NXT= IRS+1
0056171                   ACK ?
0056172                            SND.UNA= SEG.ACK
0056173                   SND.UNA > ISS ?
0056174                            state= ESTABLISHED
0056175                            <SEQ=SND.NXT><ACK= RCV.NXT><CTL=ACK>
0056176                            process ev. URG and text
0056177                            exit
0056178                   :
0056179                            state= SYN-RECEIVED
0056180                            SND.WND= SEG.WND
0056181                            SND.WL1= SEG.SEQ
0056182                            SND.WL2= SEG.ACK
0056183                            <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
0056184                            exit
0056185          :
0056186                   discard segment
0056187                   exit
0056188 */
0056189                   if (tcp_hdr_flags & THF_ACK)
0056190                   {
0056191                            if (tcp_LEmod4G(seg_ack, tcp_conn->tc_ISS) ||
0056192                                     tcp_Gmod4G(seg_ack, tcp_conn->tc_SND_NXT))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056193                                     if (tcp_hdr_flags & THF_RST)
0056194                                              break;
0056195                                     else
0056196                                     {
0056197                                              create_RST (tcp_conn, ip_hdr,
create_RST()




0056198                                                     tcp_hdr, data_len);
0056199                                              tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056200                                              break;
0056201                                     }
0056202                            acceptable_ACK= (tcp_LEmod4G(tcp_conn->tc_SND_UNA,
0056203                                     seg_ack) && tcp_LEmod4G(seg_ack,
0056204                                     tcp_conn->tc_SND_NXT));
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056205                   }
0056206                   else
0056207                            acceptable_ACK= FALSE;
0056208                   if (tcp_hdr_flags & THF_RST)
0056209                   {
0056210                            if (acceptable_ACK)
0056211                            {
0056212                                     DBLOCK(1, printf(
0056213                                              "calling tcp_close_connection\n"));
0056214 
0056215                                     tcp_close_connection(tcp_conn,
0056216                                              ECONNREFUSED);
tcp_close_connection()




0056217                            }
0056218                            break;
0056219                   }
0056220                   if (tcp_hdr_flags & THF_SYN)
0056221                   {
0056222                            tcp_conn->tc_RCV_LO= seg_seq+1;
0056223                            tcp_conn->tc_RCV_NXT= seg_seq+1;
0056224                            tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO +
0056225                                     tcp_conn->tc_rcv_wnd;
0056226                            tcp_conn->tc_RCV_UP= seg_seq;
0056227                            tcp_conn->tc_IRS= seg_seq;
0056228                            if (tcp_hdr_flags & THF_ACK)
0056229                                     tcp_conn->tc_SND_UNA= seg_ack;
0056230                            if (tcp_Gmod4G(tcp_conn->tc_SND_UNA,
0056231                                     tcp_conn->tc_ISS))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056232                            {
0056233                                     tcp_conn->tc_state= TCS_ESTABLISHED;
0056234                                     tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
0056235 
0056236                                     assert (tcp_check_conn(tcp_conn));
0056237                                     assert(tcp_conn->tc_connInprogress);
0056238 
0056239                                     tcp_restart_connect(tcp_conn->tc_fd);
tcp_restart_connect()




0056240 
0056241                                     tcp_conn->tc_flags |= TCF_SEND_ACK;
0056242                                     tcp_conn_write(tcp_conn, 1);
0056243                                     if (data_len != 0)
0056244                                     {
0056245                                              tcp_frag2conn(tcp_conn, ip_hdr,
0056246                                                     tcp_hdr, tcp_data, data_len);
tcp_frag2conn()




0056247                                              /* tcp_data is already freed */
0056248                                              return;
0056249                                     }
0056250                                     break;
0056251                            }
0056252                            tcp_conn->tc_state= TCS_SYN_RECEIVED;
0056253 
0056254                            assert (tcp_check_conn(tcp_conn));
tcp_check_conn()




0056255 
0056256                            tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
0056257                            tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056258                   }
0056259                   break;
0056260 
0056261          case TCS_SYN_RECEIVED:
0056262 /*
0056263 SYN-RECEIVED:
0056264          test if segment is acceptable:
0056265          Segment       Receive       Test
0056266          Length       Window
0056267          0       0       SEG.SEQ == RCV.NXT
0056268          0       >0       RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
0056269          >0       0       not acceptable
0056270          >0       >0       (RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND)
0056271                            || (RCV.NXT <= SEG.SEQ+SEG.LEN-1 &&
0056272                            SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND)
0056273          for urgent data: use RCV.WND+1 for RCV.WND
0056274 */
0056275                   rcv_hi= tcp_conn->tc_RCV_HI;
0056276                   if (tcp_hdr_flags & THF_URG)
0056277                            rcv_hi++;
0056278                   if (!data_len)
0056279                   {
0056280                            if (rcv_hi == tcp_conn->tc_RCV_NXT)
0056281                                     segm_acceptable= (seg_seq == rcv_hi);
0056282                            else
0056283                            {
0056284                                     assert (tcp_Gmod4G(rcv_hi,
0056285                                              tcp_conn->tc_RCV_NXT));
0056286                                     segm_acceptable= (tcp_LEmod4G(tcp_conn->
0056287                                              tc_RCV_NXT, seg_seq) &&
0056288                                              tcp_Lmod4G(seg_seq, rcv_hi));
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056289                            }
0056290                   }
0056291                   else
0056292                   {
0056293                            if (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056294                            {
0056295                                     segm_acceptable= (tcp_LEmod4G(tcp_conn->
0056296                                              tc_RCV_NXT, seg_seq) &&
0056297                                              tcp_Lmod4G(seg_seq, rcv_hi)) ||
0056298                                              (tcp_LEmod4G(tcp_conn->tc_RCV_NXT,
0056299                                              seg_seq+data_len-1) &&
0056300                                              tcp_Lmod4G(seg_seq+data_len-1,
0056301                                              rcv_hi));
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056302                            }
0056303                            else
0056304                            {
0056305                                     segm_acceptable= FALSE;
0056306                            }
0056307                   }
0056308 /*
0056309          !segment acceptable ?
0056310                   RST ?
0056311                            discard packet
0056312                            exit
0056313                   :
0056314                            <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
0056315                            exit
0056316 */
0056317                   if (!segm_acceptable)
0056318                   {
0056319                            if (!(tcp_hdr_flags & THF_RST))
0056320                            {
0056321                                     tcp_conn->tc_flags |= TCF_SEND_ACK;
0056322                                     tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056323                            }
0056324                            break;
0056325                   }
0056326 /*
0056327          RST ?
0056328                   initiated by a LISTEN ?
0056329                            state= LISTEN
0056330                            exit
0056331                   :
0056332                            state= CLOSED
0056333                            error "connection refused"
0056334                            exit
0056335 */
0056336                   if (tcp_hdr_flags & THF_RST)
0056337                   {
0056338                            if (tcp_conn->tc_orglisten)
0056339                            {
0056340                                     connuser= tcp_conn->tc_fd;
0056341 
0056342                                     tcp_conn->tc_connInprogress= 0;
0056343                                     tcp_conn->tc_fd= NULL;
0056344 
0056345                                     tcp_close_connection (tcp_conn, ECONNREFUSED);
tcp_close_connection()




0056346                                     if (connuser)
0056347                                              (void)tcp_su4listen(connuser);
tcp_su4connect()




0056348                                     break;
0056349                            }
0056350                            else
0056351                            {
0056352                                     tcp_close_connection(tcp_conn, ECONNREFUSED);
tcp_close_connection()




0056353                                     break;
0056354                            }
0056355                   }
0056356 /*
0056357          SYN in window ?
0056358                   initiated by a LISTEN ?
0056359                            state= LISTEN
0056360                            exit
0056361                   :
0056362                            state= CLOSED
0056363                            error "connection reset"
0056364                            exit
0056365 */
0056366                   if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,
0056367                            tcp_conn->tc_RCV_NXT))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056368                   {
0056369                            if (tcp_conn->tc_orglisten)
0056370                            {
0056371                                     connuser= tcp_conn->tc_fd;
0056372 
0056373                                     tcp_conn->tc_connInprogress= 0;
0056374                                     tcp_conn->tc_fd= NULL;
0056375 
0056376                                     tcp_close_connection(tcp_conn, ECONNRESET);
tcp_close_connection()




0056377                                     if (connuser)
0056378                                              (void)tcp_su4listen(connuser);
tcp_su4listen()




0056379                                     break;
0056380                            }
0056381                            tcp_close_connection(tcp_conn, ECONNRESET);
tcp_close_connection()




0056382                            break;
0056383                   }
0056384 /*
0056385          !ACK ?
0056386                   discard packet
0056387                   exit
0056388 */
0056389                   if (!(tcp_hdr_flags & THF_ACK))
0056390                            break;
0056391 /*
0056392          SND.UNA < SEG.ACK <= SND.NXT ?
0056393                   state= ESTABLISHED
0056394          :
0056395                   <SEG=SEG.ACK><CTL=RST>
0056396                   exit
0056397 */
0056398                   if (tcp_Lmod4G(tcp_conn->tc_SND_UNA, seg_ack) &&
0056399                            tcp_LEmod4G(seg_ack, tcp_conn->tc_SND_NXT))
0056400                   {
0056401                            tcp_conn->tc_state= TCS_ESTABLISHED;
0056402                            tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
0056403 
0056404                            tcp_release_retrans(tcp_conn, seg_ack, seg_wnd);
tcp_release_retrans()




0056405 
0056406                            assert (tcp_check_conn(tcp_conn));
0056407                            assert(tcp_conn->tc_connInprogress);
0056408 
0056409                            tcp_restart_connect(tcp_conn->tc_fd);
tcp_restart_connect()




0056410                            tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data,
0056411                                     data_len);
tcp_frag2conn()




0056412                            /* tcp_data is already freed */
0056413                            return;
0056414                   }
0056415                   else
0056416                   {
0056417                            create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len);
create_RST()




0056418                            tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056419                            break;
0056420                   }
0056421                   break;
0056422 
0056423          case TCS_ESTABLISHED:
0056424          case TCS_CLOSING:
0056425 /*
0056426 ESTABLISHED:
0056427 FIN-WAIT-1:
0056428 FIN-WAIT-2:
0056429 CLOSE-WAIT:
0056430 CLOSING:
0056431 LAST-ACK:
0056432 TIME-WAIT:
0056433          test if segment is acceptable:
0056434          Segment       Receive       Test
0056435          Length       Window
0056436          0       0       SEG.SEQ == RCV.NXT
0056437          0       >0       RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND
0056438          >0       0       not acceptable
0056439          >0       >0       (RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND)
0056440                            || (RCV.NXT <= SEG.SEQ+SEG.LEN-1 &&
0056441                            SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND)
0056442          for urgent data: use RCV.WND+1 for RCV.WND
0056443 */
0056444                   rcv_hi= tcp_conn->tc_RCV_HI;
0056445                   if (tcp_hdr_flags & THF_URG)
0056446                            rcv_hi++;
0056447                   if (!data_len)
0056448                   {
0056449                            if (rcv_hi == tcp_conn->tc_RCV_NXT)
0056450                                     segm_acceptable= (seg_seq == rcv_hi);
0056451                            else
0056452                            {
0056453                                     assert (tcp_Gmod4G(rcv_hi,
0056454                                              tcp_conn->tc_RCV_NXT));
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056455                                     segm_acceptable= (tcp_LEmod4G(tcp_conn->
0056456                                              tc_RCV_NXT, seg_seq) &&
0056457                                              tcp_Lmod4G(seg_seq, rcv_hi));
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056458                            }
0056459                   }
0056460                   else
0056461                   {
0056462                            if (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056463                            {
0056464                                     segm_acceptable= (tcp_LEmod4G(tcp_conn->
0056465                                              tc_RCV_NXT, seg_seq) &&
0056466                                              tcp_Lmod4G(seg_seq, rcv_hi)) ||
0056467                                              (tcp_LEmod4G(tcp_conn->tc_RCV_NXT,
0056468                                              seg_seq+data_len-1) &&
0056469                                              tcp_Lmod4G(seg_seq+data_len-1,
0056470                                              rcv_hi));
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056471                            }
0056472                            else
0056473                            {
0056474                                     segm_acceptable= FALSE;
0056475                            }
0056476                   }
0056477 /*
0056478          !segment acceptable ?
0056479                   RST ?
0056480                            discard packet
0056481                            exit
0056482                   :
0056483                            <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK>
0056484                            exit
0056485 */
0056486                   if (!segm_acceptable)
0056487                   {
0056488                            if (!(tcp_hdr_flags & THF_RST))
0056489                            {
0056490                                     DBLOCK(0x20,
0056491                                              printf("segment is not acceptable\n");
0056492                                              printf("\t");
0056493                                              tcp_print_pack(ip_hdr, tcp_hdr);
0056494                                              printf("\n\t");
0056495                                              tcp_print_conn(tcp_conn);
0056496                                              printf("\n"));
0056497                                     tcp_conn->tc_flags |= TCF_SEND_ACK;
0056498                                     tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056499 
0056500                                     /* Sometimes, a retransmission sets the PSH
0056501                                      * flag (Solaris 2.4)
0056502                                      */
0056503                                     if (tcp_conn->tc_rcvd_data != NULL &&
0056504                                              (tcp_hdr_flags & THF_PSH))
0056505                                     {
0056506                                              tcp_conn->tc_flags |= TCF_RCV_PUSH;
0056507                                              if (tcp_conn->tc_fd &&
0056508                                                     (tcp_conn->tc_fd->tf_flags &
0056509                                                     TFF_READ_IP))
0056510                                              {
0056511                                                     tcp_fd_read(tcp_conn, 1);
tcp_fd_read()




0056512                                              }
0056513                                     }
0056514                            }
0056515                            break;
0056516                   }
0056517 /*
0056518          RST ?
0056519                   state == CLOSING || state == LAST-ACK ||
0056520                            state == TIME-WAIT ?
0056521                            state= CLOSED
0056522                            exit
0056523                   :
0056524                            state= CLOSED
0056525                            error "connection reset"
0056526                            exit
0056527 */
0056528                   if (tcp_hdr_flags & THF_RST)
0056529                   {
0056530                            if ((tcp_conn->tc_flags &
0056531                                     (TCF_FIN_SENT|TCF_FIN_RECV)) ==
0056532                                     (TCF_FIN_SENT|TCF_FIN_RECV) &&
0056533                                     tcp_conn->tc_send_data == NULL)
0056534                            {
0056535                                     /* Clean shutdown, but the other side
0056536                                      * doesn't want to ACK our FIN.
0056537                                      */
0056538                                     tcp_close_connection (tcp_conn, 0);
tcp_close_connection()




0056539                            }
0056540                            else
0056541                                     tcp_close_connection(tcp_conn, ECONNRESET);
tcp_close_connection()




0056542                            break;
0056543                   }
0056544 /*
0056545          SYN in window ?
0056546                   state= CLOSED
0056547                   error "connection reset"
0056548                   exit
0056549 */
0056550                   if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq,
0056551                            tcp_conn->tc_RCV_NXT))
0056552                   {
0056553                            tcp_close_connection(tcp_conn, ECONNRESET);
tcp_close_connection()




0056554                            break;
0056555                   }
0056556 /*
0056557          !ACK ?
0056558                   discard packet
0056559                   exit
0056560 */
0056561                   if (!(tcp_hdr_flags & THF_ACK))
0056562                            break;
0056563 
0056564 /*
0056565          SND.UNA < SEG.ACK <= SND.NXT ?
0056566                   SND.UNA= SEG.ACK
0056567                   reply "send ok"
0056568                   SND.WL1 < SEG.SEQ || (SND.WL1 == SEG.SEQ &&
0056569                            SND.WL2 <= SEG.ACK ?
0056570                            SND.WND= SEG.WND
0056571                            SND.Wl1= SEG.SEQ
0056572                            SND.WL2= SEG.ACK
0056573          SEG.ACK <= SND.UNA ?
0056574                   ignore ACK
0056575          SEG.ACK > SND.NXT ?
0056576                   <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
0056577                   discard packet
0056578                   exit
0056579 */
0056580 
0056581                   /* Always reset the send timer after a valid ack is
0056582                    * received. The assumption is that either the ack really
0056583                    * acknowledges some data (normal case), contains a zero
0056584                    * window, or the remote host has another reason not
0056585                    * to accept any data. In all cases, the remote host is
0056586                    * alive, so the connection should stay alive too.
0056587                    * Do not reset stt if the state is CLOSING, i.e. if
0056588                    * the user closed the connection and we still have
0056589                    * some data to deliver. We don't want a zero window
0056590                    * to keep us from closing the connection.
0056591                    */
0056592                   if (tcp_conn->tc_state != TCS_CLOSING)
0056593                            tcp_conn->tc_stt= 0;
0056594 
0056595                   if (seg_ack == tcp_conn->tc_SND_UNA)
0056596                   {
0056597                            /* This ACK doesn't acknowledge any new data, this
0056598                             * is a likely situation if we are only receiving
0056599                             * data. We only update the window if we are
0056600                             * actually sending or if we currently have a
0056601                             * zero window.
0056602                             */
0056603                            if (tcp_conn->tc_snd_cwnd == tcp_conn->tc_SND_UNA &&
0056604                                     seg_wnd != 0)
0056605                            {
0056606                                     DBLOCK(2, printf("zero window opened\n"));
0056607                                     /* The other side opened up its receive
0056608                                      * window. */
0056609                                     if (seg_wnd > 2*tcp_conn->tc_mss)
0056610                                              seg_wnd= 2*tcp_conn->tc_mss;
0056611                                     tcp_conn->tc_snd_cwnd=
0056612                                              tcp_conn->tc_SND_UNA+seg_wnd;
0056613                                     tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056614                            }
0056615                            if (seg_wnd == 0)
0056616                            {
0056617                                     tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_TRM=
0056618                                              tcp_conn->tc_SND_UNA;
0056619                            }
0056620                   }
0056621                   else if (tcp_Lmod4G(tcp_conn->tc_SND_UNA, seg_ack)
0056622                            && tcp_LEmod4G(seg_ack, tcp_conn->
0056623                            tc_SND_NXT))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056624                   {
0056625                            tcp_release_retrans(tcp_conn, seg_ack, seg_wnd);
0056626                            if (tcp_conn->tc_state == TCS_CLOSED)
0056627                                     break;
0056628                   }
0056629                   else if (tcp_Gmod4G(seg_ack,
0056630                            tcp_conn->tc_SND_NXT))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056631                   {
0056632                            tcp_conn->tc_flags |= TCF_SEND_ACK;
0056633                            tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056634                            DBLOCK(1, printf(
0056635                            "got an ack of something I haven't send\n");
0056636                                     printf( "seg_ack= %lu, SND_NXT= %lu\n",
0056637                                     seg_ack, tcp_conn->tc_SND_NXT));
0056638                            break;
0056639                   }
0056640 
0056641 /*
0056642          process data...
0056643 */
0056644                   tcp_extract_ipopt(tcp_conn, ip_hdr);
tcp_extract_ipopt()




0056645                   tcp_extract_tcpopt(tcp_conn, tcp_hdr);
tcp_extract_tcpopt()




0056646 
0056647                   if (data_len)
0056648                   {
0056649                            if (tcp_LEmod4G(seg_seq, tcp_conn->tc_RCV_NXT))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056650                            {
0056651                                     process_data (tcp_conn, tcp_hdr,
process_data() / tcp




0056652                                              tcp_data, data_len);
0056653                            }
0056654                            else
0056655                            {
0056656                                     process_advanced_data (tcp_conn,
0056657                                              tcp_hdr, tcp_data, data_len);
process_advanced_data() / tcp




0056658                            }
0056659                            tcp_conn->tc_flags |= TCF_SEND_ACK;
0056660                            tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056661 
0056662                            /* Don't process a FIN if we got new data */
0056663                            break;
0056664                   }
0056665 /*
0056666          FIN ?
0056667                   reply pending receives
0056668                   advace RCV.NXT over the FIN
0056669                   <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
0056670 
0056671                   state == ESTABLISHED ?
0056672                            state= CLOSE-WAIT
0056673                   state == FIN-WAIT-1 ?
0056674                            state= CLOSING
0056675                   state == FIN-WAIT-2 ?
0056676                            state= TIME-WAIT
0056677                   state == TIME-WAIT ?
0056678                            restart the TIME-WAIT timer
0056679          exit
0056680 */
0056681                   if ((tcp_hdr_flags & THF_FIN) && tcp_LEmod4G(seg_seq,
0056682                            tcp_conn->tc_RCV_NXT))
0056683                   {
0056684                            if (!(tcp_conn->tc_flags & TCF_FIN_RECV) &&
0056685                                     tcp_Lmod4G(tcp_conn->tc_RCV_NXT,
0056686                                     tcp_conn->tc_RCV_HI))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056687                            {
0056688                                     tcp_conn->tc_RCV_NXT++;
0056689                                     tcp_conn->tc_flags |= TCF_FIN_RECV;
0056690                            }
0056691                            tcp_conn->tc_flags |= TCF_SEND_ACK;
0056692                            tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056693                            if (tcp_conn->tc_fd &&
0056694                                     (tcp_conn->tc_fd->tf_flags & TFF_READ_IP))
0056695                            {
0056696                                     tcp_fd_read(tcp_conn, 1);
tcp_fd_read()




0056697                            }
0056698                   }
0056699                   break;
0056700          default:
0056701 #if !CRAMPED
0056702                   printf("tcp_frag2conn: unknown state ");
0056703                   tcp_print_state(tcp_conn);
tcp_print_state()




0056704 #endif
0056705                   break;
0056706          }
0056707          if (tcp_data != NULL)
0056708                   bf_afree(tcp_data);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0056709 }
0056710 
0056711 
0056712 PRIVATE void
0056713 process_data(tcp_conn, tcp_hdr, tcp_data, data_len)
0056714 tcp_conn_t *tcp_conn;
0056715 tcp_hdr_t *tcp_hdr;
0056716 acc_t *tcp_data;
0056717 int data_len;
process_data() / tcp




0056718 {
0056719          u32_t lo_seq, hi_seq, urg_seq, seq_nr, adv_seq, nxt;
0056720          u16_t urgptr;
0056721          int tcp_hdr_flags;
0056722          unsigned int offset;
0056723          acc_t *tmp_data, *rcvd_data, *adv_data;
0056724          int len_diff;
0056725 
0056726          assert(tcp_conn->tc_busy);
0056727 
0056728          /* Note, tcp_data will be freed by the caller. */
0056729          assert (!(tcp_hdr->th_flags & THF_SYN));
0056730 
0056731          seq_nr= ntohl(tcp_hdr->th_seq_nr);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0056732          urgptr= ntohs(tcp_hdr->th_urgptr);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0056733 
0056734          tcp_data->acc_linkC++;
0056735 
0056736          lo_seq= seq_nr;
0056737          tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK;
0056738 
0056739          if (tcp_hdr_flags & THF_URG)
0056740          {
0056741                   if (urgptr > data_len)
0056742                            urgptr= data_len;
0056743                   urg_seq= lo_seq+ urgptr;
0056744 
0056745                   if (tcp_GEmod4G(urg_seq, tcp_conn->tc_RCV_HI))
0056746                            urg_seq= tcp_conn->tc_RCV_HI;
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056747                   if (tcp_conn->tc_flags & TCF_BSD_URG)
0056748                   {
0056749                            if (tcp_Gmod4G(tcp_conn->tc_RCV_NXT,
0056750                                     tcp_conn->tc_RCV_LO))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056751                            {
0056752                                     DBLOCK(1, printf(
0056753                                              "ignoring urgent data\n"));
0056754 
0056755                                     bf_afree(tcp_data);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0056756                                     /* Should set advertised window to
0056757                                      * zero */
0056758 
0056759                                     /* Flush */
0056760                                     tcp_conn->tc_flags |= TCF_RCV_PUSH;
0056761                                     if (tcp_conn->tc_fd &&
0056762                                              (tcp_conn->tc_fd->tf_flags &
0056763                                              TFF_READ_IP))
0056764                                     {
0056765                                              tcp_fd_read(tcp_conn, 1);
tcp_fd_read()




0056766                                     }
0056767                                     return;
0056768                            }
0056769                   }
0056770                   if (tcp_Gmod4G(urg_seq, tcp_conn->tc_RCV_UP))
0056771                            tcp_conn->tc_RCV_UP= urg_seq;
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056772                   if (urgptr < data_len)
0056773                   {
0056774                            data_len= urgptr;
0056775                            tmp_data= bf_cut(tcp_data, 0, data_len);
bf_cut()

If a section of a linked list needs to be duplicated, bf_cut(data, offset, length) is called. For example, if a section of length 50 starting at an offset of 75 of the linked list below needs to be duplicated, bf_cut(data, 75, 50) is called:



Note that the original linked list remains unchanged and that acc_linkC for all the accessors in the new linked list is one.

If length (the second parameter) is zero, simply duplicate the first accessor in the linked list but set acc_length=0 and acc_next=null. In other words, create a linked list of length one accessor whose acc_length is 0.

bf_cut() is used in a number of scenarios, including cutting a received ethernet packet to size.

For a full description of the network service's buffer management, click here.



0056776                            bf_afree(tcp_data);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0056777                            tcp_data= tmp_data;
0056778                            tcp_hdr_flags &= ~THF_FIN;
0056779                   }
0056780                   tcp_conn->tc_flags |= TCF_RCV_PUSH;
0056781          }
0056782          else
0056783          {
0056784                   /* Normal data. */
0056785          }
0056786 
0056787          if (tcp_hdr_flags & THF_PSH)
0056788          {
0056789                   tcp_conn->tc_flags |= TCF_RCV_PUSH;
0056790          }
0056791 
0056792          if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056793          {
0056794                   DBLOCK(0x10,
0056795                            printf("segment is a retransmission\n"));
0056796                   offset= tcp_conn->tc_RCV_NXT-lo_seq;
0056797                   tcp_data= bf_delhead(tcp_data, offset);
bf_delhead()

If only the beginning of a linked list can be freed, bf_delhead() is called. If acc_linkC and buf_linkC are one for all of the relevant accessors and their associated buffers in the linked list, the operation is straight-forward:



bf_delhead() is often called to remove the header (e.g., ip header) from a packet.

For a detailed description of the network service's buffer management, click here.


0056798                   lo_seq += offset;
0056799                   data_len -= offset;
0056800          }
0056801          assert (lo_seq == tcp_conn->tc_RCV_NXT);
0056802 
0056803          hi_seq= lo_seq+data_len;
0056804          if (tcp_Gmod4G(hi_seq, tcp_conn->tc_RCV_HI))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056805          {
0056806                   data_len= tcp_conn->tc_RCV_HI-lo_seq;
0056807                   tmp_data= bf_cut(tcp_data, 0, data_len);
bf_cut()

If a section of a linked list needs to be duplicated, bf_cut(data, offset, length) is called. For example, if a section of length 50 starting at an offset of 75 of the linked list below needs to be duplicated, bf_cut(data, 75, 50) is called:



Note that the original linked list remains unchanged and that acc_linkC for all the accessors in the new linked list is one.

If length (the second parameter) is zero, simply duplicate the first accessor in the linked list but set acc_length=0 and acc_next=null. In other words, create a linked list of length one accessor whose acc_length is 0.

bf_cut() is used in a number of scenarios, including cutting a received ethernet packet to size.

For a full description of the network service's buffer management, click here.



0056808                   bf_afree(tcp_data);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0056809                   tcp_data= tmp_data;
0056810                   hi_seq= lo_seq+data_len;
0056811                   tcp_hdr_flags &= ~THF_FIN;
0056812          }
0056813          assert (tcp_LEmod4G (hi_seq, tcp_conn->tc_RCV_HI));
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056814 
0056815          rcvd_data= tcp_conn->tc_rcvd_data;
0056816          tcp_conn->tc_rcvd_data= 0;
0056817          tmp_data= bf_append(rcvd_data, tcp_data);
bf_append()

bf_append() appends one accessor linked list to another accessor linked list. For example, if the payload of an ethernet packet (1500 bytes) is appended to an ethernet header (14 bytes):



the resulting linked list is as follows:






0056818          tcp_conn->tc_rcvd_data= tmp_data;
0056819          tcp_conn->tc_RCV_NXT= hi_seq;
0056820 
0056821          if ((tcp_hdr_flags & THF_FIN) &&
0056822                   tcp_Lmod4G(tcp_conn->tc_RCV_NXT, tcp_conn->tc_RCV_HI) &&
0056823                   !(tcp_conn->tc_flags & TCF_FIN_RECV))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056824          {
0056825                   tcp_conn->tc_RCV_NXT++;
0056826                   tcp_conn->tc_flags |= TCF_FIN_RECV;
0056827          }
0056828 
0056829          if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_READ_IP))
0056830                   tcp_fd_read(tcp_conn, 1);
tcp_fd_read()




0056831 
0056832          DIFBLOCK(2, (tcp_conn->tc_RCV_NXT == tcp_conn->tc_RCV_HI),
0056833                   printf("conn[[%d] full receive buffer\n",
0056834                   tcp_conn-tcp_conn_table));
0056835 
0056836          if (tcp_conn->tc_adv_data == NULL)
0056837                   return;
0056838          if (tcp_hdr_flags & THF_FIN)
0056839          {
0056840 #if !CRAMPED
0056841                   printf("conn[%d]: advanced data after FIN\n",
0056842                            tcp_conn-tcp_conn_table);
0056843 #endif
0056844                   tcp_data= tcp_conn->tc_adv_data;
0056845                   tcp_conn->tc_adv_data= NULL;
0056846                   bf_afree(tcp_data);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0056847                   return;
0056848          }
0056849 
0056850          lo_seq= tcp_conn->tc_adv_seq;
0056851          if (tcp_Gmod4G(lo_seq, tcp_conn->tc_RCV_NXT))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056852                   return;              /* Not yet */
0056853 
0056854          tcp_data= tcp_conn->tc_adv_data;
0056855          tcp_conn->tc_adv_data= NULL;
0056856 
0056857          data_len= bf_bufsize(tcp_data);
bf_bufsize()

bf_bufsize() returns the total buffer size of a linked list of accessors (i.e., the sum of acc_length for the accessors in a linked list).

For a detailed description of the network service's buffer management, click here.


0056858          if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056859          {
0056860                   offset= tcp_conn->tc_RCV_NXT-lo_seq;
0056861                   if (offset >= data_len)
0056862                   {
0056863                            bf_afree(tcp_data);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0056864                            return;
0056865                   }
0056866                   tcp_data= bf_delhead(tcp_data, offset);
bf_delhead()

If only the beginning of a linked list can be freed, bf_delhead() is called. If acc_linkC and buf_linkC are one for all of the relevant accessors and their associated buffers in the linked list, the operation is straight-forward:



bf_delhead() is often called to remove the header (e.g., ip header) from a packet.

For a detailed description of the network service's buffer management, click here.


0056867                   lo_seq += offset;
0056868                   data_len -= offset;
0056869          }
0056870          assert (lo_seq == tcp_conn->tc_RCV_NXT);
0056871 
0056872          hi_seq= lo_seq+data_len;
0056873          assert (tcp_LEmod4G (hi_seq, tcp_conn->tc_RCV_HI));
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056874 
0056875          rcvd_data= tcp_conn->tc_rcvd_data;
0056876          tcp_conn->tc_rcvd_data= 0;
0056877          tmp_data= bf_append(rcvd_data, tcp_data);
bf_append()

bf_append() appends one accessor linked list to another accessor linked list. For example, if the payload of an ethernet packet (1500 bytes) is appended to an ethernet header (14 bytes):



the resulting linked list is as follows:






0056878          tcp_conn->tc_rcvd_data= tmp_data;
0056879          tcp_conn->tc_RCV_NXT= hi_seq;
0056880 
0056881          assert (tcp_conn->tc_RCV_LO + bf_bufsize(tcp_conn->tc_rcvd_data) ==
0056882                   tcp_conn->tc_RCV_NXT ||
0056883                   (tcp_print_conn(tcp_conn), printf("\n"), 0));
tcp_print_conn()




0056884 
0056885          if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_READ_IP))
0056886                   tcp_fd_read(tcp_conn, 1);
tcp_fd_read()




0056887 
0056888          adv_data= tcp_conn->tc_adv_data;
0056889          if (adv_data != NULL)
0056890          {
0056891                   /* Try to use advanced data. */
0056892                   adv_seq= tcp_conn->tc_adv_seq;
0056893                   nxt= tcp_conn->tc_RCV_NXT;
0056894 
0056895                   if (tcp_Gmod4G(adv_seq, nxt))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056896                            return;              /* not yet */
0056897 
0056898                   tcp_conn->tc_adv_data= NULL;
0056899                   data_len= bf_bufsize(adv_data);
0056900 
0056901                   if (tcp_Lmod4G(adv_seq, nxt))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056902                   {
0056903                            if (tcp_LEmod4G(adv_seq+data_len, nxt))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0056904                            {
0056905                                     /* Data is not needed anymore. */
0056906                                     bf_afree(adv_data);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0056907                                     return;
0056908                            }
0056909 
0056910                            len_diff= nxt-adv_seq;
0056911                            adv_data= bf_delhead(adv_data, len_diff);
bf_delhead()

If only the beginning of a linked list can be freed, bf_delhead() is called. If acc_linkC and buf_linkC are one for all of the relevant accessors and their associated buffers in the linked list, the operation is straight-forward:



bf_delhead() is often called to remove the header (e.g., ip header) from a packet.

For a detailed description of the network service's buffer management, click here.


0056912                            data_len -= len_diff;
0056913                   }
0056914 
0056915                   DBLOCK(1, printf("using advanced data\n"));
0056916 
0056917                   /* Append data to the input buffer */
0056918                   if (tcp_conn->tc_rcvd_data == NULL)
0056919                   {
0056920                            tcp_conn->tc_rcvd_data= adv_data;
0056921                   }
0056922                   else
0056923                   {
0056924                            tcp_conn->tc_rcvd_data=
0056925                                     bf_append(tcp_conn->tc_rcvd_data, adv_data);
bf_append()

bf_append() appends one accessor linked list to another accessor linked list. For example, if the payload of an ethernet packet (1500 bytes) is appended to an ethernet header (14 bytes):



the resulting linked list is as follows:






0056926                   }
0056927                   tcp_conn->tc_SND_NXT += data_len;
0056928                   assert(tcp_check_conn(tcp_conn));
tcp_check_conn()




0056929 
0056930                   if (tcp_conn->tc_fd &&
0056931                            (tcp_conn->tc_fd->tf_flags & TFF_READ_IP))
0056932                   {
0056933                            tcp_fd_read(tcp_conn, 1);
tcp_fd_read()




0056934                   }
0056935          }
0056936 }
0056937 
0056938 PRIVATE void process_advanced_data(tcp_conn, tcp_hdr, tcp_data, data_len)
0056939 tcp_conn_t *tcp_conn;
0056940 tcp_hdr_t *tcp_hdr;
0056941 acc_t *tcp_data;
0056942 int data_len;
process_advanced_data() / tcp




0056943 {
0056944          u32_t seq, adv_seq;
0056945          acc_t *adv_data;
0056946 
0056947          assert(tcp_conn->tc_busy);
0056948 
0056949          /* Note, tcp_data will be freed by the caller. */
0056950 
0056951          /* Always send an ACK, this allows the sender to do a fast
0056952           * retransmit.
0056953           */
0056954          tcp_conn->tc_flags |= TCF_SEND_ACK;
0056955          tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0056956 
0056957          if (tcp_hdr->th_flags & THF_URG)
0056958                   return;       /* Urgent data is to complicated */
0056959          if (tcp_hdr->th_flags & THF_PSH)
0056960                   tcp_conn->tc_flags |= TCF_RCV_PUSH;
0056961          seq= ntohl(tcp_hdr->th_seq_nr);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0056962 
0056963          /* Make sure that the packet doesn't fall outside of the window
0056964           * we offered.
0056965           */
0056966          if (tcp_Gmod4G(seq+data_len, tcp_conn->tc_RCV_HI))
0056967                   return;
0056968 
0056969          adv_data= tcp_conn->tc_adv_data;
0056970          adv_seq= tcp_conn->tc_adv_seq;
0056971          tcp_conn->tc_adv_data= NULL;
0056972 
0056973          tcp_data->acc_linkC++;
0056974          if (adv_data == NULL)
0056975          {
0056976                   adv_seq= seq;
0056977                   adv_data= tcp_data;
0056978          }
0056979          else if (seq + data_len == adv_seq)
0056980          {
0056981                   /* New data fits right before exiting data. */
0056982                   adv_data= bf_append(tcp_data, adv_data);
bf_append()

bf_append() appends one accessor linked list to another accessor linked list. For example, if the payload of an ethernet packet (1500 bytes) is appended to an ethernet header (14 bytes):



the resulting linked list is as follows:






0056983                   adv_seq= seq;
0056984          }
0056985          else if (adv_seq + bf_bufsize(adv_data) == seq)
0056986          {
0056987                   /* New data fits right after exiting data. */
0056988                   adv_data= bf_append(adv_data, tcp_data);
bf_append()

bf_append() appends one accessor linked list to another accessor linked list. For example, if the payload of an ethernet packet (1500 bytes) is appended to an ethernet header (14 bytes):



the resulting linked list is as follows:






0056989          }
0056990          else
0056991          {
0056992                   /* New data doesn't fit. */
0056993                   bf_afree(tcp_data);
0056994          }
0056995          tcp_conn->tc_adv_data= adv_data;
0056996          tcp_conn->tc_adv_seq= adv_seq;
0056997 }
0056998                                     
0056999 PRIVATE void create_RST(tcp_conn, ip_hdr, tcp_hdr, data_len)
0057000 tcp_conn_t *tcp_conn;
0057001 ip_hdr_t *ip_hdr;
0057002 tcp_hdr_t *tcp_hdr;
0057003 int data_len;
create_RST()




0057004 {
0057005          acc_t *tmp_ipopt, *tmp_tcpopt, *tcp_pack;
0057006          ip_hdropt_t ip_hdropt;
0057007          tcp_hdropt_t tcp_hdropt;
0057008          acc_t *RST_acc;
0057009          ip_hdr_t *RST_ip_hdr;
0057010          tcp_hdr_t *RST_tcp_hdr;
0057011          char *ptr2RSThdr;
0057012          size_t pack_size, ip_hdr_len;
0057013 
0057014          DBLOCK(0x10, printf("in create_RST, bad pack is:\n");
0057015                   tcp_print_pack(ip_hdr, tcp_hdr); tcp_print_state(tcp_conn);
0057016                   printf("\n"));
0057017 
0057018          assert(tcp_conn->tc_busy);
0057019 
0057020          /* Only send RST packets in reponse to actual data (or SYN, FIN)
0057021           * this solves a problem during connection shutdown. The problem
0057022           * is the follow senario: a senders closes the connection instead
0057023           * of doing a shutdown and waiting for the receiver to shutdown.
0057024           * The receiver is slow in processing the last data. After the
0057025           * sender has completely closed the connection, the receiver
0057026           * sends a window update which triggers the sender to send a
0057027           * RST. The receiver closes the connection in reponse to the RST.
0057028           */
0057029          if ((tcp_hdr->th_flags & (THF_FIN|THF_SYN)) == 0 &&
0057030                   data_len == 0)
0057031          {
0057032 #if DEBUG
0057033  { printf("tcp_recv`create_RST: no data, no RST\n"); }
0057034 #endif
0057035                   return;
0057036          }
0057037 
0057038          tmp_ipopt= tcp_conn->tc_remipopt;
0057039          if (tmp_ipopt)
0057040                   tmp_ipopt->acc_linkC++;
0057041          tmp_tcpopt= tcp_conn->tc_tcpopt;
0057042          if (tmp_tcpopt)
0057043                   tmp_tcpopt->acc_linkC++;
0057044 
0057045          tcp_extract_ipopt (tcp_conn, ip_hdr);
tcp_extract_ipopt()




0057046          tcp_extract_tcpopt (tcp_conn, tcp_hdr);
tcp_extract_tcpopt()




0057047 
0057048          RST_acc= tcp_make_header (tcp_conn, &RST_ip_hdr, &RST_tcp_hdr,
tcp_make_header()




0057049                   (acc_t *)0);
0057050 
0057051          if (tcp_conn->tc_remipopt)
0057052                   bf_afree(tcp_conn->tc_remipopt);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0057053          tcp_conn->tc_remipopt= tmp_ipopt;
0057054          if (tcp_conn->tc_tcpopt)
0057055                   bf_afree(tcp_conn->tc_tcpopt);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0057056          tcp_conn->tc_tcpopt= tmp_tcpopt;
0057057 
0057058          RST_ip_hdr->ih_src= ip_hdr->ih_dst;
0057059          RST_ip_hdr->ih_dst= ip_hdr->ih_src;
0057060 
0057061          RST_tcp_hdr->th_srcport= tcp_hdr->th_dstport;
0057062          RST_tcp_hdr->th_dstport= tcp_hdr->th_srcport;
0057063          if (tcp_hdr->th_flags & THF_ACK)
0057064          {
0057065                   RST_tcp_hdr->th_seq_nr= tcp_hdr->th_ack_nr;
0057066                   RST_tcp_hdr->th_flags= THF_RST;
0057067          }
0057068          else
0057069          {
0057070                   RST_tcp_hdr->th_seq_nr= 0;
0057071                   RST_tcp_hdr->th_ack_nr=
0057072                            htonl(
0057073                                     ntohl(tcp_hdr->th_seq_nr)+
0057074                                     data_len +
0057075                                     (tcp_hdr->th_flags & THF_SYN ? 1 : 0) +
0057076                                     (tcp_hdr->th_flags & THF_FIN ? 1 : 0));
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0057077                   RST_tcp_hdr->th_flags= THF_RST|THF_ACK;
0057078          }
0057079 
0057080          pack_size= bf_bufsize(RST_acc);
bf_bufsize()

bf_bufsize() returns the total buffer size of a linked list of accessors (i.e., the sum of acc_length for the accessors in a linked list).

For a detailed description of the network service's buffer management, click here.


0057081          RST_ip_hdr->ih_length= htons(pack_size);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0057082          RST_tcp_hdr->th_window= htons(tcp_conn->tc_rcv_wnd);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0057083          RST_tcp_hdr->th_chksum= 0;
0057084 
0057085          RST_acc->acc_linkC++;
0057086          ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
0057087          tcp_pack= bf_delhead(RST_acc, ip_hdr_len);
bf_delhead()

If only the beginning of a linked list can be freed, bf_delhead() is called. If acc_linkC and buf_linkC are one for all of the relevant accessors and their associated buffers in the linked list, the operation is straight-forward:



bf_delhead() is often called to remove the header (e.g., ip header) from a packet.

For a detailed description of the network service's buffer management, click here.


0057088          RST_tcp_hdr->th_chksum= ~tcp_pack_oneCsum (RST_ip_hdr, tcp_pack);
tcp_pack_oneCsum()

tcp_pack_oneCsum() computes the checksum of a tcp packet (including several fields of its ip header). It accomplishes this by computing the checksum (by calling oneC_sum()) of each of the tcp packet's buffers.

Note that a checksum is used to determine if errors occurred during the transmission of data.


0057089          bf_afree(tcp_pack);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0057090          
0057091          DBLOCK(2, tcp_print_pack(ip_hdr, tcp_hdr); printf("\n");
0057092                   tcp_print_pack(RST_ip_hdr, RST_tcp_hdr); printf("\n"));
tcp_print_pack()




0057093 
0057094          if (tcp_conn->tc_frag2send)
0057095                   bf_afree(tcp_conn->tc_frag2send);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0057096          tcp_conn->tc_frag2send= RST_acc;
0057097          tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0057098 }
0057099 
0057100 PUBLIC void
0057101 tcp_fd_read(tcp_conn, enq)
0057102 tcp_conn_t *tcp_conn;
0057103 int enq;                                   /* Enqueue writes. */
tcp_fd_read()




0057104 {
0057105          tcp_fd_t *tcp_fd;
0057106          size_t data_size, read_size;
0057107          acc_t *data;
0057108          int fin_recv, urg, push, result;
0057109          i32_t old_window, new_window;
0057110 
0057111          assert(tcp_conn->tc_busy);
0057112 
0057113          tcp_fd= tcp_conn->tc_fd;
0057114 
0057115          assert (tcp_fd->tf_flags & TFF_READ_IP);
0057116          if (tcp_conn->tc_state == TCS_CLOSED)
0057117          {
0057118                   if (tcp_fd->tf_read_offset)
0057119                            tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset);
tcp_reply_read()




0057120                   else
0057121                            tcp_reply_read (tcp_fd, tcp_conn->tc_error);
tcp_reply_read()




0057122                   return;
0057123          }
0057124 
0057125          urg= tcp_Gmod4G(tcp_conn->tc_RCV_UP, tcp_conn->tc_RCV_LO);
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0057126          push= (tcp_conn->tc_flags & TCF_RCV_PUSH);
0057127          fin_recv= (tcp_conn->tc_flags & TCF_FIN_RECV);
0057128 
0057129          data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO;
0057130          if (fin_recv)
0057131                   data_size--;
0057132          if (urg)
0057133                   read_size= tcp_conn->tc_RCV_UP-tcp_conn->tc_RCV_LO;
0057134          else
0057135                   read_size= data_size;
0057136 
0057137          if (read_size >= tcp_fd->tf_read_count)
0057138                   read_size= tcp_fd->tf_read_count;
0057139          else if (!push && !fin_recv && !urg &&
0057140                   data_size < TCP_MIN_RCV_WND_SIZE)
0057141          {
0057142                   /* Defer the copy out until later. */
0057143                   return;
0057144          }
0057145          else if (data_size == 0 && !fin_recv)
0057146          {
0057147                   /* No data, and no end of file. */
0057148                   return;
0057149          }
0057150 
0057151          if (read_size)
0057152          {
0057153                   if (urg && !(tcp_fd->tf_flags & TFF_RECV_URG))
0057154                   {
0057155                            if (tcp_fd->tf_read_offset)
0057156                            {
0057157                                     tcp_reply_read (tcp_fd,
0057158                                              tcp_fd->tf_read_offset);
tcp_reply_read()




0057159                            }
0057160                            else
0057161                            {
0057162                                     tcp_reply_read (tcp_fd, EURG);
tcp_reply_read()




0057163                            }
0057164                            return;
0057165                   }
0057166                   else if (!urg && (tcp_fd->tf_flags & TFF_RECV_URG))
0057167                   {
0057168                            if (tcp_fd->tf_read_offset)
0057169                            {
0057170                                     tcp_reply_read (tcp_fd,
0057171                                              tcp_fd->tf_read_offset);
tcp_reply_read()




0057172                            }
0057173                            else
0057174                            {
0057175                                     tcp_reply_read(tcp_fd, ENOURG);
tcp_reply_read()




0057176                            }
0057177                            return;
0057178                   }
0057179 
0057180                   if (read_size == data_size)
0057181                   {
0057182                            data= tcp_conn->tc_rcvd_data;
0057183                            data->acc_linkC++;
0057184                   }
0057185                   else
0057186                   {
0057187                            data= bf_cut(tcp_conn->tc_rcvd_data, 0, read_size);
bf_cut()

If a section of a linked list needs to be duplicated, bf_cut(data, offset, length) is called. For example, if a section of length 50 starting at an offset of 75 of the linked list below needs to be duplicated, bf_cut(data, 75, 50) is called:



Note that the original linked list remains unchanged and that acc_linkC for all the accessors in the new linked list is one.

If length (the second parameter) is zero, simply duplicate the first accessor in the linked list but set acc_length=0 and acc_next=null. In other words, create a linked list of length one accessor whose acc_length is 0.

bf_cut() is used in a number of scenarios, including cutting a received ethernet packet to size.

For a full description of the network service's buffer management, click here.



0057188                   }
0057189                   result= (*tcp_fd->tf_put_userdata) (tcp_fd->tf_srfd,
0057190                            tcp_fd->tf_read_offset, data, FALSE);
0057191                   if (result<0)
0057192                   {
0057193                            if (tcp_fd->tf_read_offset)
0057194                                     tcp_reply_read(tcp_fd, tcp_fd->
0057195                                              tf_read_offset);
tcp_reply_read()




0057196                            else
0057197                                     tcp_reply_read(tcp_fd, result);
tcp_reply_read()




0057198                            return;
0057199                   }
0057200                   tcp_fd->tf_read_offset += read_size;
0057201                   tcp_fd->tf_read_count -= read_size;
0057202 
0057203                   if (data_size == read_size)
0057204                   {
0057205                            bf_afree(tcp_conn->tc_rcvd_data);
0057206                            tcp_conn->tc_rcvd_data= 0;
0057207                   }
0057208                   else
0057209                   {
0057210                            tcp_conn->tc_rcvd_data=
0057211                                     bf_delhead(tcp_conn->tc_rcvd_data,
0057212                                     read_size);
bf_delhead()

If only the beginning of a linked list can be freed, bf_delhead() is called. If acc_linkC and buf_linkC are one for all of the relevant accessors and their associated buffers in the linked list, the operation is straight-forward:



bf_delhead() is often called to remove the header (e.g., ip header) from a packet.

For a detailed description of the network service's buffer management, click here.


0057213                   }
0057214                   tcp_conn->tc_RCV_LO += read_size;
0057215                   data_size -= read_size;
0057216          }
0057217          if (tcp_conn->tc_RCV_HI-tcp_conn->tc_RCV_LO <= (tcp_conn->
0057218                   tc_rcv_wnd-tcp_conn->tc_mss))
0057219          {
0057220                   old_window= tcp_conn->tc_RCV_HI-tcp_conn->tc_RCV_NXT;
0057221                   tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO +
0057222                            tcp_conn->tc_rcv_wnd;
0057223                   new_window= tcp_conn->tc_RCV_HI-tcp_conn->tc_RCV_NXT;
0057224                   assert(old_window >=0 && new_window >= old_window);
0057225                   if (old_window < tcp_conn->tc_mss &&
0057226                            new_window >= tcp_conn->tc_mss)
0057227                   {
0057228                            tcp_conn->tc_flags |= TCF_SEND_ACK;
0057229                            DBLOCK(2, printf("opening window\n"));
0057230                            tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0057231                   }
0057232          }
0057233          if (tcp_conn->tc_rcvd_data == NULL &&
0057234                   tcp_conn->tc_adv_data == NULL)
0057235          {
0057236                   /* Out of data, clear PUSH flag and reply to a read. */
0057237                   tcp_conn->tc_flags &= ~TCF_RCV_PUSH;
0057238          }
0057239          if (fin_recv || urg || !tcp_fd->tf_read_count)
0057240          {
0057241                   tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset);
tcp_reply_read()




0057242                   return;
0057243          }
0057244          if (tcp_fd->tf_read_offset)
0057245          {
0057246                   tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset);
tcp_reply_read()




0057247                   return;
0057248          }
0057249 }
0057250 
0057251 /*
0057252  * $PchId: tcp_recv.c,v 1.13.2.1 2000/05/02 18:53:06 philip Exp $
0057253  */