|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*-
26: * Copyright (c) 1991, 1993
27: * The Regents of the University of California. All rights reserved.
28: *
29: * Redistribution and use in source and binary forms, with or without
30: * modification, are permitted provided that the following conditions
31: * are met:
32: * 1. Redistributions of source code must retain the above copyright
33: * notice, this list of conditions and the following disclaimer.
34: * 2. Redistributions in binary form must reproduce the above copyright
35: * notice, this list of conditions and the following disclaimer in the
36: * documentation and/or other materials provided with the distribution.
37: * 3. All advertising materials mentioning features or use of this software
38: * must display the following acknowledgement:
39: * This product includes software developed by the University of
40: * California, Berkeley and its contributors.
41: * 4. Neither the name of the University nor the names of its contributors
42: * may be used to endorse or promote products derived from this software
43: * without specific prior written permission.
44: *
45: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55: * SUCH DAMAGE.
56: *
57: * @(#)tp_subr.c 8.1 (Berkeley) 6/10/93
58: */
59:
60: /***********************************************************
61: Copyright IBM Corporation 1987
62:
63: All Rights Reserved
64:
65: Permission to use, copy, modify, and distribute this software and its
66: documentation for any purpose and without fee is hereby granted,
67: provided that the above copyright notice appear in all copies and that
68: both that copyright notice and this permission notice appear in
69: supporting documentation, and that the name of IBM not be
70: used in advertising or publicity pertaining to distribution of the
71: software without specific, written prior permission.
72:
73: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
74: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
75: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
76: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
77: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
78: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
79: SOFTWARE.
80:
81: ******************************************************************/
82:
83: /*
84: * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
85: */
86: /*
87: * ARGO TP
88: *
89: * The main work of data transfer is done here.
90: * These routines are called from tp.trans.
91: * They include the routines that check the validity of acks and Xacks,
92: * (tp_goodack() and tp_goodXack() )
93: * take packets from socket buffers and send them (tp_send()),
94: * drop the data from the socket buffers (tp_sbdrop()),
95: * and put incoming packet data into socket buffers (tp_stash()).
96: */
97:
98: #include <sys/param.h>
99: #include <sys/systm.h>
100: #include <sys/mbuf.h>
101: #include <sys/socket.h>
102: #include <sys/socketvar.h>
103: #include <sys/protosw.h>
104: #include <sys/errno.h>
105: #include <sys/time.h>
106: #include <sys/kernel.h>
107:
108: #include <netiso/tp_ip.h>
109: #include <netiso/iso.h>
110: #include <netiso/argo_debug.h>
111: #include <netiso/tp_timer.h>
112: #include <netiso/tp_param.h>
113: #include <netiso/tp_stat.h>
114: #include <netiso/tp_pcb.h>
115: #include <netiso/tp_tpdu.h>
116: #include <netiso/tp_trace.h>
117: #include <netiso/tp_meas.h>
118: #include <netiso/tp_seq.h>
119:
120: int tp_emit(), tp_sbdrop();
121: int tprexmtthresh = 3;
122: extern int ticks;
123: void tp_send();
124:
125: /*
126: * CALLED FROM:
127: * tp.trans, when an XAK arrives
128: * FUNCTION and ARGUMENTS:
129: * Determines if the sequence number (seq) from the XAK
130: * acks anything new. If so, drop the appropriate tpdu
131: * from the XPD send queue.
132: * RETURN VALUE:
133: * Returns 1 if it did this, 0 if the ack caused no action.
134: */
135: int
136: tp_goodXack(tpcb, seq)
137: struct tp_pcb *tpcb;
138: SeqNum seq;
139: {
140:
141: IFTRACE(D_XPD)
142: tptraceTPCB(TPPTgotXack,
143: seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndnew,
144: tpcb->tp_snduna);
145: ENDTRACE
146:
147: if ( seq == tpcb->tp_Xuna ) {
148: tpcb->tp_Xuna = tpcb->tp_Xsndnxt;
149:
150: /* DROP 1 packet from the Xsnd socket buf - just so happens
151: * that only one packet can be there at any time
152: * so drop the whole thing. If you allow > 1 packet
153: * the socket buffer, then you'll have to keep
154: * track of how many characters went w/ each XPD tpdu, so this
155: * will get messier
156: */
157: IFDEBUG(D_XPD)
158: dump_mbuf(tpcb->tp_Xsnd.sb_mb,
159: "tp_goodXack Xsnd before sbdrop");
160: ENDDEBUG
161:
162: IFTRACE(D_XPD)
163: tptraceTPCB(TPPTmisc,
164: "goodXack: dropping cc ",
165: (int)(tpcb->tp_Xsnd.sb_cc),
166: 0,0,0);
167: ENDTRACE
168: sbdroprecord(&tpcb->tp_Xsnd);
169: return 1;
170: }
171: return 0;
172: }
173:
174: /*
175: * CALLED FROM:
176: * tp_good_ack()
177: * FUNCTION and ARGUMENTS:
178: * updates
179: * smoothed average round trip time (*rtt)
180: * roundtrip time variance (*rtv) - actually deviation, not variance
181: * given the new value (diff)
182: * RETURN VALUE:
183: * void
184: */
185:
186: void
187: tp_rtt_rtv(tpcb)
188: register struct tp_pcb *tpcb;
189: {
190: int old = tpcb->tp_rtt;
191: int delta, elapsed = ticks - tpcb->tp_rttemit;
192:
193: if (tpcb->tp_rtt != 0) {
194: /*
195: * rtt is the smoothed round trip time in machine clock ticks (hz).
196: * It is stored as a fixed point number, unscaled (unlike the tcp
197: * srtt). The rationale here is that it is only significant to the
198: * nearest unit of slowtimo, which is at least 8 machine clock ticks
199: * so there is no need to scale. The smoothing is done according
200: * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8).
201: */
202: delta = elapsed - tpcb->tp_rtt;
203: if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0)
204: tpcb->tp_rtt = 1;
205: /*
206: * rtv is a smoothed accumulated mean difference, unscaled
207: * for reasons expressed above.
208: * It is smoothed with an alpha of .75, and the round trip timer
209: * will be set to rtt + 4*rtv, also as TCP does.
210: */
211: if (delta < 0)
212: delta = -delta;
213: if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0)
214: tpcb->tp_rtv = 1;
215: } else {
216: /*
217: * No rtt measurement yet - use the unsmoothed rtt.
218: * Set the variance to half the rtt (so our first
219: * retransmit happens at 3*rtt)
220: */
221: tpcb->tp_rtt = elapsed;
222: tpcb->tp_rtv = elapsed >> 1;
223: }
224: tpcb->tp_rttemit = 0;
225: tpcb->tp_rxtshift = 0;
226: /*
227: * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar.
228: * Because of the way we do the smoothing, srtt and rttvar
229: * will each average +1/2 tick of bias. When we compute
230: * the retransmit timer, we want 1/2 tick of rounding and
231: * 1 extra tick because of +-1/2 tick uncertainty in the
232: * firing of the timer. The bias will give us exactly the
233: * 1.5 tick we need. But, because the bias is
234: * statistical, we have to test that we don't drop below
235: * the minimum feasible timer (which is 2 ticks)."
236: */
237: TP_RANGESET(tpcb->tp_dt_ticks, TP_REXMTVAL(tpcb),
238: tpcb->tp_peer_acktime, 128 /* XXX */);
239: IFDEBUG(D_RTT)
240: printf("%s tpcb 0x%x, elapsed %d, delta %d, rtt %d, rtv %d, old %d\n",
241: "tp_rtt_rtv:",tpcb,elapsed,delta,tpcb->tp_rtt,tpcb->tp_rtv,old);
242: ENDDEBUG
243: tpcb->tp_rxtcur = tpcb->tp_dt_ticks;
244: }
245:
246: /*
247: * CALLED FROM:
248: * tp.trans when an AK arrives
249: * FUNCTION and ARGUMENTS:
250: * Given (cdt), the credit from the AK tpdu, and
251: * (seq), the sequence number from the AK tpdu,
252: * tp_goodack() determines if the AK acknowledges something in the send
253: * window, and if so, drops the appropriate packets from the retransmission
254: * list, computes the round trip time, and updates the retransmission timer
255: * based on the new smoothed round trip time.
256: * RETURN VALUE:
257: * Returns 1 if
258: * EITHER it actually acked something heretofore unacknowledged
259: * OR no news but the credit should be processed.
260: * If something heretofore unacked was acked with this sequence number,
261: * the appropriate tpdus are dropped from the retransmission control list,
262: * by calling tp_sbdrop().
263: * No need to see the tpdu itself.
264: */
265: int
266: tp_goodack(tpcb, cdt, seq, subseq)
267: register struct tp_pcb *tpcb;
268: u_int cdt;
269: register SeqNum seq;
270: u_int subseq;
271: {
272: int old_fcredit;
273: int bang = 0; /* bang --> ack for something heretofore unacked */
274: u_int bytes_acked;
275:
276: IFDEBUG(D_ACKRECV)
277: printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n",
278: tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt);
279: ENDDEBUG
280: IFTRACE(D_ACKRECV)
281: tptraceTPCB(TPPTgotack,
282: seq,cdt, tpcb->tp_snduna,tpcb->tp_sndnew,subseq);
283: ENDTRACE
284:
285: IFPERF(tpcb)
286: tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0);
287: ENDPERF
288:
289: if (seq == tpcb->tp_snduna) {
290: if (subseq < tpcb->tp_r_subseq ||
291: (subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) {
292: discard_the_ack:
293: IFDEBUG(D_ACKRECV)
294: printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n",
295: tpcb, subseq, tpcb->tp_r_subseq);
296: ENDDEBUG
297: goto done;
298: }
299: if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) {
300: tpcb->tp_r_subseq = subseq;
301: if (tpcb->tp_timer[TM_data_retrans] == 0)
302: tpcb->tp_dupacks = 0;
303: else if (++tpcb->tp_dupacks == tprexmtthresh) {
304: /* partner went out of his way to signal with different
305: subsequences that he has the same lack of an expected
306: packet. This may be an early indiciation of a loss */
307:
308: SeqNum onxt = tpcb->tp_sndnxt;
309: struct mbuf *onxt_m = tpcb->tp_sndnxt_m;
310: u_int win = min(tpcb->tp_fcredit,
311: tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2;
312: IFDEBUG(D_ACKRECV)
313: printf("%s tpcb 0x%x seq 0x%x rttseq 0x%x onxt 0x%x\n",
314: "goodack dupacks:", tpcb, seq, tpcb->tp_rttseq, onxt);
315: ENDDEBUG
316: if (win < 2)
317: win = 2;
318: tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize;
319: tpcb->tp_timer[TM_data_retrans] = 0;
320: tpcb->tp_rttemit = 0;
321: tpcb->tp_sndnxt = tpcb->tp_snduna;
322: tpcb->tp_sndnxt_m = 0;
323: tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
324: tp_send(tpcb);
325: tpcb->tp_cong_win = tpcb->tp_ssthresh +
326: tpcb->tp_dupacks * tpcb->tp_l_tpdusize;
327: if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) {
328: tpcb->tp_sndnxt = onxt;
329: tpcb->tp_sndnxt_m = onxt_m;
330: }
331:
332: } else if (tpcb->tp_dupacks > tprexmtthresh) {
333: tpcb->tp_cong_win += tpcb->tp_l_tpdusize;
334: }
335: goto done;
336: }
337: } else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna))
338: goto discard_the_ack;
339: /*
340: * If the congestion window was inflated to account
341: * for the other side's cached packets, retract it.
342: */
343: if (tpcb->tp_dupacks > tprexmtthresh &&
344: tpcb->tp_cong_win > tpcb->tp_ssthresh)
345: tpcb->tp_cong_win = tpcb->tp_ssthresh;
346: tpcb->tp_r_subseq = subseq;
347: old_fcredit = tpcb->tp_fcredit;
348: tpcb->tp_fcredit = cdt;
349: if (cdt > tpcb->tp_maxfcredit)
350: tpcb->tp_maxfcredit = cdt;
351: tpcb->tp_dupacks = 0;
352:
353: if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) {
354:
355: tpsbcheck(tpcb, 0);
356: bytes_acked = tp_sbdrop(tpcb, seq);
357: tpsbcheck(tpcb, 1);
358: /*
359: * If transmit timer is running and timed sequence
360: * number was acked, update smoothed round trip time.
361: * Since we now have an rtt measurement, cancel the
362: * timer backoff (cf., Phil Karn's retransmit alg.).
363: * Recompute the initial retransmit timer.
364: */
365: if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq))
366: tp_rtt_rtv(tpcb);
367: /*
368: * If all outstanding data is acked, stop retransmit timer.
369: * If there is more data to be acked, restart retransmit
370: * timer, using current (possibly backed-off) value.
371: * OSI combines the keepalive and persistance functions.
372: * So, there is no persistance timer per se, to restart.
373: */
374: if (tpcb->tp_class != TP_CLASS_0)
375: tpcb->tp_timer[TM_data_retrans] =
376: (seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur;
377: /*
378: * When new data is acked, open the congestion window.
379: * If the window gives us less than ssthresh packets
380: * in flight, open exponentially (maxseg per packet).
381: * Otherwise open linearly: maxseg per window
382: * (maxseg^2 / cwnd per packet), plus a constant
383: * fraction of a packet (maxseg/8) to help larger windows
384: * open quickly enough.
385: */
386: {
387: u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize;
388:
389: incr = min(incr, bytes_acked);
390: if (cw > tpcb->tp_ssthresh)
391: incr = incr * incr / cw + incr / 8;
392: tpcb->tp_cong_win =
393: min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat);
394: }
395: tpcb->tp_snduna = seq;
396: if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) {
397: tpcb->tp_sndnxt = seq;
398: tpcb->tp_sndnxt_m = 0;
399: }
400: bang++;
401: }
402:
403: if( cdt != 0 && old_fcredit == 0 ) {
404: tpcb->tp_sendfcc = 1;
405: }
406: if (cdt == 0) {
407: if (old_fcredit != 0)
408: IncStat(ts_zfcdt);
409: /* The following might mean that the window shrunk */
410: if (tpcb->tp_timer[TM_data_retrans]) {
411: tpcb->tp_timer[TM_data_retrans] = 0;
412: tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks;
413: if (tpcb->tp_sndnxt != tpcb->tp_snduna) {
414: tpcb->tp_sndnxt = tpcb->tp_snduna;
415: tpcb->tp_sndnxt_m = 0;
416: }
417: }
418: }
419: tpcb->tp_fcredit = cdt;
420: bang |= (old_fcredit < cdt);
421:
422: done:
423: IFDEBUG(D_ACKRECV)
424: printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n",
425: bang, cdt, old_fcredit, tpcb->tp_cong_win);
426: ENDDEBUG
427: /* if (bang) XXXXX Very bad to remove this test, but somethings broken */
428: tp_send(tpcb);
429: return (bang);
430: }
431:
432: /*
433: * CALLED FROM:
434: * tp_goodack()
435: * FUNCTION and ARGUMENTS:
436: * drops everything up TO but not INCLUDING seq # (seq)
437: * from the retransmission queue.
438: */
439: tp_sbdrop(tpcb, seq)
440: register struct tp_pcb *tpcb;
441: SeqNum seq;
442: {
443: struct sockbuf *sb = &tpcb->tp_sock->so_snd;
444: register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna);
445: int oldcc = sb->sb_cc, oldi = i;
446:
447: if (i >= tpcb->tp_seqhalf)
448: printf("tp_spdropping too much -- should panic");
449: while (i-- > 0)
450: sbdroprecord(sb);
451: IFDEBUG(D_ACKRECV)
452: printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n",
453: oldi, oldcc - sb->sb_cc, tpcb, seq);
454: ENDDEBUG
455: if (sb->sb_flags & SB_NOTIFY)
456: sowwakeup(tpcb->tp_sock);
457: return (oldcc - sb->sb_cc);
458: }
459:
460: /*
461: * CALLED FROM:
462: * tp.trans on user send request, arrival of AK and arrival of XAK
463: * FUNCTION and ARGUMENTS:
464: * Emits tpdus starting at sequence number (tpcb->tp_sndnxt).
465: * Emits until a) runs out of data, or b) runs into an XPD mark, or
466: * c) it hits seq number (highseq) limited by cong or credit.
467: *
468: * If you want XPD to buffer > 1 du per socket buffer, you can
469: * modifiy this to issue XPD tpdus also, but then it'll have
470: * to take some argument(s) to distinguish between the type of DU to
471: * hand tp_emit.
472: *
473: * When something is sent for the first time, its time-of-send
474: * is stashed (in system clock ticks rather than pf_slowtimo ticks).
475: * When the ack arrives, the smoothed round-trip time is figured
476: * using this value.
477: */
478: void
479: tp_send(tpcb)
480: register struct tp_pcb *tpcb;
481: {
482: register int len;
483: register struct mbuf *m;
484: struct mbuf *mb = 0;
485: struct sockbuf *sb = &tpcb->tp_sock->so_snd;
486: unsigned int eotsdu = 0;
487: SeqNum highseq, checkseq;
488: int idle, idleticks, off, cong_win;
489: #ifdef TP_PERF_MEAS
490: int send_start_time = ticks;
491: SeqNum oldnxt = tpcb->tp_sndnxt;
492: #endif /* TP_PERF_MEAS */
493:
494: idle = (tpcb->tp_snduna == tpcb->tp_sndnew);
495: if (idle) {
496: idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact];
497: if (idleticks > tpcb->tp_dt_ticks)
498: /*
499: * We have been idle for "a while" and no acks are
500: * expected to clock out any data we send --
501: * slow start to get ack "clock" running again.
502: */
503: tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
504: }
505:
506: cong_win = tpcb->tp_cong_win;
507: highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna);
508: if (tpcb->tp_Xsnd.sb_mb)
509: highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew);
510:
511: IFDEBUG(D_DATA)
512: printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n",
513: tpcb, tpcb->tp_sndnxt, cong_win, highseq);
514: ENDDEBUG
515: IFTRACE(D_DATA)
516: tptraceTPCB( TPPTmisc, "tp_send sndnew snduna",
517: tpcb->tp_sndnew, tpcb->tp_snduna, 0, 0);
518: tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin",
519: tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win);
520: ENDTRACE
521: IFTRACE(D_DATA)
522: tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin",
523: tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win);
524: ENDTRACE
525:
526: if (tpcb->tp_sndnxt_m)
527: m = tpcb->tp_sndnxt_m;
528: else {
529: off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna);
530: for (m = sb->sb_mb; m && off > 0; m = m->m_next)
531: off--;
532: }
533: send:
534: /*
535: * Avoid silly window syndrome here . . . figure out how!
536: */
537: checkseq = tpcb->tp_sndnum;
538: if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq))
539: checkseq = highseq; /* i.e. DON'T retain highest assigned packet */
540:
541: while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) {
542:
543: eotsdu = (m->m_flags & M_EOR) != 0;
544: len = m->m_pkthdr.len;
545: if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 &&
546: len < (tpcb->tp_l_tpdusize / 2))
547: break; /* Nagle . . . . . */
548: cong_win -= len;
549: /* make a copy - mb goes into the retransmission list
550: * while m gets emitted. m_copy won't copy a zero-length mbuf.
551: */
552: mb = m;
553: m = m_copy(mb, 0, M_COPYALL);
554: if (m == MNULL)
555: break;
556: IFTRACE(D_STASH)
557: tptraceTPCB( TPPTmisc,
558: "tp_send mcopy nxt high eotsdu len",
559: tpcb->tp_sndnxt, highseq, eotsdu, len);
560: ENDTRACE
561:
562: IFDEBUG(D_DATA)
563: printf("tp_sending tpcb 0x%x nxt 0x%x\n",
564: tpcb, tpcb->tp_sndnxt);
565: ENDDEBUG
566: /* when headers are precomputed, may need to fill
567: in checksum here */
568: if (tpcb->tp_sock->so_error =
569: tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) {
570: /* error */
571: break;
572: }
573: m = mb->m_nextpkt;
574: tpcb->tp_sndnxt_m = m;
575: if (tpcb->tp_sndnxt == tpcb->tp_sndnew) {
576: SEQ_INC(tpcb, tpcb->tp_sndnew);
577: /*
578: * Time this transmission if not a retransmission and
579: * not currently timing anything.
580: */
581: if (tpcb->tp_rttemit == 0) {
582: tpcb->tp_rttemit = ticks;
583: tpcb->tp_rttseq = tpcb->tp_sndnxt;
584: }
585: tpcb->tp_sndnxt = tpcb->tp_sndnew;
586: } else
587: SEQ_INC(tpcb, tpcb->tp_sndnxt);
588: /*
589: * Set retransmit timer if not currently set.
590: * Initial value for retransmit timer is smoothed
591: * round-trip time + 2 * round-trip time variance.
592: * Initialize shift counter which is used for backoff
593: * of retransmit time.
594: */
595: if (tpcb->tp_timer[TM_data_retrans] == 0 &&
596: tpcb->tp_class != TP_CLASS_0) {
597: tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks;
598: tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks;
599: tpcb->tp_rxtshift = 0;
600: }
601: }
602: if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum))
603: tpcb->tp_oktonagle = 0;
604: #ifdef TP_PERF_MEAS
605: IFPERF(tpcb)
606: {
607: register int npkts;
608: int elapsed = ticks - send_start_time, *t;
609: struct timeval now;
610:
611: npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt);
612:
613: if (npkts > 0)
614: tpcb->tp_Nwindow++;
615:
616: if (npkts > TP_PM_MAX)
617: npkts = TP_PM_MAX;
618:
619: t = &(tpcb->tp_p_meas->tps_sendtime[npkts]);
620: *t += (t - elapsed) >> TP_RTT_ALPHA;
621:
622: if (mb == 0) {
623: IncPStat(tpcb, tps_win_lim_by_data[npkts] );
624: } else {
625: IncPStat(tpcb, tps_win_lim_by_cdt[npkts] );
626: /* not true with congestion-window being used */
627: }
628: now.tv_sec = elapsed / hz;
629: now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz;
630: tpmeas( tpcb->tp_lref,
631: TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts);
632: }
633: ENDPERF
634: #endif /* TP_PERF_MEAS */
635:
636:
637: IFTRACE(D_DATA)
638: tptraceTPCB( TPPTmisc,
639: "tp_send at end: new nxt eotsdu error",
640: tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error);
641:
642: ENDTRACE
643: }
644:
645: int TPNagleok;
646: int TPNagled;
647:
648: tp_packetize(tpcb, m, eotsdu)
649: register struct tp_pcb *tpcb;
650: register struct mbuf *m;
651: int eotsdu;
652: {
653: register struct mbuf *n;
654: register struct sockbuf *sb = &tpcb->tp_sock->so_snd;
655: int maxsize = tpcb->tp_l_tpdusize
656: - tp_headersize(DT_TPDU_type, tpcb)
657: - (tpcb->tp_use_checksum?4:0) ;
658: int totlen = m->m_pkthdr.len;
659: struct mbuf *m_split();
660: /*
661: * Pre-packetize the data in the sockbuf
662: * according to negotiated mtu. Do it here
663: * where we can safely wait for mbufs.
664: *
665: * This presumes knowledge of sockbuf conventions.
666: * TODO: allocate space for header and fill it in (once!).
667: */
668: IFDEBUG(D_DATA)
669: printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n",
670: maxsize, totlen, eotsdu, tpcb->tp_sndnum);
671: ENDTRACE
672: if (tpcb->tp_oktonagle) {
673: if ((n = sb->sb_mb) == 0)
674: panic("tp_packetize");
675: while (n->m_act)
676: n = n->m_act;
677: if (n->m_flags & M_EOR)
678: panic("tp_packetize 2");
679: SEQ_INC(tpcb, tpcb->tp_sndnum);
680: if (totlen + n->m_pkthdr.len < maxsize) {
681: /* There is an unsent packet with space, combine data */
682: struct mbuf *old_n = n;
683: tpsbcheck(tpcb,3);
684: n->m_pkthdr.len += totlen;
685: while (n->m_next)
686: n = n->m_next;
687: sbcompress(sb, m, n);
688: tpsbcheck(tpcb,4);
689: n = old_n;
690: TPNagled++;
691: goto out;
692: }
693: }
694: while (m) {
695: n = m;
696: if (totlen > maxsize) {
697: if ((m = m_split(n, maxsize, M_WAIT)) == 0)
698: panic("tp_packetize");
699: } else
700: m = 0;
701: totlen -= maxsize;
702: tpsbcheck(tpcb, 5);
703: sbappendrecord(sb, n);
704: tpsbcheck(tpcb, 6);
705: SEQ_INC(tpcb, tpcb->tp_sndnum);
706: }
707: out:
708: if (eotsdu) {
709: n->m_flags |= M_EOR; /* XXX belongs at end */
710: tpcb->tp_oktonagle = 0;
711: } else {
712: SEQ_DEC(tpcb, tpcb->tp_sndnum);
713: tpcb->tp_oktonagle = 1;
714: TPNagleok++;
715: }
716: IFDEBUG(D_DATA)
717: printf("SEND out: oktonagle %d sndnum 0x%x\n",
718: tpcb->tp_oktonagle, tpcb->tp_sndnum);
719: ENDTRACE
720: return 0;
721: }
722:
723:
724: /*
725: * NAME: tp_stash()
726: * CALLED FROM:
727: * tp.trans on arrival of a DT tpdu
728: * FUNCTION, ARGUMENTS, and RETURN VALUE:
729: * Returns 1 if
730: * a) something new arrived and it's got eotsdu_reached bit on,
731: * b) this arrival was caused other out-of-sequence things to be
732: * accepted, or
733: * c) this arrival is the highest seq # for which we last gave credit
734: * (sender just sent a whole window)
735: * In other words, returns 1 if tp should send an ack immediately, 0 if
736: * the ack can wait a while.
737: *
738: * Note: this implementation no longer renegs on credit, (except
739: * when debugging option D_RENEG is on, for the purpose of testing
740: * ack subsequencing), so we don't need to check for incoming tpdus
741: * being in a reneged portion of the window.
742: */
743:
744: tp_stash(tpcb, e)
745: register struct tp_pcb *tpcb;
746: register struct tp_event *e;
747: {
748: register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH;
749: /* 0--> delay acks until full window */
750: /* 1--> ack each tpdu */
751: #ifndef lint
752: #define E e->ATTR(DT_TPDU)
753: #else /* lint */
754: #define E e->ev_union.EV_DT_TPDU
755: #endif /* lint */
756:
757: if ( E.e_eot ) {
758: register struct mbuf *n = E.e_data;
759: n->m_flags |= M_EOR;
760: n->m_act = 0;
761: }
762: IFDEBUG(D_STASH)
763: dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
764: "stash: so_rcv before appending");
765: dump_mbuf(E.e_data,
766: "stash: e_data before appending");
767: ENDDEBUG
768:
769: IFPERF(tpcb)
770: PStat(tpcb, Nb_from_ll) += E.e_datalen;
771: tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
772: E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen);
773: ENDPERF
774:
775: if (E.e_seq == tpcb->tp_rcvnxt) {
776:
777: IFDEBUG(D_STASH)
778: printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n",
779: E.e_seq, E.e_datalen, E.e_eot);
780: ENDDEBUG
781:
782: IFTRACE(D_STASH)
783: tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
784: E.e_seq, E.e_datalen, E.e_eot, 0);
785: ENDTRACE
786:
787: SET_DELACK(tpcb);
788:
789: sbappend(&tpcb->tp_sock->so_rcv, E.e_data);
790:
791: SEQ_INC( tpcb, tpcb->tp_rcvnxt );
792: /*
793: * move chains from the reassembly queue to the socket buffer
794: */
795: if (tpcb->tp_rsycnt) {
796: register struct mbuf **mp;
797: struct mbuf **mplim;
798:
799: mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit);
800: mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit;
801:
802: while (tpcb->tp_rsycnt && *mp) {
803: sbappend(&tpcb->tp_sock->so_rcv, *mp);
804: tpcb->tp_rsycnt--;
805: *mp = 0;
806: SEQ_INC(tpcb, tpcb->tp_rcvnxt);
807: ack_reason |= ACK_REORDER;
808: if (++mp == mplim)
809: mp = tpcb->tp_rsyq;
810: }
811: }
812: IFDEBUG(D_STASH)
813: dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb,
814: "stash: so_rcv after appending");
815: ENDDEBUG
816:
817: } else {
818: register struct mbuf **mp;
819: SeqNum uwe;
820:
821: IFTRACE(D_STASH)
822: tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt",
823: E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0);
824: ENDTRACE
825:
826: if (tpcb->tp_rsyq == 0)
827: tp_rsyset(tpcb);
828: uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit);
829: if (tpcb->tp_rsyq == 0 ||
830: !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) {
831: ack_reason = ACK_DONT;
832: m_freem(E.e_data);
833: } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) {
834: IFDEBUG(D_STASH)
835: printf("tp_stash - drop & ack\n");
836: ENDDEBUG
837:
838: /* retransmission - drop it and force an ack */
839: IncStat(ts_dt_dup);
840: IFPERF(tpcb)
841: IncPStat(tpcb, tps_n_ack_cuz_dup);
842: ENDPERF
843:
844: m_freem(E.e_data);
845: ack_reason |= ACK_DUP;
846: } else {
847: *mp = E.e_data;
848: tpcb->tp_rsycnt++;
849: ack_reason = ACK_DONT;
850: }
851: }
852: /* there were some comments of historical interest here. */
853: {
854: LOCAL_CREDIT(tpcb);
855:
856: if ( E.e_seq == tpcb->tp_sent_uwe )
857: ack_reason |= ACK_STRAT_FULLWIN;
858:
859: IFTRACE(D_STASH)
860: tptraceTPCB(TPPTmisc,
861: "end of stash, eot, ack_reason, sent_uwe ",
862: E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0);
863: ENDTRACE
864:
865: if ( ack_reason == ACK_DONT ) {
866: IncStat( ts_ackreason[ACK_DONT] );
867: return 0;
868: } else {
869: IFPERF(tpcb)
870: if(ack_reason & ACK_STRAT_EACH) {
871: IncPStat(tpcb, tps_n_ack_cuz_strat);
872: } else if(ack_reason & ACK_STRAT_FULLWIN) {
873: IncPStat(tpcb, tps_n_ack_cuz_fullwin);
874: } else if(ack_reason & ACK_REORDER) {
875: IncPStat(tpcb, tps_n_ack_cuz_reorder);
876: }
877: tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0,
878: SEQ_ADD(tpcb, E.e_seq, 1), 0, 0);
879: ENDPERF
880: {
881: register int i;
882:
883: /* keep track of all reasons that apply */
884: for( i=1; i<_ACK_NUM_REASONS_ ;i++) {
885: if( ack_reason & (1<<i) )
886: IncStat( ts_ackreason[i] );
887: }
888: }
889: return 1;
890: }
891: }
892: }
893:
894: /*
895: * tp_rsyflush - drop all the packets on the reassembly queue.
896: * Do this when closing the socket, or when somebody has changed
897: * the space avaible in the receive socket (XXX).
898: */
899: tp_rsyflush(tpcb)
900: register struct tp_pcb *tpcb;
901: {
902: register struct mbuf *m, **mp;
903: if (tpcb->tp_rsycnt) {
904: for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit;
905: --mp >= tpcb->tp_rsyq; )
906: if (*mp) {
907: tpcb->tp_rsycnt--;
908: m_freem(*mp);
909: }
910: if (tpcb->tp_rsycnt) {
911: printf("tp_rsyflush %x\n", tpcb);
912: tpcb->tp_rsycnt = 0;
913: }
914: }
915: free((caddr_t)tpcb->tp_rsyq, M_PCB);
916: tpcb->tp_rsyq = 0;
917: }
918:
919: tp_rsyset(tpcb)
920: register struct tp_pcb *tpcb;
921: {
922: register struct socket *so = tpcb->tp_sock;
923: int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf;
924: int old_credit = tpcb->tp_maxlcredit;
925: caddr_t rsyq;
926:
927: tpcb->tp_maxlcredit = maxcredit = min(maxcredit,
928: (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize);
929:
930: if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0)
931: return;
932: maxcredit *= sizeof(struct mbuf *);
933: if (tpcb->tp_rsyq)
934: tp_rsyflush(tpcb);
935: // if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT))
936: MALLOC(rsyq, caddr_t, maxcredit, M_PCB, M_NOWAIT);
937: if (rsyq)
938: bzero(rsyq, maxcredit);
939: tpcb->tp_rsyq = (struct mbuf **)rsyq;
940: }
941:
942: tpsbcheck(tpcb, i)
943: struct tp_pcb *tpcb;
944: {
945: register struct mbuf *n, *m;
946: register int len = 0, mbcnt = 0, pktlen;
947: struct sockbuf *sb = &tpcb->tp_sock->so_snd;
948:
949: for (n = sb->sb_mb; n; n = n->m_nextpkt) {
950: if ((n->m_flags & M_PKTHDR) == 0)
951: panic("tpsbcheck nohdr");
952: pktlen = len + n->m_pkthdr.len;
953: for (m = n; m; m = m->m_next) {
954: len += m->m_len;
955: mbcnt += MSIZE;
956: if (m->m_flags & M_EXT)
957: mbcnt += m->m_ext.ext_size;
958: }
959: if (len != pktlen) {
960: printf("test %d; len %d != pktlen %d on mbuf 0x%x\n",
961: i, len, pktlen, n);
962: panic("tpsbcheck short");
963: }
964: }
965: if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
966: printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc,
967: mbcnt, sb->sb_mbcnt);
968: panic("tpsbcheck");
969: }
970: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.