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