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