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