Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

tcp-full.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 
00003 /*
00004  * Copyright (c) Intel Corporation 2001. All rights reserved.
00005  *
00006  * License is granted to copy, to use, and to make and to use derivative
00007  * works for research and evaluation purposes, provided that Intel is
00008  * acknowledged in all documentation pertaining to any such copy or 
00009  * derivative work. Intel grants no other licenses expressed or
00010  * implied. The Intel trade name should not be used in any advertising
00011  * without its written permission. 
00012  *
00013  * INTEL CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
00014  * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
00015  * FOR ANY PARTICULAR PURPOSE.  The software is provided "as is" without 
00016  * express or implied warranty of any kind.
00017  *
00018  * These notices must be retained in any copies of any part of this 
00019  * software. 
00020  */
00021 
00022 /*
00023  * Copyright (c) 1997, 1998 The Regents of the University of California.
00024  * All rights reserved.
00025  * 
00026  * Redistribution and use in source and binary forms, with or without
00027  * modification, are permitted provided that the following conditions
00028  * are met:
00029  * 1. Redistributions of source code must retain the above copyright
00030  *    notice, this list of conditions and the following disclaimer.
00031  * 2. Redistributions in binary form must reproduce the above copyright
00032  *    notice, this list of conditions and the following disclaimer in the
00033  *    documentation and/or other materials provided with the distribution.
00034  * 3. All advertising materials mentioning features or use of this software
00035  *    must display the following acknowledgement:
00036  *      This product includes software developed by the Network Research
00037  *      Group at Lawrence Berkeley National Laboratory.
00038  * 4. Neither the name of the University nor of the Laboratory may be used
00039  *    to endorse or promote products derived from this software without
00040  *    specific prior written permission.
00041  * 
00042  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00043  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00044  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00045  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00046  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00047  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00048  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00049  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00050  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00051  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00052  * SUCH DAMAGE.
00053  */
00054 
00055 /*
00056  * Full-TCP : A two-way TCP very similar to the 4.4BSD version of Reno TCP.
00057  * This version also includes variants Tahoe, NewReno, and SACK.
00058  *
00059  * This code below has received a fairly major restructuring (Aug. 2001).
00060  * The ReassemblyQueue structure is now removed to a separate module and
00061  * entirely re-written.
00062  * Also, the SACK functionality has been re-written (almost) entirely.
00063  * -KF [kfall@intel.com]
00064  *
00065  * This code below was motivated in part by code contributed by
00066  * Kathie Nichols (nichols@baynetworks.com).  The code below is based primarily
00067  * on the 4.4BSD TCP implementation. -KF [kfall@ee.lbl.gov]
00068  *
00069  * Kathie Nichols and Van Jacobson have contributed significant bug fixes,
00070  * especially with respect to the the handling of sequence numbers during
00071  * connection establishment/clearin.  Additional fixes have followed
00072  * theirs.
00073  *
00074  * Fixes for gensack() and ReassemblyQueue::add() contributed by Richard 
00075  * Mortier <Richard.Mortier@cl.cam.ac.uk>
00076  *
00077  * Some warnings and comments:
00078  *      this version of TCP will not work correctly if the sequence number
00079  *      goes above 2147483648 due to sequence number wrap
00080  *
00081  *      this version of TCP by default sends data at the beginning of a
00082  *      connection in the "typical" way... That is,
00083  *              A   ------> SYN ------> B
00084  *              A   <----- SYN+ACK ---- B
00085  *              A   ------> ACK ------> B
00086  *              A   ------> data -----> B
00087  *
00088  *      there is no dynamic receiver's advertised window.   The advertised
00089  *      window is simulated by simply telling the sender a bound on the window
00090  *      size (wnd_).
00091  *
00092  *      in real TCP, a user process performing a read (via PRU_RCVD)
00093  *              calls tcp_output each time to (possibly) send a window
00094  *              update.  Here we don't have a user process, so we simulate
00095  *              a user process always ready to consume all the receive buffer
00096  *
00097  * Notes:
00098  *      wnd_, wnd_init_, cwnd_, ssthresh_ are in segment units
00099  *      sequence and ack numbers are in byte units
00100  *
00101  * Futures:
00102  *      there are different existing TCPs with respect to how
00103  *      ack's are handled on connection startup.  Some delay
00104  *      the ack for the first segment, which can cause connections
00105  *      to take longer to start up than if we be sure to ack it quickly.
00106  *
00107  *      some TCPs arrange for immediate ACK generation if the incoming segment
00108  *      contains the PUSH bit
00109  *
00110  *
00111  */
00112 
00113 #ifndef lint
00114 static const char rcsid[] =
00115     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-full.cc,v 1.113 2002/07/24 04:34:18 tomh Exp $ (LBL)";
00116 #endif
00117 
00118 #include "ip.h"
00119 #include "tcp-full.h"
00120 #include "flags.h"
00121 #include "random.h"
00122 #include "template.h"
00123 
00124 #ifndef TRUE
00125 #define TRUE    1
00126 #endif
00127 
00128 #ifndef FALSE
00129 #define FALSE   0
00130 #endif
00131 
00132 /*
00133  * Tcl Linkage for the following:
00134  *      Agent/TCP/FullTcp, Agent/TCP/FullTcp/Tahoe,
00135  *      Agent/TCP/FullTcp/Newreno, Agent/TCP/FullTcp/Sack
00136  *
00137  * See tcl/lib/ns-default.tcl for init methods for
00138  *      Tahoe, Newreno, and Sack
00139  */
00140 
00141 static class FullTcpClass : public TclClass { 
00142 public:
00143         FullTcpClass() : TclClass("Agent/TCP/FullTcp") {}
00144         TclObject* create(int, const char*const*) { 
00145                 return (new FullTcpAgent());
00146         }
00147 } class_full;
00148 
00149 static class TahoeFullTcpClass : public TclClass { 
00150 public:
00151         TahoeFullTcpClass() : TclClass("Agent/TCP/FullTcp/Tahoe") {}
00152         TclObject* create(int, const char*const*) { 
00153                 // ns-default sets reno_fastrecov_ to false
00154                 return (new TahoeFullTcpAgent());
00155         }
00156 } class_tahoe_full;
00157 
00158 static class NewRenoFullTcpClass : public TclClass { 
00159 public:
00160         NewRenoFullTcpClass() : TclClass("Agent/TCP/FullTcp/Newreno") {}
00161         TclObject* create(int, const char*const*) { 
00162                 // ns-default sets open_cwnd_on_pack_ to false
00163                 return (new NewRenoFullTcpAgent());
00164         }
00165 } class_newreno_full;
00166 
00167 static class SackFullTcpClass : public TclClass { 
00168 public:
00169         SackFullTcpClass() : TclClass("Agent/TCP/FullTcp/Sack") {}
00170         TclObject* create(int, const char*const*) { 
00171                 // ns-default sets reno_fastrecov_ to false
00172                 // ns-default sets open_cwnd_on_pack_ to false
00173                 return (new SackFullTcpAgent());
00174         }
00175 } class_sack_full;
00176 
00177 /*
00178  * Delayed-binding variable linkage
00179  */
00180 
00181 void
00182 FullTcpAgent::delay_bind_init_all()
00183 {
00184         delay_bind_init_one("segsperack_");
00185         delay_bind_init_one("segsize_");
00186         delay_bind_init_one("tcprexmtthresh_");
00187         delay_bind_init_one("iss_");
00188         delay_bind_init_one("nodelay_");
00189         delay_bind_init_one("data_on_syn_");
00190         delay_bind_init_one("dupseg_fix_");
00191         delay_bind_init_one("dupack_reset_");
00192         delay_bind_init_one("close_on_empty_");
00193         delay_bind_init_one("signal_on_empty_");
00194         delay_bind_init_one("interval_");
00195         delay_bind_init_one("ts_option_size_");
00196         delay_bind_init_one("reno_fastrecov_");
00197         delay_bind_init_one("pipectrl_");
00198         delay_bind_init_one("open_cwnd_on_pack_");
00199         delay_bind_init_one("halfclose_");
00200         delay_bind_init_one("nopredict_");
00201         delay_bind_init_one("spa_thresh_");
00202 
00203         TcpAgent::delay_bind_init_all();
00204        
00205         reset();
00206 }
00207 
00208 int
00209 FullTcpAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
00210 {
00211         if (delay_bind(varName, localName, "segsperack_", &segs_per_ack_, tracer)) return TCL_OK;
00212         if (delay_bind(varName, localName, "segsize_", &maxseg_, tracer)) return TCL_OK;
00213         if (delay_bind(varName, localName, "tcprexmtthresh_", &tcprexmtthresh_, tracer)) return TCL_OK;
00214         if (delay_bind(varName, localName, "iss_", &iss_, tracer)) return TCL_OK;
00215         if (delay_bind(varName, localName, "spa_thresh_", &spa_thresh_, tracer)) return TCL_OK;
00216         if (delay_bind_bool(varName, localName, "nodelay_", &nodelay_, tracer)) return TCL_OK;
00217         if (delay_bind_bool(varName, localName, "data_on_syn_", &data_on_syn_, tracer)) return TCL_OK;
00218         if (delay_bind_bool(varName, localName, "dupseg_fix_", &dupseg_fix_, tracer)) return TCL_OK;
00219         if (delay_bind_bool(varName, localName, "dupack_reset_", &dupack_reset_, tracer)) return TCL_OK;
00220         if (delay_bind_bool(varName, localName, "close_on_empty_", &close_on_empty_, tracer)) return TCL_OK;
00221         if (delay_bind_bool(varName, localName, "signal_on_empty_", &signal_on_empty_, tracer)) return TCL_OK;
00222         if (delay_bind_time(varName, localName, "interval_", &delack_interval_, tracer)) return TCL_OK;
00223         if (delay_bind(varName, localName, "ts_option_size_", &ts_option_size_, tracer)) return TCL_OK;
00224         if (delay_bind_bool(varName, localName, "reno_fastrecov_", &reno_fastrecov_, tracer)) return TCL_OK;
00225         if (delay_bind_bool(varName, localName, "pipectrl_", &pipectrl_, tracer)) return TCL_OK;
00226         if (delay_bind_bool(varName, localName, "open_cwnd_on_pack_", &open_cwnd_on_pack_, tracer)) return TCL_OK;
00227         if (delay_bind_bool(varName, localName, "halfclose_", &halfclose_, tracer)) return TCL_OK;
00228         if (delay_bind_bool(varName, localName, "nopredict_", &nopredict_, tracer)) return TCL_OK;
00229 
00230         return TcpAgent::delay_bind_dispatch(varName, localName, tracer);
00231 }
00232 
00233 void
00234 SackFullTcpAgent::delay_bind_init_all()
00235 {
00236         delay_bind_init_one("clear_on_timeout_");
00237         delay_bind_init_one("sack_rtx_cthresh_");
00238         delay_bind_init_one("sack_rtx_bthresh_");
00239         delay_bind_init_one("sack_block_size_");
00240         delay_bind_init_one("sack_option_size_");
00241         delay_bind_init_one("max_sack_blocks_");
00242         delay_bind_init_one("sack_rtx_threshmode_");
00243         FullTcpAgent::delay_bind_init_all();
00244 }
00245 
00246 int
00247 SackFullTcpAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
00248 {
00249         if (delay_bind_bool(varName, localName, "clear_on_timeout_", &clear_on_timeout_, tracer)) return TCL_OK;
00250         if (delay_bind(varName, localName, "sack_rtx_cthresh_", &sack_rtx_cthresh_, tracer)) return TCL_OK;
00251         if (delay_bind(varName, localName, "sack_rtx_bthresh_", &sack_rtx_bthresh_, tracer)) return TCL_OK;
00252         if (delay_bind(varName, localName, "sack_rtx_threshmode_", &sack_rtx_threshmode_, tracer)) return TCL_OK;
00253         if (delay_bind(varName, localName, "sack_block_size_", &sack_block_size_, tracer)) return TCL_OK;
00254         if (delay_bind(varName, localName, "sack_option_size_", &sack_option_size_, tracer)) return TCL_OK;
00255         if (delay_bind(varName, localName, "max_sack_blocks_", &max_sack_blocks_, tracer)) return TCL_OK;
00256         return FullTcpAgent::delay_bind_dispatch(varName, localName, tracer);
00257 }
00258 
00259 int
00260 FullTcpAgent::command(int argc, const char*const* argv)
00261 {
00262         // would like to have some "connect" primitive
00263         // here, but the problem is that we get called before
00264         // the simulation is running and we want to send a SYN.
00265         // Because no routing exists yet, this fails.
00266         // Instead, see code in advance().
00267         //
00268         // listen can happen any time because it just changes state_
00269         //
00270         // close is designed to happen at some point after the
00271         // simulation is running (using an ns 'at' command)
00272 
00273         if (argc == 2) {
00274                 if (strcmp(argv[1], "listen") == 0) {
00275                         // just a state transition
00276                         listen();
00277                         return (TCL_OK);
00278                 }
00279                 if (strcmp(argv[1], "close") == 0) {
00280                         usrclosed();
00281                         return (TCL_OK);
00282                 }
00283         }
00284         if (argc == 3) {
00285                 if (strcmp(argv[1], "advance") == 0) {
00286                         advanceby(atoi(argv[2]));
00287                         return (TCL_OK);
00288                 }
00289                 if (strcmp(argv[1], "advanceby") == 0) {
00290                         advanceby(atoi(argv[2]));
00291                         return (TCL_OK);
00292                 }
00293                 if (strcmp(argv[1], "advance-bytes") == 0) {
00294                         advance_bytes(atoi(argv[2]));
00295                         return (TCL_OK);
00296                 }
00297         }
00298         if (argc == 4) {
00299                 if (strcmp(argv[1], "sendmsg") == 0) {
00300                         sendmsg(atoi(argv[2]), argv[3]);
00301                         return (TCL_OK);
00302                 }
00303         }
00304         return (TcpAgent::command(argc, argv));
00305 }
00306 
00307 /*
00308  * "User Interface" Functions for Full TCP
00309  *      advanceby(number of packets)
00310  *      advance_bytes(number of bytes)
00311  *      sendmsg(int bytes, char* buf)
00312  *      listen
00313  *      close
00314  */
00315 
00316 /*
00317  * the 'advance' interface to the regular tcp is in packet
00318  * units.  Here we scale this to bytes for full tcp.
00319  *
00320  * 'advance' is normally called by an "application" (i.e. data source)
00321  * to signal that there is something to send
00322  *
00323  * 'curseq_' is the sequence number of the last byte provided
00324  * by the application.  In the case where no data has been supplied
00325  * by the application, curseq_ is the iss_.
00326  */
00327 void
00328 FullTcpAgent::advanceby(int np)
00329 {
00330         // XXX hack:
00331         //      because np is in packets and a data source
00332         //      may pass a *huge* number as a way to tell us
00333         //      to go forever, just look for the huge number
00334         //      and if it's there, pre-divide it
00335         if (np >= 0x10000000)
00336                 np /= maxseg_;
00337 
00338         advance_bytes(np * maxseg_);
00339         return;
00340 }
00341 
00342 /*
00343  * the byte-oriented interface: advance_bytes(int nbytes)
00344  */
00345 
00346 void
00347 FullTcpAgent::advance_bytes(int nb)
00348 {
00349 
00350         //
00351         // state-specific operations:
00352         //      if CLOSED or LISTEN, reset and try a new active open/connect
00353         //      if ESTABLISHED, queue and try to send more
00354         //      if SYN_SENT or SYN_RCVD, just queue
00355         //      if above ESTABLISHED, we are closing, so don't allow
00356         //
00357 
00358         switch (state_) {
00359 
00360         case TCPS_CLOSED:
00361         case TCPS_LISTEN:
00362                 reset();
00363                 curseq_ = iss_ + nb;
00364                 connect();              // initiate new connection
00365                 break;
00366 
00367         case TCPS_ESTABLISHED:
00368         case TCPS_SYN_SENT:
00369         case TCPS_SYN_RECEIVED:
00370                 if (curseq_ < iss_) 
00371                         curseq_ = iss_; 
00372                 curseq_ += nb;
00373                 break;
00374 
00375         default:
00376             fprintf(stderr,
00377             "%f: FullTcpAgent::advance(%s): cannot advance while in state %s\n",
00378                  now(), name(), statestr(state_));
00379 
00380         }
00381 
00382         if (state_ == TCPS_ESTABLISHED)
00383                 send_much(0, REASON_NORMAL, maxburst_);
00384 
00385         return;
00386 }
00387 
00388 /*
00389  * If MSG_EOF is set, by setting close_on_empty_ to TRUE, we ensure that
00390  * a FIN will be sent when the send buffer emptys.
00391  * If DAT_EOF is set, the callback function done_data is called
00392  * when the send buffer empty
00393  * 
00394  * When (in the future?) FullTcpAgent implements T/TCP, avoidance of 3-way 
00395  * handshake can be handled in this function.
00396  */
00397 void
00398 FullTcpAgent::sendmsg(int nbytes, const char *flags)
00399 {
00400         if (flags && strcmp(flags, "MSG_EOF") == 0) 
00401                 close_on_empty_ = TRUE; 
00402         if (flags && strcmp(flags, "DAT_EOF") == 0) 
00403                 signal_on_empty_ = TRUE;        
00404 
00405         if (nbytes == -1) {
00406                 infinite_send_ = TRUE;
00407                 advance_bytes(0);
00408         } else
00409                 advance_bytes(nbytes);
00410 }
00411 
00412 /*
00413  * do an active open
00414  * (in real TCP, see tcp_usrreq, case PRU_CONNECT)
00415  */
00416 void
00417 FullTcpAgent::connect()
00418 {
00419         newstate(TCPS_SYN_SENT);        // sending a SYN now
00420         sent(iss_, foutput(iss_, REASON_NORMAL));
00421         return;
00422 }
00423 
00424 /*
00425  * be a passive opener
00426  * (in real TCP, see tcp_usrreq, case PRU_LISTEN)
00427  * (for simulation, make this peer's ptype ACKs)
00428  */
00429 void
00430 FullTcpAgent::listen()
00431 {
00432         newstate(TCPS_LISTEN);
00433         type_ = PT_ACK; // instead of PT_TCP
00434 }
00435 
00436 
00437 /*
00438 * This function is invoked when the sender buffer is empty. It in turn
00439 * invokes the Tcl done_data procedure that was registered with TCP.
00440 */
00441  
00442 void
00443 FullTcpAgent::bufferempty()
00444 {
00445         signal_on_empty_=FALSE;
00446         Tcl::instance().evalf("%s done_data", this->name());
00447 }
00448 
00449 
00450 /*
00451  * called when user/application performs 'close'
00452  */
00453 
00454 void
00455 FullTcpAgent::usrclosed()
00456 {
00457         curseq_ = maxseq_ - 1;  // now, no more data
00458         infinite_send_ = FALSE; // stop infinite send
00459 
00460         switch (state_) {
00461         case TCPS_CLOSED:
00462         case TCPS_LISTEN:
00463                 cancel_timers();
00464                 newstate(TCPS_CLOSED);
00465                 finish();
00466                 break;
00467         case TCPS_SYN_SENT:
00468                 newstate(TCPS_CLOSED);
00469                 /* fall through */
00470         case TCPS_LAST_ACK:
00471                 flags_ |= TF_NEEDFIN;
00472                 send_much(1, REASON_NORMAL, maxburst_);
00473                 break;
00474         case TCPS_SYN_RECEIVED:
00475         case TCPS_ESTABLISHED:
00476                 newstate(TCPS_FIN_WAIT_1);
00477                 flags_ |= TF_NEEDFIN;
00478                 send_much(1, REASON_NORMAL, maxburst_);
00479                 break;
00480         case TCPS_CLOSE_WAIT:
00481                 newstate(TCPS_LAST_ACK);
00482                 flags_ |= TF_NEEDFIN;
00483                 send_much(1, REASON_NORMAL, maxburst_);
00484                 break;
00485         case TCPS_FIN_WAIT_1:
00486         case TCPS_FIN_WAIT_2:
00487         case TCPS_CLOSING:
00488                 /* usr asked for a close more than once [?] */
00489                 fprintf(stderr,
00490                   "%f FullTcpAgent(%s): app close in bad state %s\n",
00491                   now(), name(), statestr(state_));
00492                 break;
00493         default:
00494                 fprintf(stderr,
00495                   "%f FullTcpAgent(%s): app close in unknown state %s\n",
00496                   now(), name(), statestr(state_));
00497         }
00498 
00499         return;
00500 }
00501 
00502 /*
00503  * Utility type functions
00504  */
00505 
00506 void
00507 FullTcpAgent::cancel_timers()
00508 {
00509 
00510         // cancel: rtx, burstsend, delsnd
00511         TcpAgent::cancel_timers();      
00512         // cancel: delack
00513         delack_timer_.force_cancel();
00514 }
00515 
00516 void
00517 FullTcpAgent::newstate(int state)
00518 {
00519 //printf("%f(%s): state changed from %s to %s\n",
00520 //now(), name(), statestr(state_), statestr(state));
00521 
00522         state_ = state;
00523 }
00524 
00525 void
00526 FullTcpAgent::prpkt(Packet *pkt)
00527 {
00528         hdr_tcp *tcph = hdr_tcp::access(pkt);   // TCP header
00529         hdr_cmn *th = hdr_cmn::access(pkt);     // common header (size, etc)
00530         //hdr_flags *fh = hdr_flags::access(pkt);       // flags (CWR, CE, bits)
00531         hdr_ip* iph = hdr_ip::access(pkt);
00532         int datalen = th->size() - tcph->hlen(); // # payload bytes
00533 
00534         fprintf(stdout, " [%d:%d.%d>%d.%d] (hlen:%d, dlen:%d, seq:%d, ack:%d, flags:0x%x (%s), salen:%d, reason:0x%x)\n",
00535                 th->uid(),
00536                 iph->saddr(), iph->sport(),
00537                 iph->daddr(), iph->dport(),
00538                 tcph->hlen(),
00539                 datalen,
00540                 tcph->seqno(),
00541                 tcph->ackno(),
00542                 tcph->flags(), flagstr(tcph->flags()),
00543                 tcph->sa_length(),
00544                 tcph->reason());
00545 }
00546 
00547 char *
00548 FullTcpAgent::flagstr(int hflags)
00549 {
00550         // update this if tcp header flags change
00551         static char *flagstrs[28] = {
00552                 "<null>", "<FIN>", "<SYN>", "<SYN,FIN>",        // 0-3
00553                 "<?>", "<?,FIN>", "<?,SYN>", "<?,SYN,FIN>",     // 4-7
00554                 "<PSH>", "<PSH,FIN>", "<PSH,SYN>", "<PSH,SYN,FIN>", // 0x08-0x0b
00555                 /* do not use <??, in next line because that's an ANSI trigraph */
00556                 "<?>", "<?,FIN>", "<?,SYN>", "<?,SYN,FIN>",         // 0x0c-0x0f
00557                 "<ACK>", "<ACK,FIN>", "<ACK,SYN>", "<ACK,SYN,FIN>", // 0x10-0x13
00558                 "<ACK>", "<ACK,FIN>", "<ACK,SYN>", "<ACK,SYN,FIN>", // 0x14-0x17
00559                 "<PSH,ACK>", "<PSH,ACK,FIN>", "<PSH,ACK,SYN>", "<PSH,ACK,SYN,FIN>", // 0x18-0x1b
00560         };
00561         if (hflags < 0 || (hflags > 28))
00562                 return ("<invalid>");
00563         return (flagstrs[hflags]);
00564 }
00565 
00566 char *
00567 FullTcpAgent::statestr(int state)
00568 {
00569         static char *statestrs[TCP_NSTATES] = {
00570                 "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD",
00571                 "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING",
00572                 "LAST_ACK", "FIN_WAIT_2"
00573         };
00574         if (state < 0 || (state >= TCP_NSTATES))
00575                 return ("INVALID");
00576         return (statestrs[state]);
00577 }
00578 
00579 void
00580 DelAckTimer::expire(Event *) {
00581         a_->timeout(TCP_TIMER_DELACK);
00582 }
00583 
00584 /*
00585  * reset to starting point, don't set state_ here,
00586  * because our starting point might be LISTEN rather
00587  * than CLOSED if we're a passive opener
00588  */
00589 void
00590 FullTcpAgent::reset()
00591 {
00592         cancel_timers();        // cancel timers first
00593         TcpAgent::reset();      // resets most variables
00594         rq_.clear();            // clear reassembly queue
00595         rtt_init();             // zero rtt, srtt, backoff
00596 
00597         last_ack_sent_ = -1;
00598         rcv_nxt_ = -1;
00599         pipe_ = 0;
00600         rtxbytes_ = 0;
00601         flags_ = 0;
00602         t_seqno_ = iss_;
00603         maxseq_ = -1;
00604         irs_ = -1;
00605         last_send_time_ = -1.0;
00606         if (ts_option_)
00607                 recent_ = recent_age_ = 0.0;
00608         else
00609                 recent_ = recent_age_ = -1.0;
00610 
00611         fastrecov_ = FALSE;
00612 }
00613 
00614 /*
00615  * This function is invoked when the connection is done. It in turn
00616  * invokes the Tcl finish procedure that was registered with TCP.
00617  * This function mimics tcp_close()
00618  */
00619 
00620 void
00621 FullTcpAgent::finish()
00622 {
00623         Tcl::instance().evalf("%s done", this->name());
00624 }
00625 /*
00626  * headersize:
00627  *      how big is an IP+TCP header in bytes; include options such as ts
00628  * this function should be virtual so others (e.g. SACK) can override
00629  */
00630 int
00631 FullTcpAgent::headersize()
00632 {
00633         int total = tcpip_base_hdr_size_;
00634         if (total < 1) {
00635                 fprintf(stderr,
00636                     "%f: FullTcpAgent(%s): warning: tcpip hdr size is only %d bytes\n",
00637                         now(), name(), tcpip_base_hdr_size_);
00638         }
00639 
00640         if (ts_option_)
00641                 total += ts_option_size_;
00642 
00643         return (total);
00644 }
00645 
00646 /*
00647  * flags that are completely dependent on the tcp state
00648  * these are used for the next outgoing packet in foutput()
00649  * (in real TCP, see tcp_fsm.h, the "tcp_outflags" array)
00650  */
00651 int
00652 FullTcpAgent::outflags()
00653 {
00654         // in real TCP an RST is added in the CLOSED state
00655         static int tcp_outflags[TCP_NSTATES] = {
00656                 TH_ACK,                 /* 0, CLOSED */  
00657                 0,                      /* 1, LISTEN */ 
00658                 TH_SYN,                 /* 2, SYN_SENT */
00659                 TH_SYN|TH_ACK,          /* 3, SYN_RECEIVED */
00660                 TH_ACK,                 /* 4, ESTABLISHED */
00661                 TH_ACK,                 /* 5, CLOSE_WAIT */
00662                 TH_FIN|TH_ACK,          /* 6, FIN_WAIT_1 */
00663                 TH_FIN|TH_ACK,          /* 7, CLOSING */
00664                 TH_FIN|TH_ACK,          /* 8, LAST_ACK */
00665                 TH_ACK,                 /* 9, FIN_WAIT_2 */
00666                 /* 10, TIME_WAIT --- not used in simulator */
00667         };
00668 
00669         if (state_ < 0 || (state_ >= TCP_NSTATES)) {
00670                 fprintf(stderr, "%f FullTcpAgent(%s): invalid state %d\n",
00671                         now(), name(), state_);
00672                 return (0x0);
00673         }
00674 
00675         return (tcp_outflags[state_]);
00676 }
00677 
00678 /*
00679  * reaass() -- extract the appropriate fields from the packet
00680  *      and pass this info the ReassemblyQueue add routine
00681  *
00682  * returns the TCP header flags representing the "or" of
00683  *      the flags contained in the adjacent sequence # blocks
00684  */
00685 
00686 int
00687 FullTcpAgent::reass(Packet* pkt)
00688 {  
00689         hdr_tcp *tcph =  hdr_tcp::access(pkt);
00690         hdr_cmn *th = hdr_cmn::access(pkt);
00691    
00692         int start = tcph->seqno();
00693         int end = start + th->size() - tcph->hlen();
00694         int tiflags = tcph->flags();
00695         int fillshole = (start == rcv_nxt_);
00696         int flags;
00697    
00698         // end contains the seq of the last byte of
00699         // in the packet plus one
00700 
00701         if (start == end && (tiflags & TH_FIN) == 0) {
00702                 fprintf(stderr, "%f: FullTcpAgent(%s)::reass() -- bad condition - adding non-FIN zero-len seg\n",
00703                         now(), name());
00704                 abort();
00705         }
00706 
00707         flags = rq_.add(start, end, tiflags, 0);
00708 
00709         //present:
00710         //
00711         // If we've never received a SYN (unlikely)
00712         // or this is an out of order addition, no reason to coalesce
00713         //
00714 
00715         if (TCPS_HAVERCVDSYN(state_) == 0 || !fillshole) {
00716                 return (0x00);
00717         }
00718         //
00719         // If we get some data in SYN_RECVD, no need to present to user yet
00720         //
00721         if (state_ == TCPS_SYN_RECEIVED && (end > start))
00722                 return (0x00);
00723 
00724         // clear out data that has been passed, up to rcv_nxt_,
00725         // collects flags
00726 
00727         flags |= rq_.cleartonxt();
00728 
00729         return (flags);
00730 }
00731 
00732 /*
00733  * utility function to set rcv_next_ during inital exchange of seq #s
00734  */
00735 
00736 int
00737 FullTcpAgent::rcvseqinit(int seq, int dlen)
00738 {
00739         return (seq + dlen + 1);
00740 }
00741 
00742 /*
00743  * build a header with the timestamp option if asked
00744  */
00745 int
00746 FullTcpAgent::build_options(hdr_tcp* tcph)
00747 {
00748         int total = 0;
00749         if (ts_option_) {
00750                 tcph->ts() = now();
00751                 tcph->ts_echo() = recent_;
00752                 total += ts_option_size_;
00753         } else {
00754                 tcph->ts() = tcph->ts_echo() = -1.0;
00755         }
00756         return (total);
00757 }
00758 
00759 /*
00760  * pack() -- is the ACK a partial ACK? (not past recover_)
00761  */
00762 
00763 int
00764 FullTcpAgent::pack(Packet *pkt)
00765 {
00766         hdr_tcp *tcph = hdr_tcp::access(pkt);
00767         return (tcph->ackno() >= highest_ack_ &&
00768                 tcph->ackno() < recover_);
00769 }
00770 
00771 /*
00772  * baseline reno TCP exists fast recovery on a partial ACK
00773  */
00774 
00775 void
00776 FullTcpAgent::pack_action(Packet*)
00777 {
00778         if (reno_fastrecov_ && fastrecov_ && cwnd_ > double(ssthresh_)) {
00779                 cwnd_ = double(ssthresh_); // retract window if inflated
00780         }
00781         fastrecov_ = FALSE;
00782 //printf("%f: EXITED FAST RECOVERY\n", now());
00783         dupacks_ = 0;
00784 }
00785 
00786 /*
00787  * ack_action -- same as partial ACK action for base Reno TCP
00788  */
00789 
00790 void
00791 FullTcpAgent::ack_action(Packet* p)
00792 {
00793         FullTcpAgent::pack_action(p);
00794 }
00795 
00796 
00797 /*
00798  * sendpacket: 
00799  *      allocate a packet, fill in header fields, and send
00800  *      also keeps stats on # of data pkts, acks, re-xmits, etc
00801  *
00802  * fill in packet fields.  Agent::allocpkt() fills
00803  * in most of the network layer fields for us.
00804  * So fill in tcp hdr and adjust the packet size.
00805  *
00806  * Also, set the size of the tcp header.
00807  */
00808 void
00809 FullTcpAgent::sendpacket(int seqno, int ackno, int pflags, int datalen, int reason)
00810 {
00811         Packet* p = allocpkt();
00812         hdr_tcp *tcph = hdr_tcp::access(p);
00813         hdr_flags *fh = hdr_flags::access(p);
00814 
00815         /* build basic header w/options */
00816 
00817         tcph->seqno() = seqno;
00818         tcph->ackno() = ackno;
00819         tcph->flags() = pflags;
00820         tcph->reason() |= reason; // make tcph->reason look like ns1 pkt->flags?
00821         tcph->sa_length() = 0;    // may be increased by build_options()
00822         tcph->hlen() = tcpip_base_hdr_size_;
00823         tcph->hlen() += build_options(tcph);
00824 
00825         /*
00826          * Explicit Congestion Notification (ECN) related:
00827          * Bits in header:
00828          *      ECT (EC Capable Transport),
00829          *      ECNECHO (ECHO of ECN Notification generated at router),
00830          *      CWR (Congestion Window Reduced from RFC 2481)
00831          * States in TCP:
00832          *      ecn_: I am supposed to do ECN if my peer does
00833          *      ect_: I am doing ECN (ecn_ should be T and peer does ECN)
00834          */
00835 
00836         // set ect on data packets (not syn or ack packets)
00837         if ( datalen > 0 && ecn_ ){
00838                 fh->ect() = ect_;       // on after mutual agreement on ECT
00839         }
00840 
00841         // fill in CWR and ECE bits which don't actually sit in
00842         // the tcp_flags but in hdr_flags
00843         if ( pflags & TH_ECE) {
00844                 fh->ecnecho() = 1;
00845         } else {
00846                 fh->ecnecho() = 0;
00847         }
00848         if ( pflags & TH_CWR ) {
00849                 fh->cong_action() = 1;
00850         }
00851 
00852         //
00853         // although CWR bit is ordinarily associated with ECN,
00854         // it utility within the simulator for traces.  Thus, set
00855         // it even if we aren't doing ECN
00856         //
00857         if ( datalen > 0 )
00858                 fh->cwr() =  cong_action_;
00859 
00860         /* actual size is data length plus header length */
00861 
00862         hdr_cmn *ch = hdr_cmn::access(p);
00863         ch->size() = datalen + tcph->hlen();
00864 
00865         if (datalen <= 0)
00866                 ++nackpack_;
00867         else {
00868                 ++ndatapack_;
00869                 ndatabytes_ += datalen;
00870                 last_send_time_ = now();        // time of last data
00871         }
00872         if (reason == REASON_TIMEOUT || reason == REASON_DUPACK || reason == REASON_SACK) {
00873                 ++nrexmitpack_;
00874                 nrexmitbytes_ += datalen;
00875         }
00876 
00877         last_ack_sent_ = ackno;
00878 
00879 //if (state_ != TCPS_ESTABLISHED) {
00880 //printf("%f(%s)[state:%s]: sending pkt ", now(), name(), statestr(state_));
00881 //prpkt(p);
00882 //}
00883 
00884         send(p, 0);
00885 
00886         return;
00887 }
00888 
00889 //
00890 // reset_rtx_timer: called during a retransmission timeout
00891 // to perform exponential backoff.  Also, note that because
00892 // we have performed a retransmission, our rtt timer is now
00893 // invalidated (indicate this by setting rtt_active_ false)
00894 //
00895 void
00896 FullTcpAgent::reset_rtx_timer(int /* mild */)
00897 {
00898         // cancel old timer, set a new one
00899         /* if there is no outstanding data, don't back off rtx timer *
00900          * (Fix from T. Kelly.) */
00901         if (!(highest_ack_ == maxseq_ && restart_bugfix_)) {
00902                 rtt_backoff();          // double current timeout
00903         }
00904         set_rtx_timer();        // set new timer
00905         rtt_active_ = FALSE;    // no timing during this window
00906 }
00907 
00908 /*
00909  * see if we should send a segment, and if so, send it
00910  *      (may be ACK or data)
00911  * return the number of data bytes sent (count a SYN or FIN as 1 each)
00912  *
00913  * simulator var, desc (name in real TCP)
00914  * --------------------------------------
00915  * maxseq_, largest seq# we've sent plus one (snd_max)
00916  * flags_, flags regarding our internal state (t_state)
00917  * pflags, a local used to build up the tcp header flags (flags)
00918  * curseq_, is the highest sequence number given to us by "application"
00919  * highest_ack_, the highest ACK we've seen for our data (snd_una-1)
00920  * seqno, the next seq# we're going to send (snd_nxt)
00921  */
00922 int
00923 FullTcpAgent::foutput(int seqno, int reason)
00924 {
00925         // if maxseg_ not set, set it appropriately
00926         // Q: how can this happen?
00927 
00928         if (maxseg_ == 0) 
00929                 maxseg_ = size_ - headersize();
00930         else
00931                 size_ =  maxseg_ + headersize();
00932 
00933         int is_retransmit = (seqno < maxseq_);
00934         int quiet = (highest_ack_ == maxseq_);
00935         int pflags = outflags();
00936         int syn = (seqno == iss_);
00937         int emptying_buffer = FALSE;
00938         int buffered_bytes = (infinite_send_) ? TCP_MAXSEQ :
00939                                 curseq_ - highest_ack_ + 1;
00940 
00941         int win = window() * maxseg_;   // window (in bytes)
00942         int off = seqno - highest_ack_; // offset of seg in window
00943         int datalen;
00944         //int amtsent = 0;
00945 
00946         // be careful if we have not received any ACK yet
00947         if (highest_ack_ < 0) {
00948                 if (!infinite_send_)
00949                         buffered_bytes = curseq_ - iss_;;
00950                 off = seqno - iss_;
00951         }
00952 
00953         if (syn && !data_on_syn_)
00954                 datalen = 0;
00955         else if (pipectrl_)
00956                 datalen = buffered_bytes - off;
00957         else
00958                 datalen = min(buffered_bytes, win) - off;
00959 
00960         if ((signal_on_empty_) && (!buffered_bytes) && (!syn))
00961                         bufferempty();
00962 
00963         //
00964         // in real TCP datalen (len) could be < 0 if there was window
00965         // shrinkage, or if a FIN has been sent and neither ACKd nor
00966         // retransmitted.  Only this 2nd case concerns us here...
00967         //
00968         if (datalen < 0) {
00969                 datalen = 0;
00970         } else if (datalen > maxseg_) {
00971                 datalen = maxseg_;
00972         }
00973 
00974 
00975         //
00976         // this is an option that causes us to slow-start if we've
00977         // been idle for a "long" time, where long means a rto or longer
00978         // the slow-start is a sort that does not set ssthresh
00979         //
00980 
00981         if (slow_start_restart_ && quiet && datalen > 0) {
00982                 if (idle_restart()) {
00983                         slowdown(CLOSE_CWND_INIT);
00984                 }
00985         }
00986 
00987         //
00988         // see if sending this packet will empty the send buffer
00989         // a dataless SYN packet counts also
00990         //
00991 
00992         if (!infinite_send_ && ((seqno + datalen) > curseq_ || 
00993             (syn && datalen == 0))) {
00994                 emptying_buffer = TRUE;
00995                 //
00996                 // if not a retransmission, notify application that 
00997                 // everything has been sent out at least once.
00998                 //
00999                 if (!syn) {
01000                         idle();
01001                         if (close_on_empty_ && quiet) {
01002                                 flags_ |= TF_NEEDCLOSE;
01003                         }
01004                 }
01005                 pflags |= TH_PUSH;
01006                 //
01007                 // if close_on_empty set, we are finished
01008                 // with this connection; close it
01009                 //
01010         } else  {
01011                 /* not emptying buffer, so can't be FIN */
01012                 pflags &= ~TH_FIN;
01013         }
01014         if (infinite_send_ && (syn && datalen == 0))
01015                 pflags |= TH_PUSH;  // set PUSH for dataless SYN
01016 
01017         /* sender SWS avoidance (Nagle) */
01018 
01019         if (datalen > 0) {
01020                 // if full-sized segment, ok
01021                 if (datalen == maxseg_)
01022                         goto send;
01023                 // if Nagle disabled and buffer clearing, ok
01024                 if ((quiet || nodelay_)  && emptying_buffer)
01025                         goto send;
01026                 // if a retransmission
01027                 if (is_retransmit)
01028                         goto send;
01029                 // if big "enough", ok...
01030                 //      (this is not a likely case, and would
01031                 //      only happen for tiny windows)
01032                 if (datalen >= ((wnd_ * maxseg_) / 2.0))
01033                         goto send;
01034         }
01035 
01036         if (need_send())
01037                 goto send;
01038 
01039         /*
01040          * send now if a control packet or we owe peer an ACK
01041          * TF_ACKNOW can be set during connection establishment and
01042          * to generate acks for out-of-order data
01043          */
01044 
01045         if ((flags_ & (TF_ACKNOW|TF_NEEDCLOSE)) ||
01046             (pflags & (TH_SYN|TH_FIN))) {
01047                 goto send;
01048         }
01049 
01050         /*      
01051          * No reason to send a segment, just return.
01052          */      
01053         return 0;
01054 
01055 send:
01056 
01057         // is a syn or fin?
01058 
01059         syn = (pflags & TH_SYN) ? 1 : 0;
01060         int fin = (pflags & TH_FIN) ? 1 : 0;
01061 
01062         /* setup ECN syn and ECN SYN+ACK packet headers */
01063         if (ecn_ && syn && !(pflags & TH_ACK)){
01064                 pflags |= TH_ECE;
01065                 pflags |= TH_CWR;
01066         }
01067         if (ecn_ && syn && (pflags & TH_ACK)){
01068                 pflags |= TH_ECE;
01069                 pflags &= ~TH_CWR;
01070         }
01071   
01072         /* set CWR if necessary */
01073         if (ecn_ && ect_ && cong_action_) pflags |= TH_CWR;
01074   
01075         /* set ECE if necessary */
01076         if (ecn_ && ect_ && recent_ce_ ) pflags |= TH_ECE;
01077 
01078         /* 
01079          * Tack on the FIN flag to the data segment if close_on_empty_
01080          * was previously set-- avoids sending a separate FIN
01081          */ 
01082         if (flags_ & TF_NEEDCLOSE) {
01083                 flags_ &= ~TF_NEEDCLOSE;
01084                 if (state_ <= TCPS_ESTABLISHED && state_ != TCPS_CLOSED)
01085                 {
01086                     pflags |=TH_FIN;
01087                     fin = 1;  /* FIN consumes sequence number */
01088                     newstate(TCPS_FIN_WAIT_1);
01089                 }
01090         }
01091         sendpacket(seqno, rcv_nxt_, pflags, datalen, reason);
01092 
01093         /*      
01094          * Data sent (as far as we can tell).
01095          * Any pending ACK has now been sent.
01096          */      
01097         flags_ &= ~(TF_ACKNOW|TF_DELACK);
01098 
01099         /*
01100          * if we have reacted to congestion recently, the
01101          * slowdown() procedure will have set cong_action_ and
01102          * sendpacket will have copied that to the outgoing pkt
01103          * CWR field. If that packet contains data, then
01104          * it will be reliably delivered, so we are free to turn off the
01105          * cong_action_ state now  If only a pure ACK, we keep the state
01106          * around until we actually send a segment
01107          */
01108 
01109         int reliable = datalen + syn + fin; // seq #'s reliably sent
01110         if (cong_action_ && reliable > 0)
01111                 cong_action_ = FALSE;
01112 
01113         // highest: greatest sequence number sent + 1
01114         //      and adjusted for SYNs and FINs which use up one number
01115 
01116         int highest = seqno + reliable;
01117         if (highest > maxseq_) {
01118                 maxseq_ = highest;
01119                 //
01120                 // if we are using conventional RTT estimation,
01121                 // establish timing on this segment
01122                 //
01123                 if (!ts_option_ && rtt_active_ == FALSE) {
01124                         rtt_active_ = TRUE;     // set timer
01125                         rtt_seq_ = seqno;       // timed seq #
01126                         rtt_ts_ = now();        // when set
01127                 }
01128         }
01129 
01130         /*
01131          * Set retransmit timer if not currently set,
01132          * and not doing an ack or a keep-alive probe.
01133          * Initial value for retransmit timer is smoothed
01134          * round-trip time + 2 * round-trip time variance.
01135          * Future values are rtt + 4 * rttvar.
01136          */
01137         if (rtx_timer_.status() != TIMER_PENDING && reliable) {
01138                 set_rtx_timer();  // no timer pending, schedule one
01139         }
01140 
01141         return (reliable);
01142 }
01143 
01144 /*
01145  *
01146  * send_much: send as much data as we are allowed to.  This is
01147  * controlled by the "pipectrl_" variable.  If pipectrl_ is set
01148  * to FALSE, then we are working as a normal window-based TCP and
01149  * we are allowed to send whatever the window allows.
01150  * If pipectrl_ is set to TRUE, then we are allowed to send whatever
01151  * pipe_ allows us to send.  One tricky part is to make sure we
01152  * do not overshoot the receiver's advertised window if we are
01153  * in (pipectrl_ == TRUE) mode.
01154  */
01155   
01156 void
01157 FullTcpAgent::send_much(int force, int reason, int maxburst)
01158 {
01159         int npackets = 0;       // sent so far
01160 
01161 //if ((int(t_seqno_)) > 1)
01162 //printf("%f: send_much(f:%d, win:%d, pipectrl:%d, pipe:%d, t_seqno:%d, topwin:%d, maxseq_:%d\n",
01163 //now(), force, win, pipectrl_, pipe_, int(t_seqno_), topwin, int(maxseq_));
01164 
01165         if (!force && (delsnd_timer_.status() == TIMER_PENDING))
01166                 return;
01167 
01168         while (1) {
01169 
01170                 /*
01171                  * note that if output decides to not actually send
01172                  * (e.g. because of Nagle), then if we don't break out
01173                  * of this loop, we can loop forever at the same
01174                  * simulated time instant
01175                  */
01176                 int amt;
01177                 int seq = nxt_tseq();
01178                 if (!force && !send_allowed(seq))
01179                         break;
01180                 // Q: does this need to be here too?
01181                 if (!force && overhead_ != 0 &&
01182                     (delsnd_timer_.status() != TIMER_PENDING)) {
01183                         delsnd_timer_.resched(Random::uniform(overhead_));
01184                         return;
01185                 }
01186                 if ((amt = foutput(seq, reason)) <= 0)
01187                         break;
01188                 if ((outflags() & TH_FIN))
01189                         --amt;  // don't count FINs
01190                 sent(seq, amt);
01191                 force = 0;
01192 
01193                 if ((outflags() & (TH_SYN|TH_FIN)) ||
01194                     (maxburst && ++npackets >= maxburst))
01195                         break;
01196         }
01197         return;
01198 }
01199 
01200 /*
01201  * base TCP: we are allowed to send a sequence number if it
01202  * is in the window
01203  */
01204 int
01205 FullTcpAgent::send_allowed(int seq)
01206 {
01207         int win = window() * maxseg_;
01208         int topwin = curseq_; // 1 seq number past the last byte we can send
01209 
01210         if ((topwin > highest_ack_ + win) || infinite_send_)
01211                 topwin = highest_ack_ + win; 
01212 
01213         return (seq < topwin);
01214 }
01215 /*
01216  * Process an ACK
01217  *      this version of the routine doesn't necessarily
01218  *      require the ack to be one which advances the ack number
01219  *
01220  * if this ACKs a rtt estimate
01221  *      indicate we are not timing
01222  *      reset the exponential timer backoff (gamma)
01223  * update rtt estimate
01224  * cancel retrans timer if everything is sent and ACK'd, else set it
01225  * advance the ack number if appropriate
01226  * update segment to send next if appropriate
01227  */
01228 void
01229 FullTcpAgent::newack(Packet* pkt)
01230 {
01231         hdr_tcp *tcph = hdr_tcp::access(pkt);
01232 
01233         register int ackno = tcph->ackno();
01234         int progress = (ackno > highest_ack_);
01235 
01236         if (ackno == maxseq_) {
01237                 cancel_rtx_timer();     // all data ACKd
01238         } else if (progress) {
01239                 set_rtx_timer();
01240         }
01241 
01242         // advance the ack number if this is for new data
01243         if (progress)
01244                 highest_ack_ = ackno;
01245 
01246         // if we have suffered a retransmit timeout, t_seqno_
01247         // will have been reset to highest_ ack.  If the
01248         // receiver has cached some data above t_seqno_, the
01249         // new-ack value could (should) jump forward.  We must
01250         // update t_seqno_ here, otherwise we would be doing
01251         // go-back-n.
01252 
01253         if (t_seqno_ < highest_ack_)
01254                 t_seqno_ = highest_ack_; // seq# to send next
01255 
01256         /*
01257          * Update RTT only if it's OK to do so from info in the flags header.
01258          * This is needed for protocols in which intermediate agents
01259          * in the network intersperse acks (e.g., ack-reconstructors) for
01260          * various reasons (without violating e2e semantics).
01261          */
01262         hdr_flags *fh = hdr_flags::access(pkt);
01263 
01264         if (!fh->no_ts_) {
01265                 if (ts_option_) {
01266                         recent_age_ = now();
01267                         recent_ = tcph->ts();
01268                         rtt_update(now() - tcph->ts_echo());
01269                 } else if (rtt_active_ && ackno > rtt_seq_) {
01270                         // got an RTT sample, record it
01271                         // "t_backoff_ = 1;" deleted by T. Kelly.
01272                         rtt_active_ = FALSE;
01273                         rtt_update(now() - rtt_ts_);
01274                 }
01275 
01276                 if (!ect_ || !ecn_backoff_ ||
01277                     !hdr_flags::access(pkt)->ecnecho()) {
01278                         /*
01279                          * Don't end backoff if still in ECN-Echo with
01280                          * a congestion window of 1 packet.
01281                          * Fix from T. Kelly.
01282                          */
01283                         t_backoff_ = 1;
01284                         ecn_backoff_ = 0;
01285                 }
01286         }
01287         return;
01288 }
01289 
01290 /*
01291  * this is the simulated form of the header prediction
01292  * predicate.  While not really necessary for a simulation, it
01293  * follows the code base more closely and can sometimes help to reveal
01294  * odd behavior caused by the implementation structure..
01295  *
01296  * Here's the comment from the real TCP:
01297  *
01298  * Header prediction: check for the two common cases
01299  * of a uni-directional data xfer.  If the packet has
01300  * no control flags, is in-sequence, the window didn't
01301  * change and we're not retransmitting, it's a
01302  * candidate.  If the length is zero and the ack moved
01303  * forward, we're the sender side of the xfer.  Just
01304  * free the data acked & wake any higher level process
01305  * that was blocked waiting for space.  If the length
01306  * is non-zero and the ack didn't move, we're the
01307  * receiver side.  If we're getting packets in-order
01308  * (the reassembly queue is empty), add the data to
01309  * the socket buffer and note that we need a delayed ack.
01310  * Make sure that the hidden state-flags are also off.
01311  * Since we check for TCPS_ESTABLISHED above, it can only
01312  * be TF_NEEDSYN.
01313  */
01314 
01315 int
01316 FullTcpAgent::predict_ok(Packet* pkt)
01317 {
01318         hdr_tcp *tcph = hdr_tcp::access(pkt);
01319         hdr_flags *fh = hdr_flags::access(pkt);
01320 
01321         /* not the fastest way to do this, but perhaps clearest */
01322 
01323         int p1 = (state_ == TCPS_ESTABLISHED);          // ready
01324         int p2 = ((tcph->flags() & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK); // ACK
01325         int p3 = ((flags_ & TF_NEEDFIN) == 0);          // don't need fin
01326         int p4 = (!ts_option_ || fh->no_ts_ || (tcph->ts() >= recent_)); // tsok
01327         int p5 = (tcph->seqno() == rcv_nxt_);           // in-order data
01328         int p6 = (t_seqno_ == maxseq_);                 // not re-xmit
01329         int p7 = (!ecn_ || fh->ecnecho() == 0);         // no ECN
01330         int p8 = (tcph->sa_length() == 0);              // no SACK info
01331 
01332         return (p1 && p2 && p3 && p4 && p5 && p6 && p7 && p8);
01333 }
01334 
01335 /*
01336  * fast_retransmit using the given seqno
01337  *      perform fast RTX, set recover_, set last_cwnd_action
01338  */
01339 
01340 int
01341 FullTcpAgent::fast_retransmit(int seq)
01342 {
01343         // we are now going to fast-retransmit and willtrace that event
01344         trace_event("FAST_RETX");
01345         
01346         recover_ = maxseq_;     // recovery target
01347         last_cwnd_action_ = CWND_ACTION_DUPACK;
01348         return(foutput(seq, REASON_DUPACK));    // send one pkt
01349 }
01350 
01351 /*
01352  * real tcp determines if the remote
01353  * side should receive a window update/ACK from us, and often
01354  * results in sending an update every 2 segments, thereby
01355  * giving the familiar 2-packets-per-ack behavior of TCP.
01356  * Here, we don't advertise any windows, so we just see if
01357  * there's at least 'segs_per_ack_' pkts not yet acked
01358  *
01359  * also, provide for a segs-per-ack "threshold" where
01360  * we generate 1-ack-per-seg until enough stuff
01361  * (spa_thresh_ bytes) has been received from the other side
01362  * This idea came from vj/kmn in BayTcp.  Added 8/21/01.
01363  */
01364 
01365 int
01366 FullTcpAgent::need_send()
01367 {
01368         if (flags_ & TF_ACKNOW)
01369                 return TRUE;
01370 
01371         int spa = (spa_thresh_ > 0 && ((rcv_nxt_ - irs_)  < spa_thresh_)) ?
01372                 1 : segs_per_ack_;
01373                 
01374         return ((rcv_nxt_ - last_ack_sent_) >= (spa * maxseg_));
01375 }
01376 
01377 /*
01378  * determine whether enough time has elapsed in order to
01379  * conclude a "restart" is necessary (e.g. a slow-start)
01380  *
01381  * for now, keep track of this similarly to how rtt_update() does
01382  */
01383 
01384 int
01385 FullTcpAgent::idle_restart()
01386 {
01387         if (last_send_time_ < 0.0) {
01388                 // last_send_time_ isn't set up yet, we shouldn't
01389                 // do the idle_restart
01390                 return (0);
01391         }
01392 
01393         double tao = now() - last_send_time_;
01394         if (!ts_option_) {
01395                 double tickoff = fmod(last_send_time_ + boot_time_,
01396                         tcp_tick_);
01397                 tao = int((tao + tickoff) / tcp_tick_) * tcp_tick_;
01398         }
01399 
01400         return (tao > t_rtxcur_);  // verify this CHECKME
01401 }
01402 
01403 /*
01404  * tcp-full's version of set_initial_window()... over-rides
01405  * the one in tcp.cc
01406  */
01407 void
01408 FullTcpAgent::set_initial_window()
01409 {
01410         syn_ = TRUE;    // full-tcp always models SYN exchange
01411         TcpAgent::set_initial_window();
01412 }       
01413 
01414 /*
01415  * main reception path - 
01416  * called from the agent that handles the data path below in its muxing mode
01417  * advance() is called when connection is established with size sent from
01418  * user/application agent
01419  *
01420  * This is a fairly complex function.  It operates generally as follows:
01421  *      do header prediction for simple cases (pure ACKS or data)
01422  *      if in LISTEN and we get a SYN, begin initializing connection
01423  *      if in SYN_SENT and we get an ACK, complete connection init
01424  *      trim any redundant data from received dataful segment
01425  *      deal with ACKS:
01426  *              if in SYN_RCVD, complete connection init then go on
01427  *              see if ACK is old or at the current highest_ack
01428  *              if at current high, is the threshold reached or not
01429  *              if so, maybe do fast rtx... otherwise drop or inflate win
01430  *      deal with incoming data
01431  *      deal with FIN bit on in arriving packet
01432  */
01433 void
01434 FullTcpAgent::recv(Packet *pkt, Handler*)
01435 {
01436         hdr_tcp *tcph = hdr_tcp::access(pkt);   // TCP header
01437         hdr_cmn *th = hdr_cmn::access(pkt);     // common header (size, etc)
01438         hdr_flags *fh = hdr_flags::access(pkt); // flags (CWR, CE, bits)
01439 
01440         int needoutput = FALSE;
01441         int ourfinisacked = FALSE;
01442         int dupseg = FALSE;                     // recv'd dup data segment
01443         int todrop = 0;                         // duplicate DATA cnt in seg
01444 
01445         last_state_ = state_;
01446 
01447         int datalen = th->size() - tcph->hlen(); // # payload bytes
01448         int ackno = tcph->ackno();               // ack # from packet
01449         int tiflags = tcph->flags() ;            // tcp flags from packet
01450 
01451 //if (state_ != TCPS_ESTABLISHED || (tiflags&(TH_SYN|TH_FIN))) {
01452 //fprintf(stdout, "%f(%s)in state %s recv'd this packet: ", now(), name(), statestr(state_));
01453 //prpkt(pkt);
01454 //}
01455 
01456         /*
01457          * Don't expect to see anything while closed
01458          */
01459 
01460         if (state_ == TCPS_CLOSED) {
01461                 fprintf(stderr, "%f: FullTcp(%s): recv'd pkt in CLOSED state: ",
01462                         now(), name());
01463                 prpkt(pkt);
01464                 goto drop;
01465         }
01466 
01467         /*
01468          * Process options if not in LISTEN state,
01469          * else do it below
01470          */
01471 
01472         if (state_ != TCPS_LISTEN)
01473                 dooptions(pkt);
01474 
01475         /*
01476          * if we are using delayed-ACK timers and
01477          * no delayed-ACK timer is set, set one.
01478          * They are set to fire every 'interval_' secs, starting
01479          * at time t0 = (0.0 + k * interval_) for some k such
01480          * that t0 > now
01481          */
01482 
01483         if (delack_interval_ > 0.0 &&
01484             (delack_timer_.status() != TIMER_PENDING)) {
01485                 int last = int(now() / delack_interval_);
01486                 delack_timer_.resched(delack_interval_ * (last + 1.0) - now());
01487         }
01488 
01489         /*
01490          * sanity check for ECN: shouldn't be seeing a CE bit if
01491          * ECT wasn't set on the packet first.  If we see this, we
01492          * probably have a misbehaving router...
01493          */
01494 
01495         if (fh->ce() && !fh->ect()) {
01496             fprintf(stderr,
01497             "%f: FullTcpAgent::recv(%s): warning: CE bit on, but ECT false!\n",
01498                 now(), name());
01499         }
01500 
01501         /*
01502          * Try header prediction: in seq data or in seq pure ACK
01503          *      with no funny business
01504          */
01505 
01506         if (!nopredict_ && predict_ok(pkt)) {
01507                 /*
01508                  * If last ACK falls within this segment's sequence numbers,
01509                  * record the timestamp.
01510                  * See RFC1323 (now RFC1323 bis)
01511                  */
01512                 if (ts_option_ && !fh->no_ts_ &&
01513                     tcph->seqno() <= last_ack_sent_) {
01514                         /*
01515                          * this is the case where the ts value is newer than
01516                          * the last one we've seen, and the seq # is the one
01517                          * we expect [seqno == last_ack_sent_] or older
01518                          */
01519                         recent_age_ = now();
01520                         recent_ = tcph->ts();
01521                 }
01522 
01523                 //
01524                 // generate a stream of ecnecho bits until we see a true
01525                 // cong_action bit
01526                 //
01527                 if (ecn_) {
01528                         if (fh->ce() && fh->ect()) {
01529                                 // no CWR from peer yet... arrange to
01530                                 // keep sending ECNECHO
01531                                 recent_ce_ = TRUE;
01532                         } else if (fh->cwr()) {
01533                                 // got CWR response from peer.. stop
01534                                 // sending ECNECHO bits
01535                                 recent_ce_ = FALSE;
01536                         }
01537                 }
01538 
01539                 // Header predication basically looks to see
01540                 // if the incoming packet is an expected pure ACK
01541                 // or an expected data segment
01542 
01543                 if (datalen == 0) {
01544                         // check for a received pure ACK in the correct range..
01545                         // also checks to see if we are wnd_ limited
01546                         // (we don't change cwnd at all below), plus
01547                         // not being in fast recovery and not a partial ack.
01548                         // If we are in fast
01549                         // recovery, go below so we can remember to deflate
01550                         // the window if we need to
01551                         if (ackno > highest_ack_ && ackno < maxseq_ &&
01552                             cwnd_ >= wnd_ && !fastrecov_) {
01553                                 newack(pkt);    // update timers,  highest_ack_
01554                                 send_much(0, REASON_NORMAL, maxburst_);
01555                                 Packet::free(pkt);
01556                                 return;
01557                         }
01558                 } else if (ackno == highest_ack_ && rq_.empty()) {
01559                         // check for pure incoming segment
01560                         // the next data segment we're awaiting, and
01561                         // that there's nothing sitting in the reassem-
01562                         // bly queue
01563                         //      give to "application" here
01564                         //      note: DELACK is inspected only by
01565                         //      tcp_fasttimo() in real tcp.  Every 200 ms
01566                         //      this routine scans all tcpcb's looking for
01567                         //      DELACK segments and when it finds them
01568                         //      changes DELACK to ACKNOW and calls tcp_output()
01569                         rcv_nxt_ += datalen;
01570                         flags_ |= TF_DELACK;
01571                         recvBytes(datalen); // notify application of "delivery"
01572                         //
01573                         // special code here to simulate the operation
01574                         // of a receiver who always consumes data,
01575                         // resulting in a call to tcp_output
01576                         Packet::free(pkt);
01577                         if (need_send())
01578                                 send_much(1, REASON_NORMAL, maxburst_);
01579                         return;
01580                 }
01581         } /* header prediction */
01582 
01583 
01584         //
01585         // header prediction failed
01586         // (e.g. pure ACK out of valid range, SACK present, etc)...
01587         // do slow path processing
01588 
01589         //
01590         // the following switch does special things for these states:
01591         //      TCPS_LISTEN, TCPS_SYN_SENT
01592         //
01593 
01594         switch (state_) {
01595 
01596         /*
01597          * If the segment contains an ACK then it is bad and do reset.
01598          * If it does not contain a SYN then it is not interesting; drop it.
01599          * Otherwise initialize tp->rcv_nxt, and tp->irs, iss is already
01600          * selected, and send a segment:
01601          *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
01602          * Initialize tp->snd_nxt to tp->iss.
01603          * Enter SYN_RECEIVED state, and process any other fields of this
01604          * segment in this state.
01605          */
01606 
01607         case TCPS_LISTEN:       /* awaiting peer's SYN */
01608 
01609                 if (tiflags & TH_ACK) {
01610                         fprintf(stderr,
01611                                 "%f: FullTcpAgent(%s): warning: recv'd ACK while in LISTEN: ",
01612                                 now(), name());
01613                         prpkt(pkt);
01614                         // don't want ACKs in LISTEN
01615                         goto dropwithreset;
01616                 }
01617                 if ((tiflags & TH_SYN) == 0) {
01618                         fprintf(stderr,
01619                                 "%f: FullTcpAgent(%s): warning: recv'd NON-SYN while in LISTEN\n",
01620                                 now(), name());
01621                         prpkt(pkt);
01622                         // any non-SYN is discarded
01623                         goto drop;
01624                 }
01625 
01626                 /*
01627                  * must by a SYN (no ACK) at this point...
01628                  * in real tcp we would bump the iss counter here also
01629                  */
01630                 dooptions(pkt);
01631                 irs_ = tcph->seqno();
01632                 t_seqno_ = iss_; /* tcp_sendseqinit() macro in real tcp */
01633                 rcv_nxt_ = rcvseqinit(irs_, datalen);
01634                 flags_ |= TF_ACKNOW;
01635 
01636                 // check for a ECN-SYN with ECE|CWR
01637                 if (ecn_ && fh->ecnecho() && fh->cong_action()) {
01638 
01639                         ect_ = TRUE;
01640                 }
01641 
01642 
01643                 if (fid_ == 0) {
01644                         // XXX: sort of hack... If we do not
01645                         // have a special flow ID, pick up that
01646                         // of the sender (active opener)
01647                         hdr_ip* iph = hdr_ip::access(pkt);
01648                         fid_ = iph->flowid();
01649                 }
01650 
01651                 newstate(TCPS_SYN_RECEIVED);
01652                 goto trimthenstep6;
01653 
01654         /*
01655          * If the state is SYN_SENT:
01656          *      if seg contains an ACK, but not for our SYN, drop the input.
01657          *      if seg does not contain SYN, then drop it.
01658          * Otherwise this is an acceptable SYN segment
01659          *      initialize tp->rcv_nxt and tp->irs
01660          *      if seg contains ack then advance tp->snd_una
01661          *      if SYN has been acked change to ESTABLISHED else SYN_RCVD state
01662          *      arrange for segment to be acked (eventually)
01663          *      continue processing rest of data/controls, beginning with URG
01664          */
01665 
01666         case TCPS_SYN_SENT:     /* we sent SYN, expecting SYN+ACK (or SYN) */
01667 
01668                 /* drop if it's a SYN+ACK and the ack field is bad */
01669                 if ((tiflags & TH_ACK) &&
01670                         ((ackno <= iss_) || (ackno > maxseq_))) {
01671                         // not an ACK for our SYN, discard
01672                         fprintf(stderr,
01673                             "%f: FullTcpAgent::recv(%s): bad ACK for our SYN: ",
01674                                 now(), name());
01675                         prpkt(pkt);
01676                         goto dropwithreset;
01677                 }
01678 
01679                 if ((tiflags & TH_SYN) == 0) {
01680                         fprintf(stderr,
01681                             "%f: FullTcpAgent::recv(%s): no SYN for our SYN: ",
01682                                 now(), name());
01683                         prpkt(pkt);
01684                         goto drop;
01685                 }
01686 
01687                 /* looks like an ok SYN or SYN+ACK */
01688 #ifdef notdef
01689 cancel_rtx_timer();     // cancel timer on our 1st SYN [does this belong!?]
01690 #endif
01691                 irs_ = tcph->seqno();   // get initial recv'd seq #
01692                 rcv_nxt_ = rcvseqinit(irs_, datalen);
01693 
01694                 if (tiflags & TH_ACK) {
01695                         // SYN+ACK (our SYN was acked)
01696                         // CHECKME
01697                         // Check ECN-SYN+ACK packet
01698                         if (ecn_ && fh->ecnecho() && !fh->cong_action())
01699                                 ect_ = TRUE;
01700                         highest_ack_ = ackno;
01701                         cwnd_ = initial_window();
01702 
01703 #ifdef notdef
01704 /*
01705  * if we didn't have to retransmit the SYN,
01706  * use its rtt as our initial srtt & rtt var.
01707  */
01708 if (t_rtt_) {
01709         double tao = now() - tcph->ts();
01710         rtt_update(tao);
01711 }
01712 #endif
01713 
01714                         /*
01715                          * if there's data, delay ACK; if there's also a FIN
01716                          * ACKNOW will be turned on later.
01717                          */
01718                         if (datalen > 0) {
01719                                 flags_ |= TF_DELACK;    // data there: wait
01720                         } else {
01721                                 flags_ |= TF_ACKNOW;    // ACK peer's SYN
01722                         }
01723 
01724                         /*
01725                          * Received <SYN,ACK> in SYN_SENT[*] state.
01726                          * Transitions:
01727                          *      SYN_SENT  --> ESTABLISHED
01728                          *      SYN_SENT* --> FIN_WAIT_1
01729                          */
01730 
01731                         if (flags_ & TF_NEEDFIN) {
01732                                 newstate(TCPS_FIN_WAIT_1);
01733                                 flags_ &= ~TF_NEEDFIN;
01734                                 tiflags &= ~TH_SYN;
01735                         } else {
01736                                 newstate(TCPS_ESTABLISHED);
01737                         }
01738 
01739                         // special to ns:
01740                         //  generate pure ACK here.
01741                         //  this simulates the ordinary connection establishment
01742                         //  where the ACK of the peer's SYN+ACK contains
01743                         //  no data.  This is typically caused by the way
01744                         //  the connect() socket call works in which the
01745                         //  entire 3-way handshake occurs prior to the app
01746                         //  being able to issue a write() [which actually
01747                         //  causes the segment to be sent].
01748                         sendpacket(t_seqno_, rcv_nxt_, TH_ACK, 0, 0);
01749                 } else {
01750                         // Check ECN-SYN packet
01751                         if (ecn_ && fh->ecnecho() && fh->cong_action())
01752                                 ect_ = TRUE;
01753 
01754                         // SYN (no ACK) (simultaneous active opens)
01755                         flags_ |= TF_ACKNOW;
01756                         cancel_rtx_timer();
01757                         newstate(TCPS_SYN_RECEIVED);
01758                         /*
01759                          * decrement t_seqno_: we are sending a
01760                          * 2nd SYN (this time in the form of a
01761                          * SYN+ACK, so t_seqno_ will have been
01762                          * advanced to 2... reduce this
01763                          */
01764                         t_seqno_--;     // CHECKME
01765                 }
01766 
01767 trimthenstep6:
01768                 /*
01769                  * advance the seq# to correspond to first data byte
01770                  */
01771                 tcph->seqno()++;
01772 
01773                 if (tiflags & TH_ACK)
01774                         goto process_ACK;
01775 
01776                 goto step6;
01777 
01778         case TCPS_LAST_ACK:
01779         case TCPS_CLOSING:
01780                 break;
01781         } /* end switch(state_) */
01782 
01783         /*
01784          * States other than LISTEN or SYN_SENT.
01785          * First check timestamp, if present.
01786          * Then check that at least some bytes of segment are within
01787          * receive window.  If segment begins before rcv_nxt,
01788          * drop leading data (and SYN); if nothing left, just ack.
01789          *
01790          * RFC 1323 PAWS: If we have a timestamp reply on this segment
01791          * and it's less than ts_recent, drop it.
01792          */
01793 
01794         if (ts_option_ && !fh->no_ts_ && recent_ && tcph->ts() < recent_) {
01795                 if ((now() - recent_age_) > TCP_PAWS_IDLE) {
01796                         /*
01797                          * this is basically impossible in the simulator,
01798                          * but here it is...
01799                          */
01800                         /*
01801                          * Invalidate ts_recent.  If this segment updates
01802                          * ts_recent, the age will be reset later and ts_recent
01803                          * will get a valid value.  If it does not, setting
01804                          * ts_recent to zero will at least satisfy the
01805                          * requirement that zero be placed in the timestamp
01806                          * echo reply when ts_recent isn't valid.  The
01807                          * age isn't reset until we get a valid ts_recent
01808                          * because we don't want out-of-order segments to be
01809                          * dropped when ts_recent is old.
01810                          */
01811                         recent_ = 0.0;
01812                 } else {
01813                         fprintf(stderr, "%f: FullTcpAgent(%s): dropped pkt due to bad ts\n",
01814                                 now(), name());
01815                         goto dropafterack;
01816                 }
01817         }
01818 
01819         // check for redundant data at head/tail of segment
01820         //      note that the 4.4bsd [Net/3] code has
01821         //      a bug here which can cause us to ignore the
01822         //      perfectly good ACKs on duplicate segments.  The
01823         //      fix is described in (Stevens, Vol2, p. 959-960).
01824         //      This code is based on that correction.
01825         //
01826         // In addition, it has a modification so that duplicate segments
01827         // with dup acks don't trigger a fast retransmit when dupseg_fix_
01828         // is enabled.
01829         //
01830         // Yet one more modification: make sure that if the received
01831         //      segment had datalen=0 and wasn't a SYN or FIN that
01832         //      we don't turn on the ACKNOW status bit.  If we were to
01833         //      allow ACKNOW to be turned on, normal pure ACKs that happen
01834         //      to have seq #s below rcv_nxt can trigger an ACK war by
01835         //      forcing us to ACK the pure ACKs
01836         //
01837         // Update: if we have a dataless FIN, don't really want to
01838         // do anything with it.  In particular, would like to
01839         // avoid ACKing an incoming FIN+ACK while in CLOSING
01840         //
01841         todrop = rcv_nxt_ - tcph->seqno();  // how much overlap?
01842 
01843         if (todrop > 0 && ((tiflags & (TH_SYN)) || datalen > 0)) {
01844 //printf("%f(%s): trim 1..todrop:%d, dlen:%d\n",now(), name(), todrop, datalen);
01845                 if (tiflags & TH_SYN) {
01846                         tiflags &= ~TH_SYN;
01847                         tcph->seqno()++;
01848                         th->size()--;   // XXX Must decrease packet size too!!
01849                                         // Q: Why?.. this is only a SYN
01850                         todrop--;
01851                 }
01852                 //
01853                 // see Stevens, vol 2, p. 960 for this check;
01854                 // this check is to see if we are dropping
01855                 // more than this segment (i.e. the whole pkt + a FIN),
01856                 // or just the whole packet (no FIN)
01857                 //
01858                 if ((todrop > datalen) ||
01859                     (todrop == datalen && ((tiflags & TH_FIN) == 0))) {
01860 //printf("%f(%s): trim 2..todrop:%d, dlen:%d\n",now(), name(), todrop, datalen);
01861                         /*
01862                          * Any valid FIN must be to the left of the window.
01863                          * At this point the FIN must be a duplicate or out
01864                          * of sequence; drop it.
01865                          */
01866 
01867                         tiflags &= ~TH_FIN;
01868 
01869                         /*
01870                          * Send an ACK to resynchronize and drop any data.
01871                          * But keep on processing for RST or ACK.
01872                          */
01873 
01874                         flags_ |= TF_ACKNOW;
01875                         todrop = datalen;
01876                         dupseg = TRUE;  // *completely* duplicate
01877 
01878                 }
01879 
01880                 /*
01881                  * Trim duplicate data from the front of the packet
01882                  */
01883 
01884                 tcph->seqno() += todrop;
01885                 th->size() -= todrop;   // XXX Must decrease size too!!
01886                                         // why? [kf]..prob when put in RQ
01887                 datalen -= todrop;
01888 
01889         } /* data trim */
01890 
01891         /*
01892          * If we are doing timstamps and this packet has one, and
01893          * If last ACK falls within this segment's sequence numbers,
01894          * record the timestamp.
01895          * See RFC1323 (now RFC1323 bis)
01896          */
01897         if (ts_option_ && !fh->no_ts_ && tcph->seqno() <= last_ack_sent_) {
01898                 /*
01899                  * this is the case where the ts value is newer than
01900                  * the last one we've seen, and the seq # is the one we expect
01901                  * [seqno == last_ack_sent_] or older
01902                  */
01903                 recent_age_ = now();
01904                 recent_ = tcph->ts();
01905         }
01906 
01907         if (tiflags & TH_SYN) {
01908                 fprintf(stderr,
01909                     "%f: FullTcpAgent::recv(%s) received unexpected SYN (state:%d): ",
01910                         now(), name(), state_);
01911                 prpkt(pkt);
01912                 goto dropwithreset;
01913         }
01914 
01915         if ((tiflags & TH_ACK) == 0) {
01916                 fprintf(stderr, "%f: FullTcpAgent::recv(%s) got packet lacking ACK (state:%d): ",
01917                         now(), name(), state_);
01918                 prpkt(pkt);
01919                 goto drop;
01920         }
01921 
01922         /*
01923          * Ack processing.
01924          */
01925 
01926         switch (state_) {
01927         case TCPS_SYN_RECEIVED: /* want ACK for our SYN+ACK */
01928                 if (ackno < highest_ack_ || ackno > maxseq_) {
01929                         // not in useful range
01930                         fprintf(stderr,
01931                                 "%f: FullTcpAgent(%s): ack(%d) not in range while in SYN_RECEIVED: ",
01932                                 now(), name(), ackno);
01933                         prpkt(pkt);
01934                         goto dropwithreset;
01935                 }
01936                 /*
01937                  * Make transitions:
01938                  *      SYN-RECEIVED  -> ESTABLISHED
01939                  *      SYN-RECEIVED* -> FIN-WAIT-1
01940                  */
01941                 if (flags_ & TF_NEEDFIN) {
01942                         newstate(TCPS_FIN_WAIT_1);
01943                         flags_ &= ~TF_NEEDFIN;
01944                 } else {
01945                         newstate(TCPS_ESTABLISHED);
01946                 }
01947                 cwnd_ = initial_window();
01948                 /* fall into ... */
01949 
01950         /*
01951          * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
01952          * ACKs.  If the ack is in the range
01953          *      tp->snd_una < ti->ti_ack <= tp->snd_max
01954          * then advance tp->snd_una to ti->ti_ack and drop
01955          * data from the retransmission queue.
01956          *
01957          * note that state TIME_WAIT isn't used
01958          * in the simulator
01959          */
01960 
01961         case TCPS_ESTABLISHED:
01962         case TCPS_FIN_WAIT_1:
01963         case TCPS_FIN_WAIT_2:
01964         case TCPS_CLOSE_WAIT:
01965         case TCPS_CLOSING:
01966         case TCPS_LAST_ACK:
01967 
01968                 //
01969                 // look for ECNs in ACKs, react as necessary
01970                 //
01971 
01972                 if (fh->ecnecho() && (!ecn_ || !ect_)) {
01973                         fprintf(stderr,
01974                             "%f: FullTcp(%s): warning, recvd ecnecho but I am not ECN capable!\n",
01975                                 now(), name());
01976                 }
01977 
01978                 //
01979                 // generate a stream of ecnecho bits until we see a true
01980                 // cong_action bit
01981                 // 
01982                 if (ecn_) {
01983                         if (fh->ce() && fh->ect())
01984                                 recent_ce_ = TRUE;
01985                         else if (fh->cwr())
01986                                 recent_ce_ = FALSE;
01987                 }
01988 
01989                 //
01990                 // If ESTABLISHED or starting to close, process SACKS
01991                 //
01992 
01993                 if (state_ >= TCPS_ESTABLISHED && tcph->sa_length() > 0) {
01994                         process_sack(tcph);
01995                 }
01996 
01997                 //
01998                 // ACK indicates packet left the network
01999                 //      try not to be fooled by data
02000                 //
02001 
02002                 if (fastrecov_ && (datalen == 0 || ackno > highest_ack_))
02003                         pipe_ -= maxseg_;
02004 
02005                 // look for dup ACKs (dup ack numbers, no data)
02006                 //
02007                 // do fast retransmit/recovery if at/past thresh
02008                 if (ackno <= highest_ack_) {
02009                         // a pure ACK which doesn't advance highest_ack_
02010                         if (datalen == 0 && (!dupseg_fix_ || !dupseg)) {
02011 
02012                                 /*
02013                                  * If we have outstanding data
02014                                  * this is a completely
02015                                  * duplicate ack,
02016                                  * the ack is the biggest we've
02017                                  * seen and we've seen exactly our rexmt
02018                                  * threshhold of them, assume a packet
02019                                  * has been dropped and retransmit it.
02020                                  *
02021                                  * We know we're losing at the current
02022                                  * window size so do congestion avoidance.
02023                                  *
02024                                  * Dup acks mean that packets have left the
02025                                  * network (they're now cached at the receiver)
02026                                  * so bump cwnd by the amount in the receiver
02027                                  * to keep a constant cwnd packets in the
02028                                  * network.
02029                                  */
02030 
02031                                 if ((rtx_timer_.status() != TIMER_PENDING) ||
02032                                     ackno < highest_ack_) {
02033                                         // Q: significance of timer not pending?
02034                                         // ACK below highest_ack_
02035                                         oldack();
02036                                 } else if (++dupacks_ == tcprexmtthresh_) {
02037                                         // ACK at highest_ack_ AND meets threshold
02038                                         //trace_event("FAST_RECOVERY");
02039 
02040                                         dupack_action(); // maybe fast rexmt
02041                                         goto drop;
02042 
02043                                 } else if (dupacks_ > tcprexmtthresh_) {
02044                                         // ACK at highest_ack_ AND above threshole
02045                                         //trace_event("FAST_RECOVERY");
02046                                         extra_ack();
02047 
02048                                         // send whatever window allows
02049                                         send_much(0, REASON_DUPACK, maxburst_);
02050                                         goto drop;
02051                                 }
02052                         } else {
02053                                 // non zero-length [dataful] segment
02054                                 // with a dup ack (normal for dataful segs)
02055                                 // (or window changed in real TCP).
02056                                 if (dupack_reset_) {
02057                                         dupacks_ = 0;
02058                                         fastrecov_ = FALSE;
02059                                 }
02060                         }
02061                         break;  /* take us to "step6" */
02062                 } /* end of dup/old acks */
02063 
02064                 /*
02065                  * we've finished the fast retransmit/recovery period
02066                  * (i.e. received an ACK which advances highest_ack_)
02067                  * The ACK may be "good" or "partial"
02068                  */
02069 
02070 process_ACK:
02071 
02072                 if (ackno > maxseq_) {
02073                         // ack more than we sent(!?)
02074                         fprintf(stderr,
02075                             "%f: FullTcpAgent::recv(%s) too-big ACK (maxseq:%d): ",
02076                                 now(), name(), int(maxseq_));
02077                         prpkt(pkt);
02078                         goto dropafterack;
02079                 }
02080 
02081                 /*
02082                  * If we have a timestamp reply, update smoothed
02083                  * round trip time.  If no timestamp is present but
02084                  * transmit timer is running and timed sequence
02085                  * number was acked, update smoothed round trip time.
02086                  * Since we now have an rtt measurement, cancel the
02087                  * timer backoff (cf., Phil Karn's retransmit alg.).
02088                  * Recompute the initial retransmit timer.
02089                  *
02090                  * If all outstanding data is acked, stop retransmit
02091                  * If there is more data to be acked, restart retransmit
02092                  * timer, using current (possibly backed-off) value.
02093                  */
02094                 newack(pkt);    // handle timers, update highest_ack_
02095 
02096                 /*
02097                  * if this is a partial ACK, invoke whatever we should
02098                  * note that newack() must be called before the action
02099                  * functions, as some of them depend on side-effects
02100                  * of newack()
02101                  */
02102 
02103                 int partial = pack(pkt);
02104 
02105                 if (partial)
02106                         pack_action(pkt);
02107                 else
02108                         ack_action(pkt);
02109 
02110                 /*
02111                  * if this is an ACK with an ECN indication, handle this
02112                  * but not if it is a syn packet
02113                  */
02114 
02115                 if (fh->ecnecho() && !(tiflags&TH_SYN) )
02116                 if (fh->ecnecho()) {
02117                         // Note from Sally: In one-way TCP,
02118                         // ecn() is called before newack()...
02119                         ecn(highest_ack_);  // updated by newack(), above
02120                         // "set_rtx_timer();" from T. Kelly.
02121                         if (cwnd_ < 1)
02122                                 set_rtx_timer();
02123                 }
02124                 // CHECKME: handling of rtx timer
02125                 if (ackno == maxseq_) {
02126                         needoutput = TRUE;
02127                 }
02128 
02129                 /*
02130                  * If no data (only SYN) was ACK'd,
02131                  *    skip rest of ACK processing.
02132                  */
02133                 if (ackno == (highest_ack_ + 1))
02134                         goto step6;
02135 
02136                 // if we are delaying initial cwnd growth (probably due to
02137                 // large initial windows), then only open cwnd if data has
02138                 // been received
02139                 // Q: check when this happens
02140                 /*
02141                  * When new data is acked, open the congestion window.
02142                  * If the window gives us less than ssthresh packets
02143                  * in flight, open exponentially (maxseg per packet).
02144                  * Otherwise open about linearly: maxseg per window
02145                  * (maxseg^2 / cwnd per packet).
02146                  */
02147                 if ((!delay_growth_ || (rcv_nxt_ > 0)) &&
02148                     last_state_ == TCPS_ESTABLISHED) {
02149                         if (!partial || open_cwnd_on_pack_)
02150                           if (!ect_ || !hdr_flags::access(pkt)->ecnecho())
02151                                 opencwnd();
02152                 }
02153 
02154                 if ((state_ >= TCPS_FIN_WAIT_1) && (ackno == maxseq_)) {
02155                         ourfinisacked = TRUE;
02156                 }
02157 
02158                 //
02159                 // special additional processing when our state
02160                 // is one of the closing states:
02161                 //      FIN_WAIT_1, CLOSING, LAST_ACK
02162 
02163                 switch (state_) {
02164                 /*
02165                  * In FIN_WAIT_1 STATE in addition to the processing
02166                  * for the ESTABLISHED state if our FIN is now acknowledged
02167                  * then enter FIN_WAIT_2.
02168                  */
02169                 case TCPS_FIN_WAIT_1:   /* doing active close */
02170                         if (ourfinisacked) {
02171                                 // got the ACK, now await incoming FIN
02172                                 newstate(TCPS_FIN_WAIT_2);
02173                                 cancel_timers();
02174                                 needoutput = FALSE;
02175                         }
02176                         break;
02177 
02178                 /*
02179                  * In CLOSING STATE in addition to the processing for
02180                  * the ESTABLISHED state if the ACK acknowledges our FIN
02181                  * then enter the TIME-WAIT state, otherwise ignore
02182                  * the segment.
02183                  */
02184                 case TCPS_CLOSING:      /* simultaneous active close */;
02185                         if (ourfinisacked) {
02186                                 newstate(TCPS_CLOSED);
02187                                 cancel_timers();
02188                         }
02189                         break;
02190                 /*
02191                  * In LAST_ACK, we may still be waiting for data to drain
02192                  * and/or to be acked, as well as for the ack of our FIN.
02193                  * If our FIN is now acknowledged,
02194                  * enter the closed state and return.
02195                  */
02196                 case TCPS_LAST_ACK:     /* passive close */
02197                         // K: added state change here
02198                         if (ourfinisacked) {
02199                                 newstate(TCPS_CLOSED);
02200                                 finish(); // cancels timers, erc
02201                                 reset(); // for connection re-use (bug fix from ns-users list)
02202                                 goto drop;
02203                         } else {
02204                                 // should be a FIN we've seen
02205                                 fprintf(stderr,
02206                                 "%f: FullTcpAgent(%s)::received non-ACK (state:%d): ",
02207                                         now(), name(), state_);
02208                                 prpkt(pkt);
02209                         }
02210                         break;
02211 
02212                 /* no case for TIME_WAIT in simulator */
02213                 }  // inner state_ switch (closing states)
02214         } // outer state_ switch (ack processing)
02215 
02216 step6:
02217 
02218         /*
02219          * Processing of incoming DATAful segments.
02220          *      Code above has already trimmed redundant data.
02221          *
02222          * real TCP handles window updates and URG data here also
02223          */
02224 
02225 /* dodata: this label is in the "real" code.. here only for reference */
02226 
02227         if ((datalen > 0 || (tiflags & TH_FIN)) &&
02228             TCPS_HAVERCVDFIN(state_) == 0) {
02229 
02230                 //
02231                 // the following 'if' implements the "real" TCP
02232                 // TCP_REASS macro
02233                 //
02234 
02235                 if (tcph->seqno() == rcv_nxt_ && rq_.empty()) {
02236                         // got the in-order packet we were looking
02237                         // for, nobody is in the reassembly queue,
02238                         // so this is the common case...
02239                         // note: in "real" TCP we must also be in
02240                         // ESTABLISHED state to come here, because
02241                         // data arriving before ESTABLISHED is
02242                         // queued in the reassembly queue.  Since we
02243                         // don't really have a process anyhow, just
02244                         // accept the data here as-is (i.e. don't
02245                         // require being in ESTABLISHED state)
02246                         flags_ |= TF_DELACK;
02247                         rcv_nxt_ += datalen;
02248                         tiflags = tcph->flags() & TH_FIN;
02249 
02250                         // give to "application" here
02251                         // in "real" TCP, this is sbappend() + sorwakeup()
02252                         if (datalen)
02253                                 recvBytes(datalen); // notify app. of "delivery"
02254                         needoutput = need_send();
02255                 } else {
02256                         // see the "tcp_reass" function:
02257                         // not the one we want next (or it
02258                         // is but there's stuff on the reass queue);
02259                         // do whatever we need to do for out-of-order
02260                         // segments or hole-fills.  Also,
02261                         // send an ACK (or SACK) to the other side right now.
02262                         // Note that we may have just a FIN here (datalen = 0)
02263                         int rcv_nxt_old_ = rcv_nxt_; // notify app. if changes
02264                         tiflags = reass(pkt);
02265                         if (rcv_nxt_ > rcv_nxt_old_) {
02266                                 // if rcv_nxt_ has advanced, must have
02267                                 // been a hole fill.  In this case, there
02268                                 // is something to give to application
02269                                 recvBytes(rcv_nxt_ - rcv_nxt_old_);
02270                         }
02271                         flags_ |= TF_ACKNOW;
02272 
02273                         if (tiflags & TH_PUSH) {
02274                                 //
02275                                 // ???: does this belong here
02276                                 // K: APPLICATION recv
02277                                 needoutput = need_send();
02278                         }
02279                 }
02280         } else {
02281                 /*
02282                  * we're closing down or this is a pure ACK that
02283                  * wasn't handled by the header prediction part above
02284                  * (e.g. because cwnd < wnd)
02285                  */
02286                 // K: this is deleted
02287                 tiflags &= ~TH_FIN;
02288         }
02289 
02290         /*
02291          * if FIN is received, ACK the FIN
02292          * (let user know if we could do so)
02293          */
02294 
02295         if (tiflags & TH_FIN) {
02296                 if (TCPS_HAVERCVDFIN(state_) == 0) {
02297                         flags_ |= TF_ACKNOW;
02298                         rcv_nxt_++;
02299                 }
02300                 switch (state_) {
02301                 /*
02302                  * In SYN_RECEIVED and ESTABLISHED STATES
02303                  * enter the CLOSE_WAIT state.
02304                  * (passive close)
02305                  */
02306                 case TCPS_SYN_RECEIVED:
02307                 case TCPS_ESTABLISHED:
02308                         newstate(TCPS_CLOSE_WAIT);
02309                         break;
02310 
02311                 /*
02312                  * If still in FIN_WAIT_1 STATE FIN has not been acked so
02313                  * enter the CLOSING state.
02314                  * (simultaneous close)
02315                  */
02316                 case TCPS_FIN_WAIT_1:
02317                         newstate(TCPS_CLOSING);
02318                         break;
02319                 /*
02320                  * In FIN_WAIT_2 state enter the TIME_WAIT state,
02321                  * starting the time-wait timer, turning off the other
02322                  * standard timers.
02323                  * (in the simulator, just go to CLOSED)
02324                  * (completion of active close)
02325                  */
02326                 case TCPS_FIN_WAIT_2:
02327                         newstate(TCPS_CLOSED);
02328                         cancel_timers();
02329                         break;
02330                 }
02331         } /* end of if FIN bit on */
02332 
02333         if (needoutput || (flags_ & TF_ACKNOW))
02334                 send_much(1, REASON_NORMAL, maxburst_);
02335         else if (curseq_ >= highest_ack_ || infinite_send_)
02336                 send_much(0, REASON_NORMAL, maxburst_);
02337         // K: which state to return to when nothing left?
02338 
02339         if (!halfclose_ && state_ == TCPS_CLOSE_WAIT && highest_ack_ == maxseq_)
02340                 usrclosed();
02341 
02342         Packet::free(pkt);
02343 
02344         // haoboy: Is here the place for done{} of active close? 
02345         // It cannot be put in the switch above because we might need to do
02346         // send_much() (an ACK)
02347         if (state_ == TCPS_CLOSED) 
02348                 Tcl::instance().evalf("%s done", this->name());
02349 
02350         return;
02351 
02352         //
02353         // various ways of dropping (some also ACK, some also RST)
02354         //
02355 
02356 dropafterack:
02357         flags_ |= TF_ACKNOW;
02358         send_much(1, REASON_NORMAL, maxburst_);
02359         goto drop;
02360 
02361 dropwithreset:
02362         /* we should be sending an RST here, but can't in simulator */
02363         if (tiflags & TH_ACK) {
02364                 sendpacket(ackno, 0, 0x0, 0, REASON_NORMAL);
02365         } else {
02366                 int ack = tcph->seqno() + datalen;
02367                 if (tiflags & TH_SYN)
02368                         ack--;
02369                 sendpacket(0, ack, TH_ACK, 0, REASON_NORMAL);
02370         }
02371 drop:
02372         Packet::free(pkt);
02373         return;
02374 }
02375 /*  
02376  * Dupack-action: what to do on a DUP ACK.  After the initial check
02377  * of 'recover' below, this function implements the following truth
02378  * table:
02379  *  
02380  *      bugfix  ecn     last-cwnd == ecn        action  
02381  *  
02382  *      0       0       0                       full_reno_action
02383  *      0       0       1                       full_reno_action [impossible]
02384  *      0       1       0                       full_reno_action
02385  *      0       1       1                       1/2 window, return 
02386  *      1       0       0                       nothing 
02387  *      1       0       1                       nothing         [impossible]
02388  *      1       1       0                       nothing 
02389  *      1       1       1                       1/2 window, return
02390  */ 
02391     
02392 void
02393 FullTcpAgent::dupack_action()
02394 {   
02395 
02396         int recovered = (highest_ack_ > recover_);
02397 
02398         fastrecov_ = TRUE;
02399         rtxbytes_ = 0;
02400 
02401         if (recovered || (!bug_fix_ && !ecn_) ||
02402             // Q: is last_cwnd_action == dupack enough to trigger?
02403             // probably not.  may need to fix 1-way reno model as well
02404             last_cwnd_action_ == CWND_ACTION_DUPACK) {
02405                 goto full_reno_action;
02406         }       
02407     
02408         if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
02409                 slowdown(CLOSE_CWND_HALF);
02410                 cancel_rtx_timer();
02411                 rtt_active_ = FALSE;
02412                 (void)fast_retransmit(highest_ack_);
02413                 return; 
02414         }      
02415     
02416         if (bug_fix_) {
02417                 /*
02418                  * The line below, for "bug_fix_" true, avoids
02419                  * problems with multiple fast retransmits in one
02420                  * window of data.
02421                  */      
02422                 return;  
02423         }
02424     
02425 full_reno_action:    
02426         slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
02427         cancel_rtx_timer();
02428         rtt_active_ = FALSE;
02429         recover_ = maxseq_;
02430         (void)fast_retransmit(highest_ack_);
02431         // we measure cwnd in packets,
02432         // so don't scale by maxseg_
02433         // as real TCP does
02434         cwnd_ = double(ssthresh_) + double(dupacks_);
02435         return;
02436 }
02437 
02438 void
02439 FullTcpAgent::timeout_action()
02440 {
02441         recover_ = maxseq_;
02442 
02443         if (cwnd_ < 1.0) {
02444             fprintf(stderr,
02445             "%f: FullTcpAgent(%s):: resetting cwnd from %f to 1\n",
02446                  now(), name(), double(cwnd_));
02447                 cwnd_ = 1.0;
02448         }
02449 
02450         if (last_cwnd_action_ == CWND_ACTION_ECN) {
02451                 slowdown(CLOSE_CWND_ONE);
02452         } else {
02453                 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
02454                 last_cwnd_action_ = CWND_ACTION_TIMEOUT;
02455         }
02456         reset_rtx_timer(1);
02457         t_seqno_ = (highest_ack_ < 0) ? iss_ : int(highest_ack_);
02458         fastrecov_ = FALSE;
02459         dupacks_ = 0;
02460 }
02461 /*
02462  * deal with timers going off.
02463  * 2 types for now:
02464  *      retransmission timer (rtx_timer_)
02465  *  delayed ack timer (delack_timer_)
02466  *      delayed send (randomization) timer (delsnd_timer_)
02467  *
02468  * real TCP initializes the RTO as 6 sec
02469  *      (A + 2D, where A=0, D=3), [Stevens p. 305]
02470  * and thereafter uses
02471  *      (A + 4D, where A and D are dynamic estimates)
02472  *
02473  * note that in the simulator t_srtt_, t_rttvar_ and t_rtt_
02474  * are all measured in 'tcp_tick_'-second units
02475  */
02476 
02477 void
02478 FullTcpAgent::timeout(int tno)
02479 {
02480 
02481         if (state_ == TCPS_CLOSED || state_ == TCPS_LISTEN) {
02482                 // shouldn't be getting timeouts here
02483                 fprintf(stderr, "%f: FullTcpAgent(%s): unexpected timeout %d in state %s\n",
02484                         now(), name(), tno, statestr(state_));
02485                 return;
02486         }
02487 
02488         switch (tno) {
02489 
02490         case TCP_TIMER_RTX:
02491                 /* retransmit timer */
02492                 ++nrexmit_;
02493                 timeout_action();
02494                 /* fall thru */
02495         case TCP_TIMER_DELSND:
02496                 /* for phase effects */
02497                 send_much(1, PF_TIMEOUT, maxburst_);
02498                 break;
02499 
02500         case TCP_TIMER_DELACK:
02501                 if (flags_ & TF_DELACK) {
02502                         flags_ &= ~TF_DELACK;
02503                         flags_ |= TF_ACKNOW;
02504                         send_much(1, REASON_NORMAL, 0);
02505                 }
02506                 delack_timer_.resched(delack_interval_);
02507                 break;
02508         default:
02509                 fprintf(stderr, "%f: FullTcpAgent(%s) Unknown Timeout type %d\n",
02510                         now(), name(), tno);
02511         }
02512         return;
02513 }
02514 
02515 void
02516 FullTcpAgent::dooptions(Packet* pkt)
02517 {
02518         // interesting options: timestamps (here),
02519         //      CC, CCNEW, CCECHO (future work perhaps?)
02520 
02521         hdr_flags *fh = hdr_flags::access(pkt);
02522         hdr_tcp *tcph = hdr_tcp::access(pkt);
02523 
02524         if (ts_option_ && !fh->no_ts_) {
02525                 if (tcph->ts() < 0.0) {
02526                         fprintf(stderr,
02527                             "%f: FullTcpAgent(%s) warning: ts_option enabled in this TCP, but appears to be disabled in peer\n",
02528                                 now(), name());
02529                 } else if (tcph->flags() & TH_SYN) {
02530                         flags_ |= TF_RCVD_TSTMP;
02531                         recent_ = tcph->ts();
02532                         recent_age_ = now();
02533                 }
02534         }
02535 
02536         return;
02537 }
02538 
02539 //
02540 // this shouldn't ever happen
02541 //
02542 void
02543 FullTcpAgent::process_sack(hdr_tcp*)
02544 {
02545         fprintf(stderr, "%f: FullTcpAgent(%s) Non-SACK capable FullTcpAgent received a SACK\n",
02546                 now(), name());
02547         return;
02548 }
02549 
02550 
02551 /*
02552  * ****** Tahoe ******
02553  *
02554  * for TCP Tahoe, we force a slow-start as the dup ack
02555  * action.  Also, no window inflation due to multiple dup
02556  * acks.  The latter is arranged by setting reno_fastrecov_
02557  * false [which is performed by the Tcl init function for Tahoe in
02558  * ns-default.tcl].
02559  */
02560 
02561 /* 
02562  * Tahoe
02563  * Dupack-action: what to do on a DUP ACK.  After the initial check
02564  * of 'recover' below, this function implements the following truth
02565  * table:
02566  * 
02567  *      bugfix  ecn     last-cwnd == ecn        action  
02568  * 
02569  *      0       0       0                       full_tahoe_action
02570  *      0       0       1                       full_tahoe_action [impossible]
02571  *      0       1       0                       full_tahoe_action
02572  *      0       1       1                       1/2 window, return
02573  *      1       0       0                       nothing 
02574  *      1       0       1                       nothing         [impossible]
02575  *      1       1       0                       nothing 
02576  *      1       1       1                       1/2 window, return
02577  */
02578 
02579 void
02580 TahoeFullTcpAgent::dupack_action()
02581 {  
02582         int recovered = (highest_ack_ > recover_);
02583 
02584         fastrecov_ = TRUE;
02585         rtxbytes_ = 0;
02586 
02587         if (recovered || (!bug_fix_ && !ecn_) ||
02588             // Q: is last_cwnd_action dupack enough?
02589             last_cwnd_action_ == CWND_ACTION_DUPACK) {
02590                 goto full_tahoe_action;
02591         }
02592    
02593         if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
02594                 // slow start on ECN
02595                 last_cwnd_action_ = CWND_ACTION_DUPACK;
02596                 slowdown(CLOSE_CWND_ONE);
02597                 set_rtx_timer();
02598                 rtt_active_ = FALSE;
02599                 t_seqno_ = highest_ack_;
02600                 return; 
02601         }
02602    
02603         if (bug_fix_) {
02604                 /*
02605                  * The line below, for "bug_fix_" true, avoids
02606                  * problems with multiple fast retransmits in one
02607                  * window of data.
02608                  */      
02609                 return;  
02610         }
02611    
02612 full_tahoe_action:
02613         // slow-start and reset ssthresh
02614         trace_event("FAST_RETX");
02615         recover_ = maxseq_;
02616         last_cwnd_action_ = CWND_ACTION_DUPACK;
02617         slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_ONE);   // cwnd->1
02618         set_rtx_timer();
02619         rtt_active_ = FALSE;
02620         t_seqno_ = highest_ack_;
02621         send_much(0, REASON_NORMAL, 0);
02622         return; 
02623 }  
02624 
02625 /*
02626  * ****** Newreno ******
02627  *
02628  * for NewReno, a partial ACK does not exit fast recovery,
02629  * and does not reset the dup ACK counter (which might trigger fast
02630  * retransmits we don't want).  In addition, the number of packets
02631  * sent in response to an ACK is limited to recov_maxburst_ during
02632  * recovery periods.
02633  */
02634 
02635 NewRenoFullTcpAgent::NewRenoFullTcpAgent() : save_maxburst_(-1)
02636 {
02637         bind("recov_maxburst_", &recov_maxburst_);
02638 }
02639 
02640 void
02641 NewRenoFullTcpAgent::pack_action(Packet*)
02642 {
02643         (void)fast_retransmit(highest_ack_);
02644         cwnd_ = double(ssthresh_);
02645         if (save_maxburst_ < 0) {
02646                 save_maxburst_ = maxburst_;
02647                 maxburst_ = recov_maxburst_;
02648         }
02649         return;
02650 }
02651 
02652 void
02653 NewRenoFullTcpAgent::ack_action(Packet* p)
02654 {
02655         if (save_maxburst_ >= 0) {
02656                 maxburst_ = save_maxburst_;
02657                 save_maxburst_ = -1;
02658         }
02659         FullTcpAgent::ack_action(p);
02660         return;
02661 }
02662 
02663 /*
02664  *
02665  * ****** SACK ******
02666  *
02667  * for Sack, receiver part must report SACK data
02668  * sender part maintains a 'scoreboard' (sq_) that
02669  * records what it hears from receiver
02670  * sender fills holes during recovery and obeys
02671  * "pipe" style control until recovery is complete
02672  */
02673 
02674 void
02675 SackFullTcpAgent::reset()
02676 {
02677         sq_.clear();                    // no SACK blocks
02678         sack_min_ = h_seqno_ -1;        // no left edge of SACK blocks
02679         FullTcpAgent::reset();
02680 }
02681 
02682 
02683 int
02684 SackFullTcpAgent::hdrsize(int nsackblocks)
02685 {
02686         int total = FullTcpAgent::headersize();
02687         // use base header size plus SACK option size
02688         if (nsackblocks > 0) {
02689                 total += ((nsackblocks * sack_block_size_)
02690                         + sack_option_size_);
02691         }
02692         return (total);
02693 }
02694 
02695 void
02696 SackFullTcpAgent::dupack_action()
02697 {
02698 
02699         int recovered = (highest_ack_ > recover_);
02700 
02701         fastrecov_ = TRUE;
02702         rtxbytes_ = 0;
02703         pipe_ = maxseq_ - highest_ack_ - sq_.total();
02704 
02705 //printf("%f: SACK DUPACK-ACTION:pipe_:%d, sq-total:%d, bugfix:%d, cwnd:%d, highest_ack:%d, recover_:%d\n",
02706 //now(), pipe_, sq_.total(), bug_fix_, int(cwnd_), int(highest_ack_), recover_);
02707 
02708         if (recovered || (!bug_fix_ && !ecn_)) {
02709                 goto full_sack_action;
02710         }           
02711 
02712         if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
02713                 last_cwnd_action_ = CWND_ACTION_DUPACK;
02714                 cancel_rtx_timer();
02715                 rtt_active_ = FALSE;
02716                 send_much(1, REASON_DUPACK, maxburst_);
02717                 return; 
02718         }               
02719    
02720         if (bug_fix_) {
02721                 /*                              
02722                  * The line below, for "bug_fix_" true, avoids
02723                  * problems with multiple fast retransmits in one
02724                  * window of data.
02725                  */      
02726 
02727 //printf("%f: SACK DUPACK-ACTION BUGFIX RETURN:pipe_:%d, sq-total:%d, bugfix:%d, cwnd:%d\n",
02728 //now(), pipe_, sq_.total(), bug_fix_, int(cwnd_));
02729                 return;  
02730         }
02731    
02732 full_sack_action:                               
02733         trace_event("FAST_RECOVERY");
02734         slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
02735         cancel_rtx_timer();
02736         rtt_active_ = FALSE;
02737 
02738         // these initiate SACK-style "pipe" recovery
02739         pipectrl_ = TRUE;
02740         recover_ = maxseq_;     // where I am when recovery starts
02741 
02742         int amt = fast_retransmit(highest_ack_);
02743         h_seqno_ = highest_ack_ + amt;
02744 
02745 //printf("%f: FAST-RTX seq:%d, h_seqno_ is now:%d, pipe:%d, cwnd:%d, recover:%d\n",
02746 //now(), int(highest_ack_), h_seqno_, pipe_, int(cwnd_), recover_);
02747 
02748         send_much(0, REASON_DUPACK, maxburst_);
02749 
02750         return;
02751 }
02752 
02753 void
02754 SackFullTcpAgent::pack_action(Packet* p)
02755 {
02756         if (!sq_.empty() && sack_min_ < highest_ack_) {
02757                 sack_min_ = highest_ack_;
02758                 sq_.cleartonxt();
02759         }
02760         pipe_ -= maxseg_;       // see comment in tcp-sack1.cc
02761         if (h_seqno_ < highest_ack_)
02762                 h_seqno_ = highest_ack_;
02763 }
02764 
02765 void
02766 SackFullTcpAgent::ack_action(Packet* p)
02767 {
02768 //printf("%f: EXITING fast recovery, recover:%d\n",
02769 //now(), recover_);
02770         fastrecov_ = pipectrl_ = FALSE;
02771         if (!sq_.empty() && sack_min_ < highest_ack_) {
02772                 sack_min_ = highest_ack_;
02773                 sq_.cleartonxt();
02774         }
02775         dupacks_ = 0;
02776 }
02777 
02778 //
02779 // receiver side: if there are things in the reassembly queue,
02780 // build the appropriate SACK blocks to carry in the SACK
02781 //
02782 int
02783 SackFullTcpAgent::build_options(hdr_tcp* tcph)
02784 {
02785         int total = FullTcpAgent::build_options(tcph);
02786 
02787         if (!rq_.empty()) {
02788                 int nblk = rq_.gensack(&tcph->sa_left(0), max_sack_blocks_);
02789                 tcph->sa_length() = nblk;
02790                 total += (nblk * sack_block_size_) + sack_option_size_;
02791         } else {
02792                 tcph->sa_length() = 0;
02793         }
02794         return (total);
02795 }
02796 
02797 void
02798 SackFullTcpAgent::timeout_action()
02799 {
02800         FullTcpAgent::timeout_action();
02801 
02802         //
02803         // original SACK spec says the sender is
02804         // supposed to clear out its knowledge of what
02805         // the receiver has in the case of a timeout
02806         // (on the chance the receiver has renig'd).
02807         // Here, this happens when clear_on_timeout_ is
02808         // enabled.
02809         //
02810 
02811         if (clear_on_timeout_) {
02812                 sq_.clear();
02813                 sack_min_ = highest_ack_;
02814         }
02815 
02816         return;
02817 }
02818 
02819 void
02820 SackFullTcpAgent::process_sack(hdr_tcp* tcph)
02821 {
02822         //
02823         // Figure out how many sack blocks are
02824         // in the pkt.  Insert each block range
02825         // into the scoreboard
02826         //
02827 
02828         if (max_sack_blocks_ <= 0) {
02829                 fprintf(stderr,
02830                     "%f: FullTcpAgent(%s) warning: received SACK block but I am not SACK enabled\n",
02831                         now(), name());
02832                 return;
02833         }       
02834 
02835         int slen = tcph->sa_length(), i;
02836         for (i = 0; i < slen; ++i) {
02837                 if (tcph->sa_left(i) >= tcph->sa_right(i)) {
02838                         fprintf(stderr,
02839                             "%f: FullTcpAgent(%s) warning: received illegal SACK block [%d,%d]\n",
02840                                 now(), name(), tcph->sa_left(i), tcph->sa_right(i));
02841                         continue;
02842                 }
02843                 sq_.add(tcph->sa_left(i), tcph->sa_right(i), 0);  
02844         }
02845 
02846         return;
02847 }
02848 
02849 int
02850 SackFullTcpAgent::send_allowed(int seq)
02851 {
02852         // not in pipe control, so use regular control
02853         if (!pipectrl_)
02854                 return (FullTcpAgent::send_allowed(seq));
02855 
02856         // don't overshoot receiver's advertised window
02857         int topawin = highest_ack_ + int(wnd_) * maxseg_;
02858         if (seq >= topawin) {
02859 //printf("%f: SEND(%d) NOT ALLOWED DUE TO AWIN:%d, pipe:%d, cwnd:%d\n",
02860 //now(), seq, topawin, pipe_, int(cwnd_));
02861                 return FALSE;
02862         }
02863 
02864         // don't overshoot cwnd_
02865         int cwin = int(cwnd_) * maxseg_;
02866         return (pipe_ < cwin);
02867 }
02868 
02869 
02870 //
02871 // Calculate the next seq# to send by send_much.  If we are recovering and
02872 // we have learned about data cached at the receiver via a SACK,
02873 // we may want something other than new data (t_seqno)
02874 //
02875 
02876 int
02877 SackFullTcpAgent::nxt_tseq()
02878 {
02879 
02880         int in_recovery = (highest_ack_ < recover_);
02881         int seq = h_seqno_;
02882 
02883         if (!in_recovery) {
02884 //if (int(t_seqno_) > 1)
02885 //printf("%f: non-recovery nxt_tseq called w/t_seqno:%d\n",
02886 //now(), int(t_seqno_));
02887 //sq_.dumplist();
02888                 return (t_seqno_);
02889         }
02890 
02891         int fcnt;       // following count-- the
02892                         // count field in the block
02893                         // after the seq# we are about
02894                         // to send
02895         int fbytes;     // fcnt in bytes
02896 
02897 //if (int(t_seqno_) > 1)
02898 //printf("%f: recovery nxt_tseq called w/t_seqno:%d, seq:%d, mode:%d\n",
02899 //now(), int(t_seqno_), seq, sack_rtx_threshmode_);
02900 //sq_.dumplist();
02901 
02902         while ((seq = sq_.nexthole(seq, fcnt, fbytes)) > 0) {
02903                 // if we have a following block
02904                 // with a large enough count
02905                 // we should use the seq# we get
02906                 // from nexthole()
02907                 if (sack_rtx_threshmode_ == 0 ||
02908                     (sack_rtx_threshmode_ == 1 && fcnt >= sack_rtx_cthresh_) ||
02909                     (sack_rtx_threshmode_ == 2 && fbytes >= sack_rtx_bthresh_) ||
02910                     (sack_rtx_threshmode_ == 3 && (fcnt >= sack_rtx_cthresh_ || fbytes >= sack_rtx_bthresh_)) ||
02911                     (sack_rtx_threshmode_ == 4 && (fcnt >= sack_rtx_cthresh_ && fbytes >= sack_rtx_bthresh_))) {
02912 
02913 //if (int(t_seqno_) > 1)
02914 //printf("%f: nxt_tseq<hole> returning %d\n",
02915 //now(), int(seq));
02916                         // adjust h_seqno, as we may have
02917                         // been "jumped ahead" by learning
02918                         // about a filled hole
02919                         if (seq > h_seqno_)
02920                                 h_seqno_ = seq;
02921                         return (seq);
02922                 } else if (fcnt <= 0)
02923                         break;
02924                 else {
02925                         seq += maxseg_;
02926                 }
02927         }
02928 //if (int(t_seqno_) > 1)
02929 //printf("%f: nxt_tseq<top> returning %d\n",
02930 //now(), int(t_seqno_));
02931         return (t_seqno_);
02932 }

Generated on Tue Apr 20 12:14:35 2004 for NS2.26SourcesOriginal by doxygen 1.3.3