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