No empty .Rs/.Re
[netbsd-mini2440.git] / sys / netiso / tp.trans
blob8026b5caac3bbebd8a7180563befe6d0a5b125a1
1 /*      $NetBSD: tp.trans,v 1.6.62.5 2005/03/04 16:54:08 skrll Exp $    */
3 /* NEW */
4 /*-
5  * Copyright (c) 1991, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *      @(#)tp.trans    8.1 (Berkeley) 6/10/93
33  */
35 /***********************************************************
36                 Copyright IBM Corporation 1987
38                       All Rights Reserved
40 Permission to use, copy, modify, and distribute this software and its
41 documentation for any purpose and without fee is hereby granted,
42 provided that the above copyright notice appear in all copies and that
43 both that copyright notice and this permission notice appear in
44 supporting documentation, and that the name of IBM not be
45 used in advertising or publicity pertaining to distribution of the
46 software without specific, written prior permission.
48 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
49 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
50 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
51 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
52 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
53 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
54 SOFTWARE.
56 ******************************************************************/
59  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
60  */
62  * Transition file for TP.
63  *
64  * DO NOT:
65  * - change the order of any of the events or states.  to do so will
66  *   make tppt, netstat, etc. cease working.
67  *
68  * NOTE:
69  * some hooks exist for data on (dis)connect, but it's ***NOT***SUPPORTED***
70  * (read: may not work!)
71  *
72  * I tried to put everything that causes a change of state in here, hence
73  * there are some seemingly trivial events  like T_DETACH and T_LISTEN_req.
74  *
75  * Almost everything having to do w/ setting & cancelling timers is here
76  * but once it was debugged, I moved the setting of the
77  * keepalive (sendack) timer to tp_emit(), where an AK_TPDU is sent.
78  * This is so the code wouldn't be duplicated all over creation in here.
79  *
80  */
81 *PROTOCOL tp
83 *INCLUDE
85 /* @(#)tp.trans 8.1 (Berkeley) 6/10/93 */
86 #include <sys/param.h>
87 #include <sys/systm.h>
88 #include <sys/socket.h>
89 #include <sys/socketvar.h>
90 #include <sys/protosw.h>
91 #include <sys/mbuf.h>
92 #include <sys/time.h>
93 #include <sys/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>
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)
109 static  trick_hc = 1;
111 int     tp_emit(),
112                 tp_goodack(),                           tp_goodXack(),
113                 tp_stash()
115 void    tp_indicate(),                          tp_getoptions(),
116                 tp_soisdisconnecting(),         tp_soisdisconnected(),
117                 tp_recycle_tsuffix(),
118 #ifdef TP_DEBUG_TIMERS
119                 tp_etimeout(),                          tp_euntimeout(),
120                 tp_ctimeout(),                          tp_cuntimeout(),
121                 tp_ctimeout_MIN(),
122 #endif
123                 tp_freeref(),                           tp_detach(),
124                 tp0_stash(),                            tp0_send(),
125                 tp_netcmd(),                            tp_send()
128 typedef  struct tp_pcb tpcb_struct;
133 *PCB    tpcb_struct     SYNONYM  P
135 *STATES
137 TP_CLOSED
138 TP_CRSENT
139 TP_AKWAIT
140 TP_OPEN
141 TP_CLOSING
142 TP_REFWAIT
143 TP_LISTENING    /* Local to this implementation */
144 TP_CONFIRMING   /* Local to this implementation */
146 *EVENTS         { struct timeval e_time; }              SYNONYM  E
148  /*
149   * C (typically cancelled) timers  -
150   *
151   * let these be the first ones so for the sake of convenience
152   * their values are 0--> n-1
153   * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!!
154   */
155  TM_inact
156  TM_retrans
157                                 /* TM_retrans is used for all
158                                  * simple retransmissions - CR,CC,XPD,DR
159                                  */
161  TM_sendack
162                                 /* TM_sendack does dual duty - keepalive AND closed-window
163                                  * Probes.
164                                  * It's set w/ keepalive-ticks every time an ack is sent.
165                                  * (this is done in (void) tp_emit() ).
166                                  * Whenever a DT arrives which doesn't require immediate acking,
167                                  * a separate fast-timeout flag is set ensuring 200ms response.
168                                  */
169  TM_notused
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; }
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  */
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;          }
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
231 *TRANSITIONS
234 /* TP_AKWAIT doesn't exist in TP 0 */
235 SAME                    <==                     TP_AKWAIT                       [ CC_TPDU, DC_TPDU, XAK_TPDU ]
236         DEFAULT
237         NULLACTION
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, NULL);
246         }
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         }
261 /* applicable in TP4, TP0 */
262 SAME                    <==                     TP_REFWAIT                              [ T_DETACH, T_DISC_req ]
263         DEFAULT
264         NULLACTION
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         }
280 /* applicable in TP4, TP0 */
281 SAME                    <==                     TP_CRSENT
282                                         [ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU,  XAK_TPDU ]
283         DEFAULT
284         NULLACTION
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
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
302 /* DC_TPDU doesn't exist in TP 0 */
303 SAME                    <==                     TP_OPEN                                           DC_TPDU
304         DEFAULT
305         NULLACTION
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
315 /* applicable in TP4, TP0 */
316 TP_LISTENING    <==                     TP_CLOSED                                                       T_LISTEN_req
317         DEFAULT
318         NULLACTION
321 /* applicable in TP4, TP0 */
322 TP_CLOSED               <==             [ TP_LISTENING, TP_CLOSED ]                     T_DETACH
323         DEFAULT
324         {
325                 tp_detach($P);
326         }
329 TP_CONFIRMING   <==              TP_LISTENING                                                           CR_TPDU
330         ( $P.tp_class == TP_CLASS_0)
331         {
332                 $P.tp_refstate = REF_OPEN; /* has timers ??? */
333         }
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_refstate = REF_OPEN; /* has timers */
346                 $P.tp_fcredit = $$.e_cdt;
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 = NULL;
353                 }
354         }
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, NULL) ;
369                 $P.tp_fcredit = 1;
370         }
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                 tp_getoptions($P);
384                 soisconnecting($P.tp_sock);
385                 if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
386                         $P.tp_cong_win = $P.tp_fcredit * $P.tp_l_tpdusize;
387                 $P.tp_retrans = $P.tp_Nretrans;
388                 tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
389         }
392 /* TP4 only */
393 TP_CLOSED               <==              TP_CONFIRMING                                                          T_ACPT_req
394         DEFAULT /* emit failed */
395         {
396                 IFDEBUG(D_CONN)
397                         printf("event: CR_TPDU emit CC failed done " );
398                 ENDDEBUG
399                 soisdisconnected($P.tp_sock);
400                 tp_recycle_tsuffix($P);
401                 tp_freeref($P.tp_lref);
402                 tp_detach($P);
403         }
406 /* applicable in TP4, TP0 */
407 TP_CRSENT               <==             TP_CLOSED                                                               T_CONN_req
408         DEFAULT
409         {
410                 int error;
411                 struct mbuf *data = NULL;
413                 IFTRACE(D_CONN)
414                         tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
415                         $P.tp_ucddata, 0, 0);
416                 ENDTRACE
417                 data =  MCPY($P.tp_ucddata, M_WAIT);
418                 if (data) {
419                         IFDEBUG(D_CONN)
420                                 printf("T_CONN_req.trans m_copy cc 0x%x\n",
421                                         $P.tp_ucddata);
422                                 dump_mbuf(data, "sosnd @ T_CONN_req");
423                         ENDDEBUG
424                 }
426                 if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
427                         return error; /* driver WON'T change state; will return error */
429                 $P.tp_refstate = REF_OPEN; /* has timers */
430                 if($P.tp_class != TP_CLASS_0) {
431                         $P.tp_retrans = $P.tp_Nretrans;
432                         tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
433                 }
434         }
437 /* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */
438 TP_REFWAIT              <==             [ TP_CRSENT, TP_AKWAIT, TP_OPEN ]                       DR_TPDU
439         DEFAULT
440         {
441                 sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */
442                 if ($$.e_datalen > 0) {
443                         sbappendrecord(&$P.tp_Xrcv, $$.e_data);
444                         $$.e_data = NULL;
445                 }
446                 if ($P.tp_state == TP_OPEN)
447                         tp_indicate(T_DISCONNECT, $P, 0);
448                 else {
449                         int so_error = ECONNREFUSED;
450                         if ($$.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) &&
451                             $$.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) &&
452                             $$.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK))
453                                 so_error = ECONNABORTED;
454                         tp_indicate(T_DISCONNECT, $P, so_error);
455                 }
456                 tp_soisdisconnected($P);
457                 if ($P.tp_class != TP_CLASS_0) {
458                         if ($P.tp_state == TP_OPEN ) {
459                                 tp_euntimeout($P, TM_data_retrans); /* all */
460                                 tp_cuntimeout($P, TM_retrans);
461                                 tp_cuntimeout($P, TM_inact);
462                                 tp_cuntimeout($P, TM_sendack);
463                                 $P.tp_flags &= ~TPF_DELACK;
464                         }
465                         tp_cuntimeout($P, TM_retrans);
466                         if( $$.e_sref !=  0 )
467                                 (void) tp_emit(DC_TPDU_type, $P, 0, 0, NULL);
468                 }
469         }
472 SAME                    <==             TP_CLOSED                                                                       DR_TPDU
473         DEFAULT
474         {
475                 if( $$.e_sref != 0 )
476                         (void) tp_emit(DC_TPDU_type, $P, 0, 0, NULL);
477                 /* reference timer already set - reset it to be safe (???) */
478                 tp_euntimeout($P, TM_reference); /* all */
479                 tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
480         }
483 /* NBS(34) */
484 TP_REFWAIT              <==     TP_CRSENT                                                                       ER_TPDU
485         DEFAULT
486         {
487                 tp_cuntimeout($P, TM_retrans);
488                 tp_indicate(ER_TPDU, $P, $$.e_reason);
489                 tp_soisdisconnected($P);
490         }
493 /* NBS(27) */
494 TP_REFWAIT              <==             TP_CLOSING                                                                      DR_TPDU
495         DEFAULT
496         {
497                 tp_cuntimeout($P, TM_retrans);
498                 tp_soisdisconnected($P);
499         }
501 /* these two transitions are the same but can't be combined because xebec
502  * can't handle the use of $$.e_reason if they're combined
503  */
504 /* NBS(27) */
505 TP_REFWAIT              <==             TP_CLOSING                                                                      ER_TPDU
506         DEFAULT
507         {
508                 tp_indicate(ER_TPDU, $P, $$.e_reason);
509                 tp_cuntimeout($P, TM_retrans);
510                 tp_soisdisconnected($P);
511         }
513 /* NBS(27) */
514 TP_REFWAIT              <==             TP_CLOSING                                                                      DC_TPDU
515         DEFAULT
516         {
517                 tp_cuntimeout($P, TM_retrans);
518                 tp_soisdisconnected($P);
519         }
522 /* NBS(21) */
523 SAME                    <==     TP_CLOSED                                               [ CC_TPDU, CR_TPDU ]
524         DEFAULT
525         {       /* don't ask me why we have to do this - spec says so */
526                 (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, NULL);
527                 /* don't bother with retransmissions of the DR */
528         }
531 /* NBS(34) */
532 TP_REFWAIT              <==     TP_OPEN                                                                         ER_TPDU
533         ($P.tp_class == TP_CLASS_0)
534         {
535                 tp_soisdisconnecting($P.tp_sock);
536                 tp_indicate(ER_TPDU, $P, $$.e_reason);
537                 tp_soisdisconnected($P);
538                 tp_netcmd( $P, CONN_CLOSE );
539         }
542 TP_CLOSING              <==     [ TP_AKWAIT, TP_OPEN ]                                          ER_TPDU
543         DEFAULT
544         {
545                 if ($P.tp_state == TP_OPEN) {
546                         tp_euntimeout($P, TM_data_retrans); /* all */
547                         tp_cuntimeout($P, TM_inact);
548                         tp_cuntimeout($P, TM_sendack);
549                 }
550                 tp_soisdisconnecting($P.tp_sock);
551                 tp_indicate(ER_TPDU, $P, $$.e_reason);
552                 $P.tp_retrans = $P.tp_Nretrans;
553                 tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
554                 (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, NULL);
555         }
557 /* NBS(6) */
558 TP_OPEN                 <==             TP_CRSENT                                                                       CC_TPDU
559         ($P.tp_class == TP_CLASS_0)
560         {
561                 tp_cuntimeout($P, TM_retrans);
562                 IncStat(ts_tp0_conn);
563                 $P.tp_fcredit = 1;
564                 soisconnected($P.tp_sock);
565         }
568 TP_OPEN                 <==             TP_CRSENT                                                                       CC_TPDU
569         DEFAULT
570         {
571                 IFDEBUG(D_CONN)
572                         printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
573                             (int)$P.tp_flags);
574                 ENDDEBUG
575                 IncStat(ts_tp4_conn);
576                 $P.tp_fref = $$.e_sref;
577                 $P.tp_fcredit = $$.e_cdt;
578                 if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
579                         $P.tp_cong_win = $$.e_cdt * $P.tp_l_tpdusize;
580                 tp_getoptions($P);
581                 tp_cuntimeout($P, TM_retrans);
582                 if ($P.tp_ucddata) {
583                         IFDEBUG(D_CONN)
584                                 printf("dropping user connect data cc 0x%x\n",
585                                     $P.tp_ucddata->m_len);
586                         ENDDEBUG
587                         m_freem($P.tp_ucddata);
588                         $P.tp_ucddata = 0;
589                 }
590                 soisconnected($P.tp_sock);
591                 if ($$.e_datalen > 0) {
592                         ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
593                         sbappendrecord(&$P.tp_Xrcv, $$.e_data);
594                         $$.e_data = NULL;
595                 }
597                 (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, NULL);
598                 tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
599         }
602 /* TP4 only */
603 SAME                    <==             TP_CRSENT                                                                       TM_retrans
604         (       $P.tp_retrans > 0 )
605         {
606                 struct mbuf *data = NULL;
607                 int error;
609                 IncStat(ts_retrans_cr);
610                 $P.tp_cong_win = 1 * $P.tp_l_tpdusize;
611                 data = MCPY($P.tp_ucddata, M_NOWAIT);
612                 if($P.tp_ucddata) {
613                         IFDEBUG(D_CONN)
614                                 printf("TM_retrans.trans m_copy cc 0x%x\n", data);
615                                 dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
616                         ENDDEBUG
617                         if( data == NULL )
618                                 return ENOBUFS;
619                 }
621                 $P.tp_retrans--;
622                 if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
623                         $P.tp_sock->so_error = error;
624                 }
625                 tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
626         }
629 /* TP4 only  */
630 TP_REFWAIT              <==             TP_CRSENT                                                                       TM_retrans
631         DEFAULT /* no more CR retransmissions */
632         {
633                 IncStat(ts_conn_gaveup);
634                 $P.tp_sock->so_error = ETIMEDOUT;
635                 tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
636                 tp_soisdisconnected($P);
637         }
640 /* TP4 only */
641 SAME                    <==      TP_AKWAIT                                                                                      CR_TPDU
642         DEFAULT
643         /* duplicate CR (which doesn't really exist in the context of
644          * a connectionless network layer)
645          * Doesn't occur in class 0.
646          */
647         {
648                 int error;
649                 struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
651                 if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
652                         $P.tp_sock->so_error = error;
653                 }
654                 $P.tp_retrans = $P.tp_Nretrans;
655                 tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
656         }
659 /* TP4 only */
660 TP_OPEN                 <==             TP_AKWAIT                                                                               DT_TPDU
661         ( IN_RWINDOW( $P, $$.e_seq,
662                                         $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
663         {
664                 int doack;
666                 /*
667                  * Get rid of any confirm or connect data, so that if we
668                  * crash or close, it isn't thought of as disconnect data.
669                  */
670                 if ($P.tp_ucddata) {
671                         m_freem($P.tp_ucddata);
672                         $P.tp_ucddata = 0;
673                 }
674                 tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
675                 tp_cuntimeout($P, TM_retrans);
676                 soisconnected($P.tp_sock);
677                 tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
679                 /* see also next 2 transitions, if you make any changes */
681                 doack = tp_stash($P, $E);
682                 IFDEBUG(D_DATA)
683                         printf("tp_stash returns %d\n",doack);
684                 ENDDEBUG
686                 if (doack) {
687                         (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, NULL );
688                         tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
689                 } else
690                         tp_ctimeout( $P, TM_sendack, (int)$P.tp_sendack_ticks);
692                 IFDEBUG(D_DATA)
693                         printf("after stash calling sbwakeup\n");
694                 ENDDEBUG
695         }
698 SAME                    <==             TP_OPEN                                                                         DT_TPDU
699         ( $P.tp_class == TP_CLASS_0 )
700         {
701                 tp0_stash($P, $E);
702                 sbwakeup( &$P.tp_sock->so_rcv );
704                 IFDEBUG(D_DATA)
705                         printf("after stash calling sbwakeup\n");
706                 ENDDEBUG
707         }
710 /* TP4 only */
711 SAME                    <==             TP_OPEN                                                                         DT_TPDU
712         ( IN_RWINDOW( $P, $$.e_seq,
713                                         $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
714         {
715                 int doack; /* tells if we must ack immediately */
717                 tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
718                 sbwakeup( &$P.tp_sock->so_rcv );
720                 doack = tp_stash($P, $E);
721                 IFDEBUG(D_DATA)
722                         printf("tp_stash returns %d\n",doack);
723                 ENDDEBUG
725                 if(doack)
726                         (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, NULL );
727                 else
728                         tp_ctimeout_MIN( $P, TM_sendack, (int)$P.tp_sendack_ticks);
730                 IFDEBUG(D_DATA)
731                         printf("after stash calling sbwakeup\n");
732                 ENDDEBUG
733         }
736 /* Not in window  - we must ack under certain circumstances, namely
737  * a) if the seq number is below lwe but > lwe - (max credit ever given)
738  * (to handle lost acks) Can use max-possible-credit for this ^^^.
739  * and
740  * b) seq number is > uwe but < uwe + previously sent & withdrawn credit
742  * (see 12.2.3.8.1 of ISO spec, p. 73)
743  * We just always ack.
744  */
745 /* TP4 only */
746 SAME                    <==     [ TP_OPEN, TP_AKWAIT ]                                                  DT_TPDU
747         DEFAULT /* Not in window */
748         {
749                 IFTRACE(D_DATA)
750                         tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
751                                 $$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0);
752                 ENDTRACE
753                 IncStat(ts_dt_niw);
754                 m_freem($$.e_data);
755                 tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
756                 (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, NULL );
757         }
760 /* TP4 only */
761 TP_OPEN                 <==             TP_AKWAIT                                                                               AK_TPDU
762         DEFAULT
763         {
764                 if ($P.tp_ucddata) {
765                         m_freem($P.tp_ucddata);
766                         $P.tp_ucddata = 0;
767                 }
768                 (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
769                 tp_cuntimeout($P, TM_retrans);
771                 soisconnected($P.tp_sock);
772                 IFTRACE(D_CONN)
773                         struct socket *so = $P.tp_sock;
774                         tptrace(TPPTmisc,
775                         "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
776                                 so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
777                         tptrace(TPPTmisc,
778                         "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
779                                 so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
780                 ENDTRACE
782                 tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
783                 tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
784         }
787 /* TP4 only */
788 TP_OPEN                 <==     [ TP_OPEN, TP_AKWAIT ]                                          XPD_TPDU
789         ($P.tp_Xrcvnxt == $$.e_seq)
790         {
791                 if( $P.tp_state == TP_AKWAIT ) {
792                         if ($P.tp_ucddata) {
793                                 m_freem($P.tp_ucddata);
794                                 $P.tp_ucddata = 0;
795                         }
796                         tp_cuntimeout($P, TM_retrans);
797                         soisconnected($P.tp_sock);
798                         tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
799                         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
800                 }
801                 IFTRACE(D_XPD)
802                 tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
803                                 $P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
804                 ENDTRACE
806                 $P.tp_sock->so_state |= SS_RCVATMARK;
807                 $$.e_data->m_flags |= M_EOR;
808                 sbinsertoob(&$P.tp_Xrcv, $$.e_data);
809                 IFDEBUG(D_XPD)
810                         dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
811                 ENDDEBUG
812                 tp_indicate(T_XDATA, $P, 0);
813                 sbwakeup( &$P.tp_Xrcv );
815                 (void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, NULL);
816                 SEQ_INC($P, $P.tp_Xrcvnxt);
817         }
820 /* TP4 only */
821 SAME                    <==             TP_OPEN                                                                         T_USR_Xrcvd
822         DEFAULT
823         {
824                 if( $P.tp_Xrcv.sb_cc == 0 ) {
825                         /* kludge for select(): */
826                         /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
827                 }
828         }
829         /* OLD WAY:
830          * Ack only after the user receives the XPD.  This is better for
831          * users that use one XPD right after another.
832          * Acking right away (the NEW WAY, see the prev. transition) is
833          * better for occasional * XPD, when the receiving user doesn't
834          * want to read the XPD immediately (which is session's behavior).
835          *
836                 int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, NULL);
837                 SEQ_INC($P, $P.tp_Xrcvnxt);
838                 return error;
839         */
842 /* NOTE: presently if the user doesn't read the connection data
843  * before and expedited data PDU comes in, the connection data will
844  * be dropped. This is a bug.  To avoid it, we need somewhere else
845  * to put the connection data.
846  * On the other hand, we need not to have it sitting around forever.
847  * This is a problem with the idea of trying to accommodate
848  * data on connect w/ a passive-open user interface.
849  */
850 /* TP4 only */
852 SAME                    <==     [ TP_AKWAIT, TP_OPEN ]                                                  XPD_TPDU
853         DEFAULT /* not in window or cdt==0 */
854         {
855                 IFTRACE(D_XPD)
856                         tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
857                                 $P.tp_Xrcvnxt, $$.e_seq,  $P.tp_Xrcv.sb_cc , 0);
858                 ENDTRACE
859                 if( $P.tp_Xrcvnxt != $$.e_seq )
860                         IncStat(ts_xpd_niw);
861                 if( $P.tp_Xrcv.sb_cc ) {
862                         /* might as well kick 'em again */
863                         tp_indicate(T_XDATA, $P, 0);
864                         IncStat(ts_xpd_dup);
865                 }
866                 m_freem($$.e_data);
867                 tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
868                 /* don't send an xack because the xak gives "last one received", not
869                  * "next one i expect" (dumb)
870                  */
871         }
874 /* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries
875  * to detach all its "children"
876  * Also (CRSENT) when user kills a job that's doing a connect()
877  */
878 TP_REFWAIT              <==     TP_CRSENT                                                                               T_DETACH
879         ($P.tp_class == TP_CLASS_0)
880         {
881                 struct socket *so = $P.tp_sock;
883                 /* detach from parent socket so it can finish closing */
884                 if (so->so_head) {
885                         if (!soqremque(so, 0) && !soqremque(so, 1))
886                                 panic("tp: T_DETACH");
887                         so->so_head = 0;
888                 }
889                 tp_soisdisconnecting($P.tp_sock);
890                 tp_netcmd( $P, CONN_CLOSE);
891                 tp_soisdisconnected($P);
892         }
895 /* TP4 only */
896 TP_CLOSING              <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH
897         DEFAULT
898         {
899                 struct socket *so = $P.tp_sock;
900                 struct mbuf *data = NULL;
902                 /* detach from parent socket so it can finish closing */
903                 if (so->so_head) {
904                         if (!soqremque(so, 0) && !soqremque(so, 1))
905                                 panic("tp: T_DETACH");
906                         so->so_head = 0;
907                 }
908                 if ($P.tp_state != TP_CLOSING) {
909                         tp_soisdisconnecting($P.tp_sock);
910                         data = MCPY($P.tp_ucddata, M_NOWAIT);
911                         (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
912                         $P.tp_retrans = $P.tp_Nretrans;
913                         tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
914                 }
915         }
918 TP_REFWAIT              <==             [ TP_OPEN, TP_CRSENT ]                                          T_DISC_req
919         ( $P.tp_class == TP_CLASS_0 )
920         {
921                 tp_soisdisconnecting($P.tp_sock);
922                 tp_netcmd( $P, CONN_CLOSE);
923                 tp_soisdisconnected($P);
924         }
927 /* TP4 only */
928 TP_CLOSING              <==     [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ]  T_DISC_req
929         DEFAULT
930         {
931                 struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
933                 if($P.tp_state == TP_OPEN) {
934                         tp_euntimeout($P, TM_data_retrans); /* all */
935                         tp_cuntimeout($P, TM_inact);
936                         tp_cuntimeout($P, TM_sendack);
937                         $P.tp_flags &= ~TPF_DELACK;
938                 }
939                 if (data) {
940                         IFDEBUG(D_CONN)
941                                 printf("T_DISC_req.trans tp_ucddata 0x%x\n",
942                                         $P.tp_ucddata);
943                                 dump_mbuf(data, "ucddata @ T_DISC_req");
944                         ENDDEBUG
945                 }
946                 tp_soisdisconnecting($P.tp_sock);
947                 $P.tp_retrans = $P.tp_Nretrans;
948                 tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
950                 if( trick_hc )
951                         return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
952         }
955 /* TP4 only */
956 SAME                    <==             TP_AKWAIT                                                                       TM_retrans
957         ( $P.tp_retrans > 0 )
958         {
959                 int error;
960                 struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
962                 IncStat(ts_retrans_cc);
963                 $P.tp_retrans--;
964                 $P.tp_cong_win = 1 * $P.tp_l_tpdusize;
966                 if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) )
967                         $P.tp_sock->so_error = error;
968                 tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
969         }
972 /* TP4 only */
973 TP_CLOSING              <==             TP_AKWAIT                                                                       TM_retrans
974         DEFAULT  /* out of time */
975         {
976                 IncStat(ts_conn_gaveup);
977                 tp_soisdisconnecting($P.tp_sock);
978                 $P.tp_sock->so_error = ETIMEDOUT;
979                 tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
980                 (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, NULL);
981                 $P.tp_retrans = $P.tp_Nretrans;
982                 tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
983         }
986 /* the retrans timers had better go off BEFORE the inactivity timer does,
987  * if transmissions are going on.
988  * (i.e., TM_inact should be greater than timer for all retrans plus ack
989  * turnaround)
990  */
991 /* TP4 only */
992 TP_CLOSING              <==             TP_OPEN            [ TM_inact, TM_retrans, TM_data_retrans ]
993         DEFAULT
994         {
995                 tp_euntimeout($P, TM_data_retrans); /* all */
996                 tp_cuntimeout($P, TM_inact);
997                 tp_cuntimeout($P, TM_sendack);
999                 IncStat(ts_conn_gaveup);
1000                 tp_soisdisconnecting($P.tp_sock);
1001                 $P.tp_sock->so_error = ETIMEDOUT;
1002                 tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
1003                 (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, NULL);
1004                 $P.tp_retrans = $P.tp_Nretrans;
1005                 tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
1006         }
1009 /* TP4 only */
1010 SAME                    <==             TP_OPEN                                                                         TM_retrans
1011         ( $P.tp_retrans > 0 )
1012         {
1013                 $P.tp_cong_win = 1 * $P.tp_l_tpdusize;
1014                 /* resume XPD */
1015                 if      ( $P.tp_Xsnd.sb_mb )  {
1016                         struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
1017                         int shift;
1019                         IFTRACE(D_XPD)
1020                                 tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna",
1021                                         $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt,
1022                                         $P.tp_snduna);
1023                         ENDTRACE
1024                         IFDEBUG(D_XPD)
1025                                 dump_mbuf(m, "XPD retrans emitting M");
1026                         ENDDEBUG
1027                         IncStat(ts_retrans_xpd);
1028                         $P.tp_retrans--;
1029                         shift = max($P.tp_Nretrans - $P.tp_retrans, 6);
1030                         (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
1031                         tp_ctimeout($P, TM_retrans, ((int)$P.tp_dt_ticks) << shift);
1032                 }
1033         }
1036 /* TP4 only */
1037 SAME                    <==             TP_OPEN                                                                 TM_data_retrans
1038         ($P.tp_rxtshift < TP_NRETRANS)
1039         {
1040                 $P.tp_rxtshift++;
1041                 (void) tp_data_retrans($P);
1042         }
1045 /* TP4 only */
1046 SAME                    <==             TP_CLOSING                                                                      TM_retrans
1047         (       $P.tp_retrans > 0 )
1048         {
1049                 $P.tp_retrans--;
1050                 (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, NULL);
1051                 IncStat(ts_retrans_dr);
1052                 tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
1053         }
1056 /* TP4 only */
1057 TP_REFWAIT              <==             TP_CLOSING                                                                      TM_retrans
1058         DEFAULT /* no more retrans - gave up */
1059         {
1060                 $P.tp_sock->so_error = ETIMEDOUT;
1061                 $P.tp_refstate = REF_FROZEN;
1062                 tp_recycle_tsuffix( $P );
1063                 tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
1064         }
1068  * The resources are kept around until the ref timer goes off.
1069  * The suffixes are wiped out sooner so they can be reused right away.
1070  */
1071 /* applicable in TP4, TP0 */
1072 TP_CLOSED               <==             TP_REFWAIT                                                                      TM_reference
1073         DEFAULT
1074         {
1075                 tp_freeref($P.tp_lref);
1076                 tp_detach($P);
1077         }
1080 /* applicable in TP4, TP0 */
1081 /* A duplicate CR from connectionless network layer can't happen */
1082 SAME                    <==     TP_OPEN                                                         [ CR_TPDU, CC_TPDU ]
1083         DEFAULT
1084         {
1085                 if( $P.tp_class != TP_CLASS_0) {
1086                         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
1087                         if ( $E.ev_number == CC_TPDU )
1088                                 (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, NULL);
1089                 }
1090                 /* ignore it if class 0 - state tables are blank for this */
1091         }
1094 /* applicable in TP4, TP0 */
1095 SAME                    <==     TP_OPEN                                                                 T_DATA_req
1096         DEFAULT
1097         {
1098                 IFTRACE(D_DATA)
1099                         tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb",
1100                                 $P.tp_sndnxt, $P.tp_snduna, $P.tp_fcredit, $P);
1101                 ENDTRACE
1103                 tp_send($P);
1104         }
1107 /* TP4 only */
1108 SAME                    <==             TP_OPEN                                                                         T_XPD_req
1109         DEFAULT
1110                 /* T_XPD_req was issued by sosend iff xpd socket buf was empty
1111                  * at time of sosend(),
1112                  * AND (which means) there were no unacknowledged XPD tpdus outstanding!
1113                  */
1114         {
1115                 int error = 0;
1117                 /* resume XPD */
1118                 if      ( $P.tp_Xsnd.sb_mb )  {
1119                         struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
1120                         /* m_copy doesn't preserve the m_xlink field, but at this pt.
1121                          * that doesn't matter
1122                          */
1124                         IFTRACE(D_XPD)
1125                                 tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna",
1126                                         $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt,
1127                                         $P.tp_snduna);
1128                         ENDTRACE
1129                         IFDEBUG(D_XPD)
1130                                 printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
1131                                 dump_mbuf(m, "XPD req emitting M");
1132                         ENDDEBUG
1133                         error =
1134                                 tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
1135                         $P.tp_retrans = $P.tp_Nretrans;
1137                         tp_ctimeout($P, TM_retrans, (int)$P.tp_rxtcur);
1138                         SEQ_INC($P, $P.tp_Xsndnxt);
1139                 }
1140                 if(trick_hc)
1141                         return error;
1142         }
1145 /* TP4, faked ack in TP0 when cons send completes */
1146 SAME                    <==             TP_OPEN                                                                         AK_TPDU
1147         ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq)  )
1149         /* tp_goodack == true means
1150          * EITHER it actually acked something heretofore unacknowledged
1151          * OR no news but the credit should be processed.
1152          */
1153         {
1154                 struct sockbuf *sb = &$P.tp_sock->so_snd;
1156                 IFDEBUG(D_ACKRECV)
1157                         printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
1158                 ENDDEBUG
1159                 if( $P.tp_class != TP_CLASS_0) {
1160                         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
1161                 }
1162                 sbwakeup(sb);
1163                 IFDEBUG(D_ACKRECV)
1164                         printf("GOOD ACK new sndnxt 0x%x\n", $P.tp_sndnxt);
1165                 ENDDEBUG
1166         }
1169 /* TP4, and TP0 after sending a CC or possibly a CR */
1170 SAME                    <==             TP_OPEN                                                                          AK_TPDU
1171         DEFAULT
1172         {
1173                 IFTRACE(D_ACKRECV)
1174                         tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
1175                                 $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
1176                 ENDTRACE
1177                 if( $P.tp_class != TP_CLASS_0 ) {
1179                         if ( !$$.e_fcc_present ) {
1180                                 /* send ACK with FCC */
1181                                 IncStat( ts_ackreason[_ACK_FCC_] );
1182                                 (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, NULL);
1183                         }
1184                         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
1185                 }
1186         }
1189 /* NBS(47) */
1190         /* goes in at *** */
1191                 /* just so happens that this is never true now, because we allow
1192                  * only 1 packet in the queue at once (this could be changed)
1193                 if      ( $P.tp_Xsnd.sb_mb )  {
1194                         struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
1196                         (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
1197                         $P.tp_retrans = $P.tp_Nretrans;
1198                         tp_ctimeout($P, TM_retrans, (int)$P.tp_xpd_ticks);
1199                         SEQ_INC($P, $P.tp_Xsndnxt);
1200                 }
1201                  */
1202         /* end of the above hack */
1204 /* TP4 only */
1205 SAME                    <==     TP_OPEN                                                                         XAK_TPDU
1206         ( tp_goodXack($P, $$.e_seq) )
1207         /* tp_goodXack checks for good ack, removes the correct
1208          * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
1209          * also updates tp_Xuna
1210          */
1211         {
1212                 tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
1213                 tp_cuntimeout($P, TM_retrans);
1215                 sbwakeup( &$P.tp_sock->so_snd );
1217                 /* resume normal data */
1218                 tp_send($P);
1219         }
1222 /* TP4, and TP0 after sending a CC or possibly a CR */
1223 SAME                    <==             TP_OPEN                                                                         XAK_TPDU
1224         DEFAULT
1225         {
1226                 IFTRACE(D_ACKRECV)
1227                         tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
1228                 ENDTRACE
1229                 if( $P.tp_class != TP_CLASS_0 ) {
1230                         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
1231                 }
1232         }
1235 /* TP4 only */
1236 SAME                    <==             TP_OPEN                                                                 TM_sendack
1237         DEFAULT
1238         {
1239                 int timo;
1240                 IFTRACE(D_TIMER)
1241                         tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe,
1242                         $P.tp_sent_lcdt, 0);
1243                 ENDTRACE
1244                 IncPStat($P, tps_n_TMsendack);
1245                 (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, NULL);
1246                 if ($P.tp_fcredit == 0) {
1247                         if ($P.tp_rxtshift < TP_MAXRXTSHIFT)
1248                                 $P.tp_rxtshift++;
1249                         timo = ($P.tp_dt_ticks) << $P.tp_rxtshift;
1250                 } else
1251                         timo = $P.tp_sendack_ticks;
1252                 tp_ctimeout($P, TM_sendack, timo);
1253         }
1256 /* TP0 only */
1257 SAME                    <==             TP_OPEN                                                                         T_USR_rcvd
1258         ($P.tp_class == TP_CLASS_0)
1259         {
1260                 if (sbspace(&$P.tp_sock->so_rcv) > 0)
1261                         tp0_openflow($P);
1262         }
1265 /* TP4 only */
1266                 /* If old credit was zero,
1267                  * we'd better inform other side that we now have space
1268                  * But this is not enough.  Sender might not yet have
1269                  * seen an ack with cdt 0 but it might still think the
1270                  * window is closed, so it's going to wait.
1271                  * Best to send an ack each time.
1272                  * Strictly speaking, this ought to be a function of the
1273                  * general ack strategy.
1274                  */
1275 SAME                    <==             TP_OPEN                                                                         T_USR_rcvd
1276         DEFAULT
1277         {
1278                 if( trick_hc ) {
1279                         SeqNum ack_thresh;
1280                         /*
1281                          * If the upper window edge has advanced a reasonable
1282                          * amount beyond what was known, send an ACK.
1283                          * A reasonable amount is 2 packets, unless the max window
1284                          * is only 1 or 2 packets, in which case we
1285                          * should send an ack for any advance in the upper window edge.
1286                          */
1287                         LOCAL_CREDIT($P);
1288                         ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt,
1289                                                                          ($P.tp_maxlcredit > 2 ? 2 : 1));
1290                         if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) {
1291                                 IncStat(ts_ackreason[_ACK_USRRCV_]);
1292                                 $P.tp_flags &= ~TPF_DELACK;
1293                                 return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, NULL);
1294                         }
1295                 }
1296         }
1299 /* applicable in TP4, TP0 */
1300 SAME                    <==             TP_REFWAIT                              [ T_USR_rcvd, T_USR_Xrcvd ]
1301         DEFAULT
1302         /* This happens if other end sent a DR when  the user was waiting
1303          * on a receive.
1304          * Processing the DR includes putting us in REFWAIT state.
1305          */
1306         {
1307                 if(trick_hc)
1308                 return ECONNABORTED;
1309         }
1312 /* TP0 only */
1313 TP_REFWAIT              <==             [ TP_OPEN, TP_CRSENT, TP_LISTENING ]    T_NETRESET
1314         ( $P.tp_class != TP_CLASS_4 )
1315                 /* 0 or (4 and 0) */
1316                 /* in OPEN class will be 0 or 4 but not both */
1317                 /* in CRSENT or LISTENING it could be in negotiation, hence both */
1318                 /* Actually, this shouldn't ever happen in LISTENING */
1319         {
1320                 ASSERT( $P.tp_state != TP_LISTENING );
1321                 tp_indicate(T_DISCONNECT, $P, ECONNRESET);
1322                 tp_soisdisconnected($P);
1323         }
1326 /* TP4: ignore resets */
1327 SAME            <==             [ TP_OPEN, TP_CRSENT, TP_AKWAIT,
1328                                                 TP_CLOSING, TP_LISTENING ]                              T_NETRESET
1329         DEFAULT
1330         NULLACTION
1333 /* applicable in TP4, TP0 */
1334 SAME                    <==             [ TP_CLOSED, TP_REFWAIT ]                               T_NETRESET
1335         DEFAULT
1336         NULLACTION
1339 /* C'EST TOUT */