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