Annotation of 43BSDReno/sys/netiso/tp_subr.c, revision 1.1

1.1     ! root        1: /***********************************************************
        !             2:                Copyright IBM Corporation 1987
        !             3: 
        !             4:                       All Rights Reserved
        !             5: 
        !             6: Permission to use, copy, modify, and distribute this software and its 
        !             7: documentation for any purpose and without fee is hereby granted, 
        !             8: provided that the above copyright notice appear in all copies and that
        !             9: both that copyright notice and this permission notice appear in 
        !            10: supporting documentation, and that the name of IBM not be
        !            11: used in advertising or publicity pertaining to distribution of the
        !            12: software without specific, written prior permission.  
        !            13: 
        !            14: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
        !            15: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
        !            16: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
        !            17: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
        !            18: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
        !            19: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
        !            20: SOFTWARE.
        !            21: 
        !            22: ******************************************************************/
        !            23: 
        !            24: /*
        !            25:  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
        !            26:  */
        !            27: /* 
        !            28:  * ARGO TP
        !            29:  *
        !            30:  * $Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $
        !            31:  * $Source: /usr/argo/sys/netiso/RCS/tp_subr.c,v $
        !            32:  *     @(#)tp_subr.c   7.6 (Berkeley) 7/24/90
        !            33:  *
        !            34:  * The main work of data transfer is done here.
        !            35:  * These routines are called from tp.trans.
        !            36:  * They include the routines that check the validity of acks and Xacks,
        !            37:  * (tp_goodack() and tp_goodXack() )
        !            38:  * take packets from socket buffers and send them (tp_send()),
        !            39:  * drop the data from the socket buffers (tp_sbdrop()),  
        !            40:  * and put incoming packet data into socket buffers (tp_stash()).
        !            41:  */
        !            42: 
        !            43: #ifndef lint
        !            44: static char *rcsid = "$Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $";
        !            45: #endif lint
        !            46: 
        !            47: #include "param.h"
        !            48: #include "mbuf.h"
        !            49: #include "socket.h"
        !            50: #include "socketvar.h"
        !            51: #include "protosw.h"
        !            52: #include "errno.h"
        !            53: #include "types.h"
        !            54: #include "time.h"
        !            55: 
        !            56: #include "tp_ip.h"
        !            57: #include "iso.h"
        !            58: #include "argo_debug.h"
        !            59: #include "tp_timer.h"
        !            60: #include "tp_param.h"
        !            61: #include "tp_stat.h"
        !            62: #include "tp_pcb.h"
        !            63: #include "tp_tpdu.h"
        !            64: #include "tp_trace.h"
        !            65: #include "tp_meas.h"
        !            66: #include "tp_seq.h"
        !            67: 
        !            68: int            tp_emit();
        !            69: static void tp_sbdrop();
        !            70: 
        !            71: #define SMOOTH(newtype, alpha, old, new) \
        !            72:        (newtype) (((new - old)>>alpha) + (old))
        !            73: 
        !            74: #define ABS(type, val) \
        !            75:        (type) (((int)(val)<0)?-(val):(val))
        !            76: 
        !            77: #define TP_MAKE_RTC( Xreg, Xseq, Xeot, Xdata, Xlen, Xretval, Xtype) \
        !            78: {      struct mbuf *xxn;\
        !            79:        MGET(xxn, M_DONTWAIT, Xtype);\
        !            80:        if( xxn == (struct mbuf *)0 ) {\
        !            81:                printf("MAKE RTC FAILED: ENOBUFS\n");\
        !            82:                return (int)Xretval;\
        !            83:        }\
        !            84:        xxn->m_act=MNULL;\
        !            85:        Xreg = mtod(xxn, struct tp_rtc *);\
        !            86:        if( Xreg == (struct tp_rtc *)0 ) {\
        !            87:                return (int)Xretval;\
        !            88:        }\
        !            89:        Xreg->tprt_eot = Xeot;\
        !            90:        Xreg->tprt_seq = Xseq;\
        !            91:        Xreg->tprt_data = Xdata;\
        !            92:        Xreg->tprt_octets = Xlen;\
        !            93: }
        !            94: 
        !            95: 
        !            96: /*
        !            97:  * CALLED FROM:
        !            98:  *     tp.trans, when an XAK arrives
        !            99:  * FUNCTION and ARGUMENTS:
        !           100:  *     Determines if the sequence number (seq) from the XAK 
        !           101:  *     acks anything new.  If so, drop the appropriate tpdu
        !           102:  *     from the XPD send queue.
        !           103:  * RETURN VALUE:
        !           104:  *     Returns 1 if it did this, 0 if the ack caused no action.
        !           105:  */
        !           106: int
        !           107: tp_goodXack(tpcb, seq)
        !           108:        struct tp_pcb   *tpcb;
        !           109:        SeqNum                  seq; 
        !           110: {
        !           111: 
        !           112:        IFTRACE(D_XPD)
        !           113:                tptraceTPCB(TPPTgotXack, 
        !           114:                        seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat, 
        !           115:                        tpcb->tp_snduna); 
        !           116:        ENDTRACE
        !           117: 
        !           118:        if ( seq == tpcb->tp_Xuna ) {
        !           119:                        tpcb->tp_Xuna = tpcb->tp_Xsndnxt;
        !           120: 
        !           121:                        /* DROP 1 packet from the Xsnd socket buf - just so happens
        !           122:                         * that only one packet can be there at any time
        !           123:                         * so drop the whole thing.  If you allow > 1 packet
        !           124:                         * the socket buffer, then you'll have to keep
        !           125:                         * track of how many characters went w/ each XPD tpdu, so this
        !           126:                         * will get messier
        !           127:                         */
        !           128:                        IFDEBUG(D_XPD)
        !           129:                                dump_mbuf(tpcb->tp_Xsnd.sb_mb,
        !           130:                                        "tp_goodXack Xsnd before sbdrop");
        !           131:                        ENDDEBUG
        !           132: 
        !           133:                        IFTRACE(D_XPD)
        !           134:                                tptraceTPCB(TPPTmisc, 
        !           135:                                        "goodXack: dropping cc ",
        !           136:                                        (int)(tpcb->tp_Xsnd.sb_cc),
        !           137:                                        0,0,0);
        !           138:                        ENDTRACE
        !           139:                        sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc));
        !           140:                        CONG_ACK(tpcb, seq);
        !           141:                        return 1;
        !           142:        } 
        !           143:        return 0;
        !           144: }
        !           145: 
        !           146: /*
        !           147:  * CALLED FROM:
        !           148:  *  tp_good_ack()
        !           149:  * FUNCTION and ARGUMENTS:
        !           150:  *  updates
        !           151:  *  smoothed average round trip time (base_rtt)
        !           152:  *  roundtrip time variance (base_rtv) - actually deviation, not variance
        !           153:  *  given the new value (diff)
        !           154:  * RETURN VALUE:
        !           155:  * void
        !           156:  */
        !           157: 
        !           158: void
        !           159: tp_rtt_rtv( base_rtt, base_rtv, newmeas )
        !           160:        struct  timeval *base_rtt, *base_rtv, *newmeas;
        !           161: {
        !           162:        /* update  rt variance (really just the deviation): 
        !           163:         *      rtv.smooth_ave =  SMOOTH( | oldrtt.smooth_avg - rtt.this_instance | )
        !           164:         */
        !           165:        base_rtv->tv_sec = 
        !           166:                SMOOTH( long,  TP_RTV_ALPHA, base_rtv->tv_sec, 
        !           167:                        ABS( long, base_rtt->tv_sec - newmeas->tv_sec ));
        !           168:        base_rtv->tv_usec = 
        !           169:                SMOOTH( long,  TP_RTV_ALPHA, base_rtv->tv_usec, 
        !           170:                        ABS(long, base_rtt->tv_usec - newmeas->tv_usec ));
        !           171: 
        !           172:        /* update smoothed average rtt */
        !           173:        base_rtt->tv_sec = 
        !           174:                SMOOTH( long,  TP_RTT_ALPHA, base_rtt->tv_sec, newmeas->tv_sec);
        !           175:        base_rtt->tv_usec =
        !           176:                SMOOTH( long,  TP_RTT_ALPHA, base_rtt->tv_usec, newmeas->tv_usec);
        !           177: 
        !           178: }
        !           179: 
        !           180: /*
        !           181:  * CALLED FROM:
        !           182:  *  tp.trans when an AK arrives
        !           183:  * FUNCTION and ARGUMENTS:
        !           184:  *     Given (cdt), the credit from the AK tpdu, and 
        !           185:  *     (seq), the sequence number from the AK tpdu,
        !           186:  *  tp_goodack() determines if the AK acknowledges something in the send
        !           187:  *     window, and if so, drops the appropriate packets from the retransmission
        !           188:  *  list, computes the round trip time, and updates the retransmission timer
        !           189:  *  based on the new smoothed round trip time.
        !           190:  * RETURN VALUE:
        !           191:  *     Returns 1 if
        !           192:  *     EITHER it actually acked something heretofore unacknowledged
        !           193:  *     OR no news but the credit should be processed.
        !           194:  *     If something heretofore unacked was acked with this sequence number,
        !           195:  *     the appropriate tpdus are dropped from the retransmission control list,
        !           196:  *     by calling tp_sbdrop().
        !           197:  *     No need to see the tpdu itself.
        !           198:  */
        !           199: int
        !           200: tp_goodack(tpcb, cdt, seq, subseq)
        !           201:        register struct tp_pcb  *tpcb;
        !           202:        u_int                                   cdt;
        !           203:        register SeqNum                 seq, subseq;
        !           204: {
        !           205:        int     old_fcredit = tpcb->tp_fcredit; 
        !           206:        int     bang = 0;       /* bang --> ack for something heretofore unacked */
        !           207: 
        !           208:        IFDEBUG(D_ACKRECV)
        !           209:                printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n",
        !           210:                        seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat);
        !           211:        ENDDEBUG
        !           212:        IFTRACE(D_ACKRECV)
        !           213:                tptraceTPCB(TPPTgotack, 
        !           214:                        seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq); 
        !           215:        ENDTRACE
        !           216: 
        !           217:        IFPERF(tpcb)
        !           218:                tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0);
        !           219:        ENDPERF
        !           220: 
        !           221:        if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) {
        !           222:                /* discard the ack */
        !           223:                IFTRACE(D_ACKRECV)
        !           224:                        tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq",
        !           225:                                subseq, tpcb->tp_r_subseq, 0, 0);
        !           226:                ENDTRACE
        !           227:                return 0;
        !           228:        } else {
        !           229:                tpcb->tp_r_subseq = subseq;
        !           230:        }
        !           231: 
        !           232:        if ( IN_SWINDOW(tpcb, seq, 
        !           233:                        tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) {
        !           234: 
        !           235:                IFDEBUG(D_XPD)
        !           236:                        dump_mbuf(tpcb->tp_sock->so_snd.sb_mb, 
        !           237:                                "tp_goodack snd before sbdrop");
        !           238:                ENDDEBUG
        !           239:                tp_sbdrop(tpcb, SEQ_SUB(tpcb, seq, 1) );
        !           240: 
        !           241:                /* increase congestion window but don't let it get too big */
        !           242:                {
        !           243:                        register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf;
        !           244:                        CONG_ACK(tpcb, seq);
        !           245:                }
        !           246: 
        !           247:                /* Compute smoothed round trip time.
        !           248:                 * Only measure rtt for tp_snduna if tp_snduna was among 
        !           249:                 * the last TP_RTT_NUM seq numbers sent, and if the data
        !           250:                 * were not retransmitted.
        !           251:                 */
        !           252:                if (SEQ_GEQ(tpcb, tpcb->tp_snduna, 
        !           253:                        SEQ(tpcb, tpcb->tp_sndhiwat - TP_RTT_NUM))
        !           254:                        && SEQ_GT(tpcb, seq, SEQ_ADD(tpcb, tpcb->tp_retrans_hiwat, 1))) {
        !           255: 
        !           256:                        struct timeval *t = &tpcb->tp_rttemit[tpcb->tp_snduna & TP_RTT_NUM];
        !           257:                        struct timeval x;
        !           258: 
        !           259:                        GET_TIME_SINCE(t, &x);
        !           260: 
        !           261:                        tp_rtt_rtv( &(tpcb->tp_rtt), &(tpcb->tp_rtv), &x );
        !           262: 
        !           263:                        {       /* update the global rtt, rtv stats */
        !           264:                                register int i =
        !           265:                                   (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN);
        !           266:                                tp_rtt_rtv( &(tp_stat.ts_rtt[i]), &(tp_stat.ts_rtv[i]), &x );
        !           267: 
        !           268:                                IFTRACE(D_RTT)
        !           269:                                        tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0);
        !           270:                                ENDTRACE
        !           271:                        }
        !           272: 
        !           273:                        IFTRACE(D_RTT)
        !           274:                                tptraceTPCB(TPPTmisc, 
        !           275:                                "Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime",
        !           276:                                tpcb->tp_snduna, time.tv_sec, time.tv_usec,
        !           277:                                        tpcb->tp_peer_acktime);
        !           278: 
        !           279:                                tptraceTPCB(TPPTmisc, 
        !           280:                                "(secs): emittime diff(x) rtt, rtv",
        !           281:                                        t->tv_sec, 
        !           282:                                        x.tv_sec, 
        !           283:                                        tpcb->tp_rtt.tv_sec,
        !           284:                                        tpcb->tp_rtv.tv_sec);
        !           285:                                tptraceTPCB(TPPTmisc, 
        !           286:                                "(usecs): emittime diff(x) rtt rtv",
        !           287:                                        t->tv_usec, 
        !           288:                                        x.tv_usec, 
        !           289:                                        tpcb->tp_rtt.tv_usec,
        !           290:                                        tpcb->tp_rtv.tv_usec);
        !           291:                        ENDTRACE
        !           292: 
        !           293:                        {
        !           294:                                /* Update data retransmission timer based on the smoothed
        !           295:                                 * round trip time, peer ack time, and the pseudo-arbitrary
        !           296:                                 * number 4.
        !           297:                                 * new ticks: avg rtt + 2*dev
        !           298:                                 * rtt, rtv are in microsecs, and ticks are 500 ms
        !           299:                                 * so 1 tick = 500*1000 us = 500000 us
        !           300:                                 * so ticks = (rtt + 2 rtv)/500000
        !           301:                                 * with ticks no les than peer ack time and no less than 4
        !           302:                                 */
        !           303: 
        !           304:                                int rtt = tpcb->tp_rtt.tv_usec +
        !           305:                                        tpcb->tp_rtt.tv_sec*1000000;
        !           306:                                int rtv = tpcb->tp_rtv.tv_usec +
        !           307:                                        tpcb->tp_rtv.tv_sec*1000000;
        !           308: 
        !           309:                                IFTRACE(D_RTT)
        !           310:                                        tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks",
        !           311:                                                tpcb->tp_dt_ticks, 
        !           312:                                                rtv, rtt,
        !           313:                                                (rtt/500000 + (2 * rtv)/500000));
        !           314:                                ENDTRACE
        !           315:                                tpcb->tp_dt_ticks = (rtt+ (2 * rtv))/500000;
        !           316:                                tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, 
        !           317:                                        tpcb->tp_peer_acktime);
        !           318:                                tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks,  4);
        !           319:                        }
        !           320:                }
        !           321:                tpcb->tp_snduna = seq;
        !           322:                tpcb->tp_retrans = tpcb->tp_Nretrans; /* CE_BIT */
        !           323: 
        !           324:                bang++;
        !           325:        } 
        !           326: 
        !           327:        if( cdt != 0 && old_fcredit == 0 ) {
        !           328:                tpcb->tp_sendfcc = 1;
        !           329:        }
        !           330:        if( cdt == 0 && old_fcredit != 0 ) {
        !           331:                IncStat(ts_zfcdt);
        !           332:        }
        !           333:        tpcb->tp_fcredit = cdt;
        !           334: 
        !           335:        IFDEBUG(D_ACKRECV)
        !           336:                printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n",
        !           337:                        (bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit );
        !           338:        ENDDEBUG
        !           339: 
        !           340:        return (bang || (old_fcredit < cdt)) ;
        !           341: }
        !           342: 
        !           343: /*
        !           344:  * CALLED FROM:
        !           345:  *  tp_goodack()
        !           346:  * FUNCTION and ARGUMENTS:
        !           347:  *  drops everything up TO and INCLUDING seq # (seq)
        !           348:  *  from the retransmission queue.
        !           349:  */
        !           350: static void
        !           351: tp_sbdrop(tpcb, seq) 
        !           352:        struct  tp_pcb                  *tpcb;
        !           353:        SeqNum                                  seq;
        !           354: {
        !           355:        register struct tp_rtc  *s = tpcb->tp_snduna_rtc;
        !           356: 
        !           357:        IFDEBUG(D_ACKRECV)
        !           358:                printf("tp_sbdrop up through seq 0x%x\n", seq);
        !           359:        ENDDEBUG
        !           360:        while (s != (struct tp_rtc *)0 && (SEQ_LEQ(tpcb, s->tprt_seq, seq))) {
        !           361:                m_freem( s->tprt_data );
        !           362:                tpcb->tp_snduna_rtc = s->tprt_next;
        !           363:                (void) m_free( dtom( s ) );
        !           364:                s = tpcb->tp_snduna_rtc;
        !           365:        }
        !           366:        if(tpcb->tp_snduna_rtc == (struct tp_rtc *)0)
        !           367:                tpcb->tp_sndhiwat_rtc = (struct tp_rtc *) 0;
        !           368: 
        !           369: }
        !           370: 
        !           371: /*
        !           372:  * CALLED FROM:
        !           373:  *     tp.trans on user send request, arrival of AK and arrival of XAK
        !           374:  * FUNCTION and ARGUMENTS:
        !           375:  *     Emits tpdus starting at sequence number (lowseq).
        !           376:  *     Emits until a) runs out of data, or  b) runs into an XPD mark, or
        !           377:  *                     c) it hits seq number (highseq)
        !           378:  *     Removes the octets from the front of the socket buffer 
        !           379:  *     and repackages them in one mbuf chain per tpdu.
        !           380:  *     Moves the mbuf chain to the doubly linked list that runs from
        !           381:  *     tpcb->tp_sndhiwat_rtc to tpcb->tp_snduna_rtc.
        !           382:  *
        !           383:  *     Creates tpdus that are no larger than <tpcb->tp_l_tpdusize - headersize>,
        !           384:  *
        !           385:  *     If you want XPD to buffer > 1 du per socket buffer, you can
        !           386:  *     modifiy this to issue XPD tpdus also, but then it'll have
        !           387:  *     to take some argument(s) to distinguish between the type of DU to
        !           388:  *     hand tp_emit, the socket buffer from which to get the data, and
        !           389:  *     the chain of tp_rtc structures on which to put the data sent.
        !           390:  *
        !           391:  *     When something is sent for the first time, its time-of-send
        !           392:  *     is stashed (the last RTT_NUM of them are stashed).  When the
        !           393:  *     ack arrives, the smoothed round-trip time is figured using this value.
        !           394:  * RETURN VALUE:
        !           395:  *     the highest seq # sent successfully.
        !           396:  */
        !           397: tp_send(tpcb)
        !           398:        register struct tp_pcb  *tpcb;
        !           399: {
        !           400:        register int                    len;
        !           401:        register struct mbuf    *m; /* the one we're inspecting now */
        !           402:        struct mbuf                             *mb;/* beginning of this tpdu */
        !           403:        struct mbuf                     *nextrecord; /* NOT next tpdu but next sb record */
        !           404:        struct  sockbuf                 *sb = &tpcb->tp_sock->so_snd;
        !           405:        int                                             maxsize = tpcb->tp_l_tpdusize 
        !           406:                                                                                - tp_headersize(DT_TPDU_type, tpcb)
        !           407:                                                                                - (tpcb->tp_use_checksum?4:0) ;
        !           408:        unsigned int                    eotsdu_reached=0;
        !           409:        SeqNum                                  lowseq, highseq ;
        !           410:        SeqNum                                  lowsave; 
        !           411: #ifdef TP_PERF_MEAS
        !           412:        struct timeval                  send_start_time;
        !           413: #endif TP_PERF_MEAS
        !           414: 
        !           415:        lowsave =  lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1);
        !           416: 
        !           417:        ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff);
        !           418: 
        !           419:        if( tpcb->tp_rx_strat & TPRX_USE_CW ) {
        !           420:                        /*first hiseq is temp vbl*/
        !           421:                highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win); 
        !           422:        } else {
        !           423:                highseq = tpcb->tp_fcredit;
        !           424:        }
        !           425:        highseq = SEQ(tpcb, tpcb->tp_snduna + highseq);
        !           426:                
        !           427:        SEQ_DEC(tpcb, highseq);
        !           428: 
        !           429:        IFDEBUG(D_DATA)
        !           430:                printf( 
        !           431:                        "tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n",
        !           432:                        tpcb, lowseq, highseq);
        !           433:                dump_mbuf(sb->sb_mb, "sb_mb:");
        !           434:        ENDDEBUG
        !           435:        IFTRACE(D_DATA)
        !           436:                tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna", 
        !           437:                        lowsave, tpcb->tp_sndhiwat,  tpcb->tp_snduna, 0);
        !           438:                tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin", 
        !           439:                        lowseq, highseq, tpcb->tp_fcredit,  tpcb->tp_cong_win);
        !           440:        ENDTRACE
        !           441: 
        !           442: 
        !           443:        if      ( SEQ_GT(tpcb, lowseq, highseq) )
        !           444:                        return ; /* don't send, don't change hiwat, don't set timers */
        !           445: 
        !           446:        IFPERF(tpcb)
        !           447:                GET_CUR_TIME(&send_start_time);
        !           448:        ENDPERF
        !           449: 
        !           450:        ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) );
        !           451:        SEQ_DEC(tpcb, lowseq);
        !           452: 
        !           453:        IFTRACE(D_DATA)
        !           454:                tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin", 
        !           455:                        lowseq, highseq, tpcb->tp_fcredit,  tpcb->tp_cong_win);
        !           456:        ENDTRACE
        !           457: 
        !           458:        while ((SEQ_LT(tpcb, lowseq, highseq)) && (mb = m = sb->sb_mb)) {
        !           459:                if (tpcb->tp_Xsnd.sb_mb) {
        !           460:                        IFTRACE(D_XPD)
        !           461:                                tptraceTPCB( TPPTmisc,
        !           462:                                        "tp_send XPD mark low high tpcb.Xuna", 
        !           463:                                        lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0);
        !           464:                        ENDTRACE
        !           465:                        /* stop sending here because there are unacked XPD which were 
        !           466:                         * given to us before the next data were.
        !           467:                         */
        !           468:                        IncStat(ts_xpd_intheway);
        !           469:                        break;
        !           470:                }
        !           471:                eotsdu_reached = 0;
        !           472:                nextrecord = m->m_act;
        !           473:                for (len = 0; m; m = m->m_next) {
        !           474:                        len += m->m_len; 
        !           475:                        if (m->m_flags & M_EOR)
        !           476:                                eotsdu_reached = 1;
        !           477:                        sbfree(sb, m); /* reduce counts in socket buffer */
        !           478:                }
        !           479:                sb->sb_mb = nextrecord;
        !           480:                IFTRACE(D_STASH)
        !           481:                        tptraceTPCB(TPPTmisc, "tp_send whole mbuf: m_len len maxsize",
        !           482:                                 0, mb->m_len, len, maxsize);
        !           483:                ENDTRACE
        !           484: 
        !           485:                if ( len == 0 && !eotsdu_reached) {
        !           486:                        /* THIS SHOULD NEVER HAPPEN! */
        !           487:                        ASSERT( 0 );
        !           488:                        goto done;
        !           489:                }
        !           490: 
        !           491:                /* If we arrive here one of the following holds:
        !           492:                 * 1. We have exactly <maxsize> octets of whole mbufs,
        !           493:                 * 2. We accumulated <maxsize> octets using partial mbufs,
        !           494:                 * 3. We found an TPMT_EOT or an XPD mark 
        !           495:                 * 4. We hit the end of a chain through m_next.
        !           496:                 *    In this case, we'd LIKE to continue with the next record,
        !           497:                 *    but for the time being, for simplicity, we'll stop here.
        !           498:                 * In all cases, m points to mbuf containing first octet to be
        !           499:                 * sent in the tpdu AFTER the one we're going to send now,
        !           500:                 * or else m is null.
        !           501:                 *
        !           502:                 * The chain we're working on now begins at mb and has length <len>.
        !           503:                 */
        !           504: 
        !           505:                IFTRACE(D_STASH)
        !           506:                        tptraceTPCB( TPPTmisc, 
        !           507:                                "tp_send mcopy low high eotsdu_reached len", 
        !           508:                                lowseq, highseq, eotsdu_reached, len);
        !           509:                ENDTRACE
        !           510: 
        !           511:                /* make a copy - mb goes into the retransmission list 
        !           512:                 * while m gets emitted.  m_copy won't copy a zero-length mbuf.
        !           513:                 */
        !           514:                if (len) {
        !           515:                        if ((m = m_copy(mb, 0, len )) == MNULL)
        !           516:                                goto done;
        !           517:                } else {
        !           518:                        /* eotsdu reached */
        !           519:                        MGET(m, M_WAIT, TPMT_DATA);
        !           520:                        if (m == MNULL)
        !           521:                                goto done;
        !           522:                        m->m_len = 0;
        !           523:                }
        !           524: 
        !           525:                SEQ_INC(tpcb,lowseq);   /* it was decremented at the beginning */
        !           526:                {
        !           527:                        struct tp_rtc *t;
        !           528:                        /* make an rtc and put it at the end of the chain */
        !           529: 
        !           530:                        TP_MAKE_RTC( t, lowseq, eotsdu_reached, mb, len, lowseq, 
        !           531:                                TPMT_SNDRTC);
        !           532:                        t->tprt_next = (struct tp_rtc *)0;
        !           533: 
        !           534:                        if ( tpcb->tp_sndhiwat_rtc != (struct tp_rtc *)0 )
        !           535:                                tpcb->tp_sndhiwat_rtc->tprt_next = t;
        !           536:                        else {
        !           537:                                ASSERT( tpcb->tp_snduna_rtc == (struct tp_rtc *)0 );
        !           538:                                tpcb->tp_snduna_rtc = t;
        !           539:                        }
        !           540: 
        !           541:                        tpcb->tp_sndhiwat_rtc = t;
        !           542:                }
        !           543: 
        !           544:                IFTRACE(D_DATA)
        !           545:                        tptraceTPCB( TPPTmisc, 
        !           546:                                "tp_send emitting DT lowseq eotsdu_reached len",
        !           547:                                lowseq, eotsdu_reached, len, 0);
        !           548:                ENDTRACE
        !           549:                if( tpcb->tp_sock->so_error =
        !           550:                        tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m) )  {
        !           551:                        /* error */
        !           552:                        SEQ_DEC(tpcb, lowseq); 
        !           553:                        goto done;
        !           554:                }
        !           555:                /* set the transmit-time for computation of round-trip times */
        !           556:                bcopy( (caddr_t)&time, 
        !           557:                                (caddr_t)&( tpcb->tp_rttemit[ lowseq & TP_RTT_NUM ] ), 
        !           558:                                sizeof(struct timeval));
        !           559: 
        !           560:        }
        !           561: 
        !           562: done:
        !           563:        IFPERF(tpcb)
        !           564:                {
        !           565:                        register int npkts;
        !           566:                        struct timeval send_end_time;
        !           567:                        register struct timeval *t;
        !           568: 
        !           569:                        npkts = lowseq;
        !           570:                        SEQ_INC(tpcb, npkts);
        !           571:                        npkts = SEQ_SUB(tpcb, npkts, lowsave);
        !           572: 
        !           573:                        if(npkts > 0) 
        !           574:                                tpcb->tp_Nwindow++;
        !           575: 
        !           576:                        if (npkts > TP_PM_MAX) 
        !           577:                                npkts = TP_PM_MAX; 
        !           578: 
        !           579:                        GET_TIME_SINCE(&send_start_time, &send_end_time);
        !           580:                        t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
        !           581:                        t->tv_sec =
        !           582:                                SMOOTH( long, TP_RTT_ALPHA, t->tv_sec, send_end_time.tv_sec);
        !           583:                        t->tv_usec =
        !           584:                                SMOOTH( long, TP_RTT_ALPHA, t->tv_usec, send_end_time.tv_usec);
        !           585: 
        !           586:                        if ( SEQ_LT(tpcb, lowseq, highseq) ) {
        !           587:                                IncPStat(tpcb, tps_win_lim_by_data[npkts] );
        !           588:                        } else {
        !           589:                                IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
        !           590:                                /* not true with congestion-window being used */
        !           591:                        }
        !           592:                        tpmeas( tpcb->tp_lref, 
        !           593:                                        TPsbsend, &send_end_time, lowsave, tpcb->tp_Nwindow, npkts);
        !           594:                }
        !           595:        ENDPERF
        !           596: 
        !           597:        tpcb->tp_sndhiwat = lowseq;
        !           598: 
        !           599:        if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat)  && 
        !           600:                        (tpcb->tp_class != TP_CLASS_0) ) 
        !           601:                        tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave, 
        !           602:                                tpcb->tp_sndhiwat,
        !           603:                                (u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks);
        !           604:        IFTRACE(D_DATA)
        !           605:                tptraceTPCB( TPPTmisc, 
        !           606:                        "tp_send at end: sndhiwat lowseq eotsdu_reached error",
        !           607:                        tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error);
        !           608:                
        !           609:        ENDTRACE
        !           610: }
        !           611: 
        !           612: /*
        !           613:  * NAME: tp_stash()
        !           614:  * CALLED FROM:
        !           615:  *     tp.trans on arrival of a DT tpdu
        !           616:  * FUNCTION, ARGUMENTS, and RETURN VALUE:
        !           617:  *     Returns 1 if 
        !           618:  *             a) something new arrived and it's got eotsdu_reached bit on,
        !           619:  *             b) this arrival was caused other out-of-sequence things to be
        !           620:  *     accepted, or
        !           621:  *             c) this arrival is the highest seq # for which we last gave credit
        !           622:  *     (sender just sent a whole window)
        !           623:  *  In other words, returns 1 if tp should send an ack immediately, 0 if 
        !           624:  *  the ack can wait a while.
        !           625:  *
        !           626:  * Note: this implementation no longer renegs on credit, (except
        !           627:  * when debugging option D_RENEG is on, for the purpose of testing
        !           628:  * ack subsequencing), so we don't  need to check for incoming tpdus 
        !           629:  * being in a reneged portion of the window.
        !           630:  */
        !           631: 
        !           632: int
        !           633: tp_stash( tpcb, e )
        !           634:        register struct tp_pcb          *tpcb;
        !           635:        register struct tp_event        *e;
        !           636: {
        !           637:        register int            ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
        !           638:                                                                        /* 0--> delay acks until full window */
        !           639:                                                                        /* 1--> ack each tpdu */
        !           640:        int             newrec = 0;
        !           641: 
        !           642: #ifndef lint
        !           643: #define E e->ATTR(DT_TPDU)
        !           644: #else lint
        !           645: #define E e->ev_union.EV_DT_TPDU
        !           646: #endif lint
        !           647: 
        !           648:        if ( E.e_eot ) {
        !           649:                register struct mbuf *n = E.e_data;
        !           650:                n->m_flags |= M_EOR;
        !           651:                n->m_act = 0;
        !           652:        }
        !           653:                IFDEBUG(D_STASH)
        !           654:                        dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 
        !           655:                                "stash: so_rcv before appending");
        !           656:                        dump_mbuf(E.e_data,
        !           657:                                "stash: e_data before appending");
        !           658:                ENDDEBUG
        !           659: 
        !           660:        IFPERF(tpcb)
        !           661:                PStat(tpcb, Nb_from_ll) += E.e_datalen;
        !           662:                tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
        !           663:                        E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen);
        !           664:        ENDPERF
        !           665: 
        !           666:        if( E.e_seq == tpcb->tp_rcvnxt ) {
        !           667: 
        !           668:                IFDEBUG(D_STASH)
        !           669:                        printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 
        !           670:                        E.e_seq, E.e_datalen, E.e_eot);
        !           671:                ENDDEBUG
        !           672: 
        !           673:                IFTRACE(D_STASH)
        !           674:                        tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 
        !           675:                        E.e_seq, E.e_datalen, E.e_eot, 0);
        !           676:                ENDTRACE
        !           677: 
        !           678:                sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
        !           679: 
        !           680:                if (newrec = E.e_eot ) /* ASSIGNMENT */
        !           681:                        ack_reason |= ACK_EOT;
        !           682: 
        !           683:                SEQ_INC( tpcb, tpcb->tp_rcvnxt );
        !           684:                /* 
        !           685:                 * move chains from the rtc list to the socket buffer
        !           686:                 * and free the rtc header
        !           687:                 */
        !           688:                {
        !           689:                        register struct tp_rtc  **r =  &tpcb->tp_rcvnxt_rtc;
        !           690:                        register struct tp_rtc  *s = tpcb->tp_rcvnxt_rtc;
        !           691: 
        !           692:                        while (s != (struct tp_rtc *)0 && s->tprt_seq == tpcb->tp_rcvnxt) {
        !           693:                                *r = s->tprt_next;
        !           694: 
        !           695:                                sbappend(&tpcb->tp_sock->so_rcv, s->tprt_data);
        !           696: 
        !           697:                                SEQ_INC( tpcb, tpcb->tp_rcvnxt );
        !           698: 
        !           699:                                (void) m_free( dtom( s ) );
        !           700:                                s = *r;
        !           701:                                ack_reason |= ACK_REORDER;
        !           702:                        }
        !           703:                }
        !           704:                IFDEBUG(D_STASH)
        !           705:                        dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 
        !           706:                                "stash: so_rcv after appending");
        !           707:                ENDDEBUG
        !           708: 
        !           709:        } else {
        !           710:                register struct tp_rtc **s = &tpcb->tp_rcvnxt_rtc;
        !           711:                register struct tp_rtc *r = tpcb->tp_rcvnxt_rtc;
        !           712:                register struct tp_rtc *t;
        !           713: 
        !           714:                IFTRACE(D_STASH)
        !           715:                        tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 
        !           716:                        E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
        !           717:                ENDTRACE
        !           718: 
        !           719:                r = tpcb->tp_rcvnxt_rtc;
        !           720:                while (r != (struct tp_rtc *)0  && SEQ_LT(tpcb, r->tprt_seq, E.e_seq)) {
        !           721:                        s = &r->tprt_next;
        !           722:                        r = r->tprt_next;
        !           723:                }
        !           724: 
        !           725:                if (r == (struct tp_rtc *)0 || SEQ_GT(tpcb, r->tprt_seq, E.e_seq) ) {
        !           726:                        IncStat(ts_dt_ooo);
        !           727: 
        !           728:                        IFTRACE(D_STASH)
        !           729:                                tptrace(TPPTmisc,
        !           730:                                "tp_stash OUT OF ORDER- MAKE RTC: seq, 1st seq in list\n",
        !           731:                                        E.e_seq, r->tprt_seq,0,0);
        !           732:                        ENDTRACE
        !           733:                        IFDEBUG(D_STASH)
        !           734:                                printf("tp_stash OUT OF ORDER- MAKE RTC\n");
        !           735:                        ENDDEBUG
        !           736:                        TP_MAKE_RTC(t, E.e_seq, E.e_eot, E.e_data, E.e_datalen, 0,
        !           737:                                TPMT_RCVRTC);
        !           738: 
        !           739:                        *s = t;
        !           740:                        t->tprt_next = (struct tp_rtc *)r;
        !           741:                        ack_reason = ACK_DONT;
        !           742:                        goto done;
        !           743:                } else {
        !           744:                        IFDEBUG(D_STASH)
        !           745:                                printf("tp_stash - drop & ack\n");
        !           746:                        ENDDEBUG
        !           747: 
        !           748:                        /* retransmission - drop it and force an ack */
        !           749:                        IncStat(ts_dt_dup);
        !           750:                        IFPERF(tpcb)
        !           751:                                IncPStat(tpcb, tps_n_ack_cuz_dup);
        !           752:                        ENDPERF
        !           753: 
        !           754:                        m_freem( E.e_data );
        !           755:                        ack_reason |= ACK_DUP;
        !           756:                        goto done;
        !           757:                }
        !           758:        }
        !           759: 
        !           760: 
        !           761:        /*
        !           762:         * an ack should be sent when at least one of the
        !           763:         * following holds:
        !           764:         * a) we've received a TPDU with EOTSDU set
        !           765:         * b) the TPDU that just arrived represents the
        !           766:         *    full window last advertised, or
        !           767:         * c) when seq X arrives [ where
        !           768:         *              X = last_sent_uwe - 1/2 last_lcredit_sent 
        !           769:         *              (the packet representing 1/2 the last advertised window) ]
        !           770:         *              and lcredit at the time of X arrival >  last_lcredit_sent/2
        !           771:         *              In other words, if the last ack sent advertised cdt=8 and uwe = 8
        !           772:         *              then when seq 4 arrives I'd like to send a new ack
        !           773:         *              iff the credit at the time of 4's arrival is > 4.
        !           774:         *              The other end thinks it has cdt of 4 so if local cdt
        !           775:         *              is still 4 there's no point in sending an ack, but if
        !           776:         *              my credit has increased because the receiver has taken
        !           777:         *              some data out of the buffer (soreceive doesn't notify
        !           778:         *              me until the SYSTEM CALL finishes), I'd like to tell
        !           779:         *              the other end.  
        !           780:         */
        !           781: 
        !           782: done:
        !           783:        {
        !           784:                LOCAL_CREDIT(tpcb);
        !           785: 
        !           786:                if ( E.e_seq ==  tpcb->tp_sent_uwe )
        !           787:                        ack_reason |= ACK_STRAT_FULLWIN;
        !           788: 
        !           789:                IFTRACE(D_STASH)
        !           790:                        tptraceTPCB(TPPTmisc, 
        !           791:                                "end of stash, eot, ack_reason, sent_uwe ",
        !           792:                                E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 
        !           793:                ENDTRACE
        !           794: 
        !           795:                if ( ack_reason == ACK_DONT ) {
        !           796:                        IncStat( ts_ackreason[ACK_DONT] );
        !           797:                        return 0;
        !           798:                } else {
        !           799:                        IFPERF(tpcb)
        !           800:                                if(ack_reason & ACK_EOT) {
        !           801:                                        IncPStat(tpcb, tps_n_ack_cuz_eot);
        !           802:                                } 
        !           803:                                if(ack_reason & ACK_STRAT_EACH) {
        !           804:                                        IncPStat(tpcb, tps_n_ack_cuz_strat);
        !           805:                                } else if(ack_reason & ACK_STRAT_FULLWIN) {
        !           806:                                        IncPStat(tpcb, tps_n_ack_cuz_fullwin);
        !           807:                                } else if(ack_reason & ACK_REORDER) {
        !           808:                                        IncPStat(tpcb, tps_n_ack_cuz_reorder);
        !           809:                                }
        !           810:                                tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 
        !           811:                                                        SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
        !           812:                        ENDPERF
        !           813:                        {
        !           814:                                register int i;
        !           815: 
        !           816:                                /* keep track of all reasons that apply */
        !           817:                                for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
        !           818:                                        if( ack_reason & (1<<i) ) 
        !           819:                                                IncStat( ts_ackreason[i] );
        !           820:                                }
        !           821:                        }
        !           822:                        return 1;
        !           823:                }
        !           824:        }
        !           825: }
        !           826: 
        !           827: /* class zero version */
        !           828: void
        !           829: tp0_stash( tpcb, e )
        !           830:        register struct tp_pcb          *tpcb;
        !           831:        register struct tp_event        *e;
        !           832: {
        !           833: #ifndef lint
        !           834: #define E e->ATTR(DT_TPDU)
        !           835: #else lint
        !           836: #define E e->ev_union.EV_DT_TPDU
        !           837: #endif lint
        !           838: 
        !           839:        IFPERF(tpcb)
        !           840:                PStat(tpcb, Nb_from_ll) += E.e_datalen;
        !           841:                tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
        !           842:                                E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
        !           843:        ENDPERF
        !           844: 
        !           845:        IFDEBUG(D_STASH)
        !           846:                printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", 
        !           847:                E.e_seq, E.e_datalen, E.e_eot);
        !           848:        ENDDEBUG
        !           849: 
        !           850:        IFTRACE(D_STASH)
        !           851:                tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 
        !           852:                E.e_seq, E.e_datalen, E.e_eot, 0);
        !           853:        ENDTRACE
        !           854: 
        !           855:        if ( E.e_eot ) {
        !           856:                register struct mbuf *n = E.e_data;
        !           857:                n->m_flags |= M_EOR;
        !           858:                n->m_act = MNULL; /* set on tp_input */
        !           859:        }
        !           860:        sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
        !           861:        IFDEBUG(D_STASH)
        !           862:                dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 
        !           863:                        "stash 0: so_rcv after appending");
        !           864:        ENDDEBUG
        !           865: } 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.