1 /* $NetBSD: tp_driver.c,v 1.19 2005/12/11 12:25:12 christos Exp $ */
4 __KERNEL_RCSID(0, "$NetBSD: tp_driver.c,v 1.19 2005/12/11 12:25:12 christos Exp $");
8 static const struct act_ent
{
14 #include "tp_states.init"
17 /* @(#)tp.trans 8.1 (Berkeley) 6/10/93 */
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/socket.h>
22 #include <sys/socketvar.h>
23 #include <sys/protosw.h>
26 #include <sys/errno.h>
28 #include <netiso/tp_param.h>
29 #include <netiso/tp_var.h>
30 #include <netiso/tp_stat.h>
31 #include <netiso/tp_pcb.h>
32 #include <netiso/tp_tpdu.h>
33 #include <netiso/argo_debug.h>
34 #include <netiso/tp_trace.h>
35 #include <netiso/iso_errno.h>
36 #include <netiso/tp_seq.h>
37 #include <netiso/cons.h>
39 #define DRIVERTRACE TPPTdriver
40 #define sbwakeup(sb, dir) sowakeup(p->tp_sock, sb, dir);
41 #define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
43 static int trick_hc
= 1;
45 #include "tp_events.h"
46 static int _Xebec_action (int, struct tp_event
*, struct tp_pcb
*);
47 static int _Xebec_index (struct tp_event
*, struct tp_pcb
*);
50 _Xebec_action(int a
, struct tp_event
*e
, struct tp_pcb
*p
)
53 struct mbuf
*data
= NULL
;
55 struct socket
*so
= p
->tp_sock
;
61 return tp_protocol_error(e
, p
);
63 (void) tp_emit(DC_TPDU_type
, p
, 0, 0, NULL
);
67 if (e
->ev_number
!= AK_TPDU
)
68 printf("TPDU 0x%x in REFWAIT!!!!\n", e
->ev_number
);
72 /* oh, man is this grotesque or what? */
73 (void) tp_goodack(p
, e
->ev_union
.EV_AK_TPDU
.e_cdt
, e
->ev_union
.EV_AK_TPDU
.e_seq
, e
->ev_union
.EV_AK_TPDU
.e_subseq
);
75 * but it's necessary because this pseudo-ack may
76 * happen before the CC arrives, but we HAVE to
77 * adjust the snduna as a result of the ack, WHENEVER
85 p
->tp_refstate
= REF_OPEN
; /* has timers ??? */
89 if (tp_traceflags
[D_CONN
])
90 tptrace(TPPTmisc
, "CR datalen data",
91 e
->ev_union
.EV_CR_TPDU
.e_datalen
,
92 e
->ev_union
.EV_CR_TPDU
.e_data
, 0, 0);
95 if (argo_debug
[D_CONN
]) {
96 printf("CR datalen 0x%x data %p",
97 e
->ev_union
.EV_CR_TPDU
.e_datalen
,
98 e
->ev_union
.EV_CR_TPDU
.e_data
);
101 p
->tp_refstate
= REF_OPEN
; /* has timers */
102 p
->tp_fcredit
= e
->ev_union
.EV_CR_TPDU
.e_cdt
;
104 if (e
->ev_union
.EV_CR_TPDU
.e_datalen
> 0) {
105 /* n/a for class 0 */
106 ASSERT(p
->tp_Xrcv
.sb_cc
== 0);
107 sbappendrecord(&p
->tp_Xrcv
,
108 e
->ev_union
.EV_CR_TPDU
.e_data
);
109 e
->ev_union
.EV_CR_TPDU
.e_data
= NULL
;
113 IncStat(ts_tp0_conn
);
115 if (tp_traceflags
[D_CONN
])
116 tptrace(TPPTmisc
, "Confiming", p
, 0, 0, 0);
119 if (argo_debug
[D_CONN
]) {
120 printf("Confirming connection: p");
123 soisconnected(p
->tp_sock
);
124 (void) tp_emit(CC_TPDU_type
, p
, 0, 0, NULL
);
128 IncStat(ts_tp4_conn
); /* even though not quite open */
130 if (tp_traceflags
[D_CONN
])
131 tptrace(TPPTmisc
, "Confiming", p
, 0, 0, 0);
134 if (argo_debug
[D_CONN
]) {
135 printf("Confirming connection: p");
139 soisconnecting(p
->tp_sock
);
140 if ((p
->tp_rx_strat
& TPRX_FASTSTART
) && (p
->tp_fcredit
> 0))
141 p
->tp_cong_win
= p
->tp_fcredit
* p
->tp_l_tpdusize
;
142 p
->tp_retrans
= p
->tp_Nretrans
;
143 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_cc_ticks
);
147 if (argo_debug
[D_CONN
]) {
148 printf("event: CR_TPDU emit CC failed done ");
151 soisdisconnected(p
->tp_sock
);
152 tp_recycle_tsuffix(p
);
153 tp_freeref(p
->tp_lref
);
158 if (tp_traceflags
[D_CONN
])
159 tptrace(TPPTmisc
, "T_CONN_req flags ucddata",
160 (int) p
->tp_flags
, p
->tp_ucddata
, 0, 0);
162 data
= MCPY(p
->tp_ucddata
, M_WAIT
);
165 if (argo_debug
[D_CONN
]) {
166 printf("T_CONN_req.trans m_copy cc %p\n",
168 dump_mbuf(data
, "sosnd @ T_CONN_req");
172 if ((error
= tp_emit(CR_TPDU_type
, p
, 0, 0, data
)) != 0)
173 return error
; /* driver WON'T change state;
174 * will return error */
176 p
->tp_refstate
= REF_OPEN
; /* has timers */
177 if (p
->tp_class
!= TP_CLASS_0
) {
178 p
->tp_retrans
= p
->tp_Nretrans
;
179 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_cr_ticks
);
183 sbflush(&p
->tp_Xrcv
); /* purge non-delivered data
185 if (e
->ev_union
.EV_DR_TPDU
.e_datalen
> 0) {
186 sbappendrecord(&p
->tp_Xrcv
, e
->ev_union
.EV_DR_TPDU
.e_data
);
187 e
->ev_union
.EV_DR_TPDU
.e_data
= NULL
;
189 if (p
->tp_state
== TP_OPEN
)
190 tp_indicate(T_DISCONNECT
, p
, 0);
192 int so_error
= ECONNREFUSED
;
193 if (e
->ev_union
.EV_DR_TPDU
.e_reason
!= (E_TP_NO_SESSION
^ TP_ERROR_MASK
) &&
194 e
->ev_union
.EV_DR_TPDU
.e_reason
!= (E_TP_NO_CR_ON_NC
^ TP_ERROR_MASK
) &&
195 e
->ev_union
.EV_DR_TPDU
.e_reason
!= (E_TP_REF_OVERFLOW
^ TP_ERROR_MASK
))
196 so_error
= ECONNABORTED
;
197 tp_indicate(T_DISCONNECT
, p
, so_error
);
199 tp_soisdisconnected(p
);
200 if (p
->tp_class
!= TP_CLASS_0
) {
201 if (p
->tp_state
== TP_OPEN
) {
202 tp_euntimeout(p
, TM_data_retrans
);/* all */
203 tp_cuntimeout(p
, TM_retrans
);
204 tp_cuntimeout(p
, TM_inact
);
205 tp_cuntimeout(p
, TM_sendack
);
206 p
->tp_flags
&= ~TPF_DELACK
;
208 tp_cuntimeout(p
, TM_retrans
);
209 if (e
->ev_union
.EV_DR_TPDU
.e_sref
!= 0)
210 (void) tp_emit(DC_TPDU_type
, p
, 0, 0, NULL
);
214 if (e
->ev_union
.EV_DR_TPDU
.e_sref
!= 0)
215 (void) tp_emit(DC_TPDU_type
, p
, 0, 0, NULL
);
217 * reference timer already set - reset it to be safe
220 tp_euntimeout(p
, TM_reference
); /* all */
221 tp_etimeout(p
, TM_reference
, (int) p
->tp_refer_ticks
);
224 tp_cuntimeout(p
, TM_retrans
);
225 tp_indicate(ER_TPDU
, p
, e
->ev_union
.EV_ER_TPDU
.e_reason
);
226 tp_soisdisconnected(p
);
229 tp_cuntimeout(p
, TM_retrans
);
230 tp_soisdisconnected(p
);
233 tp_indicate(ER_TPDU
, p
, e
->ev_union
.EV_ER_TPDU
.e_reason
);
234 tp_cuntimeout(p
, TM_retrans
);
235 tp_soisdisconnected(p
);
238 tp_cuntimeout(p
, TM_retrans
);
239 tp_soisdisconnected(p
);
242 /* don't ask me why we have to do this - spec
244 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_NO_SESSION
, NULL
);
245 /* don't bother with retransmissions of the DR */
248 tp_soisdisconnecting(p
->tp_sock
);
249 tp_indicate(ER_TPDU
, p
, e
->ev_union
.EV_ER_TPDU
.e_reason
);
250 tp_soisdisconnected(p
);
251 tp_netcmd(p
, CONN_CLOSE
);
254 if (p
->tp_state
== TP_OPEN
) {
255 tp_euntimeout(p
, TM_data_retrans
); /* all */
256 tp_cuntimeout(p
, TM_inact
);
257 tp_cuntimeout(p
, TM_sendack
);
259 tp_soisdisconnecting(p
->tp_sock
);
260 tp_indicate(ER_TPDU
, p
, e
->ev_union
.EV_ER_TPDU
.e_reason
);
261 p
->tp_retrans
= p
->tp_Nretrans
;
262 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_dr_ticks
);
263 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_PROTO_ERR
, NULL
);
266 tp_cuntimeout(p
, TM_retrans
);
267 IncStat(ts_tp0_conn
);
269 soisconnected(p
->tp_sock
);
273 if (argo_debug
[D_CONN
]) {
274 printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
278 IncStat(ts_tp4_conn
);
279 p
->tp_fref
= e
->ev_union
.EV_CC_TPDU
.e_sref
;
280 p
->tp_fcredit
= e
->ev_union
.EV_CC_TPDU
.e_cdt
;
281 if ((p
->tp_rx_strat
& TPRX_FASTSTART
) &&
282 (e
->ev_union
.EV_CC_TPDU
.e_cdt
> 0))
283 p
->tp_cong_win
= e
->ev_union
.EV_CC_TPDU
.e_cdt
* p
->tp_l_tpdusize
;
285 tp_cuntimeout(p
, TM_retrans
);
288 if (argo_debug
[D_CONN
]) {
289 printf("dropping user connect data cc 0x%x\n",
290 p
->tp_ucddata
->m_len
);
293 m_freem(p
->tp_ucddata
);
296 soisconnected(p
->tp_sock
);
297 if (e
->ev_union
.EV_CC_TPDU
.e_datalen
> 0) {
298 ASSERT(p
->tp_Xrcv
.sb_cc
== 0); /* should be empty */
299 sbappendrecord(&p
->tp_Xrcv
,
300 e
->ev_union
.EV_CC_TPDU
.e_data
);
301 e
->ev_union
.EV_CC_TPDU
.e_data
= NULL
;
303 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, NULL
);
304 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
307 IncStat(ts_retrans_cr
);
308 p
->tp_cong_win
= 1 * p
->tp_l_tpdusize
;
309 data
= MCPY(p
->tp_ucddata
, M_NOWAIT
);
312 if (argo_debug
[D_CONN
]) {
313 printf("TM_retrans.trans m_copy cc %p\n",
315 dump_mbuf(p
->tp_ucddata
, "sosnd @ TM_retrans");
322 if ((error
= tp_emit(CR_TPDU_type
, p
, 0, 0, data
)) != 0) {
323 p
->tp_sock
->so_error
= error
;
325 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_cr_ticks
);
328 IncStat(ts_conn_gaveup
);
329 p
->tp_sock
->so_error
= ETIMEDOUT
;
330 tp_indicate(T_DISCONNECT
, p
, ETIMEDOUT
);
331 tp_soisdisconnected(p
);
334 data
= MCPY(p
->tp_ucddata
, M_WAIT
);
336 if ((error
= tp_emit(CC_TPDU_type
, p
, 0, 0, data
)) != 0) {
337 p
->tp_sock
->so_error
= error
;
339 p
->tp_retrans
= p
->tp_Nretrans
;
340 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_cc_ticks
);
344 * Get rid of any confirm or connect data, so that if we
345 * crash or close, it isn't thought of as disconnect data.
348 m_freem(p
->tp_ucddata
);
351 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
352 tp_cuntimeout(p
, TM_retrans
);
353 soisconnected(p
->tp_sock
);
354 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
357 * see also next 2 transitions, if you make any
361 doack
= tp_stash(p
, e
);
363 if (argo_debug
[D_DATA
]) {
364 printf("tp_stash returns %d\n", doack
);
369 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, NULL
);
370 tp_ctimeout(p
, TM_sendack
, (int) p
->tp_keepalive_ticks
);
372 tp_ctimeout(p
, TM_sendack
, (int) p
->tp_sendack_ticks
);
375 if (argo_debug
[D_DATA
]) {
376 printf("after stash calling sbwakeup\n");
382 sbwakeup(&p
->tp_sock
->so_rcv
, POLL_IN
);
385 if (argo_debug
[D_DATA
]) {
386 printf("after stash calling sbwakeup\n");
391 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
392 sbwakeup(&p
->tp_sock
->so_rcv
, POLL_IN
);
394 doack
= tp_stash(p
, e
);
396 if (argo_debug
[D_DATA
]) {
397 printf("tp_stash returns %d\n", doack
);
402 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, NULL
);
404 tp_ctimeout_MIN(p
, TM_sendack
, (int) p
->tp_sendack_ticks
);
407 if (argo_debug
[D_DATA
]) {
408 printf("after stash calling sbwakeup\n");
414 if (tp_traceflags
[D_DATA
])
415 tptrace(TPPTmisc
, "NIW seq rcvnxt lcredit ",
416 e
->ev_union
.EV_DT_TPDU
.e_seq
,
417 p
->tp_rcvnxt
, p
->tp_lcredit
, 0);
420 m_freem(e
->ev_union
.EV_DT_TPDU
.e_data
);
421 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
422 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, NULL
);
426 m_freem(p
->tp_ucddata
);
429 (void) tp_goodack(p
, e
->ev_union
.EV_AK_TPDU
.e_cdt
, e
->ev_union
.EV_AK_TPDU
.e_seq
, e
->ev_union
.EV_AK_TPDU
.e_subseq
);
430 tp_cuntimeout(p
, TM_retrans
);
432 soisconnected(p
->tp_sock
);
434 if (tp_traceflags
[D_CONN
]) {
435 struct socket
*so
= p
->tp_sock
;
437 "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
438 so
, so
->so_state
, so
->so_rcv
.sb_sel
,
439 so
->so_rcv
.sb_flags
);
441 "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
442 so
->so_qlen
, so
->so_error
, so
->so_rcv
.sb_cc
,
447 tp_ctimeout(p
, TM_sendack
, (int) p
->tp_keepalive_ticks
);
448 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
451 if (p
->tp_state
== TP_AKWAIT
) {
453 m_freem(p
->tp_ucddata
);
456 tp_cuntimeout(p
, TM_retrans
);
457 soisconnected(p
->tp_sock
);
458 tp_ctimeout(p
, TM_sendack
, (int) p
->tp_keepalive_ticks
);
459 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
462 if (tp_traceflags
[D_XPD
]) {
463 tptrace(TPPTmisc
, "XPD tpdu accepted Xrcvnxt, "
464 "e_seq datalen m_len\n", p
->tp_Xrcvnxt
,
465 e
->ev_union
.EV_XPD_TPDU
.e_seq
,
466 e
->ev_union
.EV_XPD_TPDU
.e_datalen
,
467 e
->ev_union
.EV_XPD_TPDU
.e_data
->m_len
);
471 p
->tp_sock
->so_state
|= SS_RCVATMARK
;
472 e
->ev_union
.EV_XPD_TPDU
.e_data
->m_flags
|= M_EOR
;
473 sbinsertoob(&p
->tp_Xrcv
, e
->ev_union
.EV_XPD_TPDU
.e_data
);
475 if (argo_debug
[D_XPD
]) {
476 dump_mbuf(e
->ev_union
.EV_XPD_TPDU
.e_data
, "XPD TPDU: tp_Xrcv");
479 tp_indicate(T_XDATA
, p
, 0);
480 sbwakeup(&p
->tp_Xrcv
, POLL_IN
);
482 (void) tp_emit(XAK_TPDU_type
, p
, p
->tp_Xrcvnxt
, 0, NULL
);
483 SEQ_INC(p
, p
->tp_Xrcvnxt
);
486 if (p
->tp_Xrcv
.sb_cc
== 0) {
487 /* kludge for select(): */
488 /* p->tp_sock->so_state &= ~SS_OOBAVAIL; */
493 if (tp_traceflags
[D_XPD
])
495 "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
496 p
->tp_Xrcvnxt
, e
->ev_union
.EV_XPD_TPDU
.e_seq
,
497 p
->tp_Xrcv
.sb_cc
, 0);
499 if (p
->tp_Xrcvnxt
!= e
->ev_union
.EV_XPD_TPDU
.e_seq
)
501 if (p
->tp_Xrcv
.sb_cc
) {
502 /* might as well kick 'em again */
503 tp_indicate(T_XDATA
, p
, 0);
506 m_freem(e
->ev_union
.EV_XPD_TPDU
.e_data
);
507 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
509 * don't send an xack because the xak gives "last one
510 * received", not "next one i expect" (dumb)
514 /* detach from parent socket so it can finish closing */
516 if (!soqremque(so
, 0) && !soqremque(so
, 1))
517 panic("tp: T_DETACH");
520 tp_soisdisconnecting(p
->tp_sock
);
521 tp_netcmd(p
, CONN_CLOSE
);
522 tp_soisdisconnected(p
);
525 /* detach from parent socket so it can finish closing */
527 if (!soqremque(so
, 0) && !soqremque(so
, 1))
528 panic("tp: T_DETACH");
531 if (p
->tp_state
!= TP_CLOSING
) {
532 tp_soisdisconnecting(p
->tp_sock
);
533 data
= MCPY(p
->tp_ucddata
, M_NOWAIT
);
534 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_NORMAL_DISC
, data
);
535 p
->tp_retrans
= p
->tp_Nretrans
;
536 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_dr_ticks
);
540 tp_soisdisconnecting(p
->tp_sock
);
541 tp_netcmd(p
, CONN_CLOSE
);
542 tp_soisdisconnected(p
);
545 data
= MCPY(p
->tp_ucddata
, M_WAIT
);
547 if (p
->tp_state
== TP_OPEN
) {
548 tp_euntimeout(p
, TM_data_retrans
); /* all */
549 tp_cuntimeout(p
, TM_inact
);
550 tp_cuntimeout(p
, TM_sendack
);
551 p
->tp_flags
&= ~TPF_DELACK
;
555 if (argo_debug
[D_CONN
]) {
556 printf("T_DISC_req.trans tp_ucddata %p\n",
558 dump_mbuf(data
, "ucddata @ T_DISC_req");
562 tp_soisdisconnecting(p
->tp_sock
);
563 p
->tp_retrans
= p
->tp_Nretrans
;
564 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_dr_ticks
);
567 return tp_emit(DR_TPDU_type
, p
, 0,
568 e
->ev_union
.EV_REQ_TPDU
.e_reason
,
572 data
= MCPY(p
->tp_ucddata
, M_WAIT
);
574 IncStat(ts_retrans_cc
);
576 p
->tp_cong_win
= 1 * p
->tp_l_tpdusize
;
578 if ((error
= tp_emit(CC_TPDU_type
, p
, 0, 0, data
)) != 0)
579 p
->tp_sock
->so_error
= error
;
580 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_cc_ticks
);
583 IncStat(ts_conn_gaveup
);
584 tp_soisdisconnecting(p
->tp_sock
);
585 p
->tp_sock
->so_error
= ETIMEDOUT
;
586 tp_indicate(T_DISCONNECT
, p
, ETIMEDOUT
);
587 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_CONGEST
, NULL
);
588 p
->tp_retrans
= p
->tp_Nretrans
;
589 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_dr_ticks
);
592 tp_euntimeout(p
, TM_data_retrans
); /* all */
593 tp_cuntimeout(p
, TM_inact
);
594 tp_cuntimeout(p
, TM_sendack
);
596 IncStat(ts_conn_gaveup
);
597 tp_soisdisconnecting(p
->tp_sock
);
598 p
->tp_sock
->so_error
= ETIMEDOUT
;
599 tp_indicate(T_DISCONNECT
, p
, ETIMEDOUT
);
600 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_CONGEST_2
, NULL
);
601 p
->tp_retrans
= p
->tp_Nretrans
;
602 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_dr_ticks
);
605 p
->tp_cong_win
= 1 * p
->tp_l_tpdusize
;
607 if (p
->tp_Xsnd
.sb_mb
) {
608 struct mbuf
*m
= m_copy(p
->tp_Xsnd
.sb_mb
, 0,
609 (int) p
->tp_Xsnd
.sb_cc
);
613 if (tp_traceflags
[D_XPD
]) {
615 "XPD retrans: Xuna Xsndnxt sndnxt snduna",
616 p
->tp_Xuna
, p
->tp_Xsndnxt
, p
->tp_sndnxt
,
621 if (argo_debug
[D_XPD
]) {
622 dump_mbuf(m
, "XPD retrans emitting M");
625 IncStat(ts_retrans_xpd
);
627 shift
= max(p
->tp_Nretrans
- p
->tp_retrans
, 6);
628 (void) tp_emit(XPD_TPDU_type
, p
, p
->tp_Xuna
, 1, m
);
629 tp_ctimeout(p
, TM_retrans
, ((int) p
->tp_dt_ticks
) << shift
);
634 (void) tp_data_retrans(p
);
638 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_DR_NO_REAS
, NULL
);
639 IncStat(ts_retrans_dr
);
640 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_dr_ticks
);
643 p
->tp_sock
->so_error
= ETIMEDOUT
;
644 p
->tp_refstate
= REF_FROZEN
;
645 tp_recycle_tsuffix(p
);
646 tp_etimeout(p
, TM_reference
, (int) p
->tp_refer_ticks
);
649 tp_freeref(p
->tp_lref
);
653 if (p
->tp_class
!= TP_CLASS_0
) {
654 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
655 if (e
->ev_number
== CC_TPDU
)
656 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, NULL
);
659 * ignore it if class 0 - state tables are blank for
665 if (tp_traceflags
[D_DATA
])
667 "T_DATA_req sndnxt snduna fcredit, tpcb",
668 p
->tp_sndnxt
, p
->tp_snduna
, p
->tp_fcredit
, p
);
677 if (p
->tp_Xsnd
.sb_mb
) {
678 struct mbuf
*m
= m_copy(p
->tp_Xsnd
.sb_mb
, 0, (int) p
->tp_Xsnd
.sb_cc
);
680 * m_copy doesn't preserve the m_xlink field,
681 * but at this pt. that doesn't matter
685 if (tp_traceflags
[D_XPD
])
687 "XPD req: Xuna Xsndnxt sndnxt snduna",
688 p
->tp_Xuna
, p
->tp_Xsndnxt
, p
->tp_sndnxt
,
692 if (argo_debug
[D_XPD
]) {
693 printf("T_XPD_req: sb_cc 0x%lx\n", p
->tp_Xsnd
.sb_cc
);
694 dump_mbuf(m
, "XPD req emitting M");
698 tp_emit(XPD_TPDU_type
, p
, p
->tp_Xuna
, 1, m
);
699 p
->tp_retrans
= p
->tp_Nretrans
;
701 tp_ctimeout(p
, TM_retrans
, (int) p
->tp_rxtcur
);
702 SEQ_INC(p
, p
->tp_Xsndnxt
);
708 sb
= &p
->tp_sock
->so_snd
;
711 if (argo_debug
[D_ACKRECV
]) {
712 printf("GOOD ACK seq 0x%x cdt 0x%x\n", e
->ev_union
.EV_AK_TPDU
.e_seq
, e
->ev_union
.EV_AK_TPDU
.e_cdt
);
715 if (p
->tp_class
!= TP_CLASS_0
) {
716 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
718 sbwakeup(sb
, POLL_OUT
);
720 if (argo_debug
[D_ACKRECV
]) {
721 printf("GOOD ACK new sndnxt 0x%x\n", p
->tp_sndnxt
);
727 if (tp_traceflags
[D_ACKRECV
])
729 "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
730 e
->ev_union
.EV_AK_TPDU
.e_fcc_present
,
732 e
->ev_union
.EV_AK_TPDU
.e_subseq
, 0);
734 if (p
->tp_class
!= TP_CLASS_0
) {
736 if (!e
->ev_union
.EV_AK_TPDU
.e_fcc_present
) {
737 /* send ACK with FCC */
738 IncStat(ts_ackreason
[_ACK_FCC_
]);
739 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
,
742 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
746 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
747 tp_cuntimeout(p
, TM_retrans
);
749 sbwakeup(&p
->tp_sock
->so_snd
, POLL_OUT
);
751 /* resume normal data */
756 if (tp_traceflags
[D_ACKRECV
])
757 tptrace(TPPTmisc
, "BOGUS XACK eventtype ",
758 e
->ev_number
, 0, 0, 0);
760 if (p
->tp_class
!= TP_CLASS_0
) {
761 tp_ctimeout(p
, TM_inact
, (int) p
->tp_inact_ticks
);
766 if (tp_traceflags
[D_TIMER
])
767 tptrace(TPPTsendack
, -1, p
->tp_lcredit
, p
->tp_sent_uwe
,
770 IncPStat(p
, tps_n_TMsendack
);
771 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, NULL
);
772 if (p
->tp_fcredit
== 0) {
773 if (p
->tp_rxtshift
< TP_MAXRXTSHIFT
)
775 timo
= (p
->tp_dt_ticks
) << p
->tp_rxtshift
;
777 timo
= p
->tp_sendack_ticks
;
778 tp_ctimeout(p
, TM_sendack
, timo
);
781 if (sbspace(&p
->tp_sock
->so_rcv
) > 0)
788 * If the upper window edge has advanced a reasonable
789 * amount beyond what was known, send an ACK.
790 * A reasonable amount is 2 packets, unless the max window
791 * is only 1 or 2 packets, in which case we
792 * should send an ack for any advance in the upper window edge.
795 ack_thresh
= SEQ_SUB(p
, p
->tp_lcredit
+ p
->tp_rcvnxt
,
796 (p
->tp_maxlcredit
> 2 ? 2 : 1));
797 if (SEQ_GT(p
, ack_thresh
, p
->tp_sent_uwe
)) {
798 IncStat(ts_ackreason
[_ACK_USRRCV_
]);
799 p
->tp_flags
&= ~TPF_DELACK
;
800 return tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, NULL
);
809 ASSERT(p
->tp_state
!= TP_LISTENING
);
810 tp_indicate(T_DISCONNECT
, p
, ECONNRESET
);
811 tp_soisdisconnected(p
);
818 _Xebec_index(struct tp_event
*e
, struct tp_pcb
*p
)
820 switch ((e
->ev_number
<< 4) + (p
->tp_state
)) {
822 if (p
->tp_retrans
> 0)
827 if (p
->tp_retrans
> 0)
832 if (p
->tp_retrans
> 0)
837 if (p
->tp_retrans
> 0)
842 if (p
->tp_rxtshift
< TP_NRETRANS
)
847 if (p
->tp_class
== TP_CLASS_0
)
852 if (p
->tp_class
== TP_CLASS_0
)
857 if (e
->ev_union
.EV_DR_TPDU
.e_sref
!= 0)
862 if (p
->tp_class
== TP_CLASS_0
)
867 if (p
->tp_class
== TP_CLASS_0
)
872 if (tp_goodack(p
, e
->ev_union
.EV_AK_TPDU
.e_cdt
, e
->ev_union
.EV_AK_TPDU
.e_seq
, e
->ev_union
.EV_AK_TPDU
.e_subseq
))
877 if (IN_RWINDOW(p
, e
->ev_union
.EV_DT_TPDU
.e_seq
,
878 p
->tp_rcvnxt
, SEQ(p
, p
->tp_rcvnxt
+ p
->tp_lcredit
)))
883 if (p
->tp_class
== TP_CLASS_0
)
885 else if (IN_RWINDOW(p
, e
->ev_union
.EV_DT_TPDU
.e_seq
,
886 p
->tp_rcvnxt
, SEQ(p
, p
->tp_rcvnxt
+ p
->tp_lcredit
)))
891 if (p
->tp_Xrcvnxt
== e
->ev_union
.EV_XPD_TPDU
.e_seq
)
896 if (p
->tp_Xrcvnxt
== e
->ev_union
.EV_XPD_TPDU
.e_seq
)
901 if (tp_goodXack(p
, e
->ev_union
.EV_XAK_TPDU
.e_seq
))
906 if (p
->tp_class
== TP_CLASS_0
)
911 if (p
->tp_class
== TP_CLASS_0
)
916 if (p
->tp_class
== TP_CLASS_0
)
921 if (p
->tp_class
== TP_CLASS_0
)
926 if (p
->tp_class
!= TP_CLASS_4
)
931 if (p
->tp_class
!= TP_CLASS_4
)
936 if (p
->tp_class
!= TP_CLASS_4
)
941 if (p
->tp_class
== TP_CLASS_0
)
943 else if (tp_emit(CC_TPDU_type
, p
, 0, 0, MCPY(p
->tp_ucddata
, M_NOWAIT
)) == 0)
950 } /* _Xebec_index() */
951 static const int inx
[26][9] =
953 {0, 0, 0, 0, 0, 0, 0, 0, 0,},
954 {0x0, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x0,},
955 {0x0, 0x0, -1, -1, -1, -1, 0x0, 0x0, 0x0,},
956 {0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x0, 0x0,},
957 {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,},
958 {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x0, 0x0,},
959 {0x0, 0x0, 0x0, 0x0, -1, 0x0, 0x0, 0x0, 0x0,},
960 {0x0, 0x7, 0x15, 0x1b, -1, 0x17, 0x3, 0xa, 0x0,},
961 {0x0, 0x19, 0x6, 0x20, 0x37, 0x8, 0x3, -1, 0x0,},
962 {0x0, 0x14, 0x13, 0x13, 0x13, 0x16, -1, 0xa, 0x0,},
963 {0x0, 0x7, 0x6, 0x1, 0x9, 0x18, 0x3, 0xa, 0x0,},
964 {0x0, 0x19, -1, 0x1, 0x37, 0x8, 0x3, 0xa, 0x0,},
965 {0x0, 0x7, -1, 0x26, -1, 0x8, 0x3, 0xa, 0x0,},
966 {0x0, 0x7, 0x6, -1, -1, 0x8, 0x3, 0xa, 0x0,},
967 {0x0, 0x7, 0x6, -1, -1, 0x8, 0x3, 0xa, 0x0,},
968 {0x0, 0x7, 0x6, 0x1, -1, 0x8, 0x3, 0xa, 0x0,},
969 {0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,},
970 {0x0, 0x0, -1, 0x2e, -1, 0x0, 0x4, 0x0, 0x2e,},
971 {0x0, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,},
972 {0x0, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x0,},
973 {0x0, 0x0, 0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0x0,},
974 {0x0, 0x0, 0x0, 0x0, -1, 0x0, 0x41, 0x0, 0x0,},
975 {0x0, 0x0, 0x0, 0x0, 0x28, 0x0, 0x41, 0x0, 0x0,},
976 {0x0, 0xc, -1, 0x2c, 0x0, 0x2c, 0x4, 0xc, 0x2c,},
977 {0x0, 0x49, -1, 0x45, -1, 0x44, 0x48, -1, 0x0,},
978 {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -1,},
981 tp_driver(struct tp_pcb
*p
, struct tp_event
*e
)
983 int index
, error
= 0;
984 const struct act_ent
*a
;
985 static const struct act_ent erroraction
= {0, -1};
987 index
= inx
[1 + e
->ev_number
][p
->tp_state
];
989 index
= _Xebec_index(e
, p
);
993 a
= &statetable
[index
];
996 error
= _Xebec_action(a
->a_action
, e
, p
);
998 if (tp_traceflag
[D_DRIVER
])
999 tptrace(DRIVERTRACE
, a
->a_newstate
, p
->tp_state
,
1000 e
->ev_number
, a
->a_action
, 0);
1003 p
->tp_state
= a
->a_newstate
;