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