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