]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/tp_subr.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1991, 1993
24 * The Regents of the University of California. All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * @(#)tp_subr.c 8.1 (Berkeley) 6/10/93
57 /***********************************************************
58 Copyright IBM Corporation 1987
62 Permission to use, copy, modify, and distribute this software and its
63 documentation for any purpose and without fee is hereby granted,
64 provided that the above copyright notice appear in all copies and that
65 both that copyright notice and this permission notice appear in
66 supporting documentation, and that the name of IBM not be
67 used in advertising or publicity pertaining to distribution of the
68 software without specific, written prior permission.
70 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
78 ******************************************************************/
81 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
86 * The main work of data transfer is done here.
87 * These routines are called from tp.trans.
88 * They include the routines that check the validity of acks and Xacks,
89 * (tp_goodack() and tp_goodXack() )
90 * take packets from socket buffers and send them (tp_send()),
91 * drop the data from the socket buffers (tp_sbdrop()),
92 * and put incoming packet data into socket buffers (tp_stash()).
95 #include <sys/param.h>
96 #include <sys/systm.h>
98 #include <sys/socket.h>
99 #include <sys/socketvar.h>
100 #include <sys/protosw.h>
101 #include <sys/errno.h>
102 #include <sys/time.h>
103 #include <sys/kernel.h>
105 #include <netiso/tp_ip.h>
106 #include <netiso/iso.h>
107 #include <netiso/argo_debug.h>
108 #include <netiso/tp_timer.h>
109 #include <netiso/tp_param.h>
110 #include <netiso/tp_stat.h>
111 #include <netiso/tp_pcb.h>
112 #include <netiso/tp_tpdu.h>
113 #include <netiso/tp_trace.h>
114 #include <netiso/tp_meas.h>
115 #include <netiso/tp_seq.h>
117 int tp_emit(), tp_sbdrop();
118 int tprexmtthresh
= 3;
124 * tp.trans, when an XAK arrives
125 * FUNCTION and ARGUMENTS:
126 * Determines if the sequence number (seq) from the XAK
127 * acks anything new. If so, drop the appropriate tpdu
128 * from the XPD send queue.
130 * Returns 1 if it did this, 0 if the ack caused no action.
133 tp_goodXack(tpcb
, seq
)
139 tptraceTPCB(TPPTgotXack
,
140 seq
, tpcb
->tp_Xuna
, tpcb
->tp_Xsndnxt
, tpcb
->tp_sndnew
,
144 if ( seq
== tpcb
->tp_Xuna
) {
145 tpcb
->tp_Xuna
= tpcb
->tp_Xsndnxt
;
147 /* DROP 1 packet from the Xsnd socket buf - just so happens
148 * that only one packet can be there at any time
149 * so drop the whole thing. If you allow > 1 packet
150 * the socket buffer, then you'll have to keep
151 * track of how many characters went w/ each XPD tpdu, so this
155 dump_mbuf(tpcb
->tp_Xsnd
.sb_mb
,
156 "tp_goodXack Xsnd before sbdrop");
160 tptraceTPCB(TPPTmisc
,
161 "goodXack: dropping cc ",
162 (int)(tpcb
->tp_Xsnd
.sb_cc
),
165 sbdroprecord(&tpcb
->tp_Xsnd
);
174 * FUNCTION and ARGUMENTS:
176 * smoothed average round trip time (*rtt)
177 * roundtrip time variance (*rtv) - actually deviation, not variance
178 * given the new value (diff)
185 register struct tp_pcb
*tpcb
;
187 int old
= tpcb
->tp_rtt
;
188 int delta
, elapsed
= ticks
- tpcb
->tp_rttemit
;
190 if (tpcb
->tp_rtt
!= 0) {
192 * rtt is the smoothed round trip time in machine clock ticks (hz).
193 * It is stored as a fixed point number, unscaled (unlike the tcp
194 * srtt). The rationale here is that it is only significant to the
195 * nearest unit of slowtimo, which is at least 8 machine clock ticks
196 * so there is no need to scale. The smoothing is done according
197 * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8).
199 delta
= elapsed
- tpcb
->tp_rtt
;
200 if ((tpcb
->tp_rtt
+= (delta
>> TP_RTT_ALPHA
)) <= 0)
203 * rtv is a smoothed accumulated mean difference, unscaled
204 * for reasons expressed above.
205 * It is smoothed with an alpha of .75, and the round trip timer
206 * will be set to rtt + 4*rtv, also as TCP does.
210 if ((tpcb
->tp_rtv
+= ((delta
- tpcb
->tp_rtv
) >> TP_RTV_ALPHA
)) <= 0)
214 * No rtt measurement yet - use the unsmoothed rtt.
215 * Set the variance to half the rtt (so our first
216 * retransmit happens at 3*rtt)
218 tpcb
->tp_rtt
= elapsed
;
219 tpcb
->tp_rtv
= elapsed
>> 1;
221 tpcb
->tp_rttemit
= 0;
222 tpcb
->tp_rxtshift
= 0;
224 * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar.
225 * Because of the way we do the smoothing, srtt and rttvar
226 * will each average +1/2 tick of bias. When we compute
227 * the retransmit timer, we want 1/2 tick of rounding and
228 * 1 extra tick because of +-1/2 tick uncertainty in the
229 * firing of the timer. The bias will give us exactly the
230 * 1.5 tick we need. But, because the bias is
231 * statistical, we have to test that we don't drop below
232 * the minimum feasible timer (which is 2 ticks)."
234 TP_RANGESET(tpcb
->tp_dt_ticks
, TP_REXMTVAL(tpcb
),
235 tpcb
->tp_peer_acktime
, 128 /* XXX */);
237 printf("%s tpcb 0x%x, elapsed %d, delta %d, rtt %d, rtv %d, old %d\n",
238 "tp_rtt_rtv:",tpcb
,elapsed
,delta
,tpcb
->tp_rtt
,tpcb
->tp_rtv
,old
);
240 tpcb
->tp_rxtcur
= tpcb
->tp_dt_ticks
;
245 * tp.trans when an AK arrives
246 * FUNCTION and ARGUMENTS:
247 * Given (cdt), the credit from the AK tpdu, and
248 * (seq), the sequence number from the AK tpdu,
249 * tp_goodack() determines if the AK acknowledges something in the send
250 * window, and if so, drops the appropriate packets from the retransmission
251 * list, computes the round trip time, and updates the retransmission timer
252 * based on the new smoothed round trip time.
255 * EITHER it actually acked something heretofore unacknowledged
256 * OR no news but the credit should be processed.
257 * If something heretofore unacked was acked with this sequence number,
258 * the appropriate tpdus are dropped from the retransmission control list,
259 * by calling tp_sbdrop().
260 * No need to see the tpdu itself.
263 tp_goodack(tpcb
, cdt
, seq
, subseq
)
264 register struct tp_pcb
*tpcb
;
270 int bang
= 0; /* bang --> ack for something heretofore unacked */
274 printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n",
275 tpcb
, seq
, cdt
, tpcb
->tp_snduna
, tpcb
->tp_sndnew
, tpcb
->tp_sndnxt
);
278 tptraceTPCB(TPPTgotack
,
279 seq
,cdt
, tpcb
->tp_snduna
,tpcb
->tp_sndnew
,subseq
);
283 tpmeas(tpcb
->tp_lref
, TPtime_ack_rcvd
, (struct timeval
*)0, seq
, 0, 0);
286 if (seq
== tpcb
->tp_snduna
) {
287 if (subseq
< tpcb
->tp_r_subseq
||
288 (subseq
== tpcb
->tp_r_subseq
&& cdt
<= tpcb
->tp_fcredit
)) {
291 printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n",
292 tpcb
, subseq
, tpcb
->tp_r_subseq
);
296 if (cdt
== tpcb
->tp_fcredit
/*&& thus subseq > tpcb->tp_r_subseq */) {
297 tpcb
->tp_r_subseq
= subseq
;
298 if (tpcb
->tp_timer
[TM_data_retrans
] == 0)
299 tpcb
->tp_dupacks
= 0;
300 else if (++tpcb
->tp_dupacks
== tprexmtthresh
) {
301 /* partner went out of his way to signal with different
302 subsequences that he has the same lack of an expected
303 packet. This may be an early indiciation of a loss */
305 SeqNum onxt
= tpcb
->tp_sndnxt
;
306 struct mbuf
*onxt_m
= tpcb
->tp_sndnxt_m
;
307 u_int win
= min(tpcb
->tp_fcredit
,
308 tpcb
->tp_cong_win
/ tpcb
->tp_l_tpdusize
) / 2;
310 printf("%s tpcb 0x%x seq 0x%x rttseq 0x%x onxt 0x%x\n",
311 "goodack dupacks:", tpcb
, seq
, tpcb
->tp_rttseq
, onxt
);
315 tpcb
->tp_ssthresh
= win
* tpcb
->tp_l_tpdusize
;
316 tpcb
->tp_timer
[TM_data_retrans
] = 0;
317 tpcb
->tp_rttemit
= 0;
318 tpcb
->tp_sndnxt
= tpcb
->tp_snduna
;
319 tpcb
->tp_sndnxt_m
= 0;
320 tpcb
->tp_cong_win
= tpcb
->tp_l_tpdusize
;
322 tpcb
->tp_cong_win
= tpcb
->tp_ssthresh
+
323 tpcb
->tp_dupacks
* tpcb
->tp_l_tpdusize
;
324 if (SEQ_GT(tpcb
, onxt
, tpcb
->tp_sndnxt
)) {
325 tpcb
->tp_sndnxt
= onxt
;
326 tpcb
->tp_sndnxt_m
= onxt_m
;
329 } else if (tpcb
->tp_dupacks
> tprexmtthresh
) {
330 tpcb
->tp_cong_win
+= tpcb
->tp_l_tpdusize
;
334 } else if (SEQ_LT(tpcb
, seq
, tpcb
->tp_snduna
))
335 goto discard_the_ack
;
337 * If the congestion window was inflated to account
338 * for the other side's cached packets, retract it.
340 if (tpcb
->tp_dupacks
> tprexmtthresh
&&
341 tpcb
->tp_cong_win
> tpcb
->tp_ssthresh
)
342 tpcb
->tp_cong_win
= tpcb
->tp_ssthresh
;
343 tpcb
->tp_r_subseq
= subseq
;
344 old_fcredit
= tpcb
->tp_fcredit
;
345 tpcb
->tp_fcredit
= cdt
;
346 if (cdt
> tpcb
->tp_maxfcredit
)
347 tpcb
->tp_maxfcredit
= cdt
;
348 tpcb
->tp_dupacks
= 0;
350 if (IN_SWINDOW(tpcb
, seq
, tpcb
->tp_snduna
, tpcb
->tp_sndnew
)) {
353 bytes_acked
= tp_sbdrop(tpcb
, seq
);
356 * If transmit timer is running and timed sequence
357 * number was acked, update smoothed round trip time.
358 * Since we now have an rtt measurement, cancel the
359 * timer backoff (cf., Phil Karn's retransmit alg.).
360 * Recompute the initial retransmit timer.
362 if (tpcb
->tp_rttemit
&& SEQ_GT(tpcb
, seq
, tpcb
->tp_rttseq
))
365 * If all outstanding data is acked, stop retransmit timer.
366 * If there is more data to be acked, restart retransmit
367 * timer, using current (possibly backed-off) value.
368 * OSI combines the keepalive and persistance functions.
369 * So, there is no persistance timer per se, to restart.
371 if (tpcb
->tp_class
!= TP_CLASS_0
)
372 tpcb
->tp_timer
[TM_data_retrans
] =
373 (seq
== tpcb
->tp_sndnew
) ? 0 : tpcb
->tp_rxtcur
;
375 * When new data is acked, open the congestion window.
376 * If the window gives us less than ssthresh packets
377 * in flight, open exponentially (maxseg per packet).
378 * Otherwise open linearly: maxseg per window
379 * (maxseg^2 / cwnd per packet), plus a constant
380 * fraction of a packet (maxseg/8) to help larger windows
381 * open quickly enough.
384 u_int cw
= tpcb
->tp_cong_win
, incr
= tpcb
->tp_l_tpdusize
;
386 incr
= min(incr
, bytes_acked
);
387 if (cw
> tpcb
->tp_ssthresh
)
388 incr
= incr
* incr
/ cw
+ incr
/ 8;
390 min(cw
+ incr
, tpcb
->tp_sock
->so_snd
.sb_hiwat
);
392 tpcb
->tp_snduna
= seq
;
393 if (SEQ_LT(tpcb
, tpcb
->tp_sndnxt
, seq
)) {
394 tpcb
->tp_sndnxt
= seq
;
395 tpcb
->tp_sndnxt_m
= 0;
400 if( cdt
!= 0 && old_fcredit
== 0 ) {
401 tpcb
->tp_sendfcc
= 1;
404 if (old_fcredit
!= 0)
406 /* The following might mean that the window shrunk */
407 if (tpcb
->tp_timer
[TM_data_retrans
]) {
408 tpcb
->tp_timer
[TM_data_retrans
] = 0;
409 tpcb
->tp_timer
[TM_sendack
] = tpcb
->tp_dt_ticks
;
410 if (tpcb
->tp_sndnxt
!= tpcb
->tp_snduna
) {
411 tpcb
->tp_sndnxt
= tpcb
->tp_snduna
;
412 tpcb
->tp_sndnxt_m
= 0;
416 tpcb
->tp_fcredit
= cdt
;
417 bang
|= (old_fcredit
< cdt
);
421 printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n",
422 bang
, cdt
, old_fcredit
, tpcb
->tp_cong_win
);
424 /* if (bang) XXXXX Very bad to remove this test, but somethings broken */
432 * FUNCTION and ARGUMENTS:
433 * drops everything up TO but not INCLUDING seq # (seq)
434 * from the retransmission queue.
437 register struct tp_pcb
*tpcb
;
440 struct sockbuf
*sb
= &tpcb
->tp_sock
->so_snd
;
441 register int i
= SEQ_SUB(tpcb
, seq
, tpcb
->tp_snduna
);
442 int oldcc
= sb
->sb_cc
, oldi
= i
;
444 if (i
>= tpcb
->tp_seqhalf
)
445 printf("tp_spdropping too much -- should panic");
449 printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n",
450 oldi
, oldcc
- sb
->sb_cc
, tpcb
, seq
);
452 if ((sb
->sb_flags
& SB_NOTIFY
) || (sb
->sb_sel
.si_flags
& SI_SBSEL
))
453 sowwakeup(tpcb
->tp_sock
);
454 return (oldcc
- sb
->sb_cc
);
459 * tp.trans on user send request, arrival of AK and arrival of XAK
460 * FUNCTION and ARGUMENTS:
461 * Emits tpdus starting at sequence number (tpcb->tp_sndnxt).
462 * Emits until a) runs out of data, or b) runs into an XPD mark, or
463 * c) it hits seq number (highseq) limited by cong or credit.
465 * If you want XPD to buffer > 1 du per socket buffer, you can
466 * modifiy this to issue XPD tpdus also, but then it'll have
467 * to take some argument(s) to distinguish between the type of DU to
470 * When something is sent for the first time, its time-of-send
471 * is stashed (in system clock ticks rather than pf_slowtimo ticks).
472 * When the ack arrives, the smoothed round-trip time is figured
477 register struct tp_pcb
*tpcb
;
480 register struct mbuf
*m
;
482 struct sockbuf
*sb
= &tpcb
->tp_sock
->so_snd
;
483 unsigned int eotsdu
= 0;
484 SeqNum highseq
, checkseq
;
485 int idle
, idleticks
, off
, cong_win
;
487 int send_start_time
= ticks
;
488 SeqNum oldnxt
= tpcb
->tp_sndnxt
;
489 #endif /* TP_PERF_MEAS */
491 idle
= (tpcb
->tp_snduna
== tpcb
->tp_sndnew
);
493 idleticks
= tpcb
->tp_inact_ticks
- tpcb
->tp_timer
[TM_inact
];
494 if (idleticks
> tpcb
->tp_dt_ticks
)
496 * We have been idle for "a while" and no acks are
497 * expected to clock out any data we send --
498 * slow start to get ack "clock" running again.
500 tpcb
->tp_cong_win
= tpcb
->tp_l_tpdusize
;
503 cong_win
= tpcb
->tp_cong_win
;
504 highseq
= SEQ(tpcb
, tpcb
->tp_fcredit
+ tpcb
->tp_snduna
);
505 if (tpcb
->tp_Xsnd
.sb_mb
)
506 highseq
= SEQ_MIN(tpcb
, highseq
, tpcb
->tp_sndnew
);
509 printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n",
510 tpcb
, tpcb
->tp_sndnxt
, cong_win
, highseq
);
513 tptraceTPCB( TPPTmisc
, "tp_send sndnew snduna",
514 tpcb
->tp_sndnew
, tpcb
->tp_snduna
, 0, 0);
515 tptraceTPCB( TPPTmisc
, "tp_send tpcb->tp_sndnxt win fcredit congwin",
516 tpcb
->tp_sndnxt
, cong_win
, tpcb
->tp_fcredit
, tpcb
->tp_cong_win
);
519 tptraceTPCB( TPPTmisc
, "tp_send 2 nxt high fcredit congwin",
520 tpcb
->tp_sndnxt
, highseq
, tpcb
->tp_fcredit
, cong_win
);
523 if (tpcb
->tp_sndnxt_m
)
524 m
= tpcb
->tp_sndnxt_m
;
526 off
= SEQ_SUB(tpcb
, tpcb
->tp_sndnxt
, tpcb
->tp_snduna
);
527 for (m
= sb
->sb_mb
; m
&& off
> 0; m
= m
->m_next
)
532 * Avoid silly window syndrome here . . . figure out how!
534 checkseq
= tpcb
->tp_sndnum
;
535 if (idle
&& SEQ_LT(tpcb
, tpcb
->tp_sndnum
, highseq
))
536 checkseq
= highseq
; /* i.e. DON'T retain highest assigned packet */
538 while ((SEQ_LT(tpcb
, tpcb
->tp_sndnxt
, highseq
)) && m
&& cong_win
> 0) {
540 eotsdu
= (m
->m_flags
& M_EOR
) != 0;
541 len
= m
->m_pkthdr
.len
;
542 if (tpcb
->tp_sndnxt
== checkseq
&& eotsdu
== 0 &&
543 len
< (tpcb
->tp_l_tpdusize
/ 2))
544 break; /* Nagle . . . . . */
546 /* make a copy - mb goes into the retransmission list
547 * while m gets emitted. m_copy won't copy a zero-length mbuf.
550 m
= m_copy(mb
, 0, M_COPYALL
);
554 tptraceTPCB( TPPTmisc
,
555 "tp_send mcopy nxt high eotsdu len",
556 tpcb
->tp_sndnxt
, highseq
, eotsdu
, len
);
560 printf("tp_sending tpcb 0x%x nxt 0x%x\n",
561 tpcb
, tpcb
->tp_sndnxt
);
563 /* when headers are precomputed, may need to fill
565 if (tpcb
->tp_sock
->so_error
=
566 tp_emit(DT_TPDU_type
, tpcb
, tpcb
->tp_sndnxt
, eotsdu
, m
)) {
571 tpcb
->tp_sndnxt_m
= m
;
572 if (tpcb
->tp_sndnxt
== tpcb
->tp_sndnew
) {
573 SEQ_INC(tpcb
, tpcb
->tp_sndnew
);
575 * Time this transmission if not a retransmission and
576 * not currently timing anything.
578 if (tpcb
->tp_rttemit
== 0) {
579 tpcb
->tp_rttemit
= ticks
;
580 tpcb
->tp_rttseq
= tpcb
->tp_sndnxt
;
582 tpcb
->tp_sndnxt
= tpcb
->tp_sndnew
;
584 SEQ_INC(tpcb
, tpcb
->tp_sndnxt
);
586 * Set retransmit timer if not currently set.
587 * Initial value for retransmit timer is smoothed
588 * round-trip time + 2 * round-trip time variance.
589 * Initialize shift counter which is used for backoff
590 * of retransmit time.
592 if (tpcb
->tp_timer
[TM_data_retrans
] == 0 &&
593 tpcb
->tp_class
!= TP_CLASS_0
) {
594 tpcb
->tp_timer
[TM_data_retrans
] = tpcb
->tp_dt_ticks
;
595 tpcb
->tp_timer
[TM_sendack
] = tpcb
->tp_keepalive_ticks
;
596 tpcb
->tp_rxtshift
= 0;
599 if (SEQ_GT(tpcb
, tpcb
->tp_sndnew
, tpcb
->tp_sndnum
))
600 tpcb
->tp_oktonagle
= 0;
605 int elapsed
= ticks
- send_start_time
, *t
;
608 npkts
= SEQ_SUB(tpcb
, tpcb
->tp_sndnxt
, oldnxt
);
613 if (npkts
> TP_PM_MAX
)
616 t
= &(tpcb
->tp_p_meas
->tps_sendtime
[npkts
]);
617 *t
+= (t
- elapsed
) >> TP_RTT_ALPHA
;
620 IncPStat(tpcb
, tps_win_lim_by_data
[npkts
] );
622 IncPStat(tpcb
, tps_win_lim_by_cdt
[npkts
] );
623 /* not true with congestion-window being used */
625 now
.tv_sec
= elapsed
/ hz
;
626 now
.tv_usec
= (elapsed
- (hz
* now
.tv_sec
)) * 1000000 / hz
;
627 tpmeas( tpcb
->tp_lref
,
628 TPsbsend
, &elapsed
, newseq
, tpcb
->tp_Nwindow
, npkts
);
631 #endif /* TP_PERF_MEAS */
635 tptraceTPCB( TPPTmisc
,
636 "tp_send at end: new nxt eotsdu error",
637 tpcb
->tp_sndnew
, tpcb
->tp_sndnxt
, eotsdu
, tpcb
->tp_sock
->so_error
);
645 tp_packetize(tpcb
, m
, eotsdu
)
646 register struct tp_pcb
*tpcb
;
647 register struct mbuf
*m
;
650 register struct mbuf
*n
;
651 register struct sockbuf
*sb
= &tpcb
->tp_sock
->so_snd
;
652 int maxsize
= tpcb
->tp_l_tpdusize
653 - tp_headersize(DT_TPDU_type
, tpcb
)
654 - (tpcb
->tp_use_checksum
?4:0) ;
655 int totlen
= m
->m_pkthdr
.len
;
656 struct mbuf
*m_split();
658 * Pre-packetize the data in the sockbuf
659 * according to negotiated mtu. Do it here
660 * where we can safely wait for mbufs.
662 * This presumes knowledge of sockbuf conventions.
663 * TODO: allocate space for header and fill it in (once!).
666 printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n",
667 maxsize
, totlen
, eotsdu
, tpcb
->tp_sndnum
);
669 if (tpcb
->tp_oktonagle
) {
670 if ((n
= sb
->sb_mb
) == 0)
671 panic("tp_packetize");
674 if (n
->m_flags
& M_EOR
)
675 panic("tp_packetize 2");
676 SEQ_INC(tpcb
, tpcb
->tp_sndnum
);
677 if (totlen
+ n
->m_pkthdr
.len
< maxsize
) {
678 /* There is an unsent packet with space, combine data */
679 struct mbuf
*old_n
= n
;
681 n
->m_pkthdr
.len
+= totlen
;
684 sbcompress(sb
, m
, n
);
693 if (totlen
> maxsize
) {
694 if ((m
= m_split(n
, maxsize
, M_WAIT
)) == 0)
695 panic("tp_packetize");
700 sbappendrecord(sb
, n
);
702 SEQ_INC(tpcb
, tpcb
->tp_sndnum
);
706 n
->m_flags
|= M_EOR
; /* XXX belongs at end */
707 tpcb
->tp_oktonagle
= 0;
709 SEQ_DEC(tpcb
, tpcb
->tp_sndnum
);
710 tpcb
->tp_oktonagle
= 1;
714 printf("SEND out: oktonagle %d sndnum 0x%x\n",
715 tpcb
->tp_oktonagle
, tpcb
->tp_sndnum
);
724 * tp.trans on arrival of a DT tpdu
725 * FUNCTION, ARGUMENTS, and RETURN VALUE:
727 * a) something new arrived and it's got eotsdu_reached bit on,
728 * b) this arrival was caused other out-of-sequence things to be
730 * c) this arrival is the highest seq # for which we last gave credit
731 * (sender just sent a whole window)
732 * In other words, returns 1 if tp should send an ack immediately, 0 if
733 * the ack can wait a while.
735 * Note: this implementation no longer renegs on credit, (except
736 * when debugging option D_RENEG is on, for the purpose of testing
737 * ack subsequencing), so we don't need to check for incoming tpdus
738 * being in a reneged portion of the window.
742 register struct tp_pcb
*tpcb
;
743 register struct tp_event
*e
;
745 register int ack_reason
= tpcb
->tp_ack_strat
& ACK_STRAT_EACH
;
746 /* 0--> delay acks until full window */
747 /* 1--> ack each tpdu */
749 #define E e->ATTR(DT_TPDU)
751 #define E e->ev_union.EV_DT_TPDU
755 register struct mbuf
*n
= E
.e_data
;
760 dump_mbuf(tpcb
->tp_sock
->so_rcv
.sb_mb
,
761 "stash: so_rcv before appending");
763 "stash: e_data before appending");
767 PStat(tpcb
, Nb_from_ll
) += E
.e_datalen
;
768 tpmeas(tpcb
->tp_lref
, TPtime_from_ll
, &e
->e_time
,
769 E
.e_seq
, (u_int
)PStat(tpcb
, Nb_from_ll
), (u_int
)E
.e_datalen
);
772 if (E
.e_seq
== tpcb
->tp_rcvnxt
) {
775 printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
776 E
.e_seq
, E
.e_datalen
, E
.e_eot
);
780 tptraceTPCB(TPPTmisc
, "stash EQ: seq len eot",
781 E
.e_seq
, E
.e_datalen
, E
.e_eot
, 0);
786 sbappend(&tpcb
->tp_sock
->so_rcv
, E
.e_data
);
788 SEQ_INC( tpcb
, tpcb
->tp_rcvnxt
);
790 * move chains from the reassembly queue to the socket buffer
792 if (tpcb
->tp_rsycnt
) {
793 register struct mbuf
**mp
;
796 mp
= tpcb
->tp_rsyq
+ (tpcb
->tp_rcvnxt
% tpcb
->tp_maxlcredit
);
797 mplim
= tpcb
->tp_rsyq
+ tpcb
->tp_maxlcredit
;
799 while (tpcb
->tp_rsycnt
&& *mp
) {
800 sbappend(&tpcb
->tp_sock
->so_rcv
, *mp
);
803 SEQ_INC(tpcb
, tpcb
->tp_rcvnxt
);
804 ack_reason
|= ACK_REORDER
;
810 dump_mbuf(tpcb
->tp_sock
->so_rcv
.sb_mb
,
811 "stash: so_rcv after appending");
815 register struct mbuf
**mp
;
819 tptraceTPCB(TPPTmisc
, "stash Reseq: seq rcvnxt lcdt",
820 E
.e_seq
, tpcb
->tp_rcvnxt
, tpcb
->tp_lcredit
, 0);
823 if (tpcb
->tp_rsyq
== 0)
825 uwe
= SEQ(tpcb
, tpcb
->tp_rcvnxt
+ tpcb
->tp_maxlcredit
);
826 if (tpcb
->tp_rsyq
== 0 ||
827 !IN_RWINDOW(tpcb
, E
.e_seq
, tpcb
->tp_rcvnxt
, uwe
)) {
828 ack_reason
= ACK_DONT
;
830 } else if (*(mp
= tpcb
->tp_rsyq
+ (E
.e_seq
% tpcb
->tp_maxlcredit
))) {
832 printf("tp_stash - drop & ack\n");
835 /* retransmission - drop it and force an ack */
838 IncPStat(tpcb
, tps_n_ack_cuz_dup
);
842 ack_reason
|= ACK_DUP
;
846 ack_reason
= ACK_DONT
;
849 /* there were some comments of historical interest here. */
853 if ( E
.e_seq
== tpcb
->tp_sent_uwe
)
854 ack_reason
|= ACK_STRAT_FULLWIN
;
857 tptraceTPCB(TPPTmisc
,
858 "end of stash, eot, ack_reason, sent_uwe ",
859 E
.e_eot
, ack_reason
, tpcb
->tp_sent_uwe
, 0);
862 if ( ack_reason
== ACK_DONT
) {
863 IncStat( ts_ackreason
[ACK_DONT
] );
867 if(ack_reason
& ACK_STRAT_EACH
) {
868 IncPStat(tpcb
, tps_n_ack_cuz_strat
);
869 } else if(ack_reason
& ACK_STRAT_FULLWIN
) {
870 IncPStat(tpcb
, tps_n_ack_cuz_fullwin
);
871 } else if(ack_reason
& ACK_REORDER
) {
872 IncPStat(tpcb
, tps_n_ack_cuz_reorder
);
874 tpmeas(tpcb
->tp_lref
, TPtime_ack_sent
, 0,
875 SEQ_ADD(tpcb
, E
.e_seq
, 1), 0, 0);
880 /* keep track of all reasons that apply */
881 for( i
=1; i
<_ACK_NUM_REASONS_
;i
++) {
882 if( ack_reason
& (1<<i
) )
883 IncStat( ts_ackreason
[i
] );
892 * tp_rsyflush - drop all the packets on the reassembly queue.
893 * Do this when closing the socket, or when somebody has changed
894 * the space avaible in the receive socket (XXX).
897 register struct tp_pcb
*tpcb
;
899 register struct mbuf
*m
, **mp
;
900 if (tpcb
->tp_rsycnt
) {
901 for (mp
== tpcb
->tp_rsyq
+ tpcb
->tp_maxlcredit
;
902 --mp
>= tpcb
->tp_rsyq
; )
907 if (tpcb
->tp_rsycnt
) {
908 printf("tp_rsyflush %x\n", tpcb
);
912 FREE((caddr_t
)tpcb
->tp_rsyq
, M_PCB
);
917 register struct tp_pcb
*tpcb
;
919 register struct socket
*so
= tpcb
->tp_sock
;
920 int maxcredit
= tpcb
->tp_xtd_format
? 0xffff : 0xf;
921 int old_credit
= tpcb
->tp_maxlcredit
;
924 tpcb
->tp_maxlcredit
= maxcredit
= min(maxcredit
,
925 (so
->so_rcv
.sb_hiwat
+ tpcb
->tp_l_tpdusize
)/ tpcb
->tp_l_tpdusize
);
927 if (old_credit
== tpcb
->tp_maxlcredit
&& tpcb
->tp_rsyq
!= 0)
929 maxcredit
*= sizeof(struct mbuf
*);
932 // if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT))
933 MALLOC(rsyq
, caddr_t
, maxcredit
, M_PCB
, M_NOWAIT
);
935 bzero(rsyq
, maxcredit
);
936 tpcb
->tp_rsyq
= (struct mbuf
**)rsyq
;
942 register struct mbuf
*n
, *m
;
943 register int len
= 0, mbcnt
= 0, pktlen
;
944 struct sockbuf
*sb
= &tpcb
->tp_sock
->so_snd
;
946 for (n
= sb
->sb_mb
; n
; n
= n
->m_nextpkt
) {
947 if ((n
->m_flags
& M_PKTHDR
) == 0)
948 panic("tpsbcheck nohdr");
949 pktlen
= len
+ n
->m_pkthdr
.len
;
950 for (m
= n
; m
; m
= m
->m_next
) {
953 if (m
->m_flags
& M_EXT
)
954 mbcnt
+= m
->m_ext
.ext_size
;
957 printf("test %d; len %d != pktlen %d on mbuf 0x%x\n",
959 panic("tpsbcheck short");
962 if (len
!= sb
->sb_cc
|| mbcnt
!= sb
->sb_mbcnt
) {
963 printf("test %d: cc %d != %d || mbcnt %d != %d\n", i
, len
, sb
->sb_cc
,
964 mbcnt
, sb
->sb_mbcnt
);