|
|
1.1 root 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: *
1.1.1.3 ! root 33: * from: @(#)tp.trans 7.9 (Berkeley) 5/7/91
! 34: * tp.trans,v 1.2 1993/05/20 05:27:27 cgd Exp
1.1 root 35: */
36:
37: /***********************************************************
38: Copyright IBM Corporation 1987
39:
40: All Rights Reserved
41:
42: Permission to use, copy, modify, and distribute this software and its
43: documentation for any purpose and without fee is hereby granted,
44: provided that the above copyright notice appear in all copies and that
45: both that copyright notice and this permission notice appear in
46: supporting documentation, and that the name of IBM not be
47: used in advertising or publicity pertaining to distribution of the
48: software without specific, written prior permission.
49:
50: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
51: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
52: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
53: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
54: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
55: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
56: SOFTWARE.
57:
58: ******************************************************************/
59:
60: /*
61: * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
62: */
1.1.1.3 ! root 63: /*
1.1 root 64: * Transition file for TP.
65: *
66: * DO NOT:
67: * - change the order of any of the events or states. to do so will
68: * make tppt, netstat, etc. cease working.
69: *
70: * NOTE:
71: * some hooks exist for data on (dis)connect, but it's ***NOT***SUPPORTED***
72: * (read: may not work!)
73: *
74: * I tried to put everything that causes a change of state in here, hence
75: * there are some seemingly trivial events like T_DETACH and T_LISTEN_req.
76: *
77: * Almost everything having to do w/ setting & cancelling timers is here
78: * but once it was debugged, I moved the setting of the
79: * keepalive (sendack) timer to tp_emit(), where an AK_TPDU is sent.
80: * This is so the code wouldn't be duplicated all over creation in here.
81: *
82: */
83: *PROTOCOL tp
84:
85: *INCLUDE
86: {
87: /* @(#)tp.trans 7.9 (Berkeley) 5/7/91 */
88: #include "param.h"
89: #include "socket.h"
90: #include "socketvar.h"
91: #include "protosw.h"
92: #include "mbuf.h"
93: #include "time.h"
94: #include "errno.h"
95: #include "../netiso/tp_param.h"
96: #include "../netiso/tp_stat.h"
97: #include "../netiso/tp_pcb.h"
98: #include "../netiso/tp_tpdu.h"
99: #include "../netiso/argo_debug.h"
100: #include "../netiso/tp_trace.h"
101: #include "../netiso/iso_errno.h"
102: #include "../netiso/tp_seq.h"
103: #include "../netiso/cons.h"
104:
105: #define DRIVERTRACE TPPTdriver
106: #define sbwakeup(sb) sowakeup(p->tp_sock, sb);
107: #define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
108:
109: static trick_hc = 1;
110:
111: int tp_emit(),
112: tp_goodack(), tp_goodXack(),
113: tp_stash()
114: ;
115: void tp_indicate(), tp_getoptions(),
116: tp_soisdisconnecting(), tp_soisdisconnected(),
117: tp_recycle_tsuffix(),
118: tp_etimeout(), tp_euntimeout(),
119: tp_euntimeout_lss(), tp_ctimeout(),
120: tp_cuntimeout(), tp_ctimeout_MIN(),
121: tp_freeref(), tp_detach(),
122: tp0_stash(), tp0_send(),
123: tp_netcmd(), tp_send()
124: ;
125:
126: typedef struct tp_pcb tpcb_struct;
127:
128:
129: }
130:
131: *PCB tpcb_struct SYNONYM P
132:
133: *STATES
134:
135: TP_CLOSED
136: TP_CRSENT
137: TP_AKWAIT
138: TP_OPEN
139: TP_CLOSING
140: TP_REFWAIT
141: TP_LISTENING /* Local to this implementation */
142: TP_CONFIRMING /* Local to this implementation */
143:
144: *EVENTS { struct timeval e_time; } SYNONYM E
145:
146: /*
147: * C (typically cancelled) timers -
148: *
149: * let these be the first ones so for the sake of convenience
150: * their values are 0--> n-1
151: * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!!
152: */
153: TM_inact
154: TM_retrans
155: /* TM_retrans is used for all
156: * simple retransmissions - CR,CC,XPD,DR
157: */
158:
159: TM_sendack
160: /* TM_sendack does dual duty - keepalive AND sendack.
161: * It's set w/ keepalive-ticks every time an ack is sent.
162: * (this is done in (void) tp_emit() ).
163: * It's cancelled and reset whenever a DT
164: * arrives and it doesn't require immediate acking.
165: * Note that in this case it's set w/ the minimum of
166: * its prev value and the sendack-ticks value so the
167: * purpose of the keepalive is preserved.
168: */
169: TM_notused
170:
171: /*
172: * E (typically expired) timers - these may be in any order.
173: * These cause procedures to be executed directly; may not
174: * cause an 'event' as we know them here.
175: */
176: TM_reference { SeqNum e_low; SeqNum e_high; int e_retrans; }
177: TM_data_retrans { SeqNum e_low; SeqNum e_high; int e_retrans; }
178:
179: /* NOTE: in tp_input is a minor optimization that assumes that
180: * for all tpdu types that can take e_data and e_datalen, these
181: * fields fall in the same place in the event structure, that is,
182: * e_data is the first field and e_datalen is the 2nd field.
183: */
184:
185: ER_TPDU {
186: u_char e_reason;
187: }
188: CR_TPDU { struct mbuf *e_data; /* first field */
189: int e_datalen; /* 2nd field */
190: u_int e_cdt;
191: }
192: DR_TPDU { struct mbuf *e_data; /* first field */
193: int e_datalen; /* 2nd field */
194: u_short e_sref;
195: u_char e_reason;
196: }
197: DC_TPDU
198: CC_TPDU { struct mbuf *e_data; /* first field */
199: int e_datalen; /* 2nd field */
200: u_short e_sref;
201: u_int e_cdt;
202: }
203: AK_TPDU { u_int e_cdt;
204: SeqNum e_seq;
205: SeqNum e_subseq;
206: u_char e_fcc_present;
207: }
208: DT_TPDU { struct mbuf *e_data; /* first field */
209: int e_datalen; /* 2nd field */
210: u_int e_eot;
211: SeqNum e_seq;
212: }
213: XPD_TPDU { struct mbuf *e_data; /* first field */
214: int e_datalen; /* 2nd field */
215: SeqNum e_seq;
216: }
217: XAK_TPDU { SeqNum e_seq; }
218:
219: T_CONN_req
220: T_DISC_req { u_char e_reason; }
221: T_LISTEN_req
222: T_DATA_req
223: T_XPD_req
224: T_USR_rcvd
225: T_USR_Xrcvd
226: T_DETACH
227: T_NETRESET
228: T_ACPT_req
229:
230:
231: *TRANSITIONS
232:
233:
234: /* TP_AKWAIT doesn't exist in TP 0 */
235: SAME <== TP_AKWAIT [ CC_TPDU, DC_TPDU, XAK_TPDU ]
236: DEFAULT
237: NULLACTION
238: ;
239:
240:
241: /* applicable in TP4, TP0 */
242: SAME <== TP_REFWAIT DR_TPDU
243: ( $$.e_sref != 0 )
244: {
245: (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
246: }
247: ;
248:
249: /* applicable in TP4, TP0 */
250: SAME <== TP_REFWAIT [ CR_TPDU, CC_TPDU, DT_TPDU,
251: DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ]
252: DEFAULT
253: {
254: # ifdef TP_DEBUG
255: if( $E.ev_number != AK_TPDU )
256: printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number);
257: # endif TP_DEBUG
258: }
259: ;
260:
261: /* applicable in TP4, TP0 */
262: SAME <== TP_REFWAIT [ T_DETACH, T_DISC_req ]
263: DEFAULT
264: NULLACTION
265: ;
266:
267: /* applicable in TP4, TP0 */
268: SAME <== TP_CRSENT AK_TPDU
269: ($P.tp_class == TP_CLASS_0)
270: {
271: /* oh, man is this grotesque or what? */
272: (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
273: /* but it's necessary because this pseudo-ack may happen
274: * before the CC arrives, but we HAVE to adjust the
275: * snduna as a result of the ack, WHENEVER it arrives
276: */
277: }
278: ;
279:
280: /* applicable in TP4, TP0 */
281: SAME <== TP_CRSENT
282: [ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU, XAK_TPDU ]
283: DEFAULT
284: NULLACTION
285: ;
286:
287: /* applicable in TP4, TP0 */
288: SAME <== TP_CLOSED [ DT_TPDU, XPD_TPDU,
289: ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
290: DEFAULT
291: NULLACTION
292: ;
293:
294: /* TP_CLOSING doesn't exist in TP 0 */
295: SAME <== TP_CLOSING
296: [ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ]
297: DEFAULT
298: NULLACTION
299: ;
300:
301:
302: /* DC_TPDU doesn't exist in TP 0 */
303: SAME <== TP_OPEN DC_TPDU
304: DEFAULT
305: NULLACTION
306: ;
307:
308: /* applicable in TP4, TP0 */
309: SAME <== TP_LISTENING [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU,
310: ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ]
311: DEFAULT
312: NULLACTION
313: ;
314:
315: /* applicable in TP4, TP0 */
316: TP_LISTENING <== TP_CLOSED T_LISTEN_req
317: DEFAULT
318: NULLACTION
319: ;
320:
321: /* applicable in TP4, TP0 */
322: TP_CLOSED <== [ TP_LISTENING, TP_CLOSED ] T_DETACH
323: DEFAULT
324: {
325: tp_detach($P);
326: }
327: ;
328:
329: TP_CONFIRMING <== TP_LISTENING CR_TPDU
330: ( $P.tp_class == TP_CLASS_0)
331: {
332: $P.tp_refp->tpr_state = REF_OPEN; /* has timers ??? */
333: }
334: ;
335:
336: TP_CONFIRMING <== TP_LISTENING CR_TPDU
337: DEFAULT
338: {
339: IFTRACE(D_CONN)
340: tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
341: ENDTRACE
342: IFDEBUG(D_CONN)
343: printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
344: ENDDEBUG
345: $P.tp_refp->tpr_state = REF_OPEN; /* has timers */
346: $P.tp_fcredit = $$.e_cdt;
347:
348: if ($$.e_datalen > 0) {
349: /* n/a for class 0 */
350: ASSERT($P.tp_Xrcv.sb_cc == 0);
351: sbappendrecord(&$P.tp_Xrcv, $$.e_data);
352: $$.e_data = MNULL;
353: }
354: }
355: ;
356:
357: TP_OPEN <== TP_CONFIRMING T_ACPT_req
358: ( $P.tp_class == TP_CLASS_0 )
359: {
360: IncStat(ts_tp0_conn);
361: IFTRACE(D_CONN)
362: tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
363: ENDTRACE
364: IFDEBUG(D_CONN)
365: printf("Confirming connection: $P" );
366: ENDDEBUG
367: soisconnected($P.tp_sock);
368: (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
369: $P.tp_fcredit = 1;
370: }
371: ;
372:
373: TP_AKWAIT <== TP_CONFIRMING T_ACPT_req
374: (tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0)
375: {
376: IncStat(ts_tp4_conn); /* even though not quite open */
377: IFTRACE(D_CONN)
378: tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
379: ENDTRACE
380: IFDEBUG(D_CONN)
381: printf("Confirming connection: $P" );
382: ENDDEBUG
383: soisconnecting($P.tp_sock);
384: if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
385: $P.tp_cong_win = $P.tp_fcredit;
386: $P.tp_retrans = $P.tp_Nretrans;
387: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
388: }
389: ;
390:
391: /* TP4 only */
392: TP_CLOSED <== TP_CONFIRMING T_ACPT_req
393: DEFAULT /* emit failed */
394: {
395: register struct tp_ref *r = $P.tp_refp;
396:
397: IFDEBUG(D_CONN)
398: printf("event: CR_TPDU emit CC failed done " );
399: ENDDEBUG
400: soisdisconnected($P.tp_sock);
401: tp_recycle_tsuffix( $P );
402: tp_freeref(r);
403: tp_detach($P);
404: }
405: ;
406:
407: /* applicable in TP4, TP0 */
408: TP_CRSENT <== TP_CLOSED T_CONN_req
409: DEFAULT
410: {
411: int error;
412: struct mbuf *data = MNULL;
413:
414: IFTRACE(D_CONN)
415: tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
416: $P.tp_ucddata, 0, 0);
417: ENDTRACE
418: data = MCPY($P.tp_ucddata, M_WAIT);
419: if (data) {
420: IFDEBUG(D_CONN)
421: printf("T_CONN_req.trans m_copy cc 0x%x\n",
422: $P.tp_ucddata);
423: dump_mbuf(data, "sosnd @ T_CONN_req");
424: ENDDEBUG
425: }
426:
427: if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
428: return error; /* driver WON'T change state; will return error */
429:
430: $P.tp_refp->tpr_state = REF_OPEN; /* has timers */
431: if($P.tp_class != TP_CLASS_0) {
432: $P.tp_retrans = $P.tp_Nretrans;
433: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
434: }
435: }
436: ;
437:
438: /* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */
439: TP_REFWAIT <== [ TP_CRSENT, TP_AKWAIT, TP_OPEN ] DR_TPDU
440: DEFAULT
441: {
442: sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */
443: if ($$.e_datalen > 0) {
444: sbappendrecord(&$P.tp_Xrcv, $$.e_data);
445: $$.e_data = MNULL;
446: }
447: tp_indicate(T_DISCONNECT, $P, 0);
448: tp_soisdisconnected($P);
449: if ($P.tp_class != TP_CLASS_0) {
450: if ($P.tp_state == TP_OPEN ) {
451: tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
452: tp_cuntimeout($P.tp_refp, TM_retrans);
453: tp_cuntimeout($P.tp_refp, TM_inact);
454: tp_cuntimeout($P.tp_refp, TM_sendack);
455: }
456: tp_cuntimeout($P.tp_refp, TM_retrans);
457: if( $$.e_sref != 0 )
458: (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
459: }
460: }
461: ;
462:
463: SAME <== TP_CLOSED DR_TPDU
464: DEFAULT
465: {
466: if( $$.e_sref != 0 )
467: (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
468: /* reference timer already set - reset it to be safe (???) */
469: tp_euntimeout($P.tp_refp, TM_reference); /* all */
470: tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks);
471: }
472: ;
473:
474: /* NBS(34) */
475: TP_REFWAIT <== TP_CRSENT ER_TPDU
476: DEFAULT
477: {
478: tp_cuntimeout($P.tp_refp, TM_retrans);
479: tp_indicate(ER_TPDU, $P, $$.e_reason);
480: tp_soisdisconnected($P);
481: }
482: ;
483:
484: /* NBS(27) */
485: TP_REFWAIT <== TP_CLOSING DR_TPDU
486: DEFAULT
487: {
488: tp_cuntimeout($P.tp_refp, TM_retrans);
489: tp_soisdisconnected($P);
490: }
491: ;
492: /* these two transitions are the same but can't be combined because xebec
493: * can't handle the use of $$.e_reason if they're combined
494: */
495: /* NBS(27) */
496: TP_REFWAIT <== TP_CLOSING ER_TPDU
497: DEFAULT
498: {
499: tp_indicate(ER_TPDU, $P, $$.e_reason);
500: tp_cuntimeout($P.tp_refp, TM_retrans);
501: tp_soisdisconnected($P);
502: }
503: ;
504: /* NBS(27) */
505: TP_REFWAIT <== TP_CLOSING DC_TPDU
506: DEFAULT
507: {
508: tp_cuntimeout($P.tp_refp, TM_retrans);
509: tp_soisdisconnected($P);
510: }
511: ;
512:
513: /* NBS(21) */
514: SAME <== TP_CLOSED [ CC_TPDU, CR_TPDU ]
515: DEFAULT
516: { /* don't ask me why we have to do this - spec says so */
517: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL);
518: /* don't bother with retransmissions of the DR */
519: }
520: ;
521:
522: /* NBS(34) */
523: TP_REFWAIT <== TP_OPEN ER_TPDU
524: ($P.tp_class == TP_CLASS_0)
525: {
526: tp_soisdisconnecting($P.tp_sock);
527: tp_indicate(ER_TPDU, $P, $$.e_reason);
528: tp_soisdisconnected($P);
529: tp_netcmd( $P, CONN_CLOSE );
530: }
531: ;
532:
533: TP_CLOSING <== [ TP_AKWAIT, TP_OPEN ] ER_TPDU
534: DEFAULT
535: {
536: if ($P.tp_state == TP_OPEN) {
537: tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
538: tp_cuntimeout($P.tp_refp, TM_inact);
539: tp_cuntimeout($P.tp_refp, TM_sendack);
540: }
541: tp_soisdisconnecting($P.tp_sock);
542: tp_indicate(ER_TPDU, $P, $$.e_reason);
543: $P.tp_retrans = $P.tp_Nretrans;
544: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
545: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
546: }
547: ;
548: /* NBS(6) */
549: TP_OPEN <== TP_CRSENT CC_TPDU
550: ($P.tp_class == TP_CLASS_0)
551: {
552: tp_cuntimeout($P.tp_refp, TM_retrans);
553: IncStat(ts_tp0_conn);
554: $P.tp_fcredit = 1;
555: soisconnected($P.tp_sock);
556: }
557: ;
558:
559: TP_OPEN <== TP_CRSENT CC_TPDU
560: DEFAULT
561: {
562: IFDEBUG(D_CONN)
563: printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
564: (int)$P.tp_flags);
565: ENDDEBUG
566: IncStat(ts_tp4_conn);
567: $P.tp_fref = $$.e_sref;
568: $P.tp_fcredit = $$.e_cdt;
569: $P.tp_ackrcvd = 0;
570: if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
571: $P.tp_cong_win = $$.e_cdt;
572: tp_getoptions($P);
573: tp_cuntimeout($P.tp_refp, TM_retrans);
574: if ($P.tp_ucddata) {
575: IFDEBUG(D_CONN)
576: printf("dropping user connect data cc 0x%x\n",
577: $P.tp_ucddata->m_len);
578: ENDDEBUG
579: m_freem($P.tp_ucddata);
580: $P.tp_ucddata = 0;
581: }
582: soisconnected($P.tp_sock);
583: if ($$.e_datalen > 0) {
584: ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
585: sbappendrecord(&$P.tp_Xrcv, $$.e_data);
586: $$.e_data = MNULL;
587: }
588:
589: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
590: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
591: }
592: ;
593:
594: /* TP4 only */
595: SAME <== TP_CRSENT TM_retrans
596: ( $P.tp_retrans > 0 )
597: {
598: struct mbuf *data = MNULL;
599: int error;
600:
601: IncStat(ts_retrans_cr);
602: $P.tp_cong_win = 1;
603: $P.tp_ackrcvd = 0;
604: data = MCPY($P.tp_ucddata, M_NOWAIT);
605: if($P.tp_ucddata) {
606: IFDEBUG(D_CONN)
607: printf("TM_retrans.trans m_copy cc 0x%x\n", data);
608: dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
609: ENDDEBUG
610: if( data == MNULL )
611: return ENOBUFS;
612: }
613:
614: $P.tp_retrans --;
615: if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
616: $P.tp_sock->so_error = error;
617: }
618: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
619: }
620: ;
621:
622: /* TP4 only */
623: TP_REFWAIT <== TP_CRSENT TM_retrans
624: DEFAULT /* no more CR retransmissions */
625: {
626: IncStat(ts_conn_gaveup);
627: $P.tp_sock->so_error = ETIMEDOUT;
628: tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
629: tp_soisdisconnected($P);
630: }
631: ;
632:
633: /* TP4 only */
634: SAME <== TP_AKWAIT CR_TPDU
635: DEFAULT
636: /* duplicate CR (which doesn't really exist in the context of
637: * a connectionless network layer)
638: * Doesn't occur in class 0.
639: */
640: {
641: int error;
642: struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
643:
644: if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
645: $P.tp_sock->so_error = error;
646: }
647: $P.tp_retrans = $P.tp_Nretrans;
648: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
649: }
650: ;
651:
652: /* TP4 only */
653: TP_OPEN <== TP_AKWAIT DT_TPDU
654: ( IN_RWINDOW( $P, $$.e_seq,
655: $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
656: {
657: int doack;
658:
659: /*
660: * Get rid of any confirm or connect data, so that if we
661: * crash or close, it isn't thought of as disconnect data.
662: */
663: if ($P.tp_ucddata) {
664: m_freem($P.tp_ucddata);
665: $P.tp_ucddata = 0;
666: }
667: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
668: tp_cuntimeout($P.tp_refp, TM_retrans);
669: soisconnected($P.tp_sock);
670: tp_getoptions($P);
671: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
672:
673: /* see also next 2 transitions, if you make any changes */
674:
675: doack = tp_stash($P, $E);
676: IFDEBUG(D_DATA)
677: printf("tp_stash returns %d\n",doack);
678: ENDDEBUG
679:
680: if(doack) {
681: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
682: tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
683: } else
684: tp_ctimeout( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks);
685:
686: IFDEBUG(D_DATA)
687: printf("after stash calling sbwakeup\n");
688: ENDDEBUG
689: }
690: ;
691:
692: SAME <== TP_OPEN DT_TPDU
693: ( $P.tp_class == TP_CLASS_0 )
694: {
695: tp0_stash($P, $E);
696: sbwakeup( &$P.tp_sock->so_rcv );
697:
698: IFDEBUG(D_DATA)
699: printf("after stash calling sbwakeup\n");
700: ENDDEBUG
701: }
702: ;
703:
704: /* TP4 only */
705: SAME <== TP_OPEN DT_TPDU
706: ( IN_RWINDOW( $P, $$.e_seq,
707: $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
708: {
709: int doack; /* tells if we must ack immediately */
710:
711: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
712: sbwakeup( &$P.tp_sock->so_rcv );
713:
714: doack = tp_stash($P, $E);
715: IFDEBUG(D_DATA)
716: printf("tp_stash returns %d\n",doack);
717: ENDDEBUG
718:
719: if(doack)
720: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
721: else
722: tp_ctimeout_MIN( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks);
723:
724: IFDEBUG(D_DATA)
725: printf("after stash calling sbwakeup\n");
726: ENDDEBUG
727: }
728: ;
729:
730: /* Not in window - we must ack under certain circumstances, namely
731: * a) if the seq number is below lwe but > lwe - (max credit ever given)
732: * (to handle lost acks) Can use max-possible-credit for this ^^^.
733: * and
734: * b) seq number is > uwe but < uwe + previously sent & withdrawn credit
735: *
736: * (see 12.2.3.8.1 of ISO spec, p. 73)
737: * We just always ack.
738: */
739: /* TP4 only */
740: SAME <== [ TP_OPEN, TP_AKWAIT ] DT_TPDU
741: DEFAULT /* Not in window */
742: {
743: IFTRACE(D_DATA)
744: tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
745: $$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0);
746: ENDTRACE
747: IncStat(ts_dt_niw);
748: m_freem($$.e_data);
749: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
750: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL );
751: }
752: ;
753:
754: /* TP4 only */
755: TP_OPEN <== TP_AKWAIT AK_TPDU
756: DEFAULT
757: {
758: if ($P.tp_ucddata) {
759: m_freem($P.tp_ucddata);
760: $P.tp_ucddata = 0;
761: }
762: (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
763: tp_cuntimeout($P.tp_refp, TM_retrans);
764:
765: tp_getoptions($P);
766: soisconnected($P.tp_sock);
767: IFTRACE(D_CONN)
768: struct socket *so = $P.tp_sock;
769: tptrace(TPPTmisc,
770: "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
771: so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
772: tptrace(TPPTmisc,
773: "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
774: so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
775: ENDTRACE
776:
777: tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
778: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
779: }
780: ;
781:
782: /* TP4 only */
783: TP_OPEN <== [ TP_OPEN, TP_AKWAIT ] XPD_TPDU
784: ($P.tp_Xrcvnxt == $$.e_seq)
785: {
786: if( $P.tp_state == TP_AKWAIT ) {
787: if ($P.tp_ucddata) {
788: m_freem($P.tp_ucddata);
789: $P.tp_ucddata = 0;
790: }
791: tp_cuntimeout($P.tp_refp, TM_retrans);
792: tp_getoptions($P);
793: soisconnected($P.tp_sock);
794: tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
795: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
796: }
797: IFTRACE(D_XPD)
798: tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
799: $P.tp_Xrcvnxt,$$.e_seq, $$.e_datalen, $$.e_data->m_len);
800: ENDTRACE
801:
802: $P.tp_sock->so_state |= SS_RCVATMARK;
803: $$.e_data->m_flags |= M_EOR;
804: sbinsertoob(&$P.tp_Xrcv, $$.e_data);
805: IFDEBUG(D_XPD)
806: dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
807: ENDDEBUG
808: tp_indicate(T_XDATA, $P, 0);
809: sbwakeup( &$P.tp_Xrcv );
810:
811: (void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
812: SEQ_INC($P, $P.tp_Xrcvnxt);
813: }
814: ;
815:
816: /* TP4 only */
817: SAME <== TP_OPEN T_USR_Xrcvd
818: DEFAULT
819: {
820: if( $P.tp_Xrcv.sb_cc == 0 ) {
821: /* kludge for select(): */
822: /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
823: }
824: }
825: /* OLD WAY:
826: * Ack only after the user receives the XPD. This is better for
827: * users that use one XPD right after another.
828: * Acking right away (the NEW WAY, see the prev. transition) is
829: * better for occasional * XPD, when the receiving user doesn't
830: * want to read the XPD immediately (which is session's behavior).
831: *
832: int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
833: SEQ_INC($P, $P.tp_Xrcvnxt);
834: return error;
835: */
836: ;
837:
838: /* NOTE: presently if the user doesn't read the connection data
839: * before and expedited data PDU comes in, the connection data will
840: * be dropped. This is a bug. To avoid it, we need somewhere else
841: * to put the connection data.
842: * On the other hand, we need not to have it sitting around forever.
843: * This is a problem with the idea of trying to accommodate
844: * data on connect w/ a passive-open user interface.
845: */
846: /* TP4 only */
847:
848: SAME <== [ TP_AKWAIT, TP_OPEN ] XPD_TPDU
849: DEFAULT /* not in window or cdt==0 */
850: {
851: IFTRACE(D_XPD)
852: tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
853: $P.tp_Xrcvnxt, $$.e_seq, $P.tp_Xrcv.sb_cc , 0);
854: ENDTRACE
855: if( $P.tp_Xrcvnxt != $$.e_seq )
856: IncStat(ts_xpd_niw);
857: if( $P.tp_Xrcv.sb_cc ) {
858: /* might as well kick 'em again */
859: tp_indicate(T_XDATA, $P, 0);
860: IncStat(ts_xpd_dup);
861: }
862: m_freem($$.e_data);
863: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
864: /* don't send an xack because the xak gives "last one received", not
865: * "next one i expect" (dumb)
866: */
867: }
868: ;
869:
870: /* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries
871: * to detach all its "children"
872: * Also (CRSENT) when user kills a job that's doing a connect()
873: */
874: TP_REFWAIT <== TP_CRSENT T_DETACH
875: ($P.tp_class == TP_CLASS_0)
876: {
877: struct socket *so = $P.tp_sock;
878:
879: /* detach from parent socket so it can finish closing */
880: if (so->so_head) {
881: if (!soqremque(so, 0) && !soqremque(so, 1))
882: panic("tp: T_DETACH");
883: so->so_head = 0;
884: }
885: tp_soisdisconnecting($P.tp_sock);
886: tp_netcmd( $P, CONN_CLOSE);
887: tp_soisdisconnected($P);
888: }
889: ;
890:
891: /* TP4 only */
892: TP_CLOSING <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH
893: DEFAULT
894: {
895: struct socket *so = $P.tp_sock;
896: struct mbuf *data = MNULL;
897:
898: /* detach from parent socket so it can finish closing */
899: if (so->so_head) {
900: if (!soqremque(so, 0) && !soqremque(so, 1))
901: panic("tp: T_DETACH");
902: so->so_head = 0;
903: }
904: if ($P.tp_state != TP_CLOSING) {
905: tp_soisdisconnecting($P.tp_sock);
906: data = MCPY($P.tp_ucddata, M_NOWAIT);
907: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
908: $P.tp_retrans = $P.tp_Nretrans;
909: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
910: }
911: }
912: ;
913:
914: TP_REFWAIT <== [ TP_OPEN, TP_CRSENT ] T_DISC_req
915: ( $P.tp_class == TP_CLASS_0 )
916: {
917: tp_soisdisconnecting($P.tp_sock);
918: tp_netcmd( $P, CONN_CLOSE);
919: tp_soisdisconnected($P);
920: }
921: ;
922:
923: /* TP4 only */
924: TP_CLOSING <== [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ] T_DISC_req
925: DEFAULT
926: {
927: struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
928:
929: if($P.tp_state == TP_OPEN) {
930: tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
931: tp_cuntimeout($P.tp_refp, TM_inact);
932: tp_cuntimeout($P.tp_refp, TM_sendack);
933: }
934: if (data) {
935: IFDEBUG(D_CONN)
936: printf("T_DISC_req.trans tp_ucddata 0x%x\n",
937: $P.tp_ucddata);
938: dump_mbuf(data, "ucddata @ T_DISC_req");
939: ENDDEBUG
940: }
941: tp_soisdisconnecting($P.tp_sock);
942: $P.tp_retrans = $P.tp_Nretrans;
943: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
944:
945: if( trick_hc )
946: return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
947: }
948: ;
949:
950: /* TP4 only */
951: SAME <== TP_AKWAIT TM_retrans
952: ( $P.tp_retrans > 0 )
953: {
954: int error;
955: struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
956:
957: IncStat(ts_retrans_cc);
958: $P.tp_retrans --;
959: $P.tp_cong_win = 1;
960: $P.tp_ackrcvd = 0;
961:
962: if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) )
963: $P.tp_sock->so_error = error;
964: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
965: }
966: ;
967:
968: /* TP4 only */
969: TP_CLOSING <== TP_AKWAIT TM_retrans
970: DEFAULT /* out of time */
971: {
972: IncStat(ts_conn_gaveup);
973: tp_soisdisconnecting($P.tp_sock);
974: $P.tp_sock->so_error = ETIMEDOUT;
975: tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
976: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
977: $P.tp_retrans = $P.tp_Nretrans;
978: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
979: }
980: ;
981:
982: /* the retrans timers had better go off BEFORE the inactivity timer does,
983: * if transmissions are going on.
984: * (i.e., TM_inact should be greater than timer for all retrans plus ack
985: * turnaround)
986: */
987: /* TP4 only */
988: TP_CLOSING <== TP_OPEN [ TM_inact, TM_retrans, TM_data_retrans ]
989: DEFAULT
990: {
991: tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
992: tp_cuntimeout($P.tp_refp, TM_inact);
993: tp_cuntimeout($P.tp_refp, TM_sendack);
994:
995: IncStat(ts_conn_gaveup);
996: tp_soisdisconnecting($P.tp_sock);
997: $P.tp_sock->so_error = ETIMEDOUT;
998: tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
999: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
1000: $P.tp_retrans = $P.tp_Nretrans;
1001: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
1002: }
1003: ;
1004:
1005: /* TP4 only */
1006: SAME <== TP_OPEN TM_retrans
1007: ( $P.tp_retrans > 0 )
1008: {
1009: $P.tp_cong_win = 1;
1010: $P.tp_ackrcvd = 0;
1011: /* resume XPD */
1012: if ( $P.tp_Xsnd.sb_mb ) {
1013: struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
1014: /* m_copy doesn't preserve the m_xlink field, but at this pt.
1015: * that doesn't matter
1016: */
1017:
1018: IFTRACE(D_XPD)
1019: tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna",
1020: $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
1021: $P.tp_snduna);
1022: ENDTRACE
1023: IFDEBUG(D_XPD)
1024: dump_mbuf(m, "XPD retrans emitting M");
1025: ENDDEBUG
1026: IncStat(ts_retrans_xpd);
1027: $P.tp_retrans --;
1028: (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
1029: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
1030: }
1031: }
1032: ;
1033:
1034: /* TP4 only */
1035: SAME <== TP_OPEN TM_data_retrans
1036: ( $$.e_retrans > 0 )
1037: {
1038: register SeqNum low, lowsave = 0;
1039: register struct tp_rtc *r = $P.tp_snduna_rtc;
1040: register struct mbuf *m;
1041: register SeqNum high = $$.e_high;
1042:
1043: low = $P.tp_snduna;
1044: lowsave = high = low;
1045:
1046: tp_euntimeout_lss($P.tp_refp, TM_data_retrans,
1047: SEQ_ADD($P, $P.tp_sndhiwat, 1));
1048: $P.tp_retrans_hiwat = $P.tp_sndhiwat;
1049:
1050: if (($P.tp_rx_strat & TPRX_EACH) == 0)
1051: high = (high>low)?low:high;
1052:
1053: if( $P.tp_rx_strat & TPRX_USE_CW ) {
1054: register int i;
1055:
1056: $P.tp_cong_win = 1;
1057: $P.tp_ackrcvd = 0;
1058: i = SEQ_ADD($P, low, $P.tp_cong_win);
1059:
1060: high = SEQ_MIN($P, high, $P.tp_sndhiwat);
1061:
1062: }
1063:
1064: while( SEQ_LEQ($P, low, high) ){
1065: if ( r == (struct tp_rtc *)0 ){
1066: IFDEBUG(D_RTC)
1067: printf( "tp: retrans rtc list is GONE!\n");
1068: ENDDEBUG
1069: break;
1070: }
1071: if ( r->tprt_seq == low ){
1072: if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))== MNULL)
1073: break;
1074: (void) tp_emit(DT_TPDU_type, $P, low, r->tprt_eot, m);
1075: IncStat(ts_retrans_dt);
1076: SEQ_INC($P, low );
1077: }
1078: r = r->tprt_next;
1079: }
1080: /* CE_BIT
1081: if ( SEQ_LEQ($P, lowsave, high) ){
1082: */
1083: $$.e_retrans --;
1084: tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave,
1085: (caddr_t)high, $$.e_retrans,
1086: ($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks);
1087: /* CE_BIT
1088: }
1089: */
1090: }
1091: ;
1092:
1093: /* TP4 only */
1094: SAME <== TP_CLOSING TM_retrans
1095: ( $P.tp_retrans > 0 )
1096: {
1097: $P.tp_retrans --;
1098: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
1099: IncStat(ts_retrans_dr);
1100: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
1101: }
1102: ;
1103:
1104: /* TP4 only */
1105: TP_REFWAIT <== TP_CLOSING TM_retrans
1106: DEFAULT /* no more retrans - gave up */
1107: {
1108: $P.tp_sock->so_error = ETIMEDOUT;
1109: $P.tp_refp->tpr_state = REF_FROZEN;
1110: tp_recycle_tsuffix( $P );
1111: tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks);
1112: }
1113: ;
1114:
1115: /*
1116: * The resources are kept around until the ref timer goes off.
1117: * The suffices are wiped out sooner so they can be reused right away.
1118: */
1119: /* applicable in TP4, TP0 */
1120: TP_CLOSED <== TP_REFWAIT TM_reference
1121: DEFAULT
1122: {
1123: tp_freeref($P.tp_refp);
1124: tp_detach($P);
1125: }
1126: ;
1127:
1128: /* applicable in TP4, TP0 */
1129: /* A duplicate CR from connectionless network layer can't happen */
1130: SAME <== TP_OPEN [ CR_TPDU, CC_TPDU ]
1131: DEFAULT
1132: {
1133: if( $P.tp_class != TP_CLASS_0) {
1134: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
1135: if ( $E.ev_number == CC_TPDU )
1136: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
1137: }
1138: /* ignore it if class 0 - state tables are blank for this */
1139: }
1140: ;
1141:
1142: /* applicable in TP4, TP0 */
1143: SAME <== TP_OPEN T_DATA_req
1144: DEFAULT
1145: {
1146: IFTRACE(D_DATA)
1147: tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb",
1148: $P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P);
1149: ENDTRACE
1150:
1151: tp_send($P);
1152: }
1153: ;
1154:
1155: /* TP4 only */
1156: SAME <== TP_OPEN T_XPD_req
1157: DEFAULT
1158: /* T_XPD_req was issued by sosend iff xpd socket buf was empty
1159: * at time of sosend(),
1160: * AND (which means) there were no unacknowledged XPD tpdus outstanding!
1161: */
1162: {
1163: int error = 0;
1164:
1165: /* resume XPD */
1166: if ( $P.tp_Xsnd.sb_mb ) {
1167: struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
1168: /* m_copy doesn't preserve the m_xlink field, but at this pt.
1169: * that doesn't matter
1170: */
1171:
1172: IFTRACE(D_XPD)
1173: tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna",
1174: $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat,
1175: $P.tp_snduna);
1176: ENDTRACE
1177: IFDEBUG(D_XPD)
1178: printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
1179: dump_mbuf(m, "XPD req emitting M");
1180: ENDDEBUG
1181: error =
1182: tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
1183: $P.tp_retrans = $P.tp_Nretrans;
1184: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
1185: SEQ_INC($P, $P.tp_Xsndnxt);
1186: }
1187: if(trick_hc)
1188: return error;
1189: }
1190: ;
1191:
1192: /* TP4, faked ack in TP0 when cons send completes */
1193: SAME <== TP_OPEN AK_TPDU
1194: ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq) )
1195:
1196: /* tp_goodack == true means
1197: * EITHER it actually acked something heretofore unacknowledged
1198: * OR no news but the credit should be processed.
1199: */
1200: {
1201: IFDEBUG(D_ACKRECV)
1202: printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
1203: ENDDEBUG
1204: if( $P.tp_class != TP_CLASS_0) {
1205: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
1206: tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq);
1207: }
1208: sbwakeup( &$P.tp_sock->so_snd );
1209:
1210: if ($P.tp_sndhiwat <= $P.tp_retrans_hiwat &&
1211: $P.tp_snduna <= $P.tp_retrans_hiwat) {
1212:
1213: register struct mbuf *m;
1214: /* extern struct mbuf *m_copy(); */
1215: register struct tp_rtc *r;
1216: SeqNum high, retrans, low_save;
1217:
1218: high = SEQ_MIN($P, SEQ_ADD($P, $P.tp_snduna,
1219: MIN($P.tp_cong_win, $P.tp_fcredit)) - 1,
1220: $P.tp_sndhiwat);
1221: low_save = retrans = SEQ_MAX($P, SEQ_ADD($P, $P.tp_last_retrans, 1),
1222: $P.tp_snduna);
1223: for (; SEQ_LEQ($P, retrans, high); SEQ_INC($P, retrans)) {
1224:
1225: for (r = $P.tp_snduna_rtc; r; r = r->tprt_next){
1226: if ( r->tprt_seq == retrans ){
1227: if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))
1228: == MNULL)
1229: break;
1230: (void) tp_emit(DT_TPDU_type, $P, retrans,
1231: r->tprt_eot, m);
1232: $P.tp_last_retrans = retrans;
1233: IncStat(ts_retrans_dt);
1234: break;
1235: }
1236: }
1237: if ( r == (struct tp_rtc *)0 ){
1238: IFDEBUG(D_RTC)
1239: printf( "tp: retrans rtc list is GONE!\n");
1240: ENDDEBUG
1241: break;
1242: }
1243: }
1244: tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)low_save,
1245: (caddr_t)high, $P.tp_retrans, (int)$P.tp_dt_ticks);
1246: if (SEQ_DEC($P, retrans) == $P.tp_retrans_hiwat)
1247: tp_send($P);
1248: }
1249: else {
1250: tp_send($P);
1251: }
1252: IFDEBUG(D_ACKRECV)
1253: printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat);
1254: ENDDEBUG
1255: }
1256: ;
1257:
1258: /* TP4, and TP0 after sending a CC or possibly a CR */
1259: SAME <== TP_OPEN AK_TPDU
1260: DEFAULT
1261: {
1262: IFTRACE(D_ACKRECV)
1263: tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
1264: $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
1265: ENDTRACE
1266: if( $P.tp_class != TP_CLASS_0 ) {
1267:
1268: if ( !$$.e_fcc_present ) {
1269: /* send ACK with FCC */
1270: IncStat( ts_ackreason[_ACK_FCC_] );
1271: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
1272: }
1273: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
1274: }
1275: }
1276: ;
1277:
1278: /* NBS(47) */
1279: /* goes in at *** */
1280: /* just so happens that this is never true now, because we allow
1281: * only 1 packet in the queue at once (this could be changed)
1282: if ( $P.tp_Xsnd.sb_mb ) {
1283: struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
1284:
1285: (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
1286: $P.tp_retrans = $P.tp_Nretrans;
1287: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
1288: SEQ_INC($P, $P.tp_Xsndnxt);
1289: }
1290: */
1291: /* end of the above hack */
1292:
1293: /* TP4 only */
1294: SAME <== TP_OPEN XAK_TPDU
1295: ( tp_goodXack($P, $$.e_seq) )
1296: /* tp_goodXack checks for good ack, removes the correct
1297: * tpdu from the queue and returns 1 if ack was legit, 0 if not.
1298: * also updates tp_Xuna
1299: */
1300: {
1301: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
1302: tp_cuntimeout($P.tp_refp, TM_retrans);
1303:
1304: sbwakeup( &$P.tp_sock->so_snd );
1305:
1306: /* resume normal data */
1307: tp_send($P);
1308: }
1309: ;
1310:
1311: /* TP4, and TP0 after sending a CC or possibly a CR */
1312: SAME <== TP_OPEN XAK_TPDU
1313: DEFAULT
1314: {
1315: IFTRACE(D_ACKRECV)
1316: tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
1317: ENDTRACE
1318: if( $P.tp_class != TP_CLASS_0 ) {
1319: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
1320: }
1321: }
1322: ;
1323:
1324: /* TP4 only */
1325: SAME <== TP_OPEN TM_sendack
1326: DEFAULT
1327: {
1328: IFTRACE(D_TIMER)
1329: tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe,
1330: $P.tp_sent_lcdt, 0);
1331: ENDTRACE
1332: IncPStat($P, tps_n_TMsendack);
1333: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
1334: }
1335: ;
1336:
1337: /* TP0 only */
1338: SAME <== TP_OPEN T_USR_rcvd
1339: ($P.tp_class == TP_CLASS_0)
1340: {
1341: if (sbspace(&$P.tp_sock->so_rcv) > 0)
1342: tp0_openflow($P);
1343: }
1344: ;
1345:
1346: /* TP4 only */
1347: /* If old credit was zero,
1348: * we'd better inform other side that we now have space
1349: * But this is not enough. Sender might not yet have
1350: * seen an ack with cdt 0 but it might still think the
1351: * window is closed, so it's going to wait.
1352: * Best to send an ack each time.
1353: * Strictly speaking, this ought to be a function of the
1354: * general ack strategy.
1355: */
1356: SAME <== TP_OPEN T_USR_rcvd
1357: DEFAULT
1358: {
1359: if( trick_hc ) {
1360: IncStat(ts_ackreason[_ACK_USRRCV_]);
1361:
1362: /* send an ACK only if there's new information */
1363: LOCAL_CREDIT( $P );
1364: if (($P.tp_rcvnxt != $P.tp_sent_rcvnxt) ||
1365: ($P.tp_lcredit != $P.tp_sent_lcdt))
1366:
1367: return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
1368: }
1369: }
1370: ;
1371:
1372: /* applicable in TP4, TP0 */
1373: SAME <== TP_REFWAIT [ T_USR_rcvd, T_USR_Xrcvd ]
1374: DEFAULT
1375: /* This happens if other end sent a DR when the user was waiting
1376: * on a receive.
1377: * Processing the DR includes putting us in REFWAIT state.
1378: */
1379: {
1380: if(trick_hc)
1381: return ECONNABORTED;
1382: }
1383: ;
1384:
1385: /* TP0 only */
1386: TP_REFWAIT <== [ TP_OPEN, TP_CRSENT, TP_LISTENING ] T_NETRESET
1387: ( $P.tp_class != TP_CLASS_4 )
1388: /* 0 or (4 and 0) */
1389: /* in OPEN class will be 0 or 4 but not both */
1390: /* in CRSENT or LISTENING it could be in negotiation, hence both */
1391: /* Actually, this shouldn't ever happen in LISTENING */
1392: {
1393: ASSERT( $P.tp_state != TP_LISTENING );
1394: tp_indicate(T_DISCONNECT, $P, ECONNRESET);
1395: tp_soisdisconnected($P);
1396: }
1397: ;
1398:
1399: /* TP4: ignore resets */
1400: SAME <== [ TP_OPEN, TP_CRSENT, TP_AKWAIT,
1401: TP_CLOSING, TP_LISTENING ] T_NETRESET
1402: DEFAULT
1403: NULLACTION
1404: ;
1405:
1406: /* applicable in TP4, TP0 */
1407: SAME <== [ TP_CLOSED, TP_REFWAIT ] T_NETRESET
1408: DEFAULT
1409: NULLACTION
1410: ;
1411:
1412: /* C'EST TOUT */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.