|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: #ifndef lint ! 26: static char *rcsid = "$Header/**/$"; ! 27: #endif lint ! 28: #define _XEBEC_PG static ! 29: ! 30: #include "tp_states.h" ! 31: ! 32: static struct act_ent { ! 33: int a_newstate; ! 34: int a_action; ! 35: } statetable[] = { {0,0}, ! 36: #include "tp_states.init" ! 37: }; ! 38: ! 39: /* @(#)tp.trans 8.1 (Berkeley) 6/10/93 */ ! 40: #include <sys/param.h> ! 41: #include <sys/systm.h> ! 42: #include <sys/socket.h> ! 43: #include <sys/socketvar.h> ! 44: #include <sys/protosw.h> ! 45: #include <sys/mbuf.h> ! 46: #include <sys/time.h> ! 47: #include <sys/errno.h> ! 48: #include <sys/ev.h> ! 49: ! 50: #include <netiso/tp_param.h> ! 51: #include <netiso/tp_stat.h> ! 52: #include <netiso/tp_pcb.h> ! 53: #include <netiso/tp_tpdu.h> ! 54: #include <netiso/argo_debug.h> ! 55: #include <netiso/tp_trace.h> ! 56: #include <netiso/iso_errno.h> ! 57: #include <netiso/tp_seq.h> ! 58: #include <netiso/cons.h> ! 59: ! 60: #define DRIVERTRACE TPPTdriver ! 61: #define sbwakeup(sb) sowakeup(p->tp_sock, sb); ! 62: #define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0) ! 63: ! 64: static trick_hc = 1; ! 65: ! 66: int tp_emit(), ! 67: tp_goodack(), tp_goodXack(), ! 68: tp_stash() ! 69: ; ! 70: void tp_indicate(), tp_getoptions(), ! 71: tp_soisdisconnecting(), tp_soisdisconnected(), ! 72: tp_recycle_tsuffix(), ! 73: #ifdef TP_DEBUG_TIMERS ! 74: tp_etimeout(), tp_euntimeout(), ! 75: tp_ctimeout(), tp_cuntimeout(), ! 76: tp_ctimeout_MIN(), ! 77: #endif ! 78: tp_freeref(), tp_detach(), ! 79: tp0_stash(), tp0_send(), ! 80: tp_netcmd(), tp_send() ! 81: ; ! 82: ! 83: typedef struct tp_pcb tpcb_struct; ! 84: ! 85: ! 86: ! 87: typedef tpcb_struct tp_PCB_; ! 88: ! 89: #include "tp_events.h" ! 90: ! 91: _XEBEC_PG int _Xebec_action(a,e,p) ! 92: int a; ! 93: struct tp_event *e; ! 94: tp_PCB_ *p; ! 95: { ! 96: switch(a) { ! 97: case -1: return tp_protocol_error(e,p); ! 98: case 0x1: ! 99: { ! 100: (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); ! 101: } ! 102: break; ! 103: case 0x2: ! 104: { ! 105: # ifdef TP_DEBUG ! 106: if( e->ev_number != AK_TPDU ) ! 107: printf("TPDU 0x%x in REFWAIT!!!!\n", e->ev_number); ! 108: # endif TP_DEBUG ! 109: } ! 110: break; ! 111: case 0x3: ! 112: { ! 113: /* oh, man is this grotesque or what? */ ! 114: (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); ! 115: /* but it's necessary because this pseudo-ack may happen ! 116: * before the CC arrives, but we HAVE to adjust the ! 117: * snduna as a result of the ack, WHENEVER it arrives ! 118: */ ! 119: } ! 120: break; ! 121: case 0x4: ! 122: { ! 123: tp_detach(p); ! 124: } ! 125: break; ! 126: case 0x5: ! 127: { ! 128: p->tp_refstate = REF_OPEN; /* has timers ??? */ ! 129: } ! 130: break; ! 131: case 0x6: ! 132: { ! 133: IFTRACE(D_CONN) ! 134: tptrace(TPPTmisc, "CR datalen data", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data,0,0); ! 135: ENDTRACE ! 136: IFDEBUG(D_CONN) ! 137: printf("CR datalen 0x%x data 0x%x", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data); ! 138: ENDDEBUG ! 139: p->tp_refstate = REF_OPEN; /* has timers */ ! 140: p->tp_fcredit = e->ev_union.EV_CR_TPDU.e_cdt; ! 141: ! 142: if (e->ev_union.EV_CR_TPDU.e_datalen > 0) { ! 143: /* n/a for class 0 */ ! 144: ASSERT(p->tp_Xrcv.sb_cc == 0); ! 145: sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CR_TPDU.e_data); ! 146: e->ev_union.EV_CR_TPDU.e_data = MNULL; ! 147: } ! 148: } ! 149: break; ! 150: case 0x7: ! 151: { ! 152: IncStat(ts_tp0_conn); ! 153: IFTRACE(D_CONN) ! 154: tptrace(TPPTmisc, "Confiming", p, 0,0,0); ! 155: ENDTRACE ! 156: IFDEBUG(D_CONN) ! 157: printf("Confirming connection: p" ); ! 158: ENDDEBUG ! 159: soisconnected(p->tp_sock); ! 160: (void) tp_emit(CC_TPDU_type, p, 0,0, MNULL) ; ! 161: p->tp_fcredit = 1; ! 162: } ! 163: break; ! 164: case 0x8: ! 165: { ! 166: IncStat(ts_tp4_conn); /* even though not quite open */ ! 167: IFTRACE(D_CONN) ! 168: tptrace(TPPTmisc, "Confiming", p, 0,0,0); ! 169: ENDTRACE ! 170: IFDEBUG(D_CONN) ! 171: printf("Confirming connection: p" ); ! 172: ENDDEBUG ! 173: tp_getoptions(p); ! 174: soisconnecting(p->tp_sock); ! 175: if ((p->tp_rx_strat & TPRX_FASTSTART) && (p->tp_fcredit > 0)) ! 176: p->tp_cong_win = p->tp_fcredit * p->tp_l_tpdusize; ! 177: p->tp_retrans = p->tp_Nretrans; ! 178: tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); ! 179: } ! 180: break; ! 181: case 0x9: ! 182: { ! 183: IFDEBUG(D_CONN) ! 184: printf("event: CR_TPDU emit CC failed done " ); ! 185: ENDDEBUG ! 186: soisdisconnected(p->tp_sock); ! 187: tp_recycle_tsuffix(p); ! 188: tp_freeref(p->tp_lref); ! 189: tp_detach(p); ! 190: } ! 191: break; ! 192: case 0xa: ! 193: { ! 194: int error; ! 195: struct mbuf *data = MNULL; ! 196: ! 197: IFTRACE(D_CONN) ! 198: tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)p->tp_flags, ! 199: p->tp_ucddata, 0, 0); ! 200: ENDTRACE ! 201: data = MCPY(p->tp_ucddata, M_WAIT); ! 202: if (data) { ! 203: IFDEBUG(D_CONN) ! 204: printf("T_CONN_req.trans m_copy cc 0x%x\n", ! 205: p->tp_ucddata); ! 206: dump_mbuf(data, "sosnd @ T_CONN_req"); ! 207: ENDDEBUG ! 208: } ! 209: ! 210: if (error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) ! 211: return error; /* driver WON'T change state; will return error */ ! 212: ! 213: p->tp_refstate = REF_OPEN; /* has timers */ ! 214: if(p->tp_class != TP_CLASS_0) { ! 215: p->tp_retrans = p->tp_Nretrans; ! 216: tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks); ! 217: } ! 218: } ! 219: break; ! 220: case 0xb: ! 221: { ! 222: sbflush(&p->tp_Xrcv); /* purge non-delivered data data */ ! 223: if (e->ev_union.EV_DR_TPDU.e_datalen > 0) { ! 224: sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_DR_TPDU.e_data); ! 225: e->ev_union.EV_DR_TPDU.e_data = MNULL; ! 226: } ! 227: if (p->tp_state == TP_OPEN) ! 228: tp_indicate(T_DISCONNECT, p, 0); ! 229: else { ! 230: int so_error = ECONNREFUSED; ! 231: if (e->ev_union.EV_DR_TPDU.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) && ! 232: e->ev_union.EV_DR_TPDU.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) && ! 233: e->ev_union.EV_DR_TPDU.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK)) ! 234: so_error = ECONNABORTED; ! 235: tp_indicate(T_DISCONNECT, p, so_error); ! 236: } ! 237: tp_soisdisconnected(p); ! 238: if (p->tp_class != TP_CLASS_0) { ! 239: if (p->tp_state == TP_OPEN ) { ! 240: tp_euntimeout(p, TM_data_retrans); /* all */ ! 241: tp_cuntimeout(p, TM_retrans); ! 242: tp_cuntimeout(p, TM_inact); ! 243: tp_cuntimeout(p, TM_sendack); ! 244: p->tp_flags &= ~TPF_DELACK; ! 245: } ! 246: tp_cuntimeout(p, TM_retrans); ! 247: if( e->ev_union.EV_DR_TPDU.e_sref != 0 ) ! 248: (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); ! 249: } ! 250: } ! 251: break; ! 252: case 0xc: ! 253: { ! 254: if( e->ev_union.EV_DR_TPDU.e_sref != 0 ) ! 255: (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); ! 256: /* reference timer already set - reset it to be safe (???) */ ! 257: tp_euntimeout(p, TM_reference); /* all */ ! 258: tp_etimeout(p, TM_reference, (int)p->tp_refer_ticks); ! 259: } ! 260: break; ! 261: case 0xd: ! 262: { ! 263: tp_cuntimeout(p, TM_retrans); ! 264: tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); ! 265: tp_soisdisconnected(p); ! 266: } ! 267: break; ! 268: case 0xe: ! 269: { ! 270: tp_cuntimeout(p, TM_retrans); ! 271: tp_soisdisconnected(p); ! 272: } ! 273: break; ! 274: case 0xf: ! 275: { ! 276: tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); ! 277: tp_cuntimeout(p, TM_retrans); ! 278: tp_soisdisconnected(p); ! 279: } ! 280: break; ! 281: case 0x10: ! 282: { ! 283: tp_cuntimeout(p, TM_retrans); ! 284: tp_soisdisconnected(p); ! 285: } ! 286: break; ! 287: case 0x11: ! 288: { /* don't ask me why we have to do this - spec says so */ ! 289: (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NO_SESSION, MNULL); ! 290: /* don't bother with retransmissions of the DR */ ! 291: } ! 292: break; ! 293: case 0x12: ! 294: { ! 295: tp_soisdisconnecting(p->tp_sock); ! 296: tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); ! 297: tp_soisdisconnected(p); ! 298: tp_netcmd( p, CONN_CLOSE ); ! 299: } ! 300: break; ! 301: case 0x13: ! 302: { ! 303: if (p->tp_state == TP_OPEN) { ! 304: tp_euntimeout(p, TM_data_retrans); /* all */ ! 305: tp_cuntimeout(p, TM_inact); ! 306: tp_cuntimeout(p, TM_sendack); ! 307: } ! 308: tp_soisdisconnecting(p->tp_sock); ! 309: tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); ! 310: p->tp_retrans = p->tp_Nretrans; ! 311: tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); ! 312: (void) tp_emit(DR_TPDU_type, p, 0, E_TP_PROTO_ERR, MNULL); ! 313: } ! 314: break; ! 315: case 0x14: ! 316: { ! 317: tp_cuntimeout(p, TM_retrans); ! 318: IncStat(ts_tp0_conn); ! 319: p->tp_fcredit = 1; ! 320: soisconnected(p->tp_sock); ! 321: } ! 322: break; ! 323: case 0x15: ! 324: { ! 325: IFDEBUG(D_CONN) ! 326: printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", ! 327: (int)p->tp_flags); ! 328: ENDDEBUG ! 329: IncStat(ts_tp4_conn); ! 330: p->tp_fref = e->ev_union.EV_CC_TPDU.e_sref; ! 331: p->tp_fcredit = e->ev_union.EV_CC_TPDU.e_cdt; ! 332: if ((p->tp_rx_strat & TPRX_FASTSTART) && (e->ev_union.EV_CC_TPDU.e_cdt > 0)) ! 333: p->tp_cong_win = e->ev_union.EV_CC_TPDU.e_cdt * p->tp_l_tpdusize; ! 334: tp_getoptions(p); ! 335: tp_cuntimeout(p, TM_retrans); ! 336: if (p->tp_ucddata) { ! 337: IFDEBUG(D_CONN) ! 338: printf("dropping user connect data cc 0x%x\n", ! 339: p->tp_ucddata->m_len); ! 340: ENDDEBUG ! 341: m_freem(p->tp_ucddata); ! 342: p->tp_ucddata = 0; ! 343: } ! 344: soisconnected(p->tp_sock); ! 345: if (e->ev_union.EV_CC_TPDU.e_datalen > 0) { ! 346: ASSERT(p->tp_Xrcv.sb_cc == 0); /* should be empty */ ! 347: sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CC_TPDU.e_data); ! 348: e->ev_union.EV_CC_TPDU.e_data = MNULL; ! 349: } ! 350: ! 351: (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); ! 352: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 353: } ! 354: break; ! 355: case 0x16: ! 356: { ! 357: struct mbuf *data = MNULL; ! 358: int error; ! 359: ! 360: IncStat(ts_retrans_cr); ! 361: p->tp_cong_win = 1 * p->tp_l_tpdusize; ! 362: data = MCPY(p->tp_ucddata, M_NOWAIT); ! 363: if(p->tp_ucddata) { ! 364: IFDEBUG(D_CONN) ! 365: printf("TM_retrans.trans m_copy cc 0x%x\n", data); ! 366: dump_mbuf(p->tp_ucddata, "sosnd @ TM_retrans"); ! 367: ENDDEBUG ! 368: if( data == MNULL ) ! 369: return ENOBUFS; ! 370: } ! 371: ! 372: p->tp_retrans --; ! 373: if( error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) { ! 374: p->tp_sock->so_error = error; ! 375: } ! 376: tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks); ! 377: } ! 378: break; ! 379: case 0x17: ! 380: { ! 381: IncStat(ts_conn_gaveup); ! 382: p->tp_sock->so_error = ETIMEDOUT; ! 383: tp_indicate(T_DISCONNECT, p, ETIMEDOUT); ! 384: tp_soisdisconnected(p); ! 385: } ! 386: break; ! 387: case 0x18: ! 388: { ! 389: int error; ! 390: struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); ! 391: ! 392: if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) { ! 393: p->tp_sock->so_error = error; ! 394: } ! 395: p->tp_retrans = p->tp_Nretrans; ! 396: tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); ! 397: } ! 398: break; ! 399: case 0x19: ! 400: { ! 401: int doack; ! 402: ! 403: /* ! 404: * Get rid of any confirm or connect data, so that if we ! 405: * crash or close, it isn't thought of as disconnect data. ! 406: */ ! 407: if (p->tp_ucddata) { ! 408: m_freem(p->tp_ucddata); ! 409: p->tp_ucddata = 0; ! 410: } ! 411: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 412: tp_cuntimeout(p, TM_retrans); ! 413: soisconnected(p->tp_sock); ! 414: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 415: ! 416: /* see also next 2 transitions, if you make any changes */ ! 417: ! 418: doack = tp_stash(p, e); ! 419: IFDEBUG(D_DATA) ! 420: printf("tp_stash returns %d\n",doack); ! 421: ENDDEBUG ! 422: ! 423: if (doack) { ! 424: (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); ! 425: tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); ! 426: } else ! 427: tp_ctimeout( p, TM_sendack, (int)p->tp_sendack_ticks); ! 428: ! 429: IFDEBUG(D_DATA) ! 430: printf("after stash calling sbwakeup\n"); ! 431: ENDDEBUG ! 432: } ! 433: break; ! 434: case 0x1a: ! 435: { ! 436: tp0_stash(p, e); ! 437: sbwakeup( &p->tp_sock->so_rcv ); ! 438: ! 439: IFDEBUG(D_DATA) ! 440: printf("after stash calling sbwakeup\n"); ! 441: ENDDEBUG ! 442: } ! 443: break; ! 444: case 0x1b: ! 445: { ! 446: int doack; /* tells if we must ack immediately */ ! 447: ! 448: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 449: sbwakeup( &p->tp_sock->so_rcv ); ! 450: ! 451: doack = tp_stash(p, e); ! 452: IFDEBUG(D_DATA) ! 453: printf("tp_stash returns %d\n",doack); ! 454: ENDDEBUG ! 455: ! 456: if(doack) ! 457: (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); ! 458: else ! 459: tp_ctimeout_MIN( p, TM_sendack, (int)p->tp_sendack_ticks); ! 460: ! 461: IFDEBUG(D_DATA) ! 462: printf("after stash calling sbwakeup\n"); ! 463: ENDDEBUG ! 464: } ! 465: break; ! 466: case 0x1c: ! 467: { ! 468: IFTRACE(D_DATA) ! 469: tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", ! 470: e->ev_union.EV_DT_TPDU.e_seq, p->tp_rcvnxt, p->tp_lcredit, 0); ! 471: ENDTRACE ! 472: IncStat(ts_dt_niw); ! 473: m_freem(e->ev_union.EV_DT_TPDU.e_data); ! 474: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 475: (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); ! 476: } ! 477: break; ! 478: case 0x1d: ! 479: { ! 480: if (p->tp_ucddata) { ! 481: m_freem(p->tp_ucddata); ! 482: p->tp_ucddata = 0; ! 483: } ! 484: (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); ! 485: tp_cuntimeout(p, TM_retrans); ! 486: ! 487: soisconnected(p->tp_sock); ! 488: IFTRACE(D_CONN) ! 489: struct socket *so = p->tp_sock; ! 490: tptrace(TPPTmisc, ! 491: "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", ! 492: so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); ! 493: tptrace(TPPTmisc, ! 494: "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", ! 495: so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); ! 496: ENDTRACE ! 497: ! 498: tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); ! 499: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 500: } ! 501: break; ! 502: case 0x1e: ! 503: { ! 504: if( p->tp_state == TP_AKWAIT ) { ! 505: if (p->tp_ucddata) { ! 506: m_freem(p->tp_ucddata); ! 507: p->tp_ucddata = 0; ! 508: } ! 509: tp_cuntimeout(p, TM_retrans); ! 510: soisconnected(p->tp_sock); ! 511: tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); ! 512: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 513: } ! 514: IFTRACE(D_XPD) ! 515: tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", ! 516: 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); ! 517: ENDTRACE ! 518: ! 519: p->tp_sock->so_state |= SS_RCVATMARK; ! 520: postevent(p->tp_sock, 0, EV_OOB); ! 521: e->ev_union.EV_XPD_TPDU.e_data->m_flags |= M_EOR; ! 522: sbinsertoob(&p->tp_Xrcv, e->ev_union.EV_XPD_TPDU.e_data); ! 523: IFDEBUG(D_XPD) ! 524: dump_mbuf(e->ev_union.EV_XPD_TPDU.e_data, "XPD TPDU: tp_Xrcv"); ! 525: ENDDEBUG ! 526: tp_indicate(T_XDATA, p, 0); ! 527: sbwakeup( &p->tp_Xrcv ); ! 528: ! 529: (void) tp_emit(XAK_TPDU_type, p, p->tp_Xrcvnxt, 0, MNULL); ! 530: SEQ_INC(p, p->tp_Xrcvnxt); ! 531: } ! 532: break; ! 533: case 0x1f: ! 534: { ! 535: if( p->tp_Xrcv.sb_cc == 0 ) { ! 536: /* kludge for select(): */ ! 537: /* p->tp_sock->so_state &= ~SS_OOBAVAIL; */ ! 538: } ! 539: } ! 540: break; ! 541: case 0x20: ! 542: { ! 543: IFTRACE(D_XPD) ! 544: tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n", ! 545: p->tp_Xrcvnxt, e->ev_union.EV_XPD_TPDU.e_seq, p->tp_Xrcv.sb_cc , 0); ! 546: ENDTRACE ! 547: if( p->tp_Xrcvnxt != e->ev_union.EV_XPD_TPDU.e_seq ) ! 548: IncStat(ts_xpd_niw); ! 549: if( p->tp_Xrcv.sb_cc ) { ! 550: /* might as well kick 'em again */ ! 551: tp_indicate(T_XDATA, p, 0); ! 552: IncStat(ts_xpd_dup); ! 553: } ! 554: m_freem(e->ev_union.EV_XPD_TPDU.e_data); ! 555: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 556: /* don't send an xack because the xak gives "last one received", not ! 557: * "next one i expect" (dumb) ! 558: */ ! 559: } ! 560: break; ! 561: case 0x21: ! 562: { ! 563: struct socket *so = p->tp_sock; ! 564: ! 565: /* detach from parent socket so it can finish closing */ ! 566: if (so->so_head) { ! 567: if (!soqremque(so, 0) && !soqremque(so, 1)) ! 568: panic("tp: T_DETACH"); ! 569: so->so_head = 0; ! 570: } ! 571: tp_soisdisconnecting(p->tp_sock); ! 572: tp_netcmd( p, CONN_CLOSE); ! 573: tp_soisdisconnected(p); ! 574: } ! 575: break; ! 576: case 0x22: ! 577: { ! 578: struct socket *so = p->tp_sock; ! 579: struct mbuf *data = MNULL; ! 580: ! 581: /* detach from parent socket so it can finish closing */ ! 582: if (so->so_head) { ! 583: if (!soqremque(so, 0) && !soqremque(so, 1)) ! 584: panic("tp: T_DETACH"); ! 585: so->so_head = 0; ! 586: } ! 587: if (p->tp_state != TP_CLOSING) { ! 588: tp_soisdisconnecting(p->tp_sock); ! 589: data = MCPY(p->tp_ucddata, M_NOWAIT); ! 590: (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NORMAL_DISC, data); ! 591: p->tp_retrans = p->tp_Nretrans; ! 592: tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); ! 593: } ! 594: } ! 595: break; ! 596: case 0x23: ! 597: { ! 598: tp_soisdisconnecting(p->tp_sock); ! 599: tp_netcmd( p, CONN_CLOSE); ! 600: tp_soisdisconnected(p); ! 601: } ! 602: break; ! 603: case 0x24: ! 604: { ! 605: struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); ! 606: ! 607: if(p->tp_state == TP_OPEN) { ! 608: tp_euntimeout(p, TM_data_retrans); /* all */ ! 609: tp_cuntimeout(p, TM_inact); ! 610: tp_cuntimeout(p, TM_sendack); ! 611: p->tp_flags &= ~TPF_DELACK; ! 612: } ! 613: if (data) { ! 614: IFDEBUG(D_CONN) ! 615: printf("T_DISC_req.trans tp_ucddata 0x%x\n", ! 616: p->tp_ucddata); ! 617: dump_mbuf(data, "ucddata @ T_DISC_req"); ! 618: ENDDEBUG ! 619: } ! 620: tp_soisdisconnecting(p->tp_sock); ! 621: p->tp_retrans = p->tp_Nretrans; ! 622: tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); ! 623: ! 624: if( trick_hc ) ! 625: return tp_emit(DR_TPDU_type, p, 0, e->ev_union.EV_T_DISC_req.e_reason, data); ! 626: } ! 627: break; ! 628: case 0x25: ! 629: { ! 630: int error; ! 631: struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); ! 632: ! 633: IncStat(ts_retrans_cc); ! 634: p->tp_retrans --; ! 635: p->tp_cong_win = 1 * p->tp_l_tpdusize; ! 636: ! 637: if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) ! 638: p->tp_sock->so_error = error; ! 639: tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); ! 640: } ! 641: break; ! 642: case 0x26: ! 643: { ! 644: IncStat(ts_conn_gaveup); ! 645: tp_soisdisconnecting(p->tp_sock); ! 646: p->tp_sock->so_error = ETIMEDOUT; ! 647: tp_indicate(T_DISCONNECT, p, ETIMEDOUT); ! 648: (void) tp_emit(DR_TPDU_type, p, 0, E_TP_CONGEST, MNULL); ! 649: p->tp_retrans = p->tp_Nretrans; ! 650: tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); ! 651: } ! 652: break; ! 653: case 0x27: ! 654: { ! 655: tp_euntimeout(p, TM_data_retrans); /* all */ ! 656: tp_cuntimeout(p, TM_inact); ! 657: tp_cuntimeout(p, TM_sendack); ! 658: ! 659: IncStat(ts_conn_gaveup); ! 660: tp_soisdisconnecting(p->tp_sock); ! 661: p->tp_sock->so_error = ETIMEDOUT; ! 662: tp_indicate(T_DISCONNECT, p, ETIMEDOUT); ! 663: (void) tp_emit(DR_TPDU_type, p, 0, E_TP_CONGEST_2, MNULL); ! 664: p->tp_retrans = p->tp_Nretrans; ! 665: tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); ! 666: } ! 667: break; ! 668: case 0x28: ! 669: { ! 670: p->tp_cong_win = 1 * p->tp_l_tpdusize; ! 671: /* resume XPD */ ! 672: if ( p->tp_Xsnd.sb_mb ) { ! 673: struct mbuf *m = m_copy(p->tp_Xsnd.sb_mb, 0, (int)p->tp_Xsnd.sb_cc); ! 674: int shift; ! 675: ! 676: IFTRACE(D_XPD) ! 677: tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna", ! 678: p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndnxt, ! 679: p->tp_snduna); ! 680: ENDTRACE ! 681: IFDEBUG(D_XPD) ! 682: dump_mbuf(m, "XPD retrans emitting M"); ! 683: ENDDEBUG ! 684: IncStat(ts_retrans_xpd); ! 685: p->tp_retrans --; ! 686: shift = max(p->tp_Nretrans - p->tp_retrans, 6); ! 687: (void) tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m); ! 688: tp_ctimeout(p, TM_retrans, ((int)p->tp_dt_ticks) << shift); ! 689: } ! 690: } ! 691: break; ! 692: case 0x29: ! 693: { ! 694: p->tp_rxtshift++; ! 695: (void) tp_data_retrans(p); ! 696: } ! 697: break; ! 698: case 0x2a: ! 699: { ! 700: p->tp_retrans --; ! 701: (void) tp_emit(DR_TPDU_type, p, 0, E_TP_DR_NO_REAS, MNULL); ! 702: IncStat(ts_retrans_dr); ! 703: tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); ! 704: } ! 705: break; ! 706: case 0x2b: ! 707: { ! 708: p->tp_sock->so_error = ETIMEDOUT; ! 709: p->tp_refstate = REF_FROZEN; ! 710: tp_recycle_tsuffix( p ); ! 711: tp_etimeout(p, TM_reference, (int)p->tp_refer_ticks); ! 712: } ! 713: break; ! 714: case 0x2c: ! 715: { ! 716: tp_freeref(p->tp_lref); ! 717: tp_detach(p); ! 718: } ! 719: break; ! 720: case 0x2d: ! 721: { ! 722: if( p->tp_class != TP_CLASS_0) { ! 723: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 724: if ( e->ev_number == CC_TPDU ) ! 725: (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); ! 726: } ! 727: /* ignore it if class 0 - state tables are blank for this */ ! 728: } ! 729: break; ! 730: case 0x2e: ! 731: { ! 732: IFTRACE(D_DATA) ! 733: tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb", ! 734: p->tp_sndnxt, p->tp_snduna, p->tp_fcredit, p); ! 735: ENDTRACE ! 736: ! 737: tp_send(p); ! 738: } ! 739: break; ! 740: case 0x2f: ! 741: { ! 742: int error = 0; ! 743: ! 744: /* resume XPD */ ! 745: if ( p->tp_Xsnd.sb_mb ) { ! 746: struct mbuf *m = m_copy(p->tp_Xsnd.sb_mb, 0, (int)p->tp_Xsnd.sb_cc); ! 747: /* m_copy doesn't preserve the m_xlink field, but at this pt. ! 748: * that doesn't matter ! 749: */ ! 750: ! 751: IFTRACE(D_XPD) ! 752: tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna", ! 753: p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndnxt, ! 754: p->tp_snduna); ! 755: ENDTRACE ! 756: IFDEBUG(D_XPD) ! 757: printf("T_XPD_req: sb_cc 0x%x\n", p->tp_Xsnd.sb_cc); ! 758: dump_mbuf(m, "XPD req emitting M"); ! 759: ENDDEBUG ! 760: error = ! 761: tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m); ! 762: p->tp_retrans = p->tp_Nretrans; ! 763: ! 764: tp_ctimeout(p, TM_retrans, (int)p->tp_rxtcur); ! 765: SEQ_INC(p, p->tp_Xsndnxt); ! 766: } ! 767: if(trick_hc) ! 768: return error; ! 769: } ! 770: break; ! 771: case 0x30: ! 772: { ! 773: struct sockbuf *sb = &p->tp_sock->so_snd; ! 774: ! 775: IFDEBUG(D_ACKRECV) ! 776: 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); ! 777: ENDDEBUG ! 778: if( p->tp_class != TP_CLASS_0) { ! 779: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 780: } ! 781: sbwakeup(sb); ! 782: IFDEBUG(D_ACKRECV) ! 783: printf("GOOD ACK new sndnxt 0x%x\n", p->tp_sndnxt); ! 784: ENDDEBUG ! 785: } ! 786: break; ! 787: case 0x31: ! 788: { ! 789: IFTRACE(D_ACKRECV) ! 790: tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", ! 791: e->ev_union.EV_AK_TPDU.e_fcc_present, p->tp_r_subseq, e->ev_union.EV_AK_TPDU.e_subseq, 0); ! 792: ENDTRACE ! 793: if( p->tp_class != TP_CLASS_0 ) { ! 794: ! 795: if ( !e->ev_union.EV_AK_TPDU.e_fcc_present ) { ! 796: /* send ACK with FCC */ ! 797: IncStat( ts_ackreason[_ACK_FCC_] ); ! 798: (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 1, MNULL); ! 799: } ! 800: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 801: } ! 802: } ! 803: break; ! 804: case 0x32: ! 805: { ! 806: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 807: tp_cuntimeout(p, TM_retrans); ! 808: ! 809: sbwakeup( &p->tp_sock->so_snd ); ! 810: ! 811: /* resume normal data */ ! 812: tp_send(p); ! 813: } ! 814: break; ! 815: case 0x33: ! 816: { ! 817: IFTRACE(D_ACKRECV) ! 818: tptrace(TPPTmisc, "BOGUS XACK eventtype ", e->ev_number, 0, 0,0); ! 819: ENDTRACE ! 820: if( p->tp_class != TP_CLASS_0 ) { ! 821: tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); ! 822: } ! 823: } ! 824: break; ! 825: case 0x34: ! 826: { ! 827: int timo; ! 828: IFTRACE(D_TIMER) ! 829: tptrace(TPPTsendack, -1, p->tp_lcredit, p->tp_sent_uwe, ! 830: p->tp_sent_lcdt, 0); ! 831: ENDTRACE ! 832: IncPStat(p, tps_n_TMsendack); ! 833: (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); ! 834: if (p->tp_fcredit == 0) { ! 835: if (p->tp_rxtshift < TP_MAXRXTSHIFT) ! 836: p->tp_rxtshift++; ! 837: timo = (p->tp_dt_ticks) << p->tp_rxtshift; ! 838: } else ! 839: timo = p->tp_sendack_ticks; ! 840: tp_ctimeout(p, TM_sendack, timo); ! 841: } ! 842: break; ! 843: case 0x35: ! 844: { ! 845: if (sbspace(&p->tp_sock->so_rcv) > 0) ! 846: tp0_openflow(p); ! 847: } ! 848: break; ! 849: case 0x36: ! 850: { ! 851: if( trick_hc ) { ! 852: SeqNum ack_thresh; ! 853: /* ! 854: * If the upper window edge has advanced a reasonable ! 855: * amount beyond what was known, send an ACK. ! 856: * A reasonable amount is 2 packets, unless the max window ! 857: * is only 1 or 2 packets, in which case we ! 858: * should send an ack for any advance in the upper window edge. ! 859: */ ! 860: LOCAL_CREDIT(p); ! 861: ack_thresh = SEQ_SUB(p, p->tp_lcredit + p->tp_rcvnxt, ! 862: (p->tp_maxlcredit > 2 ? 2 : 1)); ! 863: if (SEQ_GT(p, ack_thresh, p->tp_sent_uwe)) { ! 864: IncStat(ts_ackreason[_ACK_USRRCV_]); ! 865: p->tp_flags &= ~TPF_DELACK; ! 866: return tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); ! 867: } ! 868: } ! 869: } ! 870: break; ! 871: case 0x37: ! 872: { ! 873: if(trick_hc) ! 874: return ECONNABORTED; ! 875: } ! 876: break; ! 877: case 0x38: ! 878: { ! 879: ASSERT( p->tp_state != TP_LISTENING ); ! 880: tp_indicate(T_DISCONNECT, p, ECONNRESET); ! 881: tp_soisdisconnected(p); ! 882: } ! 883: break; ! 884: } ! 885: return 0; ! 886: } ! 887: ! 888: _XEBEC_PG int ! 889: _Xebec_index( e,p ) ! 890: struct tp_event *e; ! 891: tp_PCB_ *p; ! 892: { ! 893: switch( (e->ev_number<<4)+(p->tp_state) ) { ! 894: case 0x12: ! 895: if ( p->tp_retrans > 0 ) return 0x1e; ! 896: else return 0x1f; ! 897: case 0x13: ! 898: if ( p->tp_retrans > 0 ) return 0x2f; ! 899: else return 0x30; ! 900: case 0x14: ! 901: if ( p->tp_retrans > 0 ) return 0x32; ! 902: else return 0x31; ! 903: case 0x15: ! 904: if ( p->tp_retrans > 0 ) return 0x34; ! 905: else return 0x35; ! 906: case 0x54: ! 907: if (p->tp_rxtshift < TP_NRETRANS) return 0x33; ! 908: else return 0x31; ! 909: case 0x64: ! 910: if (p->tp_class == TP_CLASS_0) return 0x1a; ! 911: else return 0x1b; ! 912: case 0x77: ! 913: if ( p->tp_class == TP_CLASS_0) return 0xd; ! 914: else return 0xe; ! 915: case 0x86: ! 916: if ( e->ev_union.EV_DR_TPDU.e_sref != 0 ) return 0x2; ! 917: else return 0x3; ! 918: case 0xa2: ! 919: if (p->tp_class == TP_CLASS_0) return 0x1c; ! 920: else return 0x1d; ! 921: case 0xb2: ! 922: if (p->tp_class == TP_CLASS_0) return 0x5; ! 923: else return 0x0; ! 924: case 0xb4: ! 925: 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; ! 926: else return 0x3b; ! 927: case 0xc3: ! 928: if ( IN_RWINDOW( p, e->ev_union.EV_DT_TPDU.e_seq, ! 929: p->tp_rcvnxt, SEQ(p, p->tp_rcvnxt + p->tp_lcredit)) ) return 0x21; ! 930: else return 0x24; ! 931: case 0xc4: ! 932: if ( p->tp_class == TP_CLASS_0 ) return 0x22; ! 933: else if ( IN_RWINDOW( p, e->ev_union.EV_DT_TPDU.e_seq, ! 934: p->tp_rcvnxt, SEQ(p, p->tp_rcvnxt + p->tp_lcredit)) ) return 0x23; ! 935: else return 0x25; ! 936: case 0xd3: ! 937: if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27; ! 938: else return 0x2a; ! 939: case 0xd4: ! 940: if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27; ! 941: else return 0x29; ! 942: case 0xe4: ! 943: if ( tp_goodXack(p, e->ev_union.EV_XAK_TPDU.e_seq) ) return 0x3c; ! 944: else return 0x3d; ! 945: case 0x102: ! 946: if ( p->tp_class == TP_CLASS_0 ) return 0x2d; ! 947: else return 0x2e; ! 948: case 0x104: ! 949: if ( p->tp_class == TP_CLASS_0 ) return 0x2d; ! 950: else return 0x2e; ! 951: case 0x144: ! 952: if (p->tp_class == TP_CLASS_0) return 0x3f; ! 953: else return 0x40; ! 954: case 0x162: ! 955: if (p->tp_class == TP_CLASS_0) return 0x2b; ! 956: else return 0x2c; ! 957: case 0x172: ! 958: if ( p->tp_class != TP_CLASS_4 ) return 0x42; ! 959: else return 0x46; ! 960: case 0x174: ! 961: if ( p->tp_class != TP_CLASS_4 ) return 0x42; ! 962: else return 0x47; ! 963: case 0x177: ! 964: if ( p->tp_class != TP_CLASS_4 ) return 0x42; ! 965: else return 0x43; ! 966: case 0x188: ! 967: if ( p->tp_class == TP_CLASS_0 ) return 0xf; ! 968: else if (tp_emit(CC_TPDU_type, p, 0,0, MCPY(p->tp_ucddata, M_NOWAIT)) == 0) return 0x10; ! 969: else return 0x11; ! 970: default: return 0; ! 971: } /* end switch */ ! 972: } /* _Xebec_index() */ ! 973: static int inx[26][9] = { {0,0,0,0,0,0,0,0,0,}, ! 974: {0x0,0x0,0x0,0x0,0x31,0x0,0x0,0x0,0x0, }, ! 975: {0x0,0x0,-1,-1,-1,-1,0x0,0x0,0x0, }, ! 976: {0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0x0, }, ! 977: {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, }, ! 978: {0x0,0x0,0x0,0x0,0x0,0x0,0x36,0x0,0x0, }, ! 979: {0x0,0x0,0x0,0x0,-1,0x0,0x0,0x0,0x0, }, ! 980: {0x0,0x7,0x15,0x1b,-1,0x17,0x3,0xa,0x0, }, ! 981: {0x0,0x19,0x6,0x20,0x37,0x8,0x3,-1,0x0, }, ! 982: {0x0,0x14,0x13,0x13,0x13,0x16,-1,0xa,0x0, }, ! 983: {0x0,0x7,0x6,0x1,0x9,0x18,0x3,0xa,0x0, }, ! 984: {0x0,0x19,-1,0x1,0x37,0x8,0x3,0xa,0x0, }, ! 985: {0x0,0x7,-1,0x26,-1,0x8,0x3,0xa,0x0, }, ! 986: {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, }, ! 987: {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, }, ! 988: {0x0,0x7,0x6,0x1,-1,0x8,0x3,0xa,0x0, }, ! 989: {0x0,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0x0, }, ! 990: {0x0,0x0,-1,0x2e,-1,0x0,0x4,0x0,0x2e, }, ! 991: {0x0,0xb,0x0,0x0,0x0,0x0,0x0,0x0,0x0, }, ! 992: {0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x0, }, ! 993: {0x0,0x0,0x0,0x0,0x39,0x0,0x0,0x0,0x0, }, ! 994: {0x0,0x0,0x0,0x0,-1,0x0,0x41,0x0,0x0, }, ! 995: {0x0,0x0,0x0,0x0,0x28,0x0,0x41,0x0,0x0, }, ! 996: {0x0,0xc,-1,0x2c,0x0,0x2c,0x4,0xc,0x2c, }, ! 997: {0x0,0x49,-1,0x45,-1,0x44,0x48,-1,0x0, }, ! 998: {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,-1, }, ! 999: }; ! 1000: tp_driver(p, e) ! 1001: register tp_PCB_ *p; ! 1002: register struct tp_event *e; ! 1003: { ! 1004: register int index, error=0; ! 1005: struct act_ent *a; ! 1006: static struct act_ent erroraction = {0,-1}; ! 1007: ! 1008: index = inx[1 + e->ev_number][p->tp_state]; ! 1009: if(index<0) index=_Xebec_index(e, p); ! 1010: if (index==0) { ! 1011: a = &erroraction; ! 1012: } else ! 1013: a = &statetable[index]; ! 1014: ! 1015: if(a->a_action) ! 1016: error = _Xebec_action( a->a_action, e, p ); ! 1017: IFTRACE(D_DRIVER) ! 1018: tptrace(DRIVERTRACE, a->a_newstate, p->tp_state, e->ev_number, a->a_action, 0); ! 1019: ENDTRACE ! 1020: if(error==0) ! 1021: p->tp_state = a->a_newstate; ! 1022: return error; ! 1023: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.