added my responsibility for the `cpm' port
[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
4c45483e 34 * $Id: tp_subr.c,v 1.4 1993/11/07 17:50:02 wollman 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 */
4c45483e 441int
15637ed4
RG
442tp_send(tpcb)
443 register struct tp_pcb *tpcb;
444{
445 register int len;
446 register struct mbuf *m; /* the one we're inspecting now */
447 struct mbuf *mb;/* beginning of this tpdu */
448 struct mbuf *nextrecord; /* NOT next tpdu but next sb record */
449 struct sockbuf *sb = &tpcb->tp_sock->so_snd;
450 int maxsize = tpcb->tp_l_tpdusize
451 - tp_headersize(DT_TPDU_type, tpcb)
452 - (tpcb->tp_use_checksum?4:0) ;
453 unsigned int eotsdu_reached=0;
454 SeqNum lowseq, highseq ;
455 SeqNum lowsave;
456#ifdef TP_PERF_MEAS
457
458 struct timeval send_start_time;
459 IFPERF(tpcb)
460 GET_CUR_TIME(&send_start_time);
461 ENDPERF
462#endif TP_PERF_MEAS
463
464 lowsave = lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1);
465
466 ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff);
467
468 if( tpcb->tp_rx_strat & TPRX_USE_CW ) {
469 /*first hiseq is temp vbl*/
470 highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win);
471 } else {
472 highseq = tpcb->tp_fcredit;
473 }
474 highseq = SEQ(tpcb, tpcb->tp_snduna + highseq);
475
476 SEQ_DEC(tpcb, highseq);
477
478 IFDEBUG(D_DATA)
479 printf(
480 "tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n",
481 tpcb, lowseq, highseq);
482 dump_mbuf(sb->sb_mb, "sb_mb:");
483 ENDDEBUG
484 IFTRACE(D_DATA)
485 tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna",
486 lowsave, tpcb->tp_sndhiwat, tpcb->tp_snduna, 0);
487 tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin",
488 lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win);
489 ENDTRACE
490
491
4c45483e
GW
492 if( SEQ_GT(tpcb, lowseq, highseq) ) {
493 /* don't send, don't change hiwat, don't set timers */
494 return 0;
495 }
15637ed4
RG
496
497 ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) );
498 SEQ_DEC(tpcb, lowseq);
499
500 IFTRACE(D_DATA)
501 tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin",
502 lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win);
503 ENDTRACE
504
505 while ((SEQ_LT(tpcb, lowseq, highseq)) && (mb = m = sb->sb_mb)) {
506 if (tpcb->tp_Xsnd.sb_mb) {
507 IFTRACE(D_XPD)
508 tptraceTPCB( TPPTmisc,
509 "tp_send XPD mark low high tpcb.Xuna",
510 lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0);
511 ENDTRACE
512 /* stop sending here because there are unacked XPD which were
513 * given to us before the next data were.
514 */
515 IncStat(ts_xpd_intheway);
516 break;
517 }
518 eotsdu_reached = 0;
519 nextrecord = m->m_act;
520 for (len = 0; m; m = m->m_next) {
521 len += m->m_len;
522 if (m->m_flags & M_EOR)
523 eotsdu_reached = 1;
524 sbfree(sb, m); /* reduce counts in socket buffer */
525 }
526 sb->sb_mb = nextrecord;
527 IFTRACE(D_STASH)
528 tptraceTPCB(TPPTmisc, "tp_send whole mbuf: m_len len maxsize",
529 0, mb->m_len, len, maxsize);
530 ENDTRACE
531
532 if ( len == 0 && !eotsdu_reached) {
533 /* THIS SHOULD NEVER HAPPEN! */
534 ASSERT( 0 );
535 goto done;
536 }
537
538 /* If we arrive here one of the following holds:
539 * 1. We have exactly <maxsize> octets of whole mbufs,
540 * 2. We accumulated <maxsize> octets using partial mbufs,
541 * 3. We found an TPMT_EOT or an XPD mark
542 * 4. We hit the end of a chain through m_next.
543 * In this case, we'd LIKE to continue with the next record,
544 * but for the time being, for simplicity, we'll stop here.
545 * In all cases, m points to mbuf containing first octet to be
546 * sent in the tpdu AFTER the one we're going to send now,
547 * or else m is null.
548 *
549 * The chain we're working on now begins at mb and has length <len>.
550 */
551
552 IFTRACE(D_STASH)
553 tptraceTPCB( TPPTmisc,
554 "tp_send mcopy low high eotsdu_reached len",
555 lowseq, highseq, eotsdu_reached, len);
556 ENDTRACE
557
558 /* make a copy - mb goes into the retransmission list
559 * while m gets emitted. m_copy won't copy a zero-length mbuf.
560 */
561 if (len) {
562 if ((m = m_copy(mb, 0, len )) == MNULL)
563 goto done;
564 } else {
565 /* eotsdu reached */
566 MGET(m, M_WAIT, TPMT_DATA);
567 if (m == MNULL)
568 goto done;
569 m->m_len = 0;
570 }
571
572 SEQ_INC(tpcb,lowseq); /* it was decremented at the beginning */
573 {
574 struct tp_rtc *t;
575 /* make an rtc and put it at the end of the chain */
576
577 TP_MAKE_RTC( t, lowseq, eotsdu_reached, mb, len, lowseq,
578 TPMT_SNDRTC);
579 t->tprt_next = (struct tp_rtc *)0;
580
581 if ( tpcb->tp_sndhiwat_rtc != (struct tp_rtc *)0 )
582 tpcb->tp_sndhiwat_rtc->tprt_next = t;
583 else {
584 ASSERT( tpcb->tp_snduna_rtc == (struct tp_rtc *)0 );
585 tpcb->tp_snduna_rtc = t;
586 }
587
588 tpcb->tp_sndhiwat_rtc = t;
589 }
590
591 IFTRACE(D_DATA)
592 tptraceTPCB( TPPTmisc,
593 "tp_send emitting DT lowseq eotsdu_reached len",
594 lowseq, eotsdu_reached, len, 0);
595 ENDTRACE
596 if( tpcb->tp_sock->so_error =
597 tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m) ) {
598 /* error */
599 SEQ_DEC(tpcb, lowseq);
600 goto done;
601 }
602 /* set the transmit-time for computation of round-trip times */
603 bcopy( (caddr_t)&time,
604 (caddr_t)&( tpcb->tp_rttemit[ lowseq & TP_RTT_NUM ] ),
605 sizeof(struct timeval));
606
607 }
608
609done:
610#ifdef TP_PERF_MEAS
611 IFPERF(tpcb)
612 {
613 register int npkts;
614 struct timeval send_end_time;
615 register struct timeval *t;
616
617 npkts = lowseq;
618 SEQ_INC(tpcb, npkts);
619 npkts = SEQ_SUB(tpcb, npkts, lowsave);
620
621 if(npkts > 0)
622 tpcb->tp_Nwindow++;
623
624 if (npkts > TP_PM_MAX)
625 npkts = TP_PM_MAX;
626
627 GET_TIME_SINCE(&send_start_time, &send_end_time);
628 t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
629 t->tv_sec =
630 SMOOTH( long, TP_RTT_ALPHA, t->tv_sec, send_end_time.tv_sec);
631 t->tv_usec =
632 SMOOTH( long, TP_RTT_ALPHA, t->tv_usec, send_end_time.tv_usec);
633
634 if ( SEQ_LT(tpcb, lowseq, highseq) ) {
635 IncPStat(tpcb, tps_win_lim_by_data[npkts] );
636 } else {
637 IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
638 /* not true with congestion-window being used */
639 }
640 tpmeas( tpcb->tp_lref,
641 TPsbsend, &send_end_time, lowsave, tpcb->tp_Nwindow, npkts);
642 }
643 ENDPERF
644#endif TP_PERF_MEAS
645
646 tpcb->tp_sndhiwat = lowseq;
647
648 if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat) &&
649 (tpcb->tp_class != TP_CLASS_0) )
650 tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave,
651 tpcb->tp_sndhiwat,
652 (u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks);
653 IFTRACE(D_DATA)
654 tptraceTPCB( TPPTmisc,
655 "tp_send at end: sndhiwat lowseq eotsdu_reached error",
656 tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error);
657
658 ENDTRACE
4c45483e
GW
659 ;
660 return 0;
15637ed4
RG
661}
662
663/*
664 * NAME: tp_stash()
665 * CALLED FROM:
666 * tp.trans on arrival of a DT tpdu
667 * FUNCTION, ARGUMENTS, and RETURN VALUE:
668 * Returns 1 if
669 * a) something new arrived and it's got eotsdu_reached bit on,
670 * b) this arrival was caused other out-of-sequence things to be
671 * accepted, or
672 * c) this arrival is the highest seq # for which we last gave credit
673 * (sender just sent a whole window)
674 * In other words, returns 1 if tp should send an ack immediately, 0 if
675 * the ack can wait a while.
676 *
677 * Note: this implementation no longer renegs on credit, (except
678 * when debugging option D_RENEG is on, for the purpose of testing
679 * ack subsequencing), so we don't need to check for incoming tpdus
680 * being in a reneged portion of the window.
681 */
682
683int
684tp_stash( tpcb, e )
685 register struct tp_pcb *tpcb;
686 register struct tp_event *e;
687{
688 register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
689 /* 0--> delay acks until full window */
690 /* 1--> ack each tpdu */
691 int newrec = 0;
692
693#ifndef lint
694#define E e->ATTR(DT_TPDU)
695#else lint
696#define E e->ev_union.EV_DT_TPDU
697#endif lint
698
699 if ( E.e_eot ) {
700 register struct mbuf *n = E.e_data;
701 n->m_flags |= M_EOR;
702 n->m_act = 0;
703 }
704 IFDEBUG(D_STASH)
705 dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
706 "stash: so_rcv before appending");
707 dump_mbuf(E.e_data,
708 "stash: e_data before appending");
709 ENDDEBUG
710
711 IFPERF(tpcb)
712 PStat(tpcb, Nb_from_ll) += E.e_datalen;
713 tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
714 E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen);
715 ENDPERF
716
717 if( E.e_seq == tpcb->tp_rcvnxt ) {
718
719 IFDEBUG(D_STASH)
720 printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
721 E.e_seq, E.e_datalen, E.e_eot);
722 ENDDEBUG
723
724 IFTRACE(D_STASH)
725 tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
726 E.e_seq, E.e_datalen, E.e_eot, 0);
727 ENDTRACE
728
729 sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
730
731 if (newrec = E.e_eot ) /* ASSIGNMENT */
732 ack_reason |= ACK_EOT;
733
734 SEQ_INC( tpcb, tpcb->tp_rcvnxt );
735 /*
736 * move chains from the rtc list to the socket buffer
737 * and free the rtc header
738 */
739 {
740 register struct tp_rtc **r = &tpcb->tp_rcvnxt_rtc;
741 register struct tp_rtc *s = tpcb->tp_rcvnxt_rtc;
742
743 while (s != (struct tp_rtc *)0 && s->tprt_seq == tpcb->tp_rcvnxt) {
744 *r = s->tprt_next;
745
746 sbappend(&tpcb->tp_sock->so_rcv, s->tprt_data);
747
748 SEQ_INC( tpcb, tpcb->tp_rcvnxt );
749
750 (void) m_free( dtom( s ) );
751 s = *r;
752 ack_reason |= ACK_REORDER;
753 }
754 }
755 IFDEBUG(D_STASH)
756 dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
757 "stash: so_rcv after appending");
758 ENDDEBUG
759
760 } else {
761 register struct tp_rtc **s = &tpcb->tp_rcvnxt_rtc;
762 register struct tp_rtc *r = tpcb->tp_rcvnxt_rtc;
763 register struct tp_rtc *t;
764
765 IFTRACE(D_STASH)
766 tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt",
767 E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
768 ENDTRACE
769
770 r = tpcb->tp_rcvnxt_rtc;
771 while (r != (struct tp_rtc *)0 && SEQ_LT(tpcb, r->tprt_seq, E.e_seq)) {
772 s = &r->tprt_next;
773 r = r->tprt_next;
774 }
775
776 if (r == (struct tp_rtc *)0 || SEQ_GT(tpcb, r->tprt_seq, E.e_seq) ) {
777 IncStat(ts_dt_ooo);
778
779 IFTRACE(D_STASH)
780 tptrace(TPPTmisc,
781 "tp_stash OUT OF ORDER- MAKE RTC: seq, 1st seq in list\n",
782 E.e_seq, r->tprt_seq,0,0);
783 ENDTRACE
784 IFDEBUG(D_STASH)
785 printf("tp_stash OUT OF ORDER- MAKE RTC\n");
786 ENDDEBUG
787 TP_MAKE_RTC(t, E.e_seq, E.e_eot, E.e_data, E.e_datalen, 0,
788 TPMT_RCVRTC);
789
790 *s = t;
791 t->tprt_next = (struct tp_rtc *)r;
792 ack_reason = ACK_DONT;
793 goto done;
794 } else {
795 IFDEBUG(D_STASH)
796 printf("tp_stash - drop & ack\n");
797 ENDDEBUG
798
799 /* retransmission - drop it and force an ack */
800 IncStat(ts_dt_dup);
801 IFPERF(tpcb)
802 IncPStat(tpcb, tps_n_ack_cuz_dup);
803 ENDPERF
804
805 m_freem( E.e_data );
806 ack_reason |= ACK_DUP;
807 goto done;
808 }
809 }
810
811
812 /*
813 * an ack should be sent when at least one of the
814 * following holds:
815 * a) we've received a TPDU with EOTSDU set
816 * b) the TPDU that just arrived represents the
817 * full window last advertised, or
818 * c) when seq X arrives [ where
819 * X = last_sent_uwe - 1/2 last_lcredit_sent
820 * (the packet representing 1/2 the last advertised window) ]
821 * and lcredit at the time of X arrival > last_lcredit_sent/2
822 * In other words, if the last ack sent advertised cdt=8 and uwe = 8
823 * then when seq 4 arrives I'd like to send a new ack
824 * iff the credit at the time of 4's arrival is > 4.
825 * The other end thinks it has cdt of 4 so if local cdt
826 * is still 4 there's no point in sending an ack, but if
827 * my credit has increased because the receiver has taken
828 * some data out of the buffer (soreceive doesn't notify
829 * me until the SYSTEM CALL finishes), I'd like to tell
830 * the other end.
831 */
832
833done:
834 {
835 LOCAL_CREDIT(tpcb);
836
837 if ( E.e_seq == tpcb->tp_sent_uwe )
838 ack_reason |= ACK_STRAT_FULLWIN;
839
840 IFTRACE(D_STASH)
841 tptraceTPCB(TPPTmisc,
842 "end of stash, eot, ack_reason, sent_uwe ",
843 E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0);
844 ENDTRACE
845
846 if ( ack_reason == ACK_DONT ) {
847 IncStat( ts_ackreason[ACK_DONT] );
848 return 0;
849 } else {
850 IFPERF(tpcb)
851 if(ack_reason & ACK_EOT) {
852 IncPStat(tpcb, tps_n_ack_cuz_eot);
853 }
854 if(ack_reason & ACK_STRAT_EACH) {
855 IncPStat(tpcb, tps_n_ack_cuz_strat);
856 } else if(ack_reason & ACK_STRAT_FULLWIN) {
857 IncPStat(tpcb, tps_n_ack_cuz_fullwin);
858 } else if(ack_reason & ACK_REORDER) {
859 IncPStat(tpcb, tps_n_ack_cuz_reorder);
860 }
861 tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0,
862 SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
863 ENDPERF
864 {
865 register int i;
866
867 /* keep track of all reasons that apply */
868 for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
869 if( ack_reason & (1<<i) )
870 IncStat( ts_ackreason[i] );
871 }
872 }
873 return 1;
874 }
875 }
876}