|
|
1.1 ! root 1: /*********************************************************** ! 2: Copyright IBM Corporation 1987 ! 3: ! 4: All Rights Reserved ! 5: ! 6: Permission to use, copy, modify, and distribute this software and its ! 7: documentation for any purpose and without fee is hereby granted, ! 8: provided that the above copyright notice appear in all copies and that ! 9: both that copyright notice and this permission notice appear in ! 10: supporting documentation, and that the name of IBM not be ! 11: used in advertising or publicity pertaining to distribution of the ! 12: software without specific, written prior permission. ! 13: ! 14: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ! 15: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ! 16: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ! 17: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ! 18: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! 19: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ! 20: SOFTWARE. ! 21: ! 22: ******************************************************************/ ! 23: ! 24: /* ! 25: * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison ! 26: */ ! 27: /* $Header: tp.trans,v 5.1 88/10/12 12:22:07 root Exp $ ! 28: * ! 29: * Transition file for TP. ! 30: * ! 31: * DO NOT: ! 32: * - change the order of any of the events or states. to do so will ! 33: * make tppt, netstat, etc. cease working. ! 34: * ! 35: * NOTE: ! 36: * some hooks exist for data on (dis)connect, but it's ***NOT***SUPPORTED*** ! 37: * (read: may not work!) ! 38: * ! 39: * I tried to put everything that causes a change of state in here, hence ! 40: * there are some seemingly trivial events like T_DETACH and T_LISTEN_req. ! 41: * ! 42: * Almost everything having to do w/ setting & cancelling timers is here ! 43: * but once it was debugged, I moved the setting of the ! 44: * keepalive (sendack) timer to tp_emit(), where an AK_TPDU is sent. ! 45: * This is so the code wouldn't be duplicated all over creation in here. ! 46: * ! 47: */ ! 48: *PROTOCOL tp ! 49: ! 50: *INCLUDE ! 51: ! 52: { ! 53: /* @(#)tp.trans 7.5 (Berkeley) 6/6/90 */ ! 54: #include "param.h" ! 55: #include "socket.h" ! 56: #include "socketvar.h" ! 57: #include "protosw.h" ! 58: #include "mbuf.h" ! 59: #include "time.h" ! 60: #include "errno.h" ! 61: #include "../netiso/tp_param.h" ! 62: #include "../netiso/tp_stat.h" ! 63: #include "../netiso/tp_pcb.h" ! 64: #include "../netiso/tp_tpdu.h" ! 65: #include "../netiso/argo_debug.h" ! 66: #include "../netiso/tp_trace.h" ! 67: #include "../netiso/iso_errno.h" ! 68: #include "../netiso/tp_seq.h" ! 69: #include "../netiso/cons.h" ! 70: ! 71: #define DRIVERTRACE TPPTdriver ! 72: #define sbwakeup(sb) sowakeup(p->tp_sock, sb); ! 73: #define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0) ! 74: ! 75: static trick_hc = 1; ! 76: ! 77: int tp_emit(), ! 78: tp_goodack(), tp_goodXack(), ! 79: tp_stash() ! 80: ; ! 81: void tp_indicate(), tp_getoptions(), ! 82: tp_soisdisconnecting(), tp_soisdisconnected(), ! 83: tp_recycle_tsuffix(), ! 84: tp_etimeout(), tp_euntimeout(), ! 85: tp_euntimeout_lss(), tp_ctimeout(), ! 86: tp_cuntimeout(), tp_ctimeout_MIN(), ! 87: tp_freeref(), tp_detach(), ! 88: tp0_stash(), tp0_send(), ! 89: tp_netcmd(), tp_send() ! 90: ; ! 91: ! 92: typedef struct tp_pcb tpcb_struct; ! 93: ! 94: ! 95: } ! 96: ! 97: *PCB tpcb_struct SYNONYM P ! 98: ! 99: *STATES ! 100: ! 101: TP_CLOSED ! 102: TP_CRSENT ! 103: TP_AKWAIT ! 104: TP_OPEN ! 105: TP_CLOSING ! 106: TP_REFWAIT ! 107: TP_LISTENING /* Local to this implementation */ ! 108: TP_CONFIRMING /* Local to this implementation */ ! 109: ! 110: *EVENTS { struct timeval e_time; } SYNONYM E ! 111: ! 112: /* ! 113: * C (typically cancelled) timers - ! 114: * ! 115: * let these be the first ones so for the sake of convenience ! 116: * their values are 0--> n-1 ! 117: * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!! ! 118: */ ! 119: TM_inact ! 120: TM_retrans ! 121: /* TM_retrans is used for all ! 122: * simple retransmissions - CR,CC,XPD,DR ! 123: */ ! 124: ! 125: TM_sendack ! 126: /* TM_sendack does dual duty - keepalive AND sendack. ! 127: * It's set w/ keepalive-ticks every time an ack is sent. ! 128: * (this is done in (void) tp_emit() ). ! 129: * It's cancelled and reset whenever a DT ! 130: * arrives and it doesn't require immediate acking. ! 131: * Note that in this case it's set w/ the minimum of ! 132: * its prev value and the sendack-ticks value so the ! 133: * purpose of the keepalive is preserved. ! 134: */ ! 135: TM_notused ! 136: ! 137: /* ! 138: * E (typically expired) timers - these may be in any order. ! 139: * These cause procedures to be executed directly; may not ! 140: * cause an 'event' as we know them here. ! 141: */ ! 142: TM_reference { SeqNum e_low; SeqNum e_high; int e_retrans; } ! 143: TM_data_retrans { SeqNum e_low; SeqNum e_high; int e_retrans; } ! 144: ! 145: /* NOTE: in tp_input is a minor optimization that assumes that ! 146: * for all tpdu types that can take e_data and e_datalen, these ! 147: * fields fall in the same place in the event structure, that is, ! 148: * e_data is the first field and e_datalen is the 2nd field. ! 149: */ ! 150: ! 151: ER_TPDU { ! 152: u_char e_reason; ! 153: } ! 154: CR_TPDU { struct mbuf *e_data; /* first field */ ! 155: int e_datalen; /* 2nd field */ ! 156: u_int e_cdt; ! 157: } ! 158: DR_TPDU { struct mbuf *e_data; /* first field */ ! 159: int e_datalen; /* 2nd field */ ! 160: u_short e_sref; ! 161: u_char e_reason; ! 162: } ! 163: DC_TPDU ! 164: CC_TPDU { struct mbuf *e_data; /* first field */ ! 165: int e_datalen; /* 2nd field */ ! 166: u_short e_sref; ! 167: u_int e_cdt; ! 168: } ! 169: AK_TPDU { u_int e_cdt; ! 170: SeqNum e_seq; ! 171: SeqNum e_subseq; ! 172: u_char e_fcc_present; ! 173: } ! 174: DT_TPDU { struct mbuf *e_data; /* first field */ ! 175: int e_datalen; /* 2nd field */ ! 176: u_int e_eot; ! 177: SeqNum e_seq; ! 178: } ! 179: XPD_TPDU { struct mbuf *e_data; /* first field */ ! 180: int e_datalen; /* 2nd field */ ! 181: SeqNum e_seq; ! 182: } ! 183: XAK_TPDU { SeqNum e_seq; } ! 184: ! 185: T_CONN_req ! 186: T_DISC_req { u_char e_reason; } ! 187: T_LISTEN_req ! 188: T_DATA_req ! 189: T_XPD_req ! 190: T_USR_rcvd ! 191: T_USR_Xrcvd ! 192: T_DETACH ! 193: T_NETRESET ! 194: T_ACPT_req ! 195: ! 196: ! 197: *TRANSITIONS ! 198: ! 199: ! 200: /* TP_AKWAIT doesn't exist in TP 0 */ ! 201: SAME <== TP_AKWAIT [ CC_TPDU, DC_TPDU, XAK_TPDU ] ! 202: DEFAULT ! 203: NULLACTION ! 204: ; ! 205: ! 206: ! 207: /* applicable in TP4, TP0 */ ! 208: SAME <== TP_REFWAIT DR_TPDU ! 209: ( $$.e_sref != 0 ) ! 210: { ! 211: (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); ! 212: } ! 213: ; ! 214: ! 215: /* applicable in TP4, TP0 */ ! 216: SAME <== TP_REFWAIT [ CR_TPDU, CC_TPDU, DT_TPDU, ! 217: DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ] ! 218: DEFAULT ! 219: { ! 220: # ifdef TP_DEBUG ! 221: if( $E.ev_number != AK_TPDU ) ! 222: printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number); ! 223: # endif TP_DEBUG ! 224: } ! 225: ; ! 226: ! 227: /* applicable in TP4, TP0 */ ! 228: SAME <== TP_REFWAIT [ T_DETACH, T_DISC_req ] ! 229: DEFAULT ! 230: NULLACTION ! 231: ; ! 232: ! 233: /* applicable in TP4, TP0 */ ! 234: SAME <== TP_CRSENT AK_TPDU ! 235: ($P.tp_class == TP_CLASS_0) ! 236: { ! 237: /* oh, man is this grotesque or what? */ ! 238: (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); ! 239: /* but it's necessary because this pseudo-ack may happen ! 240: * before the CC arrives, but we HAVE to adjust the ! 241: * snduna as a result of the ack, WHENEVER it arrives ! 242: */ ! 243: } ! 244: ; ! 245: ! 246: /* applicable in TP4, TP0 */ ! 247: SAME <== TP_CRSENT ! 248: [ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU, XAK_TPDU ] ! 249: DEFAULT ! 250: NULLACTION ! 251: ; ! 252: ! 253: /* applicable in TP4, TP0 */ ! 254: SAME <== TP_CLOSED [ DT_TPDU, XPD_TPDU, ! 255: ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] ! 256: DEFAULT ! 257: NULLACTION ! 258: ; ! 259: ! 260: /* TP_CLOSING doesn't exist in TP 0 */ ! 261: SAME <== TP_CLOSING ! 262: [ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ] ! 263: DEFAULT ! 264: NULLACTION ! 265: ; ! 266: ! 267: ! 268: /* DC_TPDU doesn't exist in TP 0 */ ! 269: SAME <== TP_OPEN DC_TPDU ! 270: DEFAULT ! 271: NULLACTION ! 272: ; ! 273: ! 274: /* applicable in TP4, TP0 */ ! 275: SAME <== TP_LISTENING [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU, ! 276: ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] ! 277: DEFAULT ! 278: NULLACTION ! 279: ; ! 280: ! 281: /* applicable in TP4, TP0 */ ! 282: TP_LISTENING <== TP_CLOSED T_LISTEN_req ! 283: DEFAULT ! 284: NULLACTION ! 285: ; ! 286: ! 287: /* applicable in TP4, TP0 */ ! 288: TP_CLOSED <== [ TP_LISTENING, TP_CLOSED ] T_DETACH ! 289: DEFAULT ! 290: { ! 291: tp_detach($P); ! 292: } ! 293: ; ! 294: ! 295: TP_CONFIRMING <== TP_LISTENING CR_TPDU ! 296: ( $P.tp_class == TP_CLASS_0) ! 297: { ! 298: $P.tp_refp->tpr_state = REF_OPEN; /* has timers ??? */ ! 299: } ! 300: ; ! 301: ! 302: TP_CONFIRMING <== TP_LISTENING CR_TPDU ! 303: DEFAULT ! 304: { ! 305: IFTRACE(D_CONN) ! 306: tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0); ! 307: ENDTRACE ! 308: IFDEBUG(D_CONN) ! 309: printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data); ! 310: ENDDEBUG ! 311: $P.tp_refp->tpr_state = REF_OPEN; /* has timers */ ! 312: $P.tp_fcredit = $$.e_cdt; ! 313: ! 314: if ($$.e_datalen > 0) { ! 315: /* n/a for class 0 */ ! 316: ASSERT($P.tp_Xrcv.sb_cc == 0); ! 317: sbappendrecord(&$P.tp_Xrcv, $$.e_data); ! 318: /*$P.tp_flags |= TPF_CONN_DATA_IN;*/ ! 319: $$.e_data = MNULL; ! 320: } ! 321: } ! 322: ; ! 323: ! 324: TP_OPEN <== TP_CONFIRMING T_ACPT_req ! 325: ( $P.tp_class == TP_CLASS_0 ) ! 326: { ! 327: IncStat(ts_tp0_conn); ! 328: IFTRACE(D_CONN) ! 329: tptrace(TPPTmisc, "Confiming", $P, 0,0,0); ! 330: ENDTRACE ! 331: IFDEBUG(D_CONN) ! 332: printf("Confirming connection: $P" ); ! 333: ENDDEBUG ! 334: soisconnected($P.tp_sock); ! 335: (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ; ! 336: $P.tp_fcredit = 1; ! 337: } ! 338: ; ! 339: ! 340: TP_AKWAIT <== TP_CONFIRMING T_ACPT_req ! 341: (tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0) ! 342: { ! 343: IncStat(ts_tp4_conn); /* even though not quite open */ ! 344: IFTRACE(D_CONN) ! 345: tptrace(TPPTmisc, "Confiming", $P, 0,0,0); ! 346: ENDTRACE ! 347: IFDEBUG(D_CONN) ! 348: printf("Confirming connection: $P" ); ! 349: ENDDEBUG ! 350: soisconnecting($P.tp_sock); ! 351: if($P.tp_rx_strat & TPRX_FASTSTART) ! 352: $P.tp_cong_win = $P.tp_fcredit; ! 353: $P.tp_retrans = $P.tp_Nretrans; ! 354: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); ! 355: } ! 356: ; ! 357: ! 358: /* TP4 only */ ! 359: TP_CLOSED <== TP_CONFIRMING T_ACPT_req ! 360: DEFAULT /* emit failed */ ! 361: { ! 362: register struct tp_ref *r = $P.tp_refp; ! 363: ! 364: IFDEBUG(D_CONN) ! 365: printf("event: CR_TPDU emit CC failed done " ); ! 366: ENDDEBUG ! 367: soisdisconnected($P.tp_sock); ! 368: tp_recycle_tsuffix( $P ); ! 369: tp_freeref(r); ! 370: tp_detach($P); ! 371: } ! 372: ; ! 373: ! 374: /* applicable in TP4, TP0 */ ! 375: TP_CRSENT <== TP_CLOSED T_CONN_req ! 376: DEFAULT ! 377: { ! 378: int error; ! 379: struct mbuf *data = MNULL; ! 380: ! 381: IFTRACE(D_CONN) ! 382: tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags, ! 383: $P.tp_ucddata, 0, 0); ! 384: ENDTRACE ! 385: data = MCPY($P.tp_ucddata, M_WAIT); ! 386: if (data) { ! 387: IFDEBUG(D_CONN) ! 388: printf("T_CONN_req.trans m_copy cc 0x%x\n", ! 389: $P.tp_ucddata); ! 390: dump_mbuf(data, "sosnd @ T_CONN_req"); ! 391: ENDDEBUG ! 392: } ! 393: ! 394: if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) ! 395: return error; /* driver WON'T change state; will return error */ ! 396: ! 397: $P.tp_refp->tpr_state = REF_OPEN; /* has timers */ ! 398: if($P.tp_class != TP_CLASS_0) { ! 399: $P.tp_retrans = $P.tp_Nretrans; ! 400: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks); ! 401: } ! 402: } ! 403: ; ! 404: ! 405: /* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */ ! 406: TP_REFWAIT <== [ TP_CRSENT, TP_AKWAIT, TP_OPEN ] DR_TPDU ! 407: DEFAULT ! 408: { ! 409: if ($$.e_datalen > 0 && $P.tp_class != TP_CLASS_0) { ! 410: /*sbdrop(&$P.tp_Xrcv, $P.tp_Xrcv.sb_cc); /* purge expedited data */ ! 411: sbflush(&$P.tp_Xrcv); ! 412: $P.tp_flags |= TPF_DISC_DATA_IN; ! 413: sbappendrecord(&$P.tp_Xrcv, $$.e_data); ! 414: $$.e_data = MNULL; ! 415: } ! 416: tp_indicate(T_DISCONNECT, $P, TP_ERROR_MASK | (u_short)$$.e_reason); ! 417: tp_soisdisconnected($P); ! 418: if ($P.tp_class != TP_CLASS_0) { ! 419: if ($P.tp_state == TP_OPEN ) { ! 420: tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ ! 421: tp_cuntimeout($P.tp_refp, TM_retrans); ! 422: tp_cuntimeout($P.tp_refp, TM_inact); ! 423: tp_cuntimeout($P.tp_refp, TM_sendack); ! 424: } ! 425: tp_cuntimeout($P.tp_refp, TM_retrans); ! 426: if( $$.e_sref != 0 ) ! 427: (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); ! 428: } ! 429: } ! 430: ; ! 431: ! 432: SAME <== TP_CLOSED DR_TPDU ! 433: DEFAULT ! 434: { ! 435: if( $$.e_sref != 0 ) ! 436: (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); ! 437: /* reference timer already set - reset it to be safe (???) */ ! 438: tp_euntimeout($P.tp_refp, TM_reference); /* all */ ! 439: tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks); ! 440: } ! 441: ; ! 442: ! 443: /* NBS(34) */ ! 444: TP_REFWAIT <== TP_CRSENT ER_TPDU ! 445: DEFAULT ! 446: { ! 447: tp_cuntimeout($P.tp_refp, TM_retrans); ! 448: tp_indicate(T_DISCONNECT, $P, ! 449: TP_ERROR_MASK |(u_short)($$.e_reason | 0x40)); ! 450: tp_soisdisconnected($P); ! 451: } ! 452: ; ! 453: ! 454: /* NBS(27) */ ! 455: TP_REFWAIT <== TP_CLOSING DR_TPDU ! 456: DEFAULT ! 457: { ! 458: $P.tp_sock->so_error = (u_short)$$.e_reason; ! 459: tp_cuntimeout($P.tp_refp, TM_retrans); ! 460: tp_soisdisconnected($P); ! 461: } ! 462: ; ! 463: /* these two transitions are the same but can't be combined because xebec ! 464: * can't handle the use of $$.e_reason if they're combined ! 465: */ ! 466: /* NBS(27) */ ! 467: TP_REFWAIT <== TP_CLOSING ER_TPDU ! 468: DEFAULT ! 469: { ! 470: $P.tp_sock->so_error = (u_short)$$.e_reason; ! 471: tp_cuntimeout($P.tp_refp, TM_retrans); ! 472: tp_soisdisconnected($P); ! 473: } ! 474: ; ! 475: /* NBS(27) */ ! 476: TP_REFWAIT <== TP_CLOSING DC_TPDU ! 477: DEFAULT ! 478: { ! 479: tp_cuntimeout($P.tp_refp, TM_retrans); ! 480: tp_soisdisconnected($P); ! 481: } ! 482: ; ! 483: ! 484: /* NBS(21) */ ! 485: SAME <== TP_CLOSED [ CC_TPDU, CR_TPDU ] ! 486: DEFAULT ! 487: { /* don't ask me why we have to do this - spec says so */ ! 488: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL); ! 489: /* don't bother with retransmissions of the DR */ ! 490: } ! 491: ; ! 492: ! 493: /* NBS(34) */ ! 494: TP_REFWAIT <== TP_OPEN ER_TPDU ! 495: ($P.tp_class == TP_CLASS_0) ! 496: { ! 497: tp_soisdisconnecting($P.tp_sock); ! 498: tp_indicate(T_DISCONNECT, $P, ! 499: TP_ERROR_MASK |(u_short)($$.e_reason | 0x40)); ! 500: ! 501: tp_soisdisconnected($P); ! 502: tp_netcmd( $P, CONN_CLOSE ); ! 503: } ! 504: ; ! 505: ! 506: TP_CLOSING <== [ TP_AKWAIT, TP_OPEN ] ER_TPDU ! 507: DEFAULT ! 508: { ! 509: if ($P.tp_state == TP_OPEN) { ! 510: tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ ! 511: tp_cuntimeout($P.tp_refp, TM_inact); ! 512: tp_cuntimeout($P.tp_refp, TM_sendack); ! 513: } ! 514: tp_soisdisconnecting($P.tp_sock); ! 515: tp_indicate(T_DISCONNECT, $P, ! 516: TP_ERROR_MASK |(u_short)($$.e_reason | 0x40)); ! 517: $P.tp_retrans = $P.tp_Nretrans; ! 518: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); ! 519: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL); ! 520: } ! 521: ; ! 522: /* NBS(6) */ ! 523: TP_OPEN <== TP_CRSENT CC_TPDU ! 524: ($P.tp_class == TP_CLASS_0) ! 525: { ! 526: tp_cuntimeout($P.tp_refp, TM_retrans); ! 527: IncStat(ts_tp0_conn); ! 528: $P.tp_fcredit = 1; ! 529: soisconnected($P.tp_sock); ! 530: } ! 531: ; ! 532: ! 533: TP_OPEN <== TP_CRSENT CC_TPDU ! 534: DEFAULT ! 535: { ! 536: IFDEBUG(D_CONN) ! 537: printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", ! 538: (int)$P.tp_flags); ! 539: ENDDEBUG ! 540: IncStat(ts_tp4_conn); ! 541: $P.tp_fref = $$.e_sref; ! 542: $P.tp_fcredit = $$.e_cdt; ! 543: $P.tp_ackrcvd = 0; ! 544: if($P.tp_rx_strat & TPRX_FASTSTART) ! 545: $P.tp_cong_win = $$.e_cdt; ! 546: tp_getoptions($P); ! 547: tp_cuntimeout($P.tp_refp, TM_retrans); ! 548: if ($P.tp_ucddata) { ! 549: IFDEBUG(D_CONN) ! 550: printf("dropping user connect data cc 0x%x\n", ! 551: $P.tp_ucddata->m_len); ! 552: ENDDEBUG ! 553: m_freem($P.tp_ucddata); ! 554: $P.tp_ucddata = 0; ! 555: } ! 556: soisconnected($P.tp_sock); ! 557: if ($$.e_datalen > 0) { ! 558: ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */ ! 559: sbappendrecord(&$P.tp_Xrcv, $$.e_data); ! 560: $P.tp_flags |= TPF_CONN_DATA_IN; ! 561: $$.e_data = MNULL; ! 562: } ! 563: ! 564: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); ! 565: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 566: } ! 567: ; ! 568: ! 569: /* TP4 only */ ! 570: SAME <== TP_CRSENT TM_retrans ! 571: ( $P.tp_retrans > 0 ) ! 572: { ! 573: struct mbuf *data = MNULL; ! 574: int error; ! 575: ! 576: IncStat(ts_retrans_cr); ! 577: $P.tp_cong_win = 1; ! 578: $P.tp_ackrcvd = 0; ! 579: data = MCPY($P.tp_ucddata, M_NOWAIT); ! 580: if($P.tp_ucddata) { ! 581: IFDEBUG(D_CONN) ! 582: printf("TM_retrans.trans m_copy cc 0x%x\n", data); ! 583: dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans"); ! 584: ENDDEBUG ! 585: if( data == MNULL ) ! 586: return ENOBUFS; ! 587: } ! 588: ! 589: $P.tp_retrans --; ! 590: if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) { ! 591: $P.tp_sock->so_error = error; ! 592: } ! 593: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks); ! 594: } ! 595: ; ! 596: ! 597: /* TP4 only */ ! 598: TP_REFWAIT <== TP_CRSENT TM_retrans ! 599: DEFAULT /* no more CR retransmissions */ ! 600: { ! 601: IncStat(ts_conn_gaveup); ! 602: $P.tp_sock->so_error = ETIMEDOUT; ! 603: tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); ! 604: tp_soisdisconnected($P); ! 605: } ! 606: ; ! 607: ! 608: /* TP4 only */ ! 609: SAME <== TP_AKWAIT CR_TPDU ! 610: DEFAULT ! 611: /* duplicate CR (which doesn't really exist in the context of ! 612: * a connectionless network layer) ! 613: * Doesn't occur in class 0. ! 614: */ ! 615: { ! 616: int error; ! 617: struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); ! 618: ! 619: if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) { ! 620: $P.tp_sock->so_error = error; ! 621: } ! 622: $P.tp_retrans = $P.tp_Nretrans; ! 623: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); ! 624: } ! 625: ; ! 626: ! 627: /* TP4 only */ ! 628: TP_OPEN <== TP_AKWAIT DT_TPDU ! 629: ( IN_RWINDOW( $P, $$.e_seq, ! 630: $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) ! 631: { ! 632: int doack; ! 633: ! 634: /* ! 635: * Get rid of any confirm or connect data, so that if we ! 636: * crash or close, it isn't thought of as disconnect data. ! 637: */ ! 638: if ($P.tp_ucddata) { ! 639: m_freem($P.tp_ucddata); ! 640: $P.tp_ucddata = 0; ! 641: } ! 642: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 643: tp_cuntimeout($P.tp_refp, TM_retrans); ! 644: soisconnected($P.tp_sock); ! 645: tp_getoptions($P); ! 646: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 647: ! 648: /* see also next 2 transitions, if you make any changes */ ! 649: ! 650: doack = tp_stash($P, $E); ! 651: IFDEBUG(D_DATA) ! 652: printf("tp_stash returns %d\n",doack); ! 653: ENDDEBUG ! 654: ! 655: if(doack) { ! 656: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); ! 657: tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks); ! 658: } else ! 659: tp_ctimeout( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks); ! 660: ! 661: IFDEBUG(D_DATA) ! 662: printf("after stash calling sbwakeup\n"); ! 663: ENDDEBUG ! 664: } ! 665: ; ! 666: ! 667: SAME <== TP_OPEN DT_TPDU ! 668: ( $P.tp_class == TP_CLASS_0 ) ! 669: { ! 670: tp0_stash($P, $E); ! 671: sbwakeup( &$P.tp_sock->so_rcv ); ! 672: ! 673: IFDEBUG(D_DATA) ! 674: printf("after stash calling sbwakeup\n"); ! 675: ENDDEBUG ! 676: } ! 677: ; ! 678: ! 679: /* TP4 only */ ! 680: SAME <== TP_OPEN DT_TPDU ! 681: ( IN_RWINDOW( $P, $$.e_seq, ! 682: $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) ! 683: { ! 684: int doack; /* tells if we must ack immediately */ ! 685: ! 686: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 687: sbwakeup( &$P.tp_sock->so_rcv ); ! 688: ! 689: doack = tp_stash($P, $E); ! 690: IFDEBUG(D_DATA) ! 691: printf("tp_stash returns %d\n",doack); ! 692: ENDDEBUG ! 693: ! 694: if(doack) ! 695: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); ! 696: else ! 697: tp_ctimeout_MIN( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks); ! 698: ! 699: IFDEBUG(D_DATA) ! 700: printf("after stash calling sbwakeup\n"); ! 701: ENDDEBUG ! 702: } ! 703: ; ! 704: ! 705: /* Not in window - we must ack under certain circumstances, namely ! 706: * a) if the seq number is below lwe but > lwe - (max credit ever given) ! 707: * (to handle lost acks) Can use max-possible-credit for this ^^^. ! 708: * and ! 709: * b) seq number is > uwe but < uwe + previously sent & withdrawn credit ! 710: * ! 711: * (see 12.2.3.8.1 of ISO spec, p. 73) ! 712: * We just always ack. ! 713: */ ! 714: /* TP4 only */ ! 715: SAME <== [ TP_OPEN, TP_AKWAIT ] DT_TPDU ! 716: DEFAULT /* Not in window */ ! 717: { ! 718: IFTRACE(D_DATA) ! 719: tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", ! 720: $$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0); ! 721: ENDTRACE ! 722: IncStat(ts_dt_niw); ! 723: m_freem($$.e_data); ! 724: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 725: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); ! 726: } ! 727: ; ! 728: ! 729: /* TP4 only */ ! 730: TP_OPEN <== TP_AKWAIT AK_TPDU ! 731: DEFAULT ! 732: { ! 733: if ($P.tp_ucddata) { ! 734: m_freem($P.tp_ucddata); ! 735: $P.tp_ucddata = 0; ! 736: } ! 737: (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); ! 738: tp_cuntimeout($P.tp_refp, TM_retrans); ! 739: ! 740: tp_getoptions($P); ! 741: soisconnected($P.tp_sock); ! 742: IFTRACE(D_CONN) ! 743: struct socket *so = $P.tp_sock; ! 744: tptrace(TPPTmisc, ! 745: "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", ! 746: so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); ! 747: tptrace(TPPTmisc, ! 748: "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", ! 749: so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); ! 750: ENDTRACE ! 751: ! 752: tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks); ! 753: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 754: } ! 755: ; ! 756: ! 757: /* TP4 only */ ! 758: TP_OPEN <== [ TP_OPEN, TP_AKWAIT ] XPD_TPDU ! 759: ( $P.tp_Xrcvnxt == $$.e_seq /* && $P.tp_Xrcv.sb_cc == 0*/) ! 760: { ! 761: if( $P.tp_state == TP_AKWAIT ) { ! 762: if ($P.tp_ucddata) { ! 763: m_freem($P.tp_ucddata); ! 764: $P.tp_ucddata = 0; ! 765: } ! 766: tp_cuntimeout($P.tp_refp, TM_retrans); ! 767: tp_getoptions($P); ! 768: soisconnected($P.tp_sock); ! 769: tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks); ! 770: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 771: } ! 772: IFTRACE(D_XPD) ! 773: tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", ! 774: $P.tp_Xrcvnxt,$$.e_seq, $$.e_datalen, $$.e_data->m_len); ! 775: ENDTRACE ! 776: ! 777: $P.tp_sock->so_state |= SS_RCVATMARK; ! 778: sbinsertoob(&$P.tp_Xrcv, $$.e_data); ! 779: IFDEBUG(D_XPD) ! 780: dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv"); ! 781: ENDDEBUG ! 782: tp_indicate(T_XDATA, $P, 0); ! 783: sbwakeup( &$P.tp_Xrcv ); ! 784: ! 785: (void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); ! 786: SEQ_INC($P, $P.tp_Xrcvnxt); ! 787: } ! 788: ; ! 789: ! 790: /* TP4 only */ ! 791: SAME <== TP_OPEN T_USR_Xrcvd ! 792: DEFAULT ! 793: { ! 794: if( $P.tp_Xrcv.sb_cc == 0 ) { ! 795: /*$P.tp_flags &= ~TPF_XPD_PRESENT;*/ ! 796: /* kludge for select(): */ ! 797: /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */ ! 798: } ! 799: } ! 800: /* OLD WAY: ! 801: * Ack only after the user receives the XPD. This is better for ! 802: * users that use one XPD right after another. ! 803: * Acking right away (the NEW WAY, see the prev. transition) is ! 804: * better for occasional * XPD, when the receiving user doesn't ! 805: * want to read the XPD immediately (which is session's behavior). ! 806: * ! 807: int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); ! 808: SEQ_INC($P, $P.tp_Xrcvnxt); ! 809: return error; ! 810: */ ! 811: ; ! 812: ! 813: /* NOTE: presently if the user doesn't read the connection data ! 814: * before and expedited data PDU comes in, the connection data will ! 815: * be dropped. This is a bug. To avoid it, we need somewhere else ! 816: * to put the connection data. ! 817: * On the other hand, we need not to have it sitting around forever. ! 818: * This is a problem with the idea of trying to accommodate ! 819: * data on connect w/ a passive-open user interface. ! 820: */ ! 821: /* TP4 only */ ! 822: ! 823: SAME <== [ TP_AKWAIT, TP_OPEN ] XPD_TPDU ! 824: DEFAULT /* not in window or cdt==0 */ ! 825: { ! 826: IFTRACE(D_XPD) ! 827: tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n", ! 828: $P.tp_Xrcvnxt, $$.e_seq, $P.tp_Xrcv.sb_cc , 0); ! 829: ENDTRACE ! 830: if( $P.tp_Xrcvnxt != $$.e_seq ) ! 831: IncStat(ts_xpd_niw); ! 832: if( $P.tp_Xrcv.sb_cc ) { ! 833: #ifdef notdef ! 834: if( $P.tp_flags & TPF_CONN_DATA_IN ) { ! 835: /* user isn't reading the connection data; see note above */ ! 836: sbdrop(&$P.tp_Xrcv, $P.tp_Xrcv.sb_cc); ! 837: $P.tp_flags &= ~TPF_CONN_DATA_IN; ! 838: } ! 839: #endif notdef ! 840: /* might as well kick 'em again */ ! 841: tp_indicate(T_XDATA, $P, 0); ! 842: IncStat(ts_xpd_dup); ! 843: } ! 844: m_freem($$.e_data); ! 845: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 846: /* don't send an xack because the xak gives "last one received", not ! 847: * "next one i expect" (dumb) ! 848: */ ! 849: } ! 850: ; ! 851: ! 852: /* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries ! 853: * to detach all its "children" ! 854: * Also (CRSENT) when user kills a job that's doing a connect() ! 855: */ ! 856: TP_REFWAIT <== TP_CRSENT T_DETACH ! 857: ($P.tp_class == TP_CLASS_0) ! 858: { ! 859: struct socket *so = $P.tp_sock; ! 860: ! 861: /* detach from parent socket so it can finish closing */ ! 862: if (so->so_head) { ! 863: if (!soqremque(so, 0) && !soqremque(so, 1)) ! 864: panic("tp: T_DETACH"); ! 865: so->so_head = 0; ! 866: } ! 867: tp_soisdisconnecting($P.tp_sock); ! 868: tp_netcmd( $P, CONN_CLOSE); ! 869: tp_soisdisconnected($P); ! 870: } ! 871: ; ! 872: ! 873: /* TP4 only */ ! 874: TP_CLOSING <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH ! 875: DEFAULT ! 876: { ! 877: struct socket *so = $P.tp_sock; ! 878: struct mbuf *data = MNULL; ! 879: ! 880: /* detach from parent socket so it can finish closing */ ! 881: if (so->so_head) { ! 882: if (!soqremque(so, 0) && !soqremque(so, 1)) ! 883: panic("tp: T_DETACH"); ! 884: so->so_head = 0; ! 885: } ! 886: if ($P.tp_state != TP_CLOSING) { ! 887: tp_soisdisconnecting($P.tp_sock); ! 888: data = MCPY($P.tp_ucddata, M_NOWAIT); ! 889: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data); ! 890: $P.tp_retrans = $P.tp_Nretrans; ! 891: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); ! 892: } ! 893: } ! 894: ; ! 895: ! 896: TP_REFWAIT <== [ TP_OPEN, TP_CRSENT ] T_DISC_req ! 897: ( $P.tp_class == TP_CLASS_0 ) ! 898: { ! 899: tp_soisdisconnecting($P.tp_sock); ! 900: tp_netcmd( $P, CONN_CLOSE); ! 901: tp_soisdisconnected($P); ! 902: } ! 903: ; ! 904: ! 905: /* TP4 only */ ! 906: TP_CLOSING <== [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ] T_DISC_req ! 907: DEFAULT ! 908: { ! 909: struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); ! 910: ! 911: if($P.tp_state == TP_OPEN) { ! 912: tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ ! 913: tp_cuntimeout($P.tp_refp, TM_inact); ! 914: tp_cuntimeout($P.tp_refp, TM_sendack); ! 915: } ! 916: if (data) { ! 917: IFDEBUG(D_CONN) ! 918: printf("T_DISC_req.trans tp_ucddata 0x%x\n", ! 919: $P.tp_ucddata); ! 920: dump_mbuf(data, "ucddata @ T_DISC_req"); ! 921: ENDDEBUG ! 922: } ! 923: tp_soisdisconnecting($P.tp_sock); ! 924: $P.tp_retrans = $P.tp_Nretrans; ! 925: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); ! 926: ! 927: if( trick_hc ) ! 928: return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data); ! 929: } ! 930: ; ! 931: ! 932: /* TP4 only */ ! 933: SAME <== TP_AKWAIT TM_retrans ! 934: ( $P.tp_retrans > 0 ) ! 935: { ! 936: int error; ! 937: struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); ! 938: ! 939: IncStat(ts_retrans_cc); ! 940: $P.tp_retrans --; ! 941: $P.tp_cong_win = 1; ! 942: $P.tp_ackrcvd = 0; ! 943: ! 944: if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) ! 945: $P.tp_sock->so_error = error; ! 946: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks); ! 947: } ! 948: ; ! 949: ! 950: /* TP4 only */ ! 951: TP_CLOSING <== TP_AKWAIT TM_retrans ! 952: DEFAULT /* out of time */ ! 953: { ! 954: IncStat(ts_conn_gaveup); ! 955: tp_soisdisconnecting($P.tp_sock); ! 956: $P.tp_sock->so_error = ETIMEDOUT; ! 957: tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); ! 958: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL); ! 959: $P.tp_retrans = $P.tp_Nretrans; ! 960: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); ! 961: } ! 962: ; ! 963: ! 964: /* the retrans timers had better go off BEFORE the inactivity timer does, ! 965: * if transmissions are going on. ! 966: * (i.e., TM_inact should be greater than timer for all retrans plus ack ! 967: * turnaround) ! 968: */ ! 969: /* TP4 only */ ! 970: TP_CLOSING <== TP_OPEN [ TM_inact, TM_retrans, TM_data_retrans ] ! 971: DEFAULT ! 972: { ! 973: tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */ ! 974: tp_cuntimeout($P.tp_refp, TM_inact); ! 975: tp_cuntimeout($P.tp_refp, TM_sendack); ! 976: ! 977: IncStat(ts_conn_gaveup); ! 978: tp_soisdisconnecting($P.tp_sock); ! 979: $P.tp_sock->so_error = ETIMEDOUT; ! 980: tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); ! 981: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL); ! 982: $P.tp_retrans = $P.tp_Nretrans; ! 983: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); ! 984: } ! 985: ; ! 986: ! 987: /* TP4 only */ ! 988: SAME <== TP_OPEN TM_retrans ! 989: ( $P.tp_retrans > 0 ) ! 990: { ! 991: $P.tp_cong_win = 1; ! 992: $P.tp_ackrcvd = 0; ! 993: /* resume XPD */ ! 994: if ( $P.tp_Xsnd.sb_mb ) { ! 995: struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); ! 996: /* m_copy doesn't preserve the m_xlink field, but at this pt. ! 997: * that doesn't matter ! 998: */ ! 999: ! 1000: IFTRACE(D_XPD) ! 1001: tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna", ! 1002: $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat, ! 1003: $P.tp_snduna); ! 1004: ENDTRACE ! 1005: IFDEBUG(D_XPD) ! 1006: dump_mbuf(m, "XPD retrans emitting M"); ! 1007: ENDDEBUG ! 1008: IncStat(ts_retrans_xpd); ! 1009: $P.tp_retrans --; ! 1010: (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); ! 1011: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); ! 1012: } ! 1013: } ! 1014: ; ! 1015: ! 1016: /* TP4 only */ ! 1017: SAME <== TP_OPEN TM_data_retrans ! 1018: ( $$.e_retrans > 0 ) ! 1019: { ! 1020: register SeqNum low, lowsave = 0; ! 1021: register struct tp_rtc *r = $P.tp_snduna_rtc; ! 1022: register struct mbuf *m; ! 1023: register SeqNum high = $$.e_high; ! 1024: ! 1025: low = $P.tp_snduna; ! 1026: lowsave = high = low; ! 1027: ! 1028: tp_euntimeout_lss($P.tp_refp, TM_data_retrans, ! 1029: SEQ_ADD($P, $P.tp_sndhiwat, 1)); ! 1030: $P.tp_retrans_hiwat = $P.tp_sndhiwat; ! 1031: ! 1032: if (($P.tp_rx_strat & TPRX_EACH) == 0) ! 1033: high = (high>low)?low:high; ! 1034: ! 1035: if( $P.tp_rx_strat & TPRX_USE_CW ) { ! 1036: register int i; ! 1037: ! 1038: $P.tp_cong_win = 1; ! 1039: $P.tp_ackrcvd = 0; ! 1040: i = SEQ_ADD($P, low, $P.tp_cong_win); ! 1041: ! 1042: high = SEQ_MIN($P, high, $P.tp_sndhiwat); ! 1043: ! 1044: } ! 1045: ! 1046: while( SEQ_LEQ($P, low, high) ){ ! 1047: if ( r == (struct tp_rtc *)0 ){ ! 1048: IFDEBUG(D_RTC) ! 1049: printf( "tp: retrans rtc list is GONE!\n"); ! 1050: ENDDEBUG ! 1051: break; ! 1052: } ! 1053: if ( r->tprt_seq == low ){ ! 1054: if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))== MNULL) ! 1055: break; ! 1056: (void) tp_emit(DT_TPDU_type, $P, low, r->tprt_eot, m); ! 1057: IncStat(ts_retrans_dt); ! 1058: SEQ_INC($P, low ); ! 1059: } ! 1060: r = r->tprt_next; ! 1061: } ! 1062: /* CE_BIT ! 1063: if ( SEQ_LEQ($P, lowsave, high) ){ ! 1064: */ ! 1065: $$.e_retrans --; ! 1066: tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave, ! 1067: (caddr_t)high, $$.e_retrans, ! 1068: ($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks); ! 1069: /* CE_BIT ! 1070: } ! 1071: */ ! 1072: } ! 1073: ; ! 1074: ! 1075: /* TP4 only */ ! 1076: SAME <== TP_CLOSING TM_retrans ! 1077: ( $P.tp_retrans > 0 ) ! 1078: { ! 1079: $P.tp_retrans --; ! 1080: (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL); ! 1081: IncStat(ts_retrans_dr); ! 1082: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks); ! 1083: } ! 1084: ; ! 1085: ! 1086: /* TP4 only */ ! 1087: TP_REFWAIT <== TP_CLOSING TM_retrans ! 1088: DEFAULT /* no more retrans - gave up */ ! 1089: { ! 1090: $P.tp_sock->so_error = ETIMEDOUT; ! 1091: $P.tp_refp->tpr_state = REF_FROZEN; ! 1092: tp_recycle_tsuffix( $P ); ! 1093: tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks); ! 1094: } ! 1095: ; ! 1096: ! 1097: /* ! 1098: * The resources are kept around until the ref timer goes off. ! 1099: * The suffices are wiped out sooner so they can be reused right away. ! 1100: */ ! 1101: /* applicable in TP4, TP0 */ ! 1102: TP_CLOSED <== TP_REFWAIT TM_reference ! 1103: DEFAULT ! 1104: { ! 1105: tp_freeref($P.tp_refp); ! 1106: tp_detach($P); ! 1107: } ! 1108: ; ! 1109: ! 1110: /* applicable in TP4, TP0 */ ! 1111: /* A duplicate CR from connectionless network layer can't happen */ ! 1112: SAME <== TP_OPEN [ CR_TPDU, CC_TPDU ] ! 1113: DEFAULT ! 1114: { ! 1115: if( $P.tp_class != TP_CLASS_0) { ! 1116: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 1117: if ( $E.ev_number == CC_TPDU ) ! 1118: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); ! 1119: } ! 1120: /* ignore it if class 0 - state tables are blank for this */ ! 1121: } ! 1122: ; ! 1123: ! 1124: /* applicable in TP4, TP0 */ ! 1125: SAME <== TP_OPEN T_DATA_req ! 1126: DEFAULT ! 1127: { ! 1128: IFTRACE(D_DATA) ! 1129: tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb", ! 1130: $P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P); ! 1131: ENDTRACE ! 1132: ! 1133: tp_send($P); ! 1134: } ! 1135: ; ! 1136: ! 1137: /* TP4 only */ ! 1138: SAME <== TP_OPEN T_XPD_req ! 1139: DEFAULT ! 1140: /* T_XPD_req was issued by sosend iff xpd socket buf was empty ! 1141: * at time of sosend(), ! 1142: * AND (which means) there were no unacknowledged XPD tpdus outstanding! ! 1143: */ ! 1144: { ! 1145: int error = 0; ! 1146: ! 1147: /* resume XPD */ ! 1148: if ( $P.tp_Xsnd.sb_mb ) { ! 1149: struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); ! 1150: /* m_copy doesn't preserve the m_xlink field, but at this pt. ! 1151: * that doesn't matter ! 1152: */ ! 1153: ! 1154: IFTRACE(D_XPD) ! 1155: tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna", ! 1156: $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat, ! 1157: $P.tp_snduna); ! 1158: ENDTRACE ! 1159: IFDEBUG(D_XPD) ! 1160: printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc); ! 1161: dump_mbuf(m, "XPD req emitting M"); ! 1162: ENDDEBUG ! 1163: error = ! 1164: tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); ! 1165: $P.tp_retrans = $P.tp_Nretrans; ! 1166: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); ! 1167: SEQ_INC($P, $P.tp_Xsndnxt); ! 1168: } ! 1169: if(trick_hc) ! 1170: return error; ! 1171: } ! 1172: ; ! 1173: ! 1174: /* TP4, faked ack in TP0 when cons send completes */ ! 1175: SAME <== TP_OPEN AK_TPDU ! 1176: ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq) ) ! 1177: ! 1178: /* tp_goodack == true means ! 1179: * EITHER it actually acked something heretofore unacknowledged ! 1180: * OR no news but the credit should be processed. ! 1181: */ ! 1182: { ! 1183: IFDEBUG(D_ACKRECV) ! 1184: printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt); ! 1185: ENDDEBUG ! 1186: if( $P.tp_class != TP_CLASS_0) { ! 1187: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 1188: tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq); ! 1189: } ! 1190: sbwakeup( &$P.tp_sock->so_snd ); ! 1191: ! 1192: if ($P.tp_sndhiwat <= $P.tp_retrans_hiwat && ! 1193: $P.tp_snduna <= $P.tp_retrans_hiwat) { ! 1194: ! 1195: register struct mbuf *m; ! 1196: /* extern struct mbuf *m_copy(); */ ! 1197: register struct tp_rtc *r; ! 1198: SeqNum high, retrans, low_save; ! 1199: ! 1200: high = SEQ_MIN($P, SEQ_ADD($P, $P.tp_snduna, ! 1201: MIN($P.tp_cong_win, $P.tp_fcredit)) - 1, ! 1202: $P.tp_sndhiwat); ! 1203: low_save = retrans = SEQ_MAX($P, SEQ_ADD($P, $P.tp_last_retrans, 1), ! 1204: $P.tp_snduna); ! 1205: for (; SEQ_LEQ($P, retrans, high); SEQ_INC($P, retrans)) { ! 1206: ! 1207: for (r = $P.tp_snduna_rtc; r; r = r->tprt_next){ ! 1208: if ( r->tprt_seq == retrans ){ ! 1209: if(( m = m_copy(r->tprt_data, 0, r->tprt_octets )) ! 1210: == MNULL) ! 1211: break; ! 1212: (void) tp_emit(DT_TPDU_type, $P, retrans, ! 1213: r->tprt_eot, m); ! 1214: $P.tp_last_retrans = retrans; ! 1215: IncStat(ts_retrans_dt); ! 1216: break; ! 1217: } ! 1218: } ! 1219: if ( r == (struct tp_rtc *)0 ){ ! 1220: IFDEBUG(D_RTC) ! 1221: printf( "tp: retrans rtc list is GONE!\n"); ! 1222: ENDDEBUG ! 1223: break; ! 1224: } ! 1225: } ! 1226: tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)low_save, ! 1227: (caddr_t)high, $P.tp_retrans, (int)$P.tp_dt_ticks); ! 1228: if (SEQ_DEC($P, retrans) == $P.tp_retrans_hiwat) ! 1229: tp_send($P); ! 1230: } ! 1231: else { ! 1232: tp_send($P); ! 1233: } ! 1234: IFDEBUG(D_ACKRECV) ! 1235: printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat); ! 1236: ENDDEBUG ! 1237: } ! 1238: ; ! 1239: ! 1240: /* TP4, and TP0 after sending a CC or possibly a CR */ ! 1241: SAME <== TP_OPEN AK_TPDU ! 1242: DEFAULT ! 1243: { ! 1244: IFTRACE(D_ACKRECV) ! 1245: tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", ! 1246: $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0); ! 1247: ENDTRACE ! 1248: if( $P.tp_class != TP_CLASS_0 ) { ! 1249: ! 1250: if ( !$$.e_fcc_present ) { ! 1251: /* send ACK with FCC */ ! 1252: IncStat( ts_ackreason[_ACK_FCC_] ); ! 1253: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL); ! 1254: } ! 1255: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 1256: } ! 1257: } ! 1258: ; ! 1259: ! 1260: /* NBS(47) */ ! 1261: /* goes in at *** */ ! 1262: /* just so happens that this is never true now, because we allow ! 1263: * only 1 packet in the queue at once (this could be changed) ! 1264: if ( $P.tp_Xsnd.sb_mb ) { ! 1265: struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??); ! 1266: ! 1267: (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); ! 1268: $P.tp_retrans = $P.tp_Nretrans; ! 1269: tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks); ! 1270: SEQ_INC($P, $P.tp_Xsndnxt); ! 1271: } ! 1272: */ ! 1273: /* end of the above hack */ ! 1274: ! 1275: /* TP4 only */ ! 1276: SAME <== TP_OPEN XAK_TPDU ! 1277: ( tp_goodXack($P, $$.e_seq) ) ! 1278: /* tp_goodXack checks for good ack, removes the correct ! 1279: * tpdu from the queue and returns 1 if ack was legit, 0 if not. ! 1280: * also updates tp_Xuna ! 1281: */ ! 1282: { ! 1283: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 1284: tp_cuntimeout($P.tp_refp, TM_retrans); ! 1285: ! 1286: sbwakeup( &$P.tp_sock->so_snd ); ! 1287: ! 1288: /* resume normal data */ ! 1289: tp_send($P); ! 1290: } ! 1291: ; ! 1292: ! 1293: /* TP4, and TP0 after sending a CC or possibly a CR */ ! 1294: SAME <== TP_OPEN XAK_TPDU ! 1295: DEFAULT ! 1296: { ! 1297: IFTRACE(D_ACKRECV) ! 1298: tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0); ! 1299: ENDTRACE ! 1300: if( $P.tp_class != TP_CLASS_0 ) { ! 1301: tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks); ! 1302: } ! 1303: } ! 1304: ; ! 1305: ! 1306: /* TP4 only */ ! 1307: SAME <== TP_OPEN TM_sendack ! 1308: DEFAULT ! 1309: { ! 1310: IFTRACE(D_TIMER) ! 1311: tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, ! 1312: $P.tp_sent_lcdt, 0); ! 1313: ENDTRACE ! 1314: IncPStat($P, tps_n_TMsendack); ! 1315: (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); ! 1316: } ! 1317: ; ! 1318: ! 1319: /* TP0 only */ ! 1320: SAME <== TP_OPEN T_USR_rcvd ! 1321: ($P.tp_class == TP_CLASS_0) ! 1322: NULLACTION ! 1323: ; ! 1324: ! 1325: /* TP4 only */ ! 1326: /* If old credit was zero, ! 1327: * we'd better inform other side that we now have space ! 1328: * But this is not enough. Sender might not yet have ! 1329: * seen an ack with cdt 0 but it might still think the ! 1330: * window is closed, so it's going to wait. ! 1331: * Best to send an ack each time. ! 1332: * Strictly speaking, this ought to be a function of the ! 1333: * general ack strategy. ! 1334: */ ! 1335: SAME <== TP_OPEN T_USR_rcvd ! 1336: DEFAULT ! 1337: { ! 1338: if( trick_hc ) { ! 1339: IncStat(ts_ackreason[_ACK_USRRCV_]); ! 1340: ! 1341: /* send an ACK only if there's new information */ ! 1342: LOCAL_CREDIT( $P ); ! 1343: if (($P.tp_rcvnxt != $P.tp_sent_rcvnxt) || ! 1344: ($P.tp_lcredit != $P.tp_sent_lcdt)) ! 1345: ! 1346: return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); ! 1347: } ! 1348: } ! 1349: ; ! 1350: ! 1351: /* applicable in TP4, TP0 */ ! 1352: SAME <== TP_REFWAIT [ T_USR_rcvd, T_USR_Xrcvd ] ! 1353: DEFAULT ! 1354: /* This happens if other end sent a DR when the user was waiting ! 1355: * on a receive. ! 1356: * Processing the DR includes putting us in REFWAIT state. ! 1357: */ ! 1358: { ! 1359: if(trick_hc) ! 1360: return ECONNABORTED; ! 1361: } ! 1362: ; ! 1363: ! 1364: /* TP0 only */ ! 1365: TP_REFWAIT <== [ TP_OPEN, TP_CRSENT, TP_LISTENING ] T_NETRESET ! 1366: ( $P.tp_class != TP_CLASS_4 ) ! 1367: /* 0 or (4 and 0) */ ! 1368: /* in OPEN class will be 0 or 4 but not both */ ! 1369: /* in CRSENT or LISTENING it could be in negotiation, hence both */ ! 1370: /* Actually, this shouldn't ever happen in LISTENING */ ! 1371: { ! 1372: ASSERT( $P.tp_state != TP_LISTENING ); ! 1373: tp_indicate(T_DISCONNECT, $P, ECONNRESET); ! 1374: tp_soisdisconnected($P); ! 1375: } ! 1376: ; ! 1377: ! 1378: /* TP4: ignore resets */ ! 1379: SAME <== [ TP_OPEN, TP_CRSENT, TP_AKWAIT, ! 1380: TP_CLOSING, TP_LISTENING ] T_NETRESET ! 1381: DEFAULT ! 1382: NULLACTION ! 1383: ; ! 1384: ! 1385: /* applicable in TP4, TP0 */ ! 1386: SAME <== [ TP_CLOSED, TP_REFWAIT ] T_NETRESET ! 1387: DEFAULT ! 1388: NULLACTION ! 1389: ; ! 1390: ! 1391: /* C'EST TOUT */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.