|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 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. ! 11: * ! 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 ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: #ifndef lint ! 23: static char *rcsid = "$Header/**/$"; ! 24: #endif lint ! 25: #define _XEBEC_PG static ! 26: ! 27: #include "tp_states.h" ! 28: ! 29: static struct act_ent { ! 30: int a_newstate; ! 31: int a_action; ! 32: } statetable[] = { {0,0}, ! 33: #include "tp_states.init" ! 34: }; ! 35: ! 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> ! 42: #include <sys/mbuf.h> ! 43: #include <sys/time.h> ! 44: #include <sys/errno.h> ! 45: #include <sys/ev.h> ! 46: ! 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> ! 56: ! 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) ! 60: ! 61: static trick_hc = 1; ! 62: ! 63: int tp_emit(), ! 64: tp_goodack(), tp_goodXack(), ! 65: tp_stash() ! 66: ; ! 67: void tp_indicate(), tp_getoptions(), ! 68: tp_soisdisconnecting(), tp_soisdisconnected(), ! 69: tp_recycle_tsuffix(), ! 70: #ifdef TP_DEBUG_TIMERS ! 71: tp_etimeout(), tp_euntimeout(), ! 72: tp_ctimeout(), tp_cuntimeout(), ! 73: tp_ctimeout_MIN(), ! 74: #endif ! 75: tp_freeref(), tp_detach(), ! 76: tp0_stash(), tp0_send(), ! 77: tp_netcmd(), tp_send() ! 78: ; ! 79: ! 80: typedef struct tp_pcb tpcb_struct; ! 81: ! 82: ! 83: ! 84: typedef tpcb_struct tp_PCB_; ! 85: ! 86: #include "tp_events.h" ! 87: ! 88: _XEBEC_PG int _Xebec_action(a,e,p) ! 89: int a; ! 90: struct tp_event *e; ! 91: tp_PCB_ *p; ! 92: { ! 93: switch(a) { ! 94: case -1: return tp_protocol_error(e,p); ! 95: case 0x1: ! 96: { ! 97: (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); ! 98: } ! 99: break; ! 100: case 0x2: ! 101: { ! 102: # ifdef TP_DEBUG ! 103: if( e->ev_number != AK_TPDU ) ! 104: printf("TPDU 0x%x in REFWAIT!!!!\n", e->ev_number); ! 105: # endif TP_DEBUG ! 106: } ! 107: break; ! 108: case 0x3: ! 109: { ! 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 ! 115: */ ! 116: } ! 117: break; ! 118: case 0x4: ! 119: { ! 120: tp_detach(p); ! 121: } ! 122: break; ! 123: case 0x5: ! 124: { ! 125: p->tp_refstate = REF_OPEN; /* has timers ??? */ ! 126: } ! 127: break; ! 128: case 0x6: ! 129: { ! 130: IFTRACE(D_CONN) ! 131: tptrace(TPPTmisc, "CR datalen data", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data,0,0); ! 132: ENDTRACE ! 133: IFDEBUG(D_CONN) ! 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); ! 135: ENDDEBUG ! 136: p->tp_refstate = REF_OPEN; /* has timers */ ! 137: p->tp_fcredit = e->ev_union.EV_CR_TPDU.e_cdt; ! 138: ! 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; ! 144: } ! 145: } ! 146: break; ! 147: case 0x7: ! 148: { ! 149: IncStat(ts_tp0_conn); ! 150: IFTRACE(D_CONN) ! 151: tptrace(TPPTmisc, "Confiming", p, 0,0,0); ! 152: ENDTRACE ! 153: IFDEBUG(D_CONN) ! 154: printf("Confirming connection: p" ); ! 155: ENDDEBUG ! 156: soisconnected(p->tp_sock); ! 157: (void) tp_emit(CC_TPDU_type, p, 0,0, MNULL) ; ! 158: p->tp_fcredit = 1; ! 159: } ! 160: break; ! 161: case 0x8: ! 162: { ! 163: IncStat(ts_tp4_conn); /* even though not quite open */ ! 164: IFTRACE(D_CONN) ! 165: tptrace(TPPTmisc, "Confiming", p, 0,0,0); ! 166: ENDTRACE ! 167: IFDEBUG(D_CONN) ! 168: printf("Confirming connection: p" ); ! 169: ENDDEBUG ! 170: tp_getoptions(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); ! 176: } ! 177: break; ! 178: case 0x9: ! 179: { ! 180: IFDEBUG(D_CONN) ! 181: printf("event: CR_TPDU emit CC failed done " ); ! 182: ENDDEBUG ! 183: soisdisconnected(p->tp_sock); ! 184: tp_recycle_tsuffix(p); ! 185: tp_freeref(p->tp_lref); ! 186: tp_detach(p); ! 187: } ! 188: break; ! 189: case 0xa: ! 190: { ! 191: int error; ! 192: struct mbuf *data = MNULL; ! 193: ! 194: IFTRACE(D_CONN) ! 195: tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)p->tp_flags, ! 196: p->tp_ucddata, 0, 0); ! 197: ENDTRACE ! 198: data = MCPY(p->tp_ucddata, M_WAIT); ! 199: if (data) { ! 200: IFDEBUG(D_CONN) ! 201: printf("T_CONN_req.trans m_copy cc 0x%x\n", ! 202: p->tp_ucddata); ! 203: dump_mbuf(data, "sosnd @ T_CONN_req"); ! 204: ENDDEBUG ! 205: } ! 206: ! 207: if (error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) ! 208: return error; /* driver WON'T change state; will return error */ ! 209: ! 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); ! 214: } ! 215: } ! 216: break; ! 217: case 0xb: ! 218: { ! 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; ! 223: } ! 224: if (p->tp_state == TP_OPEN) ! 225: tp_indicate(T_DISCONNECT, p, 0); ! 226: else { ! 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); ! 233: } ! 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; ! 242: } ! 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); ! 246: } ! 247: } ! 248: break; ! 249: case 0xc: ! 250: { ! 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); ! 256: } ! 257: break; ! 258: case 0xd: ! 259: { ! 260: tp_cuntimeout(p, TM_retrans); ! 261: tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); ! 262: tp_soisdisconnected(p); ! 263: } ! 264: break; ! 265: case 0xe: ! 266: { ! 267: tp_cuntimeout(p, TM_retrans); ! 268: tp_soisdisconnected(p); ! 269: } ! 270: break; ! 271: case 0xf: ! 272: { ! 273: tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); ! 274: tp_cuntimeout(p, TM_retrans); ! 275: tp_soisdisconnected(p); ! 276: } ! 277: break; ! 278: case 0x10: ! 279: { ! 280: tp_cuntimeout(p, TM_retrans); ! 281: tp_soisdisconnected(p); ! 282: } ! 283: break; ! 284: case 0x11: ! 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 */ ! 288: } ! 289: break; ! 290: case 0x12: ! 291: { ! 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 ); ! 296: } ! 297: break; ! 298: case 0x13: ! 299: { ! 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); ! 304: } ! 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); ! 310: } ! 311: break; ! 312: case 0x14: ! 313: { ! 314: tp_cuntimeout(p, TM_retrans); ! 315: IncStat(ts_tp0_conn); ! 316: p->tp_fcredit = 1; ! 317: soisconnected(p->tp_sock); ! 318: } ! 319: break; ! 320: case 0x15: ! 321: { ! 322: IFDEBUG(D_CONN) ! 323: printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", ! 324: (int)p->tp_flags); ! 325: ENDDEBUG ! 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; ! 331: tp_getoptions(p); ! 332: tp_cuntimeout(p, TM_retrans); ! 333: if (p->tp_ucddata) { ! 334: IFDEBUG(D_CONN) ! 335: printf("dropping user connect data cc 0x%x\n", ! 336: p->tp_ucddata->m_len); ! 337: ENDDEBUG ! 338: m_freem(p->tp_ucddata); ! 339: p->tp_ucddata = 0; ! 340: } ! 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; ! 346: } ! 347: ! 348: (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); ! 349: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 350: } ! 351: break; ! 352: case 0x16: ! 353: { ! 354: struct mbuf *data = MNULL; ! 355: int error; ! 356: ! 357: IncStat(ts_retrans_cr); ! 358: p->tp_cong_win = 1 * p->tp_l_tpdusize; ! 359: data = MCPY(p->tp_ucddata, M_NOWAIT); ! 360: if(p->tp_ucddata) { ! 361: IFDEBUG(D_CONN) ! 362: printf("TM_retrans.trans m_copy cc 0x%x\n", data); ! 363: dump_mbuf(p->tp_ucddata, "sosnd @ TM_retrans"); ! 364: ENDDEBUG ! 365: if( data == MNULL ) ! 366: return ENOBUFS; ! 367: } ! 368: ! 369: p->tp_retrans --; ! 370: if( error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) { ! 371: p->tp_sock->so_error = error; ! 372: } ! 373: tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks); ! 374: } ! 375: break; ! 376: case 0x17: ! 377: { ! 378: IncStat(ts_conn_gaveup); ! 379: p->tp_sock->so_error = ETIMEDOUT; ! 380: tp_indicate(T_DISCONNECT, p, ETIMEDOUT); ! 381: tp_soisdisconnected(p); ! 382: } ! 383: break; ! 384: case 0x18: ! 385: { ! 386: int error; ! 387: struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); ! 388: ! 389: if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) { ! 390: p->tp_sock->so_error = error; ! 391: } ! 392: p->tp_retrans = p->tp_Nretrans; ! 393: tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); ! 394: } ! 395: break; ! 396: case 0x19: ! 397: { ! 398: int doack; ! 399: ! 400: /* ! 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. ! 403: */ ! 404: if (p->tp_ucddata) { ! 405: m_freem(p->tp_ucddata); ! 406: p->tp_ucddata = 0; ! 407: } ! 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); ! 412: ! 413: /* see also next 2 transitions, if you make any changes */ ! 414: ! 415: doack = tp_stash(p, e); ! 416: IFDEBUG(D_DATA) ! 417: printf("tp_stash returns %d\n",doack); ! 418: ENDDEBUG ! 419: ! 420: if (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); ! 423: } else ! 424: tp_ctimeout( p, TM_sendack, (int)p->tp_sendack_ticks); ! 425: ! 426: IFDEBUG(D_DATA) ! 427: printf("after stash calling sbwakeup\n"); ! 428: ENDDEBUG ! 429: } ! 430: break; ! 431: case 0x1a: ! 432: { ! 433: tp0_stash(p, e); ! 434: sbwakeup( &p->tp_sock->so_rcv ); ! 435: ! 436: IFDEBUG(D_DATA) ! 437: printf("after stash calling sbwakeup\n"); ! 438: ENDDEBUG ! 439: } ! 440: break; ! 441: case 0x1b: ! 442: { ! 443: int doack; /* tells if we must ack immediately */ ! 444: ! 445: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 446: sbwakeup( &p->tp_sock->so_rcv ); ! 447: ! 448: doack = tp_stash(p, e); ! 449: IFDEBUG(D_DATA) ! 450: printf("tp_stash returns %d\n",doack); ! 451: ENDDEBUG ! 452: ! 453: if(doack) ! 454: (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); ! 455: else ! 456: tp_ctimeout_MIN( p, TM_sendack, (int)p->tp_sendack_ticks); ! 457: ! 458: IFDEBUG(D_DATA) ! 459: printf("after stash calling sbwakeup\n"); ! 460: ENDDEBUG ! 461: } ! 462: break; ! 463: case 0x1c: ! 464: { ! 465: IFTRACE(D_DATA) ! 466: tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", ! 467: e->ev_union.EV_DT_TPDU.e_seq, p->tp_rcvnxt, p->tp_lcredit, 0); ! 468: ENDTRACE ! 469: IncStat(ts_dt_niw); ! 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 ); ! 473: } ! 474: break; ! 475: case 0x1d: ! 476: { ! 477: if (p->tp_ucddata) { ! 478: m_freem(p->tp_ucddata); ! 479: p->tp_ucddata = 0; ! 480: } ! 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); ! 483: ! 484: soisconnected(p->tp_sock); ! 485: IFTRACE(D_CONN) ! 486: struct socket *so = p->tp_sock; ! 487: tptrace(TPPTmisc, ! 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); ! 490: tptrace(TPPTmisc, ! 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); ! 493: ENDTRACE ! 494: ! 495: tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); ! 496: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 497: } ! 498: break; ! 499: case 0x1e: ! 500: { ! 501: if( p->tp_state == TP_AKWAIT ) { ! 502: if (p->tp_ucddata) { ! 503: m_freem(p->tp_ucddata); ! 504: p->tp_ucddata = 0; ! 505: } ! 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); ! 510: } ! 511: IFTRACE(D_XPD) ! 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); ! 514: ENDTRACE ! 515: ! 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); ! 520: IFDEBUG(D_XPD) ! 521: dump_mbuf(e->ev_union.EV_XPD_TPDU.e_data, "XPD TPDU: tp_Xrcv"); ! 522: ENDDEBUG ! 523: tp_indicate(T_XDATA, p, 0); ! 524: sbwakeup( &p->tp_Xrcv ); ! 525: ! 526: (void) tp_emit(XAK_TPDU_type, p, p->tp_Xrcvnxt, 0, MNULL); ! 527: SEQ_INC(p, p->tp_Xrcvnxt); ! 528: } ! 529: break; ! 530: case 0x1f: ! 531: { ! 532: if( p->tp_Xrcv.sb_cc == 0 ) { ! 533: /* kludge for select(): */ ! 534: /* p->tp_sock->so_state &= ~SS_OOBAVAIL; */ ! 535: } ! 536: } ! 537: break; ! 538: case 0x20: ! 539: { ! 540: IFTRACE(D_XPD) ! 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); ! 543: ENDTRACE ! 544: if( p->tp_Xrcvnxt != e->ev_union.EV_XPD_TPDU.e_seq ) ! 545: IncStat(ts_xpd_niw); ! 546: if( p->tp_Xrcv.sb_cc ) { ! 547: /* might as well kick 'em again */ ! 548: tp_indicate(T_XDATA, p, 0); ! 549: IncStat(ts_xpd_dup); ! 550: } ! 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) ! 555: */ ! 556: } ! 557: break; ! 558: case 0x21: ! 559: { ! 560: struct socket *so = p->tp_sock; ! 561: ! 562: /* detach from parent socket so it can finish closing */ ! 563: if (so->so_head) { ! 564: if (!soqremque(so, 0) && !soqremque(so, 1)) ! 565: panic("tp: T_DETACH"); ! 566: so->so_head = 0; ! 567: } ! 568: tp_soisdisconnecting(p->tp_sock); ! 569: tp_netcmd( p, CONN_CLOSE); ! 570: tp_soisdisconnected(p); ! 571: } ! 572: break; ! 573: case 0x22: ! 574: { ! 575: struct socket *so = p->tp_sock; ! 576: struct mbuf *data = MNULL; ! 577: ! 578: /* detach from parent socket so it can finish closing */ ! 579: if (so->so_head) { ! 580: if (!soqremque(so, 0) && !soqremque(so, 1)) ! 581: panic("tp: T_DETACH"); ! 582: so->so_head = 0; ! 583: } ! 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); ! 590: } ! 591: } ! 592: break; ! 593: case 0x23: ! 594: { ! 595: tp_soisdisconnecting(p->tp_sock); ! 596: tp_netcmd( p, CONN_CLOSE); ! 597: tp_soisdisconnected(p); ! 598: } ! 599: break; ! 600: case 0x24: ! 601: { ! 602: struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); ! 603: ! 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; ! 609: } ! 610: if (data) { ! 611: IFDEBUG(D_CONN) ! 612: printf("T_DISC_req.trans tp_ucddata 0x%x\n", ! 613: p->tp_ucddata); ! 614: dump_mbuf(data, "ucddata @ T_DISC_req"); ! 615: ENDDEBUG ! 616: } ! 617: tp_soisdisconnecting(p->tp_sock); ! 618: p->tp_retrans = p->tp_Nretrans; ! 619: tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); ! 620: ! 621: if( trick_hc ) ! 622: return tp_emit(DR_TPDU_type, p, 0, e->ev_union.EV_T_DISC_req.e_reason, data); ! 623: } ! 624: break; ! 625: case 0x25: ! 626: { ! 627: int error; ! 628: struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); ! 629: ! 630: IncStat(ts_retrans_cc); ! 631: p->tp_retrans --; ! 632: p->tp_cong_win = 1 * p->tp_l_tpdusize; ! 633: ! 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); ! 637: } ! 638: break; ! 639: case 0x26: ! 640: { ! 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); ! 648: } ! 649: break; ! 650: case 0x27: ! 651: { ! 652: tp_euntimeout(p, TM_data_retrans); /* all */ ! 653: tp_cuntimeout(p, TM_inact); ! 654: tp_cuntimeout(p, TM_sendack); ! 655: ! 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); ! 663: } ! 664: break; ! 665: case 0x28: ! 666: { ! 667: p->tp_cong_win = 1 * p->tp_l_tpdusize; ! 668: /* resume XPD */ ! 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); ! 671: int shift; ! 672: ! 673: IFTRACE(D_XPD) ! 674: tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna", ! 675: p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndnxt, ! 676: p->tp_snduna); ! 677: ENDTRACE ! 678: IFDEBUG(D_XPD) ! 679: dump_mbuf(m, "XPD retrans emitting M"); ! 680: ENDDEBUG ! 681: IncStat(ts_retrans_xpd); ! 682: p->tp_retrans --; ! 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); ! 686: } ! 687: } ! 688: break; ! 689: case 0x29: ! 690: { ! 691: p->tp_rxtshift++; ! 692: (void) tp_data_retrans(p); ! 693: } ! 694: break; ! 695: case 0x2a: ! 696: { ! 697: p->tp_retrans --; ! 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); ! 701: } ! 702: break; ! 703: case 0x2b: ! 704: { ! 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); ! 709: } ! 710: break; ! 711: case 0x2c: ! 712: { ! 713: tp_freeref(p->tp_lref); ! 714: tp_detach(p); ! 715: } ! 716: break; ! 717: case 0x2d: ! 718: { ! 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); ! 723: } ! 724: /* ignore it if class 0 - state tables are blank for this */ ! 725: } ! 726: break; ! 727: case 0x2e: ! 728: { ! 729: IFTRACE(D_DATA) ! 730: tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb", ! 731: p->tp_sndnxt, p->tp_snduna, p->tp_fcredit, p); ! 732: ENDTRACE ! 733: ! 734: tp_send(p); ! 735: } ! 736: break; ! 737: case 0x2f: ! 738: { ! 739: int error = 0; ! 740: ! 741: /* resume XPD */ ! 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 ! 746: */ ! 747: ! 748: IFTRACE(D_XPD) ! 749: tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna", ! 750: p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndnxt, ! 751: p->tp_snduna); ! 752: ENDTRACE ! 753: IFDEBUG(D_XPD) ! 754: printf("T_XPD_req: sb_cc 0x%x\n", p->tp_Xsnd.sb_cc); ! 755: dump_mbuf(m, "XPD req emitting M"); ! 756: ENDDEBUG ! 757: error = ! 758: tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m); ! 759: p->tp_retrans = p->tp_Nretrans; ! 760: ! 761: tp_ctimeout(p, TM_retrans, (int)p->tp_rxtcur); ! 762: SEQ_INC(p, p->tp_Xsndnxt); ! 763: } ! 764: if(trick_hc) ! 765: return error; ! 766: } ! 767: break; ! 768: case 0x30: ! 769: { ! 770: struct sockbuf *sb = &p->tp_sock->so_snd; ! 771: ! 772: IFDEBUG(D_ACKRECV) ! 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); ! 774: ENDDEBUG ! 775: if( p->tp_class != TP_CLASS_0) { ! 776: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 777: } ! 778: sbwakeup(sb); ! 779: IFDEBUG(D_ACKRECV) ! 780: printf("GOOD ACK new sndnxt 0x%x\n", p->tp_sndnxt); ! 781: ENDDEBUG ! 782: } ! 783: break; ! 784: case 0x31: ! 785: { ! 786: IFTRACE(D_ACKRECV) ! 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); ! 789: ENDTRACE ! 790: if( p->tp_class != TP_CLASS_0 ) { ! 791: ! 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); ! 796: } ! 797: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 798: } ! 799: } ! 800: break; ! 801: case 0x32: ! 802: { ! 803: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 804: tp_cuntimeout(p, TM_retrans); ! 805: ! 806: sbwakeup( &p->tp_sock->so_snd ); ! 807: ! 808: /* resume normal data */ ! 809: tp_send(p); ! 810: } ! 811: break; ! 812: case 0x33: ! 813: { ! 814: IFTRACE(D_ACKRECV) ! 815: tptrace(TPPTmisc, "BOGUS XACK eventtype ", e->ev_number, 0, 0,0); ! 816: ENDTRACE ! 817: if( p->tp_class != TP_CLASS_0 ) { ! 818: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 819: } ! 820: } ! 821: break; ! 822: case 0x34: ! 823: { ! 824: int timo; ! 825: IFTRACE(D_TIMER) ! 826: tptrace(TPPTsendack, -1, p->tp_lcredit, p->tp_sent_uwe, ! 827: p->tp_sent_lcdt, 0); ! 828: ENDTRACE ! 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) ! 833: p->tp_rxtshift++; ! 834: timo = (p->tp_dt_ticks) << p->tp_rxtshift; ! 835: } else ! 836: timo = p->tp_sendack_ticks; ! 837: tp_ctimeout(p, TM_sendack, timo); ! 838: } ! 839: break; ! 840: case 0x35: ! 841: { ! 842: if (sbspace(&p->tp_sock->so_rcv) > 0) ! 843: tp0_openflow(p); ! 844: } ! 845: break; ! 846: case 0x36: ! 847: { ! 848: if( trick_hc ) { ! 849: SeqNum ack_thresh; ! 850: /* ! 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. ! 856: */ ! 857: LOCAL_CREDIT(p); ! 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); ! 864: } ! 865: } ! 866: } ! 867: break; ! 868: case 0x37: ! 869: { ! 870: if(trick_hc) ! 871: return ECONNABORTED; ! 872: } ! 873: break; ! 874: case 0x38: ! 875: { ! 876: ASSERT( p->tp_state != TP_LISTENING ); ! 877: tp_indicate(T_DISCONNECT, p, ECONNRESET); ! 878: tp_soisdisconnected(p); ! 879: } ! 880: break; ! 881: } ! 882: return 0; ! 883: } ! 884: ! 885: _XEBEC_PG int ! 886: _Xebec_index( e,p ) ! 887: struct tp_event *e; ! 888: tp_PCB_ *p; ! 889: { ! 890: switch( (e->ev_number<<4)+(p->tp_state) ) { ! 891: case 0x12: ! 892: if ( p->tp_retrans > 0 ) return 0x1e; ! 893: else return 0x1f; ! 894: case 0x13: ! 895: if ( p->tp_retrans > 0 ) return 0x2f; ! 896: else return 0x30; ! 897: case 0x14: ! 898: if ( p->tp_retrans > 0 ) return 0x32; ! 899: else return 0x31; ! 900: case 0x15: ! 901: if ( p->tp_retrans > 0 ) return 0x34; ! 902: else return 0x35; ! 903: case 0x54: ! 904: if (p->tp_rxtshift < TP_NRETRANS) return 0x33; ! 905: else return 0x31; ! 906: case 0x64: ! 907: if (p->tp_class == TP_CLASS_0) return 0x1a; ! 908: else return 0x1b; ! 909: case 0x77: ! 910: if ( p->tp_class == TP_CLASS_0) return 0xd; ! 911: else return 0xe; ! 912: case 0x86: ! 913: if ( e->ev_union.EV_DR_TPDU.e_sref != 0 ) return 0x2; ! 914: else return 0x3; ! 915: case 0xa2: ! 916: if (p->tp_class == TP_CLASS_0) return 0x1c; ! 917: else return 0x1d; ! 918: case 0xb2: ! 919: if (p->tp_class == TP_CLASS_0) return 0x5; ! 920: else return 0x0; ! 921: case 0xb4: ! 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; ! 923: else return 0x3b; ! 924: case 0xc3: ! 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; ! 927: else return 0x24; ! 928: case 0xc4: ! 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; ! 932: else return 0x25; ! 933: case 0xd3: ! 934: if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27; ! 935: else return 0x2a; ! 936: case 0xd4: ! 937: if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27; ! 938: else return 0x29; ! 939: case 0xe4: ! 940: if ( tp_goodXack(p, e->ev_union.EV_XAK_TPDU.e_seq) ) return 0x3c; ! 941: else return 0x3d; ! 942: case 0x102: ! 943: if ( p->tp_class == TP_CLASS_0 ) return 0x2d; ! 944: else return 0x2e; ! 945: case 0x104: ! 946: if ( p->tp_class == TP_CLASS_0 ) return 0x2d; ! 947: else return 0x2e; ! 948: case 0x144: ! 949: if (p->tp_class == TP_CLASS_0) return 0x3f; ! 950: else return 0x40; ! 951: case 0x162: ! 952: if (p->tp_class == TP_CLASS_0) return 0x2b; ! 953: else return 0x2c; ! 954: case 0x172: ! 955: if ( p->tp_class != TP_CLASS_4 ) return 0x42; ! 956: else return 0x46; ! 957: case 0x174: ! 958: if ( p->tp_class != TP_CLASS_4 ) return 0x42; ! 959: else return 0x47; ! 960: case 0x177: ! 961: if ( p->tp_class != TP_CLASS_4 ) return 0x42; ! 962: else return 0x43; ! 963: case 0x188: ! 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; ! 966: else return 0x11; ! 967: default: return 0; ! 968: } /* end switch */ ! 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, }, ! 996: }; ! 997: tp_driver(p, e) ! 998: register tp_PCB_ *p; ! 999: register struct tp_event *e; ! 1000: { ! 1001: register int index, error=0; ! 1002: struct act_ent *a; ! 1003: static struct act_ent erroraction = {0,-1}; ! 1004: ! 1005: index = inx[1 + e->ev_number][p->tp_state]; ! 1006: if(index<0) index=_Xebec_index(e, p); ! 1007: if (index==0) { ! 1008: a = &erroraction; ! 1009: } else ! 1010: a = &statetable[index]; ! 1011: ! 1012: if(a->a_action) ! 1013: error = _Xebec_action( a->a_action, e, p ); ! 1014: IFTRACE(D_DRIVER) ! 1015: tptrace(DRIVERTRACE, a->a_newstate, p->tp_state, e->ev_number, a->a_action, 0); ! 1016: ENDTRACE ! 1017: if(error==0) ! 1018: p->tp_state = a->a_newstate; ! 1019: return error; ! 1020: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.