📄 tp_driver.c
字号:
/* $Header$ *//* $Source$ */#ifndef lintstatic char *rcsid = "$Header/**/$";#endif lint#define _XEBEC_PG static#include "tp_states.h"static struct act_ent { int a_newstate; int a_action;} statetable[] = { {0,0},#include "tp_states.init"};/* @(#)tp.trans 8.1 (Berkeley) 6/10/93 */#include <sys/param.h>#include <sys/systm.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/protosw.h>#include <sys/mbuf.h>#include <sys/time.h>#include <sys/errno.h>#include <netiso/tp_param.h>#include <netiso/tp_stat.h>#include <netiso/tp_pcb.h>#include <netiso/tp_tpdu.h>#include <netiso/argo_debug.h>#include <netiso/tp_trace.h>#include <netiso/iso_errno.h>#include <netiso/tp_seq.h>#include <netiso/cons.h>#define DRIVERTRACE TPPTdriver#define sbwakeup(sb) sowakeup(p->tp_sock, sb);#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)static trick_hc = 1;int tp_emit(), tp_goodack(), tp_goodXack(), tp_stash();void tp_indicate(), tp_getoptions(), tp_soisdisconnecting(), tp_soisdisconnected(), tp_recycle_tsuffix(), #ifdef TP_DEBUG_TIMERS tp_etimeout(), tp_euntimeout(), tp_ctimeout(), tp_cuntimeout(), tp_ctimeout_MIN(),#endif tp_freeref(), tp_detach(), tp0_stash(), tp0_send(), tp_netcmd(), tp_send();typedef struct tp_pcb tpcb_struct;typedef tpcb_struct tp_PCB_;#include "tp_events.h"_XEBEC_PG int _Xebec_action(a,e,p)int a;struct tp_event *e;tp_PCB_ *p;{switch(a) {case -1: return tp_protocol_error(e,p);case 0x1: { (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); } break;case 0x2: {# ifdef TP_DEBUG if( e->ev_number != AK_TPDU ) printf("TPDU 0x%x in REFWAIT!!!!\n", e->ev_number);# endif TP_DEBUG } break;case 0x3: { /* oh, man is this grotesque or what? */ (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); /* but it's necessary because this pseudo-ack may happen * before the CC arrives, but we HAVE to adjust the * snduna as a result of the ack, WHENEVER it arrives */ } break;case 0x4: { tp_detach(p); } break;case 0x5: { p->tp_refstate = REF_OPEN; /* has timers ??? */ } break;case 0x6: { IFTRACE(D_CONN) tptrace(TPPTmisc, "CR datalen data", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data,0,0); ENDTRACE IFDEBUG(D_CONN) printf("CR datalen 0x%x data 0x%x", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data); ENDDEBUG p->tp_refstate = REF_OPEN; /* has timers */ p->tp_fcredit = e->ev_union.EV_CR_TPDU.e_cdt; if (e->ev_union.EV_CR_TPDU.e_datalen > 0) { /* n/a for class 0 */ ASSERT(p->tp_Xrcv.sb_cc == 0); sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CR_TPDU.e_data); e->ev_union.EV_CR_TPDU.e_data = MNULL; } } break;case 0x7: { IncStat(ts_tp0_conn); IFTRACE(D_CONN) tptrace(TPPTmisc, "Confiming", p, 0,0,0); ENDTRACE IFDEBUG(D_CONN) printf("Confirming connection: p" ); ENDDEBUG soisconnected(p->tp_sock); (void) tp_emit(CC_TPDU_type, p, 0,0, MNULL) ; p->tp_fcredit = 1; } break;case 0x8: { IncStat(ts_tp4_conn); /* even though not quite open */ IFTRACE(D_CONN) tptrace(TPPTmisc, "Confiming", p, 0,0,0); ENDTRACE IFDEBUG(D_CONN) printf("Confirming connection: p" ); ENDDEBUG tp_getoptions(p); soisconnecting(p->tp_sock); if ((p->tp_rx_strat & TPRX_FASTSTART) && (p->tp_fcredit > 0)) p->tp_cong_win = p->tp_fcredit * p->tp_l_tpdusize; p->tp_retrans = p->tp_Nretrans; tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); } break;case 0x9: { IFDEBUG(D_CONN) printf("event: CR_TPDU emit CC failed done " ); ENDDEBUG soisdisconnected(p->tp_sock); tp_recycle_tsuffix(p); tp_freeref(p->tp_lref); tp_detach(p); } break;case 0xa: { int error; struct mbuf *data = MNULL; IFTRACE(D_CONN) tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)p->tp_flags, p->tp_ucddata, 0, 0); ENDTRACE data = MCPY(p->tp_ucddata, M_WAIT); if (data) { IFDEBUG(D_CONN) printf("T_CONN_req.trans m_copy cc 0x%x\n", p->tp_ucddata); dump_mbuf(data, "sosnd @ T_CONN_req"); ENDDEBUG } if (error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) return error; /* driver WON'T change state; will return error */ p->tp_refstate = REF_OPEN; /* has timers */ if(p->tp_class != TP_CLASS_0) { p->tp_retrans = p->tp_Nretrans; tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks); } } break;case 0xb: { sbflush(&p->tp_Xrcv); /* purge non-delivered data data */ if (e->ev_union.EV_DR_TPDU.e_datalen > 0) { sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_DR_TPDU.e_data); e->ev_union.EV_DR_TPDU.e_data = MNULL; } if (p->tp_state == TP_OPEN) tp_indicate(T_DISCONNECT, p, 0); else { int so_error = ECONNREFUSED; if (e->ev_union.EV_DR_TPDU.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) && e->ev_union.EV_DR_TPDU.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) && e->ev_union.EV_DR_TPDU.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK)) so_error = ECONNABORTED; tp_indicate(T_DISCONNECT, p, so_error); } tp_soisdisconnected(p); if (p->tp_class != TP_CLASS_0) { if (p->tp_state == TP_OPEN ) { tp_euntimeout(p, TM_data_retrans); /* all */ tp_cuntimeout(p, TM_retrans); tp_cuntimeout(p, TM_inact); tp_cuntimeout(p, TM_sendack); p->tp_flags &= ~TPF_DELACK; } tp_cuntimeout(p, TM_retrans); if( e->ev_union.EV_DR_TPDU.e_sref != 0 ) (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); } } break;case 0xc: { if( e->ev_union.EV_DR_TPDU.e_sref != 0 ) (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); /* reference timer already set - reset it to be safe (???) */ tp_euntimeout(p, TM_reference); /* all */ tp_etimeout(p, TM_reference, (int)p->tp_refer_ticks); } break;case 0xd: { tp_cuntimeout(p, TM_retrans); tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); tp_soisdisconnected(p); } break;case 0xe: { tp_cuntimeout(p, TM_retrans); tp_soisdisconnected(p); } break;case 0xf: { tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); tp_cuntimeout(p, TM_retrans); tp_soisdisconnected(p); } break;case 0x10: { tp_cuntimeout(p, TM_retrans); tp_soisdisconnected(p); } break;case 0x11: { /* don't ask me why we have to do this - spec says so */ (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NO_SESSION, MNULL); /* don't bother with retransmissions of the DR */ } break;case 0x12: { tp_soisdisconnecting(p->tp_sock); tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); tp_soisdisconnected(p); tp_netcmd( p, CONN_CLOSE ); } break;case 0x13: { if (p->tp_state == TP_OPEN) { tp_euntimeout(p, TM_data_retrans); /* all */ tp_cuntimeout(p, TM_inact); tp_cuntimeout(p, TM_sendack); } tp_soisdisconnecting(p->tp_sock); tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); p->tp_retrans = p->tp_Nretrans; tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); (void) tp_emit(DR_TPDU_type, p, 0, E_TP_PROTO_ERR, MNULL); } break;case 0x14: { tp_cuntimeout(p, TM_retrans); IncStat(ts_tp0_conn); p->tp_fcredit = 1; soisconnected(p->tp_sock); } break;case 0x15: { IFDEBUG(D_CONN) printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", (int)p->tp_flags); ENDDEBUG IncStat(ts_tp4_conn); p->tp_fref = e->ev_union.EV_CC_TPDU.e_sref; p->tp_fcredit = e->ev_union.EV_CC_TPDU.e_cdt; if ((p->tp_rx_strat & TPRX_FASTSTART) && (e->ev_union.EV_CC_TPDU.e_cdt > 0)) p->tp_cong_win = e->ev_union.EV_CC_TPDU.e_cdt * p->tp_l_tpdusize; tp_getoptions(p); tp_cuntimeout(p, TM_retrans); if (p->tp_ucddata) { IFDEBUG(D_CONN) printf("dropping user connect data cc 0x%x\n", p->tp_ucddata->m_len); ENDDEBUG m_freem(p->tp_ucddata); p->tp_ucddata = 0; } soisconnected(p->tp_sock); if (e->ev_union.EV_CC_TPDU.e_datalen > 0) { ASSERT(p->tp_Xrcv.sb_cc == 0); /* should be empty */ sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CC_TPDU.e_data); e->ev_union.EV_CC_TPDU.e_data = MNULL; } (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); } break;case 0x16: { struct mbuf *data = MNULL; int error; IncStat(ts_retrans_cr); p->tp_cong_win = 1 * p->tp_l_tpdusize; data = MCPY(p->tp_ucddata, M_NOWAIT); if(p->tp_ucddata) { IFDEBUG(D_CONN) printf("TM_retrans.trans m_copy cc 0x%x\n", data); dump_mbuf(p->tp_ucddata, "sosnd @ TM_retrans"); ENDDEBUG if( data == MNULL ) return ENOBUFS; } p->tp_retrans --; if( error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) { p->tp_sock->so_error = error; } tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks); } break;case 0x17: { IncStat(ts_conn_gaveup); p->tp_sock->so_error = ETIMEDOUT; tp_indicate(T_DISCONNECT, p, ETIMEDOUT); tp_soisdisconnected(p); } break;case 0x18: { int error; struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) { p->tp_sock->so_error = error; } p->tp_retrans = p->tp_Nretrans; tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); } break;case 0x19: { int doack; /* * Get rid of any confirm or connect data, so that if we * crash or close, it isn't thought of as disconnect data. */ if (p->tp_ucddata) { m_freem(p->tp_ucddata); p->tp_ucddata = 0; } tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); tp_cuntimeout(p, TM_retrans); soisconnected(p->tp_sock); tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); /* see also next 2 transitions, if you make any changes */ doack = tp_stash(p, e); IFDEBUG(D_DATA) printf("tp_stash returns %d\n",doack); ENDDEBUG if (doack) { (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); } else tp_ctimeout( p, TM_sendack, (int)p->tp_sendack_ticks); IFDEBUG(D_DATA) printf("after stash calling sbwakeup\n"); ENDDEBUG } break;case 0x1a: { tp0_stash(p, e); sbwakeup( &p->tp_sock->so_rcv ); IFDEBUG(D_DATA) printf("after stash calling sbwakeup\n"); ENDDEBUG } break;case 0x1b: { int doack; /* tells if we must ack immediately */ tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); sbwakeup( &p->tp_sock->so_rcv ); doack = tp_stash(p, e); IFDEBUG(D_DATA) printf("tp_stash returns %d\n",doack); ENDDEBUG if(doack) (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); else tp_ctimeout_MIN( p, TM_sendack, (int)p->tp_sendack_ticks); IFDEBUG(D_DATA) printf("after stash calling sbwakeup\n"); ENDDEBUG } break;case 0x1c: { IFTRACE(D_DATA) tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", e->ev_union.EV_DT_TPDU.e_seq, p->tp_rcvnxt, p->tp_lcredit, 0); ENDTRACE IncStat(ts_dt_niw); m_freem(e->ev_union.EV_DT_TPDU.e_data); tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); } break;case 0x1d: { if (p->tp_ucddata) { m_freem(p->tp_ucddata); p->tp_ucddata = 0; } (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); tp_cuntimeout(p, TM_retrans); soisconnected(p->tp_sock); IFTRACE(D_CONN) struct socket *so = p->tp_sock; tptrace(TPPTmisc, "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); tptrace(TPPTmisc, "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); ENDTRACE tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); } break;case 0x1e: { if( p->tp_state == TP_AKWAIT ) { if (p->tp_ucddata) { m_freem(p->tp_ucddata); p->tp_ucddata = 0; } tp_cuntimeout(p, TM_retrans); soisconnected(p->tp_sock); tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); } IFTRACE(D_XPD) tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", 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); ENDTRACE p->tp_sock->so_state |= SS_RCVATMARK; e->ev_union.EV_XPD_TPDU.e_data->m_flags |= M_EOR; sbinsertoob(&p->tp_Xrcv, e->ev_union.EV_XPD_TPDU.e_data); IFDEBUG(D_XPD) dump_mbuf(e->ev_union.EV_XPD_TPDU.e_data, "XPD TPDU: tp_Xrcv");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -