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