149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*50901Ssklower * @(#)tp_subr.c 7.11 (Berkeley) 08/28/91 849268Sbostic */ 949268Sbostic 1036413Ssklower /*********************************************************** 1136413Ssklower Copyright IBM Corporation 1987 1236413Ssklower 1336413Ssklower All Rights Reserved 1436413Ssklower 1536413Ssklower Permission to use, copy, modify, and distribute this software and its 1636413Ssklower documentation for any purpose and without fee is hereby granted, 1736413Ssklower provided that the above copyright notice appear in all copies and that 1836413Ssklower both that copyright notice and this permission notice appear in 1936413Ssklower supporting documentation, and that the name of IBM not be 2036413Ssklower used in advertising or publicity pertaining to distribution of the 2136413Ssklower software without specific, written prior permission. 2236413Ssklower 2336413Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436413Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536413Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636413Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736413Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836413Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936413Ssklower SOFTWARE. 3036413Ssklower 3136413Ssklower ******************************************************************/ 3236413Ssklower 3336413Ssklower /* 3436413Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536413Ssklower */ 3636413Ssklower /* 3736413Ssklower * ARGO TP 3836413Ssklower * 3936413Ssklower * $Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $ 4036413Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_subr.c,v $ 4136413Ssklower * 4236413Ssklower * The main work of data transfer is done here. 4336413Ssklower * These routines are called from tp.trans. 4436413Ssklower * They include the routines that check the validity of acks and Xacks, 4536413Ssklower * (tp_goodack() and tp_goodXack() ) 4636413Ssklower * take packets from socket buffers and send them (tp_send()), 4736413Ssklower * drop the data from the socket buffers (tp_sbdrop()), 4836413Ssklower * and put incoming packet data into socket buffers (tp_stash()). 4936413Ssklower */ 5036413Ssklower 5136413Ssklower #include "param.h" 5236413Ssklower #include "mbuf.h" 5336413Ssklower #include "socket.h" 5436413Ssklower #include "socketvar.h" 5536413Ssklower #include "protosw.h" 5636413Ssklower #include "errno.h" 5736413Ssklower #include "types.h" 5836413Ssklower #include "time.h" 5936413Ssklower 6037469Ssklower #include "tp_ip.h" 6137469Ssklower #include "iso.h" 6237469Ssklower #include "argo_debug.h" 6337469Ssklower #include "tp_timer.h" 6437469Ssklower #include "tp_param.h" 6537469Ssklower #include "tp_stat.h" 6637469Ssklower #include "tp_pcb.h" 6737469Ssklower #include "tp_tpdu.h" 6837469Ssklower #include "tp_trace.h" 6937469Ssklower #include "tp_meas.h" 7037469Ssklower #include "tp_seq.h" 7136413Ssklower 7236413Ssklower int tp_emit(); 7336413Ssklower static void tp_sbdrop(); 7436413Ssklower 7536413Ssklower #define SMOOTH(newtype, alpha, old, new) \ 7636413Ssklower (newtype) (((new - old)>>alpha) + (old)) 7736413Ssklower 7836413Ssklower #define ABS(type, val) \ 7936413Ssklower (type) (((int)(val)<0)?-(val):(val)) 8036413Ssklower 8136413Ssklower 8236413Ssklower /* 8336413Ssklower * CALLED FROM: 8436413Ssklower * tp.trans, when an XAK arrives 8536413Ssklower * FUNCTION and ARGUMENTS: 8636413Ssklower * Determines if the sequence number (seq) from the XAK 8736413Ssklower * acks anything new. If so, drop the appropriate tpdu 8836413Ssklower * from the XPD send queue. 8936413Ssklower * RETURN VALUE: 9036413Ssklower * Returns 1 if it did this, 0 if the ack caused no action. 9136413Ssklower */ 9236413Ssklower int 9336413Ssklower tp_goodXack(tpcb, seq) 9436413Ssklower struct tp_pcb *tpcb; 9536413Ssklower SeqNum seq; 9636413Ssklower { 9736413Ssklower 9836413Ssklower IFTRACE(D_XPD) 9936413Ssklower tptraceTPCB(TPPTgotXack, 10036413Ssklower seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat, 10136413Ssklower tpcb->tp_snduna); 10236413Ssklower ENDTRACE 10336413Ssklower 10436413Ssklower if ( seq == tpcb->tp_Xuna ) { 10536413Ssklower tpcb->tp_Xuna = tpcb->tp_Xsndnxt; 10636413Ssklower 10736413Ssklower /* DROP 1 packet from the Xsnd socket buf - just so happens 10836413Ssklower * that only one packet can be there at any time 10936413Ssklower * so drop the whole thing. If you allow > 1 packet 11036413Ssklower * the socket buffer, then you'll have to keep 11136413Ssklower * track of how many characters went w/ each XPD tpdu, so this 11236413Ssklower * will get messier 11336413Ssklower */ 11436413Ssklower IFDEBUG(D_XPD) 11536413Ssklower dump_mbuf(tpcb->tp_Xsnd.sb_mb, 11636413Ssklower "tp_goodXack Xsnd before sbdrop"); 11736413Ssklower ENDDEBUG 11836413Ssklower 11936413Ssklower IFTRACE(D_XPD) 12036413Ssklower tptraceTPCB(TPPTmisc, 12136413Ssklower "goodXack: dropping cc ", 12236413Ssklower (int)(tpcb->tp_Xsnd.sb_cc), 12336413Ssklower 0,0,0); 12436413Ssklower ENDTRACE 12536413Ssklower sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc)); 12639922Ssklower CONG_ACK(tpcb, seq); 12736413Ssklower return 1; 12836413Ssklower } 12936413Ssklower return 0; 13036413Ssklower } 13136413Ssklower 13236413Ssklower /* 13336413Ssklower * CALLED FROM: 13436413Ssklower * tp_good_ack() 13536413Ssklower * FUNCTION and ARGUMENTS: 13636413Ssklower * updates 13736413Ssklower * smoothed average round trip time (base_rtt) 13836413Ssklower * roundtrip time variance (base_rtv) - actually deviation, not variance 13936413Ssklower * given the new value (diff) 14036413Ssklower * RETURN VALUE: 14136413Ssklower * void 14236413Ssklower */ 14336413Ssklower 14436413Ssklower void 14536413Ssklower tp_rtt_rtv( base_rtt, base_rtv, newmeas ) 14636413Ssklower struct timeval *base_rtt, *base_rtv, *newmeas; 14736413Ssklower { 14836413Ssklower /* update rt variance (really just the deviation): 14936413Ssklower * rtv.smooth_ave = SMOOTH( | oldrtt.smooth_avg - rtt.this_instance | ) 15036413Ssklower */ 15136413Ssklower base_rtv->tv_sec = 15236413Ssklower SMOOTH( long, TP_RTV_ALPHA, base_rtv->tv_sec, 15344948Ssklower ABS( long, base_rtt->tv_sec - newmeas->tv_sec )); 15436413Ssklower base_rtv->tv_usec = 15536413Ssklower SMOOTH( long, TP_RTV_ALPHA, base_rtv->tv_usec, 15644948Ssklower ABS(long, base_rtt->tv_usec - newmeas->tv_usec )); 15736413Ssklower 15836413Ssklower /* update smoothed average rtt */ 15936413Ssklower base_rtt->tv_sec = 16036413Ssklower SMOOTH( long, TP_RTT_ALPHA, base_rtt->tv_sec, newmeas->tv_sec); 16136413Ssklower base_rtt->tv_usec = 16236413Ssklower SMOOTH( long, TP_RTT_ALPHA, base_rtt->tv_usec, newmeas->tv_usec); 16336413Ssklower 16436413Ssklower } 16536413Ssklower 16636413Ssklower /* 16736413Ssklower * CALLED FROM: 16836413Ssklower * tp.trans when an AK arrives 16936413Ssklower * FUNCTION and ARGUMENTS: 17036413Ssklower * Given (cdt), the credit from the AK tpdu, and 17136413Ssklower * (seq), the sequence number from the AK tpdu, 17236413Ssklower * tp_goodack() determines if the AK acknowledges something in the send 17336413Ssklower * window, and if so, drops the appropriate packets from the retransmission 17436413Ssklower * list, computes the round trip time, and updates the retransmission timer 17536413Ssklower * based on the new smoothed round trip time. 17636413Ssklower * RETURN VALUE: 17736413Ssklower * Returns 1 if 17836413Ssklower * EITHER it actually acked something heretofore unacknowledged 17936413Ssklower * OR no news but the credit should be processed. 18036413Ssklower * If something heretofore unacked was acked with this sequence number, 18136413Ssklower * the appropriate tpdus are dropped from the retransmission control list, 18236413Ssklower * by calling tp_sbdrop(). 18336413Ssklower * No need to see the tpdu itself. 18436413Ssklower */ 18536413Ssklower int 18636413Ssklower tp_goodack(tpcb, cdt, seq, subseq) 18736413Ssklower register struct tp_pcb *tpcb; 18836413Ssklower u_int cdt; 18936413Ssklower register SeqNum seq, subseq; 19036413Ssklower { 19136413Ssklower int old_fcredit = tpcb->tp_fcredit; 19236413Ssklower int bang = 0; /* bang --> ack for something heretofore unacked */ 19336413Ssklower 19436413Ssklower IFDEBUG(D_ACKRECV) 19536413Ssklower printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n", 19636413Ssklower seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat); 19736413Ssklower ENDDEBUG 19836413Ssklower IFTRACE(D_ACKRECV) 19936413Ssklower tptraceTPCB(TPPTgotack, 20036413Ssklower seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq); 20136413Ssklower ENDTRACE 20236413Ssklower 20336413Ssklower IFPERF(tpcb) 20437469Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); 20536413Ssklower ENDPERF 20636413Ssklower 20736413Ssklower if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) { 20836413Ssklower /* discard the ack */ 20936413Ssklower IFTRACE(D_ACKRECV) 21036413Ssklower tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq", 21136413Ssklower subseq, tpcb->tp_r_subseq, 0, 0); 21236413Ssklower ENDTRACE 21336413Ssklower return 0; 21436413Ssklower } else { 21536413Ssklower tpcb->tp_r_subseq = subseq; 21636413Ssklower } 21736413Ssklower 21836413Ssklower if ( IN_SWINDOW(tpcb, seq, 21936413Ssklower tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) { 22036413Ssklower 22136413Ssklower IFDEBUG(D_XPD) 22236413Ssklower dump_mbuf(tpcb->tp_sock->so_snd.sb_mb, 22336413Ssklower "tp_goodack snd before sbdrop"); 22436413Ssklower ENDDEBUG 225*50901Ssklower tpsbcheck(tpcb, 0); 226*50901Ssklower tp_sbdrop(tpcb, seq); 227*50901Ssklower tpsbcheck(tpcb, 1); 22836413Ssklower 22936413Ssklower /* increase congestion window but don't let it get too big */ 23036413Ssklower { 23136413Ssklower register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf; 23239922Ssklower CONG_ACK(tpcb, seq); 23336413Ssklower } 23436413Ssklower 23536413Ssklower /* Compute smoothed round trip time. 23636413Ssklower * Only measure rtt for tp_snduna if tp_snduna was among 23739922Ssklower * the last TP_RTT_NUM seq numbers sent, and if the data 23839922Ssklower * were not retransmitted. 23936413Ssklower */ 24036413Ssklower if (SEQ_GEQ(tpcb, tpcb->tp_snduna, 24139922Ssklower SEQ(tpcb, tpcb->tp_sndhiwat - TP_RTT_NUM)) 24239922Ssklower && SEQ_GT(tpcb, seq, SEQ_ADD(tpcb, tpcb->tp_retrans_hiwat, 1))) { 24336413Ssklower 24436413Ssklower struct timeval *t = &tpcb->tp_rttemit[tpcb->tp_snduna & TP_RTT_NUM]; 24536413Ssklower struct timeval x; 24636413Ssklower 24736413Ssklower GET_TIME_SINCE(t, &x); 24836413Ssklower 24936413Ssklower tp_rtt_rtv( &(tpcb->tp_rtt), &(tpcb->tp_rtv), &x ); 25036413Ssklower 25136413Ssklower { /* update the global rtt, rtv stats */ 25236413Ssklower register int i = 25336413Ssklower (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); 25436413Ssklower tp_rtt_rtv( &(tp_stat.ts_rtt[i]), &(tp_stat.ts_rtv[i]), &x ); 25536413Ssklower 25636413Ssklower IFTRACE(D_RTT) 25736413Ssklower tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0); 25836413Ssklower ENDTRACE 25936413Ssklower } 26036413Ssklower 26136413Ssklower IFTRACE(D_RTT) 26236413Ssklower tptraceTPCB(TPPTmisc, 26336413Ssklower "Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime", 26436413Ssklower tpcb->tp_snduna, time.tv_sec, time.tv_usec, 26536413Ssklower tpcb->tp_peer_acktime); 26636413Ssklower 26736413Ssklower tptraceTPCB(TPPTmisc, 26836413Ssklower "(secs): emittime diff(x) rtt, rtv", 26936413Ssklower t->tv_sec, 27036413Ssklower x.tv_sec, 27136413Ssklower tpcb->tp_rtt.tv_sec, 27236413Ssklower tpcb->tp_rtv.tv_sec); 27336413Ssklower tptraceTPCB(TPPTmisc, 27436413Ssklower "(usecs): emittime diff(x) rtt rtv", 27536413Ssklower t->tv_usec, 27636413Ssklower x.tv_usec, 27736413Ssklower tpcb->tp_rtt.tv_usec, 27836413Ssklower tpcb->tp_rtv.tv_usec); 27936413Ssklower ENDTRACE 28036413Ssklower 28136413Ssklower { 28236413Ssklower /* Update data retransmission timer based on the smoothed 28336413Ssklower * round trip time, peer ack time, and the pseudo-arbitrary 28436413Ssklower * number 4. 28536413Ssklower * new ticks: avg rtt + 2*dev 28636413Ssklower * rtt, rtv are in microsecs, and ticks are 500 ms 28736413Ssklower * so 1 tick = 500*1000 us = 500000 us 28836413Ssklower * so ticks = (rtt + 2 rtv)/500000 28936413Ssklower * with ticks no les than peer ack time and no less than 4 29036413Ssklower */ 29136413Ssklower 29236413Ssklower int rtt = tpcb->tp_rtt.tv_usec + 29336413Ssklower tpcb->tp_rtt.tv_sec*1000000; 29436413Ssklower int rtv = tpcb->tp_rtv.tv_usec + 29536413Ssklower tpcb->tp_rtv.tv_sec*1000000; 29636413Ssklower 29736413Ssklower IFTRACE(D_RTT) 29836413Ssklower tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks", 29936413Ssklower tpcb->tp_dt_ticks, 30036413Ssklower rtv, rtt, 30136413Ssklower (rtt/500000 + (2 * rtv)/500000)); 30236413Ssklower ENDTRACE 30336413Ssklower tpcb->tp_dt_ticks = (rtt+ (2 * rtv))/500000; 30436413Ssklower tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, 30536413Ssklower tpcb->tp_peer_acktime); 30636413Ssklower tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, 4); 30736413Ssklower } 30836413Ssklower } 30936413Ssklower tpcb->tp_snduna = seq; 31039922Ssklower tpcb->tp_retrans = tpcb->tp_Nretrans; /* CE_BIT */ 31136413Ssklower 31236413Ssklower bang++; 31336413Ssklower } 31436413Ssklower 31536413Ssklower if( cdt != 0 && old_fcredit == 0 ) { 31636413Ssklower tpcb->tp_sendfcc = 1; 31736413Ssklower } 31836413Ssklower if( cdt == 0 && old_fcredit != 0 ) { 31936413Ssklower IncStat(ts_zfcdt); 32036413Ssklower } 32136413Ssklower tpcb->tp_fcredit = cdt; 32236413Ssklower 32336413Ssklower IFDEBUG(D_ACKRECV) 32436413Ssklower printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n", 32536413Ssklower (bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit ); 32636413Ssklower ENDDEBUG 32736413Ssklower 32836413Ssklower return (bang || (old_fcredit < cdt)) ; 32936413Ssklower } 33036413Ssklower 33136413Ssklower /* 33236413Ssklower * CALLED FROM: 33336413Ssklower * tp_goodack() 33436413Ssklower * FUNCTION and ARGUMENTS: 335*50901Ssklower * drops everything up TO but not INCLUDING seq # (seq) 33636413Ssklower * from the retransmission queue. 33736413Ssklower */ 33836413Ssklower static void 33936413Ssklower tp_sbdrop(tpcb, seq) 340*50901Ssklower register struct tp_pcb *tpcb; 34136413Ssklower SeqNum seq; 34236413Ssklower { 343*50901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 344*50901Ssklower register int i = ((int)seq)-((int)tpcb->tp_snduna); 34536413Ssklower 346*50901Ssklower if (i < 0) i += tpcb->tp_seqhalf; 34736413Ssklower IFDEBUG(D_ACKRECV) 348*50901Ssklower printf("tp_sbdroping %d up through seq 0x%x\n", i, seq); 34936413Ssklower ENDDEBUG 350*50901Ssklower while (i-- > 0) 351*50901Ssklower sbdroprecord(sb); 352*50901Ssklower if (SEQ_LT(tpcb, tpcb->tp_sndhiwat, seq)) 353*50901Ssklower tpcb->tp_sndhiwat_m = 0; 35436413Ssklower 35536413Ssklower } 35636413Ssklower 35736413Ssklower /* 35836413Ssklower * CALLED FROM: 35936413Ssklower * tp.trans on user send request, arrival of AK and arrival of XAK 36036413Ssklower * FUNCTION and ARGUMENTS: 36136413Ssklower * Emits tpdus starting at sequence number (lowseq). 36236413Ssklower * Emits until a) runs out of data, or b) runs into an XPD mark, or 36336413Ssklower * c) it hits seq number (highseq) 36436413Ssklower * 36536413Ssklower * If you want XPD to buffer > 1 du per socket buffer, you can 36636413Ssklower * modifiy this to issue XPD tpdus also, but then it'll have 36736413Ssklower * to take some argument(s) to distinguish between the type of DU to 368*50901Ssklower * hand tp_emit. 36936413Ssklower * 37036413Ssklower * When something is sent for the first time, its time-of-send 37136413Ssklower * is stashed (the last RTT_NUM of them are stashed). When the 37236413Ssklower * ack arrives, the smoothed round-trip time is figured using this value. 37336413Ssklower * RETURN VALUE: 37436413Ssklower * the highest seq # sent successfully. 37536413Ssklower */ 37636413Ssklower tp_send(tpcb) 37736413Ssklower register struct tp_pcb *tpcb; 37836413Ssklower { 37936413Ssklower register int len; 38036413Ssklower register struct mbuf *m; /* the one we're inspecting now */ 38136413Ssklower struct mbuf *mb;/* beginning of this tpdu */ 38236413Ssklower struct mbuf *nextrecord; /* NOT next tpdu but next sb record */ 38336413Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 38436413Ssklower unsigned int eotsdu_reached=0; 38536413Ssklower SeqNum lowseq, highseq ; 38636413Ssklower SeqNum lowsave; 38736413Ssklower #ifdef TP_PERF_MEAS 38850236Ssklower 38936413Ssklower struct timeval send_start_time; 39050236Ssklower IFPERF(tpcb) 39150236Ssklower GET_CUR_TIME(&send_start_time); 39250236Ssklower ENDPERF 39336413Ssklower #endif TP_PERF_MEAS 39436413Ssklower 39536413Ssklower lowsave = lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1); 39636413Ssklower 39736413Ssklower ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff); 39836413Ssklower 39936413Ssklower if( tpcb->tp_rx_strat & TPRX_USE_CW ) { 40036413Ssklower /*first hiseq is temp vbl*/ 40136413Ssklower highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win); 40236413Ssklower } else { 40336413Ssklower highseq = tpcb->tp_fcredit; 40436413Ssklower } 40536413Ssklower highseq = SEQ(tpcb, tpcb->tp_snduna + highseq); 40636413Ssklower 40736413Ssklower SEQ_DEC(tpcb, highseq); 40836413Ssklower 40936413Ssklower IFDEBUG(D_DATA) 41036413Ssklower printf( 41136413Ssklower "tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n", 41236413Ssklower tpcb, lowseq, highseq); 41336413Ssklower dump_mbuf(sb->sb_mb, "sb_mb:"); 41436413Ssklower ENDDEBUG 41536413Ssklower IFTRACE(D_DATA) 41636413Ssklower tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna", 41736413Ssklower lowsave, tpcb->tp_sndhiwat, tpcb->tp_snduna, 0); 41836413Ssklower tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin", 41936413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 42036413Ssklower ENDTRACE 42136413Ssklower 42236413Ssklower 42336413Ssklower if ( SEQ_GT(tpcb, lowseq, highseq) ) 42436413Ssklower return ; /* don't send, don't change hiwat, don't set timers */ 42536413Ssklower 42636413Ssklower ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) ); 42736413Ssklower SEQ_DEC(tpcb, lowseq); 42836413Ssklower 429*50901Ssklower if (tpcb->tp_Xsnd.sb_mb) { 430*50901Ssklower IFTRACE(D_XPD) 431*50901Ssklower tptraceTPCB( TPPTmisc, 432*50901Ssklower "tp_send XPD mark low high tpcb.Xuna", 433*50901Ssklower lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0); 434*50901Ssklower ENDTRACE 435*50901Ssklower /* stop sending here because there are unacked XPD present 436*50901Ssklower */ 437*50901Ssklower IncStat(ts_xpd_intheway); 438*50901Ssklower goto done; 439*50901Ssklower } 44036413Ssklower IFTRACE(D_DATA) 44136413Ssklower tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin", 44236413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 44336413Ssklower ENDTRACE 44436413Ssklower 445*50901Ssklower if (m = tpcb->tp_sndhiwat_m) 446*50901Ssklower mb = m->m_nextpkt; 447*50901Ssklower else 448*50901Ssklower mb = sb->sb_mb; 449*50901Ssklower while ((SEQ_LT(tpcb, lowseq, highseq)) && mb ) { 45036413Ssklower 451*50901Ssklower /* 45236413Ssklower * In all cases, m points to mbuf containing first octet to be 45336413Ssklower * sent in the tpdu AFTER the one we're going to send now, 45436413Ssklower * or else m is null. 45536413Ssklower * 45636413Ssklower * The chain we're working on now begins at mb and has length <len>. 45736413Ssklower */ 45836413Ssklower 459*50901Ssklower eotsdu_reached = (mb->m_flags & M_EOR) != 0; 460*50901Ssklower len = mb->m_pkthdr.len; 46136413Ssklower IFTRACE(D_STASH) 46236413Ssklower tptraceTPCB( TPPTmisc, 46336413Ssklower "tp_send mcopy low high eotsdu_reached len", 46436413Ssklower lowseq, highseq, eotsdu_reached, len); 46536413Ssklower ENDTRACE 46636413Ssklower 46736413Ssklower /* make a copy - mb goes into the retransmission list 46836413Ssklower * while m gets emitted. m_copy won't copy a zero-length mbuf. 46936413Ssklower */ 470*50901Ssklower m = m_copy(mb, 0, M_COPYALL); 471*50901Ssklower if (m == MNULL) 47236413Ssklower goto done; 47336413Ssklower SEQ_INC(tpcb,lowseq); /* it was decremented at the beginning */ 47436413Ssklower IFTRACE(D_DATA) 47536413Ssklower tptraceTPCB( TPPTmisc, 47639196Ssklower "tp_send emitting DT lowseq eotsdu_reached len", 47739196Ssklower lowseq, eotsdu_reached, len, 0); 47836413Ssklower ENDTRACE 479*50901Ssklower if (mb->m_nextpkt == 0 && tpcb->tp_oktonagle) { 480*50901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 481*50901Ssklower tpcb->tp_oktonagle = 0; 482*50901Ssklower /* when headers are precomputed, may need to fill 483*50901Ssklower in checksum here */ 484*50901Ssklower } 485*50901Ssklower if (tpcb->tp_sock->so_error = 486*50901Ssklower tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m)) { 48736413Ssklower /* error */ 48836413Ssklower SEQ_DEC(tpcb, lowseq); 48936413Ssklower goto done; 49036413Ssklower } 491*50901Ssklower tpcb->tp_sndhiwat_m = mb; 492*50901Ssklower mb = mb->m_nextpkt; 49336413Ssklower /* set the transmit-time for computation of round-trip times */ 49436413Ssklower bcopy( (caddr_t)&time, 49536413Ssklower (caddr_t)&( tpcb->tp_rttemit[ lowseq & TP_RTT_NUM ] ), 49636413Ssklower sizeof(struct timeval)); 49736413Ssklower 49836413Ssklower } 49936413Ssklower 50036413Ssklower done: 50150236Ssklower #ifdef TP_PERF_MEAS 50236413Ssklower IFPERF(tpcb) 50336413Ssklower { 50436413Ssklower register int npkts; 50536413Ssklower struct timeval send_end_time; 50636413Ssklower register struct timeval *t; 50736413Ssklower 50836413Ssklower npkts = lowseq; 50936413Ssklower SEQ_INC(tpcb, npkts); 51036413Ssklower npkts = SEQ_SUB(tpcb, npkts, lowsave); 51136413Ssklower 51236413Ssklower if(npkts > 0) 51336413Ssklower tpcb->tp_Nwindow++; 51436413Ssklower 51536413Ssklower if (npkts > TP_PM_MAX) 51636413Ssklower npkts = TP_PM_MAX; 51736413Ssklower 51836413Ssklower GET_TIME_SINCE(&send_start_time, &send_end_time); 51936413Ssklower t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); 52036413Ssklower t->tv_sec = 52136413Ssklower SMOOTH( long, TP_RTT_ALPHA, t->tv_sec, send_end_time.tv_sec); 52236413Ssklower t->tv_usec = 52336413Ssklower SMOOTH( long, TP_RTT_ALPHA, t->tv_usec, send_end_time.tv_usec); 52436413Ssklower 52536413Ssklower if ( SEQ_LT(tpcb, lowseq, highseq) ) { 52636413Ssklower IncPStat(tpcb, tps_win_lim_by_data[npkts] ); 52736413Ssklower } else { 52836413Ssklower IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); 52936413Ssklower /* not true with congestion-window being used */ 53036413Ssklower } 53136413Ssklower tpmeas( tpcb->tp_lref, 53236413Ssklower TPsbsend, &send_end_time, lowsave, tpcb->tp_Nwindow, npkts); 53336413Ssklower } 53436413Ssklower ENDPERF 53550236Ssklower #endif TP_PERF_MEAS 53636413Ssklower 53736413Ssklower tpcb->tp_sndhiwat = lowseq; 53836413Ssklower 53936413Ssklower if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat) && 54036413Ssklower (tpcb->tp_class != TP_CLASS_0) ) 54136413Ssklower tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave, 54236413Ssklower tpcb->tp_sndhiwat, 54336413Ssklower (u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks); 54436413Ssklower IFTRACE(D_DATA) 54536413Ssklower tptraceTPCB( TPPTmisc, 54636413Ssklower "tp_send at end: sndhiwat lowseq eotsdu_reached error", 54736413Ssklower tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error); 54836413Ssklower 54936413Ssklower ENDTRACE 55036413Ssklower } 55136413Ssklower 552*50901Ssklower int TPNagleok; 553*50901Ssklower int TPNagled; 554*50901Ssklower 555*50901Ssklower tp_packetize(tpcb, m, eotsdu) 556*50901Ssklower register struct tp_pcb *tpcb; 557*50901Ssklower register struct mbuf *m; 558*50901Ssklower int eotsdu; 559*50901Ssklower { 560*50901Ssklower register struct mbuf *n; 561*50901Ssklower register struct sockbuf *sb = &tpcb->tp_sock->so_snd; 562*50901Ssklower int maxsize = tpcb->tp_l_tpdusize 563*50901Ssklower - tp_headersize(DT_TPDU_type, tpcb) 564*50901Ssklower - (tpcb->tp_use_checksum?4:0) ; 565*50901Ssklower int totlen = m->m_pkthdr.len; 566*50901Ssklower struct mbuf *m_split(); 567*50901Ssklower /* 568*50901Ssklower * Pre-packetize the data in the sockbuf 569*50901Ssklower * according to negotiated mtu. Do it here 570*50901Ssklower * where we can safely wait for mbufs. 571*50901Ssklower * 572*50901Ssklower * This presumes knowledge of sockbuf conventions. 573*50901Ssklower * TODO: allocate space for header and fill it in (once!). 574*50901Ssklower */ 575*50901Ssklower IFTRACE(D_DATA) 576*50901Ssklower tptraceTPCB(TPPTmisc, 577*50901Ssklower "SEND BF: maxsize totlen eotsdu", 578*50901Ssklower maxsize, totlen, eotsdu, 0); 579*50901Ssklower ENDTRACE 580*50901Ssklower if (tpcb->tp_oktonagle) { 581*50901Ssklower if ((n = sb->sb_mb) == 0) 582*50901Ssklower panic("tp_packetize"); 583*50901Ssklower while (n->m_act) 584*50901Ssklower n = n->m_act; 585*50901Ssklower if (n->m_flags & M_EOR) 586*50901Ssklower panic("tp_packetize 2"); 587*50901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 588*50901Ssklower if (totlen + n->m_pkthdr.len < maxsize) { 589*50901Ssklower /* There is an unsent packet with space, combine data */ 590*50901Ssklower struct mbuf *old_n = n; 591*50901Ssklower tpsbcheck(tpcb,3); 592*50901Ssklower n->m_pkthdr.len += totlen; 593*50901Ssklower while (n->m_next) 594*50901Ssklower n = n->m_next; 595*50901Ssklower sbcompress(sb, m, n); 596*50901Ssklower tpsbcheck(tpcb,4); 597*50901Ssklower n = old_n; 598*50901Ssklower TPNagled++; 599*50901Ssklower goto out; 600*50901Ssklower } 601*50901Ssklower } 602*50901Ssklower while (m) { 603*50901Ssklower n = m; 604*50901Ssklower if (totlen > maxsize) { 605*50901Ssklower if ((m = m_split(n, maxsize, M_WAIT)) == 0) 606*50901Ssklower panic("tp_packetize"); 607*50901Ssklower } else 608*50901Ssklower m = 0; 609*50901Ssklower totlen -= maxsize; 610*50901Ssklower tpsbcheck(tpcb, 5); 611*50901Ssklower sbappendrecord(sb, n); 612*50901Ssklower tpsbcheck(tpcb, 6); 613*50901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 614*50901Ssklower } 615*50901Ssklower out: 616*50901Ssklower if (eotsdu) { 617*50901Ssklower n->m_flags |= M_EOR; /* XXX belongs at end */ 618*50901Ssklower tpcb->tp_oktonagle = 0; 619*50901Ssklower } else { 620*50901Ssklower SEQ_DEC(tpcb, tpcb->tp_sndnum); 621*50901Ssklower tpcb->tp_oktonagle = 1; 622*50901Ssklower TPNagleok++; 623*50901Ssklower } 624*50901Ssklower return 0; 625*50901Ssklower } 626*50901Ssklower 627*50901Ssklower 62836413Ssklower /* 62936413Ssklower * NAME: tp_stash() 63036413Ssklower * CALLED FROM: 63136413Ssklower * tp.trans on arrival of a DT tpdu 63236413Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 63336413Ssklower * Returns 1 if 63436413Ssklower * a) something new arrived and it's got eotsdu_reached bit on, 63536413Ssklower * b) this arrival was caused other out-of-sequence things to be 63636413Ssklower * accepted, or 63736413Ssklower * c) this arrival is the highest seq # for which we last gave credit 63836413Ssklower * (sender just sent a whole window) 63936413Ssklower * In other words, returns 1 if tp should send an ack immediately, 0 if 64036413Ssklower * the ack can wait a while. 64136413Ssklower * 64236413Ssklower * Note: this implementation no longer renegs on credit, (except 64336413Ssklower * when debugging option D_RENEG is on, for the purpose of testing 64436413Ssklower * ack subsequencing), so we don't need to check for incoming tpdus 64536413Ssklower * being in a reneged portion of the window. 64636413Ssklower */ 64736413Ssklower 64836413Ssklower tp_stash( tpcb, e ) 64936413Ssklower register struct tp_pcb *tpcb; 65036413Ssklower register struct tp_event *e; 65136413Ssklower { 65236413Ssklower register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; 65336413Ssklower /* 0--> delay acks until full window */ 65436413Ssklower /* 1--> ack each tpdu */ 65536413Ssklower #ifndef lint 65636413Ssklower #define E e->ATTR(DT_TPDU) 65736413Ssklower #else lint 65836413Ssklower #define E e->ev_union.EV_DT_TPDU 65936413Ssklower #endif lint 66036413Ssklower 66136413Ssklower if ( E.e_eot ) { 66236413Ssklower register struct mbuf *n = E.e_data; 66337469Ssklower n->m_flags |= M_EOR; 66438841Ssklower n->m_act = 0; 66537469Ssklower } 66636413Ssklower IFDEBUG(D_STASH) 66736413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 66836413Ssklower "stash: so_rcv before appending"); 66936413Ssklower dump_mbuf(E.e_data, 67036413Ssklower "stash: e_data before appending"); 67136413Ssklower ENDDEBUG 67236413Ssklower 67336413Ssklower IFPERF(tpcb) 67436413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 67536413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 67637469Ssklower E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 67736413Ssklower ENDPERF 67836413Ssklower 67936413Ssklower if( E.e_seq == tpcb->tp_rcvnxt ) { 68036413Ssklower 68136413Ssklower IFDEBUG(D_STASH) 68236413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 68336413Ssklower E.e_seq, E.e_datalen, E.e_eot); 68436413Ssklower ENDDEBUG 68536413Ssklower 68636413Ssklower IFTRACE(D_STASH) 68736413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 68836413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 68936413Ssklower ENDTRACE 69036413Ssklower 69137469Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 69237469Ssklower 69336413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 69436413Ssklower /* 695*50901Ssklower * move chains from the reassembly queue to the socket buffer 69636413Ssklower */ 697*50901Ssklower if (tpcb->tp_rsycnt) { 698*50901Ssklower register struct mbuf **mp; 699*50901Ssklower struct mbuf **mplim; 70036413Ssklower 701*50901Ssklower mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); 702*50901Ssklower mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; 70336413Ssklower 704*50901Ssklower while (tpcb->tp_rsycnt && *mp) { 705*50901Ssklower sbappend(&tpcb->tp_sock->so_rcv, *mp); 706*50901Ssklower tpcb->tp_rsycnt--; 707*50901Ssklower *mp = 0; 708*50901Ssklower SEQ_INC(tpcb, tpcb->tp_rcvnxt); 70936413Ssklower ack_reason |= ACK_REORDER; 710*50901Ssklower if (++mp == mplim) 711*50901Ssklower mp = tpcb->tp_rsyq; 71236413Ssklower } 71336413Ssklower } 71436413Ssklower IFDEBUG(D_STASH) 71536413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 71636413Ssklower "stash: so_rcv after appending"); 71736413Ssklower ENDDEBUG 71836413Ssklower 71936413Ssklower } else { 720*50901Ssklower register struct mbuf **mp; 721*50901Ssklower SeqNum uwe; 72236413Ssklower 72336413Ssklower IFTRACE(D_STASH) 72436413Ssklower tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 72536413Ssklower E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 72636413Ssklower ENDTRACE 72736413Ssklower 728*50901Ssklower if (tpcb->tp_rsyq == 0 || 729*50901Ssklower (tpcb->tp_rsycnt == 0 && 730*50901Ssklower (tpcb->tp_sbmax != tpcb->tp_sock->so_rcv.sb_hiwat))) 731*50901Ssklower tp_rsyset(tpcb); 732*50901Ssklower uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); 733*50901Ssklower if (tpcb->tp_rsyq == 0 || 734*50901Ssklower !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { 73536413Ssklower ack_reason = ACK_DONT; 736*50901Ssklower m_freem(E.e_data); 737*50901Ssklower } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { 73836413Ssklower IFDEBUG(D_STASH) 73936413Ssklower printf("tp_stash - drop & ack\n"); 74036413Ssklower ENDDEBUG 74136413Ssklower 74236413Ssklower /* retransmission - drop it and force an ack */ 74336413Ssklower IncStat(ts_dt_dup); 74436413Ssklower IFPERF(tpcb) 74536413Ssklower IncPStat(tpcb, tps_n_ack_cuz_dup); 74636413Ssklower ENDPERF 74736413Ssklower 748*50901Ssklower m_freem(E.e_data); 74936413Ssklower ack_reason |= ACK_DUP; 750*50901Ssklower } else { 751*50901Ssklower *mp = E.e_data; 752*50901Ssklower tpcb->tp_rsycnt++; 753*50901Ssklower ack_reason = ACK_DONT; 75436413Ssklower } 75536413Ssklower } 75636413Ssklower /* 75736413Ssklower * an ack should be sent when at least one of the 75836413Ssklower * following holds: 759*50901Ssklower * a) the TPDU that just arrived represents the 76036413Ssklower * full window last advertised, or 761*50901Ssklower * b) when seq X arrives [ where 76236413Ssklower * X = last_sent_uwe - 1/2 last_lcredit_sent 76336413Ssklower * (the packet representing 1/2 the last advertised window) ] 76436413Ssklower * and lcredit at the time of X arrival > last_lcredit_sent/2 76536413Ssklower * In other words, if the last ack sent advertised cdt=8 and uwe = 8 76636413Ssklower * then when seq 4 arrives I'd like to send a new ack 76736413Ssklower * iff the credit at the time of 4's arrival is > 4. 76836413Ssklower * The other end thinks it has cdt of 4 so if local cdt 76936413Ssklower * is still 4 there's no point in sending an ack, but if 77036413Ssklower * my credit has increased because the receiver has taken 77136413Ssklower * some data out of the buffer (soreceive doesn't notify 77236413Ssklower * me until the SYSTEM CALL finishes), I'd like to tell 77336413Ssklower * the other end. 77436413Ssklower */ 77536413Ssklower { 77636413Ssklower LOCAL_CREDIT(tpcb); 77736413Ssklower 77836413Ssklower if ( E.e_seq == tpcb->tp_sent_uwe ) 77936413Ssklower ack_reason |= ACK_STRAT_FULLWIN; 78036413Ssklower 78136413Ssklower IFTRACE(D_STASH) 78236413Ssklower tptraceTPCB(TPPTmisc, 78336413Ssklower "end of stash, eot, ack_reason, sent_uwe ", 78436413Ssklower E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 78536413Ssklower ENDTRACE 78636413Ssklower 78736413Ssklower if ( ack_reason == ACK_DONT ) { 78836413Ssklower IncStat( ts_ackreason[ACK_DONT] ); 78936413Ssklower return 0; 79036413Ssklower } else { 79136413Ssklower IFPERF(tpcb) 79236413Ssklower if(ack_reason & ACK_STRAT_EACH) { 79336413Ssklower IncPStat(tpcb, tps_n_ack_cuz_strat); 79436413Ssklower } else if(ack_reason & ACK_STRAT_FULLWIN) { 79536413Ssklower IncPStat(tpcb, tps_n_ack_cuz_fullwin); 79636413Ssklower } else if(ack_reason & ACK_REORDER) { 79736413Ssklower IncPStat(tpcb, tps_n_ack_cuz_reorder); 79836413Ssklower } 79936413Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 80036413Ssklower SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 80136413Ssklower ENDPERF 80236413Ssklower { 80336413Ssklower register int i; 80436413Ssklower 80536413Ssklower /* keep track of all reasons that apply */ 80636413Ssklower for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 80736413Ssklower if( ack_reason & (1<<i) ) 80836413Ssklower IncStat( ts_ackreason[i] ); 80936413Ssklower } 81036413Ssklower } 81136413Ssklower return 1; 81236413Ssklower } 81336413Ssklower } 81436413Ssklower } 815*50901Ssklower 816*50901Ssklower /* 817*50901Ssklower * tp_rsyflush - drop all the packets on the reassembly queue. 818*50901Ssklower * Do this when closing the socket, or when somebody has changed 819*50901Ssklower * the space avaible in the receive socket (XXX). 820*50901Ssklower */ 821*50901Ssklower tp_rsyflush(tpcb) 822*50901Ssklower register struct tp_pcb *tpcb; 823*50901Ssklower { 824*50901Ssklower register struct mbuf *m, **mp; 825*50901Ssklower if (tpcb->tp_rsycnt) { 826*50901Ssklower for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; 827*50901Ssklower --mp >= tpcb->tp_rsyq; ) 828*50901Ssklower if (*mp) { 829*50901Ssklower tpcb->tp_rsycnt--; 830*50901Ssklower m_freem(*mp); 831*50901Ssklower } 832*50901Ssklower if (tpcb->tp_rsycnt) 833*50901Ssklower panic("tp_rsyflush"); 834*50901Ssklower } 835*50901Ssklower free((caddr_t)tpcb->tp_rsyq, M_PCB); 836*50901Ssklower tpcb->tp_rsyq = 0; 837*50901Ssklower } 838*50901Ssklower 839*50901Ssklower tp_rsyset(tpcb) 840*50901Ssklower register struct tp_pcb *tpcb; 841*50901Ssklower { 842*50901Ssklower register struct socket *so = tpcb->tp_sock; 843*50901Ssklower int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; 844*50901Ssklower caddr_t rsyq; 845*50901Ssklower 846*50901Ssklower tpcb->tp_sbmax = so->so_rcv.sb_hiwat; 847*50901Ssklower tpcb->tp_maxlcredit = maxcredit = min(maxcredit, 848*50901Ssklower (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); 849*50901Ssklower 850*50901Ssklower maxcredit *= sizeof(struct mbuf *); 851*50901Ssklower if (tpcb->tp_rsyq) 852*50901Ssklower tp_rsyflush(tpcb); 853*50901Ssklower if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) 854*50901Ssklower bzero(rsyq, maxcredit); 855*50901Ssklower tpcb->tp_rsyq = (struct mbuf **)rsyq; 856*50901Ssklower } 857*50901Ssklower 858*50901Ssklower tpsbcheck(tpcb, i) 859*50901Ssklower struct tp_pcb *tpcb; 860*50901Ssklower { 861*50901Ssklower register struct mbuf *n, *m; 862*50901Ssklower register int len = 0, mbcnt = 0, pktlen; 863*50901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 864*50901Ssklower 865*50901Ssklower for (n = sb->sb_mb; n; n = n->m_nextpkt) { 866*50901Ssklower if ((n->m_flags & M_PKTHDR) == 0) 867*50901Ssklower panic("tpsbcheck nohdr"); 868*50901Ssklower pktlen = len + n->m_pkthdr.len; 869*50901Ssklower for (m = n; m; m = m->m_next) { 870*50901Ssklower len += m->m_len; 871*50901Ssklower mbcnt += MSIZE; 872*50901Ssklower if (m->m_flags & M_EXT) 873*50901Ssklower mbcnt += m->m_ext.ext_size; 874*50901Ssklower } 875*50901Ssklower if (len != pktlen) { 876*50901Ssklower printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", 877*50901Ssklower i, len, pktlen, n); 878*50901Ssklower panic("tpsbcheck short"); 879*50901Ssklower } 880*50901Ssklower } 881*50901Ssklower if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { 882*50901Ssklower printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, 883*50901Ssklower mbcnt, sb->sb_mbcnt); 884*50901Ssklower panic("tpsbcheck"); 885*50901Ssklower } 886*50901Ssklower } 887