]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/tp_driver.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 static char *rcsid
= "$Header/**/$";
25 #define _XEBEC_PG static
27 #include "tp_states.h"
29 static struct act_ent
{
32 } statetable
[] = { {0,0},
33 #include "tp_states.init"
36 /* @(#)tp.trans 8.1 (Berkeley) 6/10/93 */
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <sys/protosw.h>
44 #include <sys/errno.h>
47 #include <netiso/tp_param.h>
48 #include <netiso/tp_stat.h>
49 #include <netiso/tp_pcb.h>
50 #include <netiso/tp_tpdu.h>
51 #include <netiso/argo_debug.h>
52 #include <netiso/tp_trace.h>
53 #include <netiso/iso_errno.h>
54 #include <netiso/tp_seq.h>
55 #include <netiso/cons.h>
57 #define DRIVERTRACE TPPTdriver
58 #define sbwakeup(sb) sowakeup(p->tp_sock, sb);
59 #define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
64 tp_goodack(), tp_goodXack(),
67 void tp_indicate(), tp_getoptions(),
68 tp_soisdisconnecting(), tp_soisdisconnected(),
70 #ifdef TP_DEBUG_TIMERS
71 tp_etimeout(), tp_euntimeout(),
72 tp_ctimeout(), tp_cuntimeout(),
75 tp_freeref(), tp_detach(),
76 tp0_stash(), tp0_send(),
77 tp_netcmd(), tp_send()
80 typedef struct tp_pcb tpcb_struct
;
84 typedef tpcb_struct tp_PCB_
;
86 #include "tp_events.h"
88 _XEBEC_PG
int _Xebec_action(a
,e
,p
)
94 case -1: return tp_protocol_error(e
,p
);
97 (void) tp_emit(DC_TPDU_type
, p
, 0, 0, MNULL
);
103 if( e
->ev_number
!= AK_TPDU
)
104 printf("TPDU 0x%x in REFWAIT!!!!\n", e
->ev_number
);
110 /* oh, man is this grotesque or what? */
111 (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
);
112 /* but it's necessary because this pseudo-ack may happen
113 * before the CC arrives, but we HAVE to adjust the
114 * snduna as a result of the ack, WHENEVER it arrives
125 p
->tp_refstate
= REF_OPEN
; /* has timers ??? */
131 tptrace(TPPTmisc
, "CR datalen data", e
->ev_union
.EV_CR_TPDU
.e_datalen
, e
->ev_union
.EV_CR_TPDU
.e_data
,0,0);
134 printf("CR datalen 0x%x data 0x%x", e
->ev_union
.EV_CR_TPDU
.e_datalen
, e
->ev_union
.EV_CR_TPDU
.e_data
);
136 p
->tp_refstate
= REF_OPEN
; /* has timers */
137 p
->tp_fcredit
= e
->ev_union
.EV_CR_TPDU
.e_cdt
;
139 if (e
->ev_union
.EV_CR_TPDU
.e_datalen
> 0) {
140 /* n/a for class 0 */
141 ASSERT(p
->tp_Xrcv
.sb_cc
== 0);
142 sbappendrecord(&p
->tp_Xrcv
, e
->ev_union
.EV_CR_TPDU
.e_data
);
143 e
->ev_union
.EV_CR_TPDU
.e_data
= MNULL
;
149 IncStat(ts_tp0_conn
);
151 tptrace(TPPTmisc
, "Confiming", p
, 0,0,0);
154 printf("Confirming connection: p" );
156 soisconnected(p
->tp_sock
);
157 (void) tp_emit(CC_TPDU_type
, p
, 0,0, MNULL
) ;
163 IncStat(ts_tp4_conn
); /* even though not quite open */
165 tptrace(TPPTmisc
, "Confiming", p
, 0,0,0);
168 printf("Confirming connection: p" );
171 soisconnecting(p
->tp_sock
);
172 if ((p
->tp_rx_strat
& TPRX_FASTSTART
) && (p
->tp_fcredit
> 0))
173 p
->tp_cong_win
= p
->tp_fcredit
* p
->tp_l_tpdusize
;
174 p
->tp_retrans
= p
->tp_Nretrans
;
175 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_cc_ticks
);
181 printf("event: CR_TPDU emit CC failed done " );
183 soisdisconnected(p
->tp_sock
);
184 tp_recycle_tsuffix(p
);
185 tp_freeref(p
->tp_lref
);
192 struct mbuf
*data
= MNULL
;
195 tptrace(TPPTmisc
, "T_CONN_req flags ucddata", (int)p
->tp_flags
,
196 p
->tp_ucddata
, 0, 0);
198 data
= MCPY(p
->tp_ucddata
, M_WAIT
);
201 printf("T_CONN_req.trans m_copy cc 0x%x\n",
203 dump_mbuf(data
, "sosnd @ T_CONN_req");
207 if (error
= tp_emit(CR_TPDU_type
, p
, 0, 0, data
) )
208 return error
; /* driver WON'T change state; will return error */
210 p
->tp_refstate
= REF_OPEN
; /* has timers */
211 if(p
->tp_class
!= TP_CLASS_0
) {
212 p
->tp_retrans
= p
->tp_Nretrans
;
213 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_cr_ticks
);
219 sbflush(&p
->tp_Xrcv
); /* purge non-delivered data data */
220 if (e
->ev_union
.EV_DR_TPDU
.e_datalen
> 0) {
221 sbappendrecord(&p
->tp_Xrcv
, e
->ev_union
.EV_DR_TPDU
.e_data
);
222 e
->ev_union
.EV_DR_TPDU
.e_data
= MNULL
;
224 if (p
->tp_state
== TP_OPEN
)
225 tp_indicate(T_DISCONNECT
, p
, 0);
227 int so_error
= ECONNREFUSED
;
228 if (e
->ev_union
.EV_DR_TPDU
.e_reason
!= (E_TP_NO_SESSION
^ TP_ERROR_MASK
) &&
229 e
->ev_union
.EV_DR_TPDU
.e_reason
!= (E_TP_NO_CR_ON_NC
^ TP_ERROR_MASK
) &&
230 e
->ev_union
.EV_DR_TPDU
.e_reason
!= (E_TP_REF_OVERFLOW
^ TP_ERROR_MASK
))
231 so_error
= ECONNABORTED
;
232 tp_indicate(T_DISCONNECT
, p
, so_error
);
234 tp_soisdisconnected(p
);
235 if (p
->tp_class
!= TP_CLASS_0
) {
236 if (p
->tp_state
== TP_OPEN
) {
237 tp_euntimeout(p
, TM_data_retrans
); /* all */
238 tp_cuntimeout(p
, TM_retrans
);
239 tp_cuntimeout(p
, TM_inact
);
240 tp_cuntimeout(p
, TM_sendack
);
241 p
->tp_flags
&= ~TPF_DELACK
;
243 tp_cuntimeout(p
, TM_retrans
);
244 if( e
->ev_union
.EV_DR_TPDU
.e_sref
!= 0 )
245 (void) tp_emit(DC_TPDU_type
, p
, 0, 0, MNULL
);
251 if( e
->ev_union
.EV_DR_TPDU
.e_sref
!= 0 )
252 (void) tp_emit(DC_TPDU_type
, p
, 0, 0, MNULL
);
253 /* reference timer already set - reset it to be safe (???) */
254 tp_euntimeout(p
, TM_reference
); /* all */
255 tp_etimeout(p
, TM_reference
, (int)p
->tp_refer_ticks
);
260 tp_cuntimeout(p
, TM_retrans
);
261 tp_indicate(ER_TPDU
, p
, e
->ev_union
.EV_ER_TPDU
.e_reason
);
262 tp_soisdisconnected(p
);
267 tp_cuntimeout(p
, TM_retrans
);
268 tp_soisdisconnected(p
);
273 tp_indicate(ER_TPDU
, p
, e
->ev_union
.EV_ER_TPDU
.e_reason
);
274 tp_cuntimeout(p
, TM_retrans
);
275 tp_soisdisconnected(p
);
280 tp_cuntimeout(p
, TM_retrans
);
281 tp_soisdisconnected(p
);
285 { /* don't ask me why we have to do this - spec says so */
286 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_NO_SESSION
, MNULL
);
287 /* don't bother with retransmissions of the DR */
292 tp_soisdisconnecting(p
->tp_sock
);
293 tp_indicate(ER_TPDU
, p
, e
->ev_union
.EV_ER_TPDU
.e_reason
);
294 tp_soisdisconnected(p
);
295 tp_netcmd( p
, CONN_CLOSE
);
300 if (p
->tp_state
== TP_OPEN
) {
301 tp_euntimeout(p
, TM_data_retrans
); /* all */
302 tp_cuntimeout(p
, TM_inact
);
303 tp_cuntimeout(p
, TM_sendack
);
305 tp_soisdisconnecting(p
->tp_sock
);
306 tp_indicate(ER_TPDU
, p
, e
->ev_union
.EV_ER_TPDU
.e_reason
);
307 p
->tp_retrans
= p
->tp_Nretrans
;
308 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_dr_ticks
);
309 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_PROTO_ERR
, MNULL
);
314 tp_cuntimeout(p
, TM_retrans
);
315 IncStat(ts_tp0_conn
);
317 soisconnected(p
->tp_sock
);
323 printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
326 IncStat(ts_tp4_conn
);
327 p
->tp_fref
= e
->ev_union
.EV_CC_TPDU
.e_sref
;
328 p
->tp_fcredit
= e
->ev_union
.EV_CC_TPDU
.e_cdt
;
329 if ((p
->tp_rx_strat
& TPRX_FASTSTART
) && (e
->ev_union
.EV_CC_TPDU
.e_cdt
> 0))
330 p
->tp_cong_win
= e
->ev_union
.EV_CC_TPDU
.e_cdt
* p
->tp_l_tpdusize
;
332 tp_cuntimeout(p
, TM_retrans
);
335 printf("dropping user connect data cc 0x%x\n",
336 p
->tp_ucddata
->m_len
);
338 m_freem(p
->tp_ucddata
);
341 soisconnected(p
->tp_sock
);
342 if (e
->ev_union
.EV_CC_TPDU
.e_datalen
> 0) {
343 ASSERT(p
->tp_Xrcv
.sb_cc
== 0); /* should be empty */
344 sbappendrecord(&p
->tp_Xrcv
, e
->ev_union
.EV_CC_TPDU
.e_data
);
345 e
->ev_union
.EV_CC_TPDU
.e_data
= MNULL
;
348 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, MNULL
);
349 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
354 struct mbuf
*data
= MNULL
;
357 IncStat(ts_retrans_cr
);
358 p
->tp_cong_win
= 1 * p
->tp_l_tpdusize
;
359 data
= MCPY(p
->tp_ucddata
, M_NOWAIT
);
362 printf("TM_retrans.trans m_copy cc 0x%x\n", data
);
363 dump_mbuf(p
->tp_ucddata
, "sosnd @ TM_retrans");
370 if( error
= tp_emit(CR_TPDU_type
, p
, 0, 0, data
) ) {
371 p
->tp_sock
->so_error
= error
;
373 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_cr_ticks
);
378 IncStat(ts_conn_gaveup
);
379 p
->tp_sock
->so_error
= ETIMEDOUT
;
380 tp_indicate(T_DISCONNECT
, p
, ETIMEDOUT
);
381 tp_soisdisconnected(p
);
387 struct mbuf
*data
= MCPY(p
->tp_ucddata
, M_WAIT
);
389 if( error
= tp_emit(CC_TPDU_type
, p
, 0, 0, data
) ) {
390 p
->tp_sock
->so_error
= error
;
392 p
->tp_retrans
= p
->tp_Nretrans
;
393 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_cc_ticks
);
401 * Get rid of any confirm or connect data, so that if we
402 * crash or close, it isn't thought of as disconnect data.
405 m_freem(p
->tp_ucddata
);
408 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
409 tp_cuntimeout(p
, TM_retrans
);
410 soisconnected(p
->tp_sock
);
411 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
413 /* see also next 2 transitions, if you make any changes */
415 doack
= tp_stash(p
, e
);
417 printf("tp_stash returns %d\n",doack
);
421 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, MNULL
);
422 tp_ctimeout(p
, TM_sendack
, (int)p
->tp_keepalive_ticks
);
424 tp_ctimeout( p
, TM_sendack
, (int)p
->tp_sendack_ticks
);
427 printf("after stash calling sbwakeup\n");
434 sbwakeup( &p
->tp_sock
->so_rcv
);
437 printf("after stash calling sbwakeup\n");
443 int doack
; /* tells if we must ack immediately */
445 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
446 sbwakeup( &p
->tp_sock
->so_rcv
);
448 doack
= tp_stash(p
, e
);
450 printf("tp_stash returns %d\n",doack
);
454 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, MNULL
);
456 tp_ctimeout_MIN( p
, TM_sendack
, (int)p
->tp_sendack_ticks
);
459 printf("after stash calling sbwakeup\n");
466 tptrace(TPPTmisc
, "NIW seq rcvnxt lcredit ",
467 e
->ev_union
.EV_DT_TPDU
.e_seq
, p
->tp_rcvnxt
, p
->tp_lcredit
, 0);
470 m_freem(e
->ev_union
.EV_DT_TPDU
.e_data
);
471 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
472 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, MNULL
);
478 m_freem(p
->tp_ucddata
);
481 (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
);
482 tp_cuntimeout(p
, TM_retrans
);
484 soisconnected(p
->tp_sock
);
486 struct socket
*so
= p
->tp_sock
;
488 "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
489 so
, so
->so_state
, so
->so_rcv
.sb_sel
, so
->so_rcv
.sb_flags
);
491 "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
492 so
->so_qlen
, so
->so_error
, so
->so_rcv
.sb_cc
, so
->so_head
);
495 tp_ctimeout(p
, TM_sendack
, (int)p
->tp_keepalive_ticks
);
496 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
501 if( p
->tp_state
== TP_AKWAIT
) {
503 m_freem(p
->tp_ucddata
);
506 tp_cuntimeout(p
, TM_retrans
);
507 soisconnected(p
->tp_sock
);
508 tp_ctimeout(p
, TM_sendack
, (int)p
->tp_keepalive_ticks
);
509 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
512 tptrace(TPPTmisc
, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
513 p
->tp_Xrcvnxt
,e
->ev_union
.EV_XPD_TPDU
.e_seq
, e
->ev_union
.EV_XPD_TPDU
.e_datalen
, e
->ev_union
.EV_XPD_TPDU
.e_data
->m_len
);
516 p
->tp_sock
->so_state
|= SS_RCVATMARK
;
517 postevent(p
->tp_sock
, 0, EV_OOB
);
518 e
->ev_union
.EV_XPD_TPDU
.e_data
->m_flags
|= M_EOR
;
519 sbinsertoob(&p
->tp_Xrcv
, e
->ev_union
.EV_XPD_TPDU
.e_data
);
521 dump_mbuf(e
->ev_union
.EV_XPD_TPDU
.e_data
, "XPD TPDU: tp_Xrcv");
523 tp_indicate(T_XDATA
, p
, 0);
524 sbwakeup( &p
->tp_Xrcv
);
526 (void) tp_emit(XAK_TPDU_type
, p
, p
->tp_Xrcvnxt
, 0, MNULL
);
527 SEQ_INC(p
, p
->tp_Xrcvnxt
);
532 if( p
->tp_Xrcv
.sb_cc
== 0 ) {
533 /* kludge for select(): */
534 /* p->tp_sock->so_state &= ~SS_OOBAVAIL; */
541 tptrace(TPPTmisc
, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
542 p
->tp_Xrcvnxt
, e
->ev_union
.EV_XPD_TPDU
.e_seq
, p
->tp_Xrcv
.sb_cc
, 0);
544 if( p
->tp_Xrcvnxt
!= e
->ev_union
.EV_XPD_TPDU
.e_seq
)
546 if( p
->tp_Xrcv
.sb_cc
) {
547 /* might as well kick 'em again */
548 tp_indicate(T_XDATA
, p
, 0);
551 m_freem(e
->ev_union
.EV_XPD_TPDU
.e_data
);
552 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
553 /* don't send an xack because the xak gives "last one received", not
554 * "next one i expect" (dumb)
560 struct socket
*so
= p
->tp_sock
;
562 /* detach from parent socket so it can finish closing */
564 if (!soqremque(so
, 0) && !soqremque(so
, 1))
565 panic("tp: T_DETACH");
568 tp_soisdisconnecting(p
->tp_sock
);
569 tp_netcmd( p
, CONN_CLOSE
);
570 tp_soisdisconnected(p
);
575 struct socket
*so
= p
->tp_sock
;
576 struct mbuf
*data
= MNULL
;
578 /* detach from parent socket so it can finish closing */
580 if (!soqremque(so
, 0) && !soqremque(so
, 1))
581 panic("tp: T_DETACH");
584 if (p
->tp_state
!= TP_CLOSING
) {
585 tp_soisdisconnecting(p
->tp_sock
);
586 data
= MCPY(p
->tp_ucddata
, M_NOWAIT
);
587 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_NORMAL_DISC
, data
);
588 p
->tp_retrans
= p
->tp_Nretrans
;
589 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_dr_ticks
);
595 tp_soisdisconnecting(p
->tp_sock
);
596 tp_netcmd( p
, CONN_CLOSE
);
597 tp_soisdisconnected(p
);
602 struct mbuf
*data
= MCPY(p
->tp_ucddata
, M_WAIT
);
604 if(p
->tp_state
== TP_OPEN
) {
605 tp_euntimeout(p
, TM_data_retrans
); /* all */
606 tp_cuntimeout(p
, TM_inact
);
607 tp_cuntimeout(p
, TM_sendack
);
608 p
->tp_flags
&= ~TPF_DELACK
;
612 printf("T_DISC_req.trans tp_ucddata 0x%x\n",
614 dump_mbuf(data
, "ucddata @ T_DISC_req");
617 tp_soisdisconnecting(p
->tp_sock
);
618 p
->tp_retrans
= p
->tp_Nretrans
;
619 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_dr_ticks
);
622 return tp_emit(DR_TPDU_type
, p
, 0, e
->ev_union
.EV_T_DISC_req
.e_reason
, data
);
628 struct mbuf
*data
= MCPY(p
->tp_ucddata
, M_WAIT
);
630 IncStat(ts_retrans_cc
);
632 p
->tp_cong_win
= 1 * p
->tp_l_tpdusize
;
634 if( error
= tp_emit(CC_TPDU_type
, p
, 0, 0, data
) )
635 p
->tp_sock
->so_error
= error
;
636 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_cc_ticks
);
641 IncStat(ts_conn_gaveup
);
642 tp_soisdisconnecting(p
->tp_sock
);
643 p
->tp_sock
->so_error
= ETIMEDOUT
;
644 tp_indicate(T_DISCONNECT
, p
, ETIMEDOUT
);
645 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_CONGEST
, MNULL
);
646 p
->tp_retrans
= p
->tp_Nretrans
;
647 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_dr_ticks
);
652 tp_euntimeout(p
, TM_data_retrans
); /* all */
653 tp_cuntimeout(p
, TM_inact
);
654 tp_cuntimeout(p
, TM_sendack
);
656 IncStat(ts_conn_gaveup
);
657 tp_soisdisconnecting(p
->tp_sock
);
658 p
->tp_sock
->so_error
= ETIMEDOUT
;
659 tp_indicate(T_DISCONNECT
, p
, ETIMEDOUT
);
660 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_CONGEST_2
, MNULL
);
661 p
->tp_retrans
= p
->tp_Nretrans
;
662 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_dr_ticks
);
667 p
->tp_cong_win
= 1 * p
->tp_l_tpdusize
;
669 if ( p
->tp_Xsnd
.sb_mb
) {
670 struct mbuf
*m
= m_copy(p
->tp_Xsnd
.sb_mb
, 0, (int)p
->tp_Xsnd
.sb_cc
);
674 tptrace(TPPTmisc
, "XPD retrans: Xuna Xsndnxt sndnxt snduna",
675 p
->tp_Xuna
, p
->tp_Xsndnxt
, p
->tp_sndnxt
,
679 dump_mbuf(m
, "XPD retrans emitting M");
681 IncStat(ts_retrans_xpd
);
683 shift
= max(p
->tp_Nretrans
- p
->tp_retrans
, 6);
684 (void) tp_emit(XPD_TPDU_type
, p
, p
->tp_Xuna
, 1, m
);
685 tp_ctimeout(p
, TM_retrans
, ((int)p
->tp_dt_ticks
) << shift
);
692 (void) tp_data_retrans(p
);
698 (void) tp_emit(DR_TPDU_type
, p
, 0, E_TP_DR_NO_REAS
, MNULL
);
699 IncStat(ts_retrans_dr
);
700 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_dr_ticks
);
705 p
->tp_sock
->so_error
= ETIMEDOUT
;
706 p
->tp_refstate
= REF_FROZEN
;
707 tp_recycle_tsuffix( p
);
708 tp_etimeout(p
, TM_reference
, (int)p
->tp_refer_ticks
);
713 tp_freeref(p
->tp_lref
);
719 if( p
->tp_class
!= TP_CLASS_0
) {
720 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
721 if ( e
->ev_number
== CC_TPDU
)
722 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, MNULL
);
724 /* ignore it if class 0 - state tables are blank for this */
730 tptrace(TPPTmisc
, "T_DATA_req sndnxt snduna fcredit, tpcb",
731 p
->tp_sndnxt
, p
->tp_snduna
, p
->tp_fcredit
, p
);
742 if ( p
->tp_Xsnd
.sb_mb
) {
743 struct mbuf
*m
= m_copy(p
->tp_Xsnd
.sb_mb
, 0, (int)p
->tp_Xsnd
.sb_cc
);
744 /* m_copy doesn't preserve the m_xlink field, but at this pt.
745 * that doesn't matter
749 tptrace(TPPTmisc
, "XPD req: Xuna Xsndnxt sndnxt snduna",
750 p
->tp_Xuna
, p
->tp_Xsndnxt
, p
->tp_sndnxt
,
754 printf("T_XPD_req: sb_cc 0x%x\n", p
->tp_Xsnd
.sb_cc
);
755 dump_mbuf(m
, "XPD req emitting M");
758 tp_emit(XPD_TPDU_type
, p
, p
->tp_Xuna
, 1, m
);
759 p
->tp_retrans
= p
->tp_Nretrans
;
761 tp_ctimeout(p
, TM_retrans
, (int)p
->tp_rxtcur
);
762 SEQ_INC(p
, p
->tp_Xsndnxt
);
770 struct sockbuf
*sb
= &p
->tp_sock
->so_snd
;
773 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
);
775 if( p
->tp_class
!= TP_CLASS_0
) {
776 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
780 printf("GOOD ACK new sndnxt 0x%x\n", p
->tp_sndnxt
);
787 tptrace(TPPTmisc
, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
788 e
->ev_union
.EV_AK_TPDU
.e_fcc_present
, p
->tp_r_subseq
, e
->ev_union
.EV_AK_TPDU
.e_subseq
, 0);
790 if( p
->tp_class
!= TP_CLASS_0
) {
792 if ( !e
->ev_union
.EV_AK_TPDU
.e_fcc_present
) {
793 /* send ACK with FCC */
794 IncStat( ts_ackreason
[_ACK_FCC_
] );
795 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 1, MNULL
);
797 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
803 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
804 tp_cuntimeout(p
, TM_retrans
);
806 sbwakeup( &p
->tp_sock
->so_snd
);
808 /* resume normal data */
815 tptrace(TPPTmisc
, "BOGUS XACK eventtype ", e
->ev_number
, 0, 0,0);
817 if( p
->tp_class
!= TP_CLASS_0
) {
818 tp_ctimeout(p
, TM_inact
, (int)p
->tp_inact_ticks
);
826 tptrace(TPPTsendack
, -1, p
->tp_lcredit
, p
->tp_sent_uwe
,
829 IncPStat(p
, tps_n_TMsendack
);
830 (void) tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, MNULL
);
831 if (p
->tp_fcredit
== 0) {
832 if (p
->tp_rxtshift
< TP_MAXRXTSHIFT
)
834 timo
= (p
->tp_dt_ticks
) << p
->tp_rxtshift
;
836 timo
= p
->tp_sendack_ticks
;
837 tp_ctimeout(p
, TM_sendack
, timo
);
842 if (sbspace(&p
->tp_sock
->so_rcv
) > 0)
851 * If the upper window edge has advanced a reasonable
852 * amount beyond what was known, send an ACK.
853 * A reasonable amount is 2 packets, unless the max window
854 * is only 1 or 2 packets, in which case we
855 * should send an ack for any advance in the upper window edge.
858 ack_thresh
= SEQ_SUB(p
, p
->tp_lcredit
+ p
->tp_rcvnxt
,
859 (p
->tp_maxlcredit
> 2 ? 2 : 1));
860 if (SEQ_GT(p
, ack_thresh
, p
->tp_sent_uwe
)) {
861 IncStat(ts_ackreason
[_ACK_USRRCV_
]);
862 p
->tp_flags
&= ~TPF_DELACK
;
863 return tp_emit(AK_TPDU_type
, p
, p
->tp_rcvnxt
, 0, MNULL
);
876 ASSERT( p
->tp_state
!= TP_LISTENING
);
877 tp_indicate(T_DISCONNECT
, p
, ECONNRESET
);
878 tp_soisdisconnected(p
);
890 switch( (e
->ev_number
<<4)+(p
->tp_state
) ) {
892 if ( p
->tp_retrans
> 0 ) return 0x1e;
895 if ( p
->tp_retrans
> 0 ) return 0x2f;
898 if ( p
->tp_retrans
> 0 ) return 0x32;
901 if ( p
->tp_retrans
> 0 ) return 0x34;
904 if (p
->tp_rxtshift
< TP_NRETRANS
) return 0x33;
907 if (p
->tp_class
== TP_CLASS_0
) return 0x1a;
910 if ( p
->tp_class
== TP_CLASS_0
) return 0xd;
913 if ( e
->ev_union
.EV_DR_TPDU
.e_sref
!= 0 ) return 0x2;
916 if (p
->tp_class
== TP_CLASS_0
) return 0x1c;
919 if (p
->tp_class
== TP_CLASS_0
) return 0x5;
922 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
) ) return 0x3a;
925 if ( IN_RWINDOW( p
, e
->ev_union
.EV_DT_TPDU
.e_seq
,
926 p
->tp_rcvnxt
, SEQ(p
, p
->tp_rcvnxt
+ p
->tp_lcredit
)) ) return 0x21;
929 if ( p
->tp_class
== TP_CLASS_0
) return 0x22;
930 else if ( IN_RWINDOW( p
, e
->ev_union
.EV_DT_TPDU
.e_seq
,
931 p
->tp_rcvnxt
, SEQ(p
, p
->tp_rcvnxt
+ p
->tp_lcredit
)) ) return 0x23;
934 if (p
->tp_Xrcvnxt
== e
->ev_union
.EV_XPD_TPDU
.e_seq
) return 0x27;
937 if (p
->tp_Xrcvnxt
== e
->ev_union
.EV_XPD_TPDU
.e_seq
) return 0x27;
940 if ( tp_goodXack(p
, e
->ev_union
.EV_XAK_TPDU
.e_seq
) ) return 0x3c;
943 if ( p
->tp_class
== TP_CLASS_0
) return 0x2d;
946 if ( p
->tp_class
== TP_CLASS_0
) return 0x2d;
949 if (p
->tp_class
== TP_CLASS_0
) return 0x3f;
952 if (p
->tp_class
== TP_CLASS_0
) return 0x2b;
955 if ( p
->tp_class
!= TP_CLASS_4
) return 0x42;
958 if ( p
->tp_class
!= TP_CLASS_4
) return 0x42;
961 if ( p
->tp_class
!= TP_CLASS_4
) return 0x42;
964 if ( p
->tp_class
== TP_CLASS_0
) return 0xf;
965 else if (tp_emit(CC_TPDU_type
, p
, 0,0, MCPY(p
->tp_ucddata
, M_NOWAIT
)) == 0) return 0x10;
969 } /* _Xebec_index() */
970 static int inx
[26][9] = { {0,0,0,0,0,0,0,0,0,},
971 {0x0,0x0,0x0,0x0,0x31,0x0,0x0,0x0,0x0, },
972 {0x0,0x0,-1,-1,-1,-1,0x0,0x0,0x0, },
973 {0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0x0, },
974 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, },
975 {0x0,0x0,0x0,0x0,0x0,0x0,0x36,0x0,0x0, },
976 {0x0,0x0,0x0,0x0,-1,0x0,0x0,0x0,0x0, },
977 {0x0,0x7,0x15,0x1b,-1,0x17,0x3,0xa,0x0, },
978 {0x0,0x19,0x6,0x20,0x37,0x8,0x3,-1,0x0, },
979 {0x0,0x14,0x13,0x13,0x13,0x16,-1,0xa,0x0, },
980 {0x0,0x7,0x6,0x1,0x9,0x18,0x3,0xa,0x0, },
981 {0x0,0x19,-1,0x1,0x37,0x8,0x3,0xa,0x0, },
982 {0x0,0x7,-1,0x26,-1,0x8,0x3,0xa,0x0, },
983 {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, },
984 {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, },
985 {0x0,0x7,0x6,0x1,-1,0x8,0x3,0xa,0x0, },
986 {0x0,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0x0, },
987 {0x0,0x0,-1,0x2e,-1,0x0,0x4,0x0,0x2e, },
988 {0x0,0xb,0x0,0x0,0x0,0x0,0x0,0x0,0x0, },
989 {0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x0, },
990 {0x0,0x0,0x0,0x0,0x39,0x0,0x0,0x0,0x0, },
991 {0x0,0x0,0x0,0x0,-1,0x0,0x41,0x0,0x0, },
992 {0x0,0x0,0x0,0x0,0x28,0x0,0x41,0x0,0x0, },
993 {0x0,0xc,-1,0x2c,0x0,0x2c,0x4,0xc,0x2c, },
994 {0x0,0x49,-1,0x45,-1,0x44,0x48,-1,0x0, },
995 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,-1, },
999 register struct tp_event
*e
;
1001 register int index
, error
=0;
1003 static struct act_ent erroraction
= {0,-1};
1005 index
= inx
[1 + e
->ev_number
][p
->tp_state
];
1006 if(index
<0) index
=_Xebec_index(e
, p
);
1010 a
= &statetable
[index
];
1013 error
= _Xebec_action( a
->a_action
, e
, p
);
1015 tptrace(DRIVERTRACE
, a
->a_newstate
, p
->tp_state
, e
->ev_number
, a
->a_action
, 0);
1018 p
->tp_state
= a
->a_newstate
;