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