|
|
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: /* ! 28: * ARGO TP ! 29: * ! 30: * $Header: tp_emit.c,v 5.5 88/11/18 17:27:20 nhall Exp $ ! 31: * $Source: /usr/argo/sys/netiso/RCS/tp_emit.c,v $ ! 32: * @(#)tp_emit.c 7.5 (Berkeley) 5/30/90 * ! 33: * ! 34: * This file contains tp_emit() and tp_error_emit(), which ! 35: * form TPDUs and hand them to ip. ! 36: * They take data in the form of mbuf chain, allocate mbufs as ! 37: * necessary for headers, and set the fields as appropriate from ! 38: * information found in the tpcb and net-level pcb. ! 39: * ! 40: * The worst thing about this code is adding the variable-length ! 41: * options on a machine that requires alignment for any memory access ! 42: * that isn't of size 1. See the macro ADDOPTION() below. ! 43: * ! 44: * We don't do any concatenation. (There's a kludge to test the ! 45: * basic mechanism of separation under the 'w' tpdebug option, that's all.) ! 46: */ ! 47: ! 48: #ifndef lint ! 49: static char *rcsid = "$Header: tp_emit.c,v 5.5 88/11/18 17:27:20 nhall Exp $"; ! 50: #endif lint ! 51: ! 52: ! 53: #include "argoxtwentyfive.h" ! 54: #include "param.h" ! 55: #include "mbuf.h" ! 56: #include "socket.h" ! 57: #include "socketvar.h" ! 58: #include "protosw.h" ! 59: #include "errno.h" ! 60: #include "types.h" ! 61: #include "time.h" ! 62: #include "iso.h" ! 63: #include "argo_debug.h" ! 64: #include "tp_timer.h" ! 65: #include "tp_param.h" ! 66: #include "tp_stat.h" ! 67: #include "tp_pcb.h" ! 68: #include "tp_tpdu.h" ! 69: #include "tp_trace.h" ! 70: #include "tp_meas.h" ! 71: #include "tp_seq.h" ! 72: #include "iso_errno.h" ! 73: ! 74: void iso_gen_csum(); ! 75: ! 76: ! 77: /* Here is a mighty kludge. The token ring misorders packets if you ! 78: * fire them at it too fast, and TP sans checksum is "too fast", so ! 79: * we have introduced a delay when checksumming isn't used. ! 80: */ ! 81: char tp_delay = 0x00; /* delay to keep token ring from blowing it */ ! 82: ! 83: /* ! 84: * NAME: tp_emit() ! 85: * ! 86: * CALLED FROM: tp.trans and from tp_sbsend() ! 87: * ! 88: * FUNCTION and ARGUMENTS: ! 89: * Emits one tpdu of the type (dutype), of the format appropriate ! 90: * to the connection described by the pcb (tpcb), with sequence ! 91: * number (seq) (where appropriate), end-of-tsdu bit (eot) where ! 92: * appropriate, and with the data in the mbuf chain (data). ! 93: * For DR and ER tpdus, the argument (eot) is ! 94: * the reason for issuing the tpdu rather than an end-of-tsdu indicator. ! 95: * ! 96: * RETURNS: ! 97: * 0 OK ! 98: * ENOBUFS ! 99: * E* returned from net layer output rtn ! 100: * ! 101: * SIDE EFFECTS: ! 102: * ! 103: * NOTES: ! 104: * ! 105: * WE ASSUME that the tp header + all options will fit in ONE mbuf. ! 106: * If mbufs are 256 this will most likely be true, but if they are 128 it's ! 107: * possible that they won't. ! 108: * If you used every option on the CR + max. user data you'd overrun ! 109: * 112 but unless you used > 115 bytes for the security ! 110: * parameter, it would fit in a 256-byte mbuf (240 bytes for the header) ! 111: * We don't support the security parameter, so this isn't a problem. ! 112: * If security is added, we ought to remove this assumption. ! 113: * ! 114: * We do not implement the flow control confirmation "element of procedure". ! 115: * A) it should not affect interoperability, ! 116: * B) it should not be necessary - the protocol will eventually ! 117: * straighten things out w/o FCC, as long as we don't have severely ! 118: * mismatched keepalive and inactivity timers, and ! 119: * C) it appears not to be REQUIRED, and ! 120: * D) it's incredibly grotesque, and no doubt will lengthen a few ! 121: * critical paths. ! 122: * HOWEVER, we're thinking about putting it in anyway, for ! 123: * completeness, just like we did with ack subsequencing. ! 124: */ ! 125: ! 126: int ! 127: tp_emit(dutype, tpcb, seq, eot, data) ! 128: int dutype; ! 129: struct tp_pcb *tpcb; ! 130: SeqNum seq; ! 131: u_int eot; ! 132: struct mbuf *data; ! 133: { ! 134: register struct tpdu *hdr; ! 135: register struct mbuf *m; ! 136: int csum_offset=0; ! 137: int datalen = 0; ! 138: int error = 0; ! 139: ! 140: /* NOTE: ! 141: * here we treat tpdu_li as if it DID include the li field, up until ! 142: * the end, at which time we subtract 1 ! 143: * THis is because if we subtract 1 right away, we end up adding ! 144: * one every time we add an option. ! 145: */ ! 146: IFDEBUG(D_EMIT) ! 147: printf( ! 148: "tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x", ! 149: dutype, tpcb, eot, seq, data); ! 150: ENDDEBUG ! 151: ! 152: if (dutype == CR_TPDU || dutype == CC_TPDU) { ! 153: m = (struct mbuf *) malloc((u_long)256, M_MBUF, M_DONTWAIT); ! 154: if (m) { ! 155: m->m_type = TPMT_TPHDR; ! 156: mbstat.m_mtypes[TPMT_TPHDR]++; ! 157: m->m_next = MNULL; ! 158: m->m_data = m->m_dat; ! 159: m->m_flags = 0; ! 160: } ! 161: } else { ! 162: MGET(m, M_DONTWAIT, TPMT_TPHDR); ! 163: } ! 164: if (m == NULL) { ! 165: if(data != (struct mbuf *)0) ! 166: m_freem(data); ! 167: error = ENOBUFS; ! 168: goto done; ! 169: } ! 170: m->m_len = sizeof(struct tpdu); ! 171: m->m_act = MNULL; ! 172: ! 173: hdr = mtod(m, struct tpdu *); ! 174: bzero((caddr_t)hdr, sizeof(struct tpdu)); ! 175: ! 176: { ! 177: int tp_headersize(); ! 178: ! 179: hdr->tpdu_type = dutype; ! 180: hdr->tpdu_li = tp_headersize(dutype, tpcb); ! 181: /* ! 182: * class 0 doesn't use this for DT ! 183: * it'll just get overwritten below ! 184: */ ! 185: hdr->tpdu_dref = htons(tpcb->tp_fref); ! 186: if( tpcb->tp_use_checksum || ! 187: (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4) )) { ! 188: csum_offset = hdr->tpdu_li + 2; /* DOESN'T include csum */ ! 189: ADDOPTION(TPP_checksum, hdr, 2, eot /* dummy arg */); ! 190: IFDEBUG(D_CHKSUM) ! 191: printf( ! 192: "tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n", ! 193: csum_offset, hdr->tpdu_li); ! 194: ENDDEBUG ! 195: } ! 196: /* ! 197: * VARIABLE PARTS... ! 198: */ ! 199: switch( dutype ) { ! 200: ! 201: case CR_TPDU_type: ! 202: hdr->tpdu_CRdref_0 = 0; /* must be zero */ ! 203: if (!tpcb->tp_cebit_off) { ! 204: tpcb->tp_win_recv = tp_start_win << 8; ! 205: LOCAL_CREDIT(tpcb); ! 206: CONG_INIT_SAMPLE(tpcb); ! 207: tpcb->tp_ackrcvd = 0; ! 208: } ! 209: else ! 210: LOCAL_CREDIT(tpcb); ! 211: ! 212: ! 213: case CC_TPDU_type: ! 214: { ! 215: u_char x; ! 216: ! 217: hdr->tpdu_CCsref = htons(tpcb->tp_lref); /* same as CRsref */ ! 218: ! 219: if( tpcb->tp_class > TP_CLASS_1 ) { ! 220: /* ifdef CE_BIT, we did this in tp_input when the CR came in */ ! 221: if (tpcb->tp_cebit_off) ! 222: LOCAL_CREDIT( tpcb ); ! 223: tpcb->tp_sent_uwe = tpcb->tp_lcredit -1; ! 224: tpcb->tp_sent_rcvnxt = 1; ! 225: tpcb->tp_sent_lcdt = tpcb->tp_lcredit; ! 226: hdr->tpdu_cdt = tpcb->tp_lcredit; ! 227: } else { ! 228: hdr->tpdu_cdt = 0; ! 229: } ! 230: hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class); ! 231: hdr->tpdu_CCoptions = ! 232: (tpcb->tp_xtd_format? TPO_XTD_FMT:0) | ! 233: (tpcb->tp_use_efc? TPO_USE_EFC:0); ! 234: ! 235: IFPERF(tpcb) ! 236: u_char perf_meas = tpcb->tp_perf_on; ! 237: ADDOPTION(TPP_perf_meas, hdr, sizeof(perf_meas), perf_meas); ! 238: ENDPERF ! 239: ! 240: if( dutype == CR_TPDU_type ) { ! 241: IncStat(ts_CR_sent); ! 242: ! 243: ASSERT( tpcb->tp_lsuffixlen > 0 ); ! 244: ASSERT( tpcb->tp_fsuffixlen > 0 ); ! 245: ! 246: ADDOPTION(TPP_calling_sufx, hdr, ! 247: tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]); ! 248: ADDOPTION(TPP_called_sufx, hdr, ! 249: tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]); ! 250: } else { ! 251: IncStat(ts_CC_sent); ! 252: } ! 253: ! 254: ADDOPTION(TPP_tpdu_size, hdr, ! 255: sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize); ! 256: ! 257: if (tpcb->tp_class != TP_CLASS_0) { ! 258: short millisec = 500*(tpcb->tp_sendack_ticks); ! 259: ! 260: millisec = htons(millisec); ! 261: ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec); ! 262: ! 263: x = (tpcb->tp_use_nxpd? TPAO_USE_NXPD: 0) ! 264: | (tpcb->tp_use_rcc? TPAO_USE_RCC : 0) ! 265: | (tpcb->tp_use_checksum?0: TPAO_NO_CSUM) ! 266: | (tpcb->tp_xpd_service? TPAO_USE_TXPD: 0); ! 267: ADDOPTION(TPP_addl_opt, hdr, 1, x); ! 268: ! 269: } ! 270: ! 271: if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){ ! 272: ! 273: ASSERT( 1 == sizeof(tpcb->tp_vers) ); ! 274: ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers); ! 275: ! 276: /* for each alt protocol class x, ! 277: * x = x<<4; ! 278: * option = concat(option, x); ! 279: * Well, for now we only have TP0 for an ! 280: * alternative so... this is easy. ! 281: * ! 282: * HOWEVER... There should be NO alt protocol ! 283: * class over CLNS. Need to see if the route suggests ! 284: * CONS, and iff so add alt class. ! 285: */ ! 286: x = 0; ! 287: ADDOPTION(TPP_alt_class, hdr, 1, x); ! 288: } ! 289: ! 290: if( hdr->tpdu_li > MLEN) ! 291: panic("tp_emit CR/CC"); ! 292: } ! 293: break; ! 294: ! 295: case DR_TPDU_type: ! 296: if( hdr->tpdu_DRdref == 0 ) { ! 297: /* don't issue the DR */ ! 298: goto done; ! 299: } ! 300: hdr->tpdu_cdt = 0; ! 301: hdr->tpdu_DRsref = htons(tpcb->tp_lref); ! 302: hdr->tpdu_DRreason = (u_char)eot; /* WHICH BYTE OF THIS??? */ ! 303: ! 304: /* forget the add'l information variable part */ ! 305: IncStat(ts_DR_sent); ! 306: break; ! 307: ! 308: case DC_TPDU_type: /* not used in class 0 */ ! 309: ASSERT( tpcb->tp_class != TP_CLASS_0); ! 310: hdr->tpdu_DCsref = htons(tpcb->tp_lref); ! 311: hdr->tpdu_cdt = 0; ! 312: data = (struct mbuf *)0; ! 313: IncStat(ts_DC_sent); ! 314: break; ! 315: ! 316: case XAK_TPDU_type: /* xak not used in class 0 */ ! 317: ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */ ! 318: hdr->tpdu_cdt = 0; ! 319: ! 320: IFTRACE(D_XPD) ! 321: tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0); ! 322: ENDTRACE ! 323: data = (struct mbuf *)0; ! 324: if (tpcb->tp_xtd_format) { ! 325: #ifdef BYTE_ORDER ! 326: hdr->tpdu_XAKseqX = htonl(seq); ! 327: #else ! 328: hdr->tpdu_XAKseqX = seq; ! 329: #endif BYTE_ORDER ! 330: } else { ! 331: hdr->tpdu_XAKseq = seq; ! 332: } ! 333: IncStat(ts_XAK_sent); ! 334: IncPStat(tpcb, tps_XAK_sent); ! 335: break; ! 336: ! 337: case XPD_TPDU_type: /* xpd not used in class 0 */ ! 338: ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */ ! 339: hdr->tpdu_cdt = 0; ! 340: if (tpcb->tp_xtd_format) { ! 341: #ifdef BYTE_ORDER ! 342: union seq_type seqeotX; ! 343: ! 344: seqeotX.s_seq = seq; ! 345: seqeotX.s_eot = 1; ! 346: hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); ! 347: #else ! 348: hdr->tpdu_XPDseqX = seq; ! 349: hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */ ! 350: #endif BYTE_ORDER ! 351: } else { ! 352: hdr->tpdu_XPDseq = seq; ! 353: hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */ ! 354: } ! 355: IncStat(ts_XPD_sent); ! 356: IncPStat(tpcb, tps_XPD_sent); ! 357: ! 358: /* kludge to test the input size checking */ ! 359: IFDEBUG(D_SIZE_CHECK) ! 360: /*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) { ! 361: printf("Sending too much data on XPD: 18 bytes\n"); ! 362: data->m_len = 18; ! 363: }*/ ! 364: ENDDEBUG ! 365: break; ! 366: ! 367: case DT_TPDU_type: ! 368: hdr->tpdu_cdt = 0; ! 369: IFTRACE(D_DATA) ! 370: tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq, ! 371: hdr->tpdu_li, 0); ! 372: ENDTRACE ! 373: if (tpcb->tp_xtd_format) { ! 374: #ifdef BYTE_ORDER ! 375: union seq_type seqeotX; ! 376: ! 377: seqeotX.s_seq = seq; ! 378: seqeotX.s_eot = eot; ! 379: hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); ! 380: #else ! 381: hdr->tpdu_DTseqX = seq; ! 382: hdr->tpdu_DTeotX = eot; ! 383: #endif BYTE_ORDER ! 384: } else if (tpcb->tp_class == TP_CLASS_0) { ! 385: IFDEBUG(D_EMIT) ! 386: printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr); ! 387: dump_buf( hdr, hdr->tpdu_li + 1 ); ! 388: ENDDEBUG ! 389: ((struct tp0du *)hdr)->tp0du_eot = eot; ! 390: ((struct tp0du *)hdr)->tp0du_mbz = 0; ! 391: IFDEBUG(D_EMIT) ! 392: printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr); ! 393: dump_buf( hdr, hdr->tpdu_li + 1 ); ! 394: ENDDEBUG ! 395: } else { ! 396: hdr->tpdu_DTseq = seq; ! 397: hdr->tpdu_DTeot = eot; ! 398: } ! 399: if(eot) { ! 400: IncStat(ts_EOT_sent); ! 401: } ! 402: IncStat(ts_DT_sent); ! 403: IncPStat(tpcb, tps_DT_sent); ! 404: break; ! 405: ! 406: case AK_TPDU_type:/* ak not used in class 0 */ ! 407: ASSERT( tpcb->tp_class != TP_CLASS_0); ! 408: data = (struct mbuf *)0; ! 409: { SeqNum olduwe = tpcb->tp_sent_uwe; ! 410: ! 411: tpcb->tp_sent_uwe = ! 412: SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1); ! 413: LOCAL_CREDIT( tpcb ); ! 414: tpcb->tp_sent_lcdt = tpcb->tp_lcredit; ! 415: ! 416: IFDEBUG(D_RENEG) ! 417: /* occasionally fake a reneging so ! 418: you can test subsequencing */ ! 419: if( olduwe & 0x1 ) { ! 420: tpcb->tp_reneged = 1; ! 421: IncStat(ts_ldebug); ! 422: } ! 423: ENDDEBUG ! 424: /* Are we about to reneg on credit? ! 425: * When might we do so? ! 426: * a) when using optimistic credit (which we no longer do). ! 427: * b) when drain() gets implemented (not in the plans). ! 428: * c) when D_RENEG is on. ! 429: * d) when DEC BIT response is implemented. ! 430: * (not- when we do this, we'll need to implement flow control ! 431: * confirmation) ! 432: */ ! 433: if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) { ! 434: tpcb->tp_reneged = 1; ! 435: IncStat(ts_lcdt_reduced); ! 436: IFTRACE(D_CREDIT) ! 437: tptraceTPCB(TPPTmisc, ! 438: "RENEG: olduwe newuwe lcredit rcvnxt", ! 439: olduwe, ! 440: tpcb->tp_sent_uwe, tpcb->tp_lcredit, ! 441: tpcb->tp_rcvnxt); ! 442: ENDTRACE ! 443: } ! 444: ! 445: IFPERF(tpcb) ! 446: /* new lwe is less than old uwe means we're ! 447: * acking before we received a whole window full ! 448: */ ! 449: if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) { ! 450: /* tmp1 = number of pkts fewer than the full window */ ! 451: register int tmp1 = ! 452: (int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt); ! 453: ! 454: if(tmp1 > TP_PM_MAX) ! 455: tmp1 = TP_PM_MAX; ! 456: IncPStat( tpcb, tps_ack_early[tmp1] ); ! 457: ! 458: /* tmp1 = amt of new cdt we're advertising */ ! 459: tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt); ! 460: if(tmp1 > TP_PM_MAX ) ! 461: tmp1 = TP_PM_MAX; ! 462: ! 463: IncPStat( tpcb, ! 464: tps_cdt_acked [ tmp1 ] ! 465: [ ((tpcb->tp_lcredit > TP_PM_MAX)? ! 466: TP_PM_MAX:tpcb->tp_lcredit) ] ); ! 467: ! 468: } ! 469: ENDPERF ! 470: } ! 471: IFTRACE(D_ACKSEND) ! 472: tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe, ! 473: tpcb->tp_r_subseq, 0); ! 474: ENDTRACE ! 475: if (tpcb->tp_xtd_format) { ! 476: #ifdef BYTE_ORDER ! 477: hdr->tpdu_cdt = 0; ! 478: hdr->tpdu_AKseqX = htonl(seq); ! 479: hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit); ! 480: #else ! 481: hdr->tpdu_cdt = 0; ! 482: hdr->tpdu_AKseqX = seq; ! 483: hdr->tpdu_AKcdtX = tpcb->tp_lcredit; ! 484: #endif BYTE_ORDER ! 485: } else { ! 486: hdr->tpdu_AKseq = seq; ! 487: hdr->tpdu_AKcdt = tpcb->tp_lcredit; ! 488: } ! 489: if ((tpcb->tp_class == TP_CLASS_4) && tpcb->tp_reneged ) { ! 490: /* ! 491: * Ack subsequence parameter req'd if WE reneged on ! 492: * credit offered. (ISO 8073, 12.2.3.8.2, p. 74) ! 493: */ ! 494: IFDEBUG(D_RENEG) ! 495: printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq); ! 496: ENDDEBUG ! 497: tpcb->tp_s_subseq++; ! 498: /* ! 499: * add tmp subseq and do a htons on it. ! 500: */ ! 501: ADDOPTION(TPP_subseq, hdr, ! 502: sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq); ! 503: } else ! 504: tpcb->tp_s_subseq = 0; ! 505: ! 506: if ( tpcb->tp_sendfcc || eot ) /* overloaded to mean SEND FCC */ { ! 507: /* ! 508: * Rules for sending FCC ("should" send when) : ! 509: * %a) received an ack from peer with NO NEWS whatsoever, ! 510: * and it did not contain an FCC ! 511: * b) received an ack from peer that opens its closed window. ! 512: * c) received an ack from peer after it reneged on its ! 513: * offered credit, AND this ack raises UWE but LWE is same ! 514: * and below UWE at time of reneging (reduction) ! 515: * Now, ISO 8073 12.2.3.8.3 says ! 516: * that a retransmitted AK shall not contain the FCC ! 517: * parameter. Now, how the hell you tell the difference ! 518: * between a retransmitted ack and an ack that's sent in ! 519: * response to a received ack, I don't know, because without ! 520: * any local activity, and w/o any received DTs, they ! 521: * will contain exactly the same credit/seq# information. ! 522: * Anyway, given that the "retransmission of acks" ! 523: * procedure (ISO 8073 12.2.3.8.3) is optional, and we ! 524: * don't do it (although the peer can't tell that), we ! 525: * ignore this last rule. ! 526: * ! 527: * We send FCC for reasons a) and b) only. ! 528: * To add reason c) would require a ridiculous amount of state. ! 529: * ! 530: */ ! 531: u_short bogus[4]; /* lwe(32), subseq(16), cdt(16) */ ! 532: SeqNum lwe; ! 533: u_short subseq, fcredit; ! 534: ! 535: tpcb->tp_sendfcc = 0; ! 536: ! 537: lwe = (SeqNum) htonl(tpcb->tp_snduna); ! 538: subseq = htons(tpcb->tp_r_subseq); ! 539: fcredit = htons(tpcb->tp_fcredit); ! 540: ! 541: bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum)); ! 542: bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short)); ! 543: bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short)); ! 544: ! 545: IFTRACE(D_ACKSEND) ! 546: tptraceTPCB(TPPTmisc, ! 547: "emit w/FCC: snduna r_subseq fcredit", ! 548: tpcb->tp_snduna, tpcb->tp_r_subseq, ! 549: tpcb->tp_fcredit, 0); ! 550: ENDTRACE ! 551: ! 552: IFDEBUG(D_ACKSEND) ! 553: printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n", ! 554: TPP_flow_cntl_conf, ! 555: hdr, sizeof(bogus), bogus[0]); ! 556: ENDDEBUG ! 557: ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]); ! 558: IFDEBUG(D_ACKSEND) ! 559: printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n", ! 560: hdr, hdr->tpdu_li); ! 561: printf( ! 562: "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", ! 563: csum_offset, hdr->tpdu_li); ! 564: ENDDEBUG ! 565: ! 566: } ! 567: tpcb->tp_reneged = 0; ! 568: tpcb->tp_sent_rcvnxt = seq; ! 569: tp_ctimeout(tpcb->tp_refp, TM_sendack, ! 570: (int)tpcb->tp_keepalive_ticks); ! 571: IncStat(ts_AK_sent); ! 572: IncPStat(tpcb, tps_AK_sent); ! 573: IFDEBUG(D_ACKSEND) ! 574: printf( ! 575: "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", ! 576: csum_offset, hdr->tpdu_li); ! 577: ENDDEBUG ! 578: break; ! 579: ! 580: case ER_TPDU_type: ! 581: hdr->tpdu_ERreason = eot; ! 582: hdr->tpdu_cdt = 0; ! 583: /* no user data */ ! 584: data = (struct mbuf *)0; ! 585: IncStat(ts_ER_sent); ! 586: break; ! 587: } ! 588: ! 589: } ! 590: ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) ); ! 591: ! 592: m->m_next = data; ! 593: ! 594: ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */ ! 595: ASSERT( hdr->tpdu_li != 0 ); /* leave this in */ ! 596: ! 597: m->m_len = hdr->tpdu_li ; ! 598: hdr->tpdu_li --; /* doesn't include the li field */ ! 599: ! 600: datalen = m_datalen( m ); /* total len */ ! 601: ! 602: ASSERT( datalen <= tpcb->tp_l_tpdusize ); /* may become a problem ! 603: when CLNP is used; leave in here for the time being */ ! 604: IFDEBUG(D_ACKSEND) ! 605: printf( ! 606: "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", ! 607: csum_offset, hdr->tpdu_li); ! 608: ENDDEBUG ! 609: if( datalen > tpcb->tp_l_tpdusize ) { ! 610: printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n", ! 611: datalen, tpcb->tp_l_tpdusize); ! 612: } ! 613: IFDEBUG(D_EMIT) ! 614: printf( ! 615: "tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n", ! 616: m->m_len, csum_offset, datalen); ! 617: ENDDEBUG ! 618: if( tpcb->tp_use_checksum || ! 619: (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) { ! 620: iso_gen_csum(m, csum_offset, datalen); ! 621: } ! 622: ! 623: IFDEBUG(D_EMIT) ! 624: printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n", ! 625: tpcb, dutype, datalen); ! 626: dump_buf(mtod(m, caddr_t), datalen); ! 627: ENDDEBUG ! 628: ! 629: IFPERF(tpcb) ! 630: if( dutype == DT_TPDU_type ) { ! 631: PStat(tpcb, Nb_to_ll) += (datalen - m->m_len); ! 632: tpmeas( tpcb->tp_lref, TPtime_to_ll, (struct timeval *)0, ! 633: seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len)); ! 634: } ! 635: ENDPERF ! 636: ! 637: IFTRACE(D_EMIT) ! 638: tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0); ! 639: ENDTRACE ! 640: IFDEBUG(D_EMIT) ! 641: printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n", ! 642: tpcb, tpcb->tp_npcb, tpcb->tp_sock); ! 643: ENDDEBUG ! 644: ! 645: { extern char tp_delay; ! 646: ! 647: if( tp_delay ) ! 648: if( tpcb->tp_use_checksum == 0 ) { ! 649: register u_int i = tp_delay; ! 650: for (; i!= 0; i--) ! 651: (void) iso_check_csum(m, datalen); ! 652: } ! 653: } ! 654: ASSERT( m->m_len > 0 ); ! 655: error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen, ! 656: !tpcb->tp_use_checksum); ! 657: IFDEBUG(D_EMIT) ! 658: printf("OUTPUT: returned 0x%x\n", error); ! 659: ENDDEBUG ! 660: IFTRACE(D_EMIT) ! 661: tptraceTPCB(TPPTmisc, ! 662: "tp_emit nlproto->output netservice returns datalen", ! 663: tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen); ! 664: ENDTRACE ! 665: done: ! 666: if( error == E_CO_QFULL ) { ! 667: tp_quench(tpcb, PRC_QUENCH); ! 668: return 0; ! 669: } ! 670: return error; ! 671: } ! 672: /* ! 673: * NAME: tp_error_emit() ! 674: * CALLED FROM: tp_input() when a DR or ER is to be issued in ! 675: * response to an input error. ! 676: * FUNCTION and ARGUMENTS: ! 677: * The error type is the first argument. ! 678: * The argument (sref) is the source reference on the bad incoming tpdu, ! 679: * and is used for a destination reference on the outgoing packet. ! 680: * (faddr) and (laddr) are the foreign and local addresses for this ! 681: * connection. ! 682: * (erdata) is a ptr to the errant incoming tpdu, and is copied into the ! 683: * outgoing ER, if an ER is to be issued. ! 684: * (erlen) is the number of octets of the errant tpdu that we should ! 685: * try to copy. ! 686: * (tpcb) is the pcb that describes the connection for which the bad tpdu ! 687: * arrived. ! 688: * RETURN VALUES: ! 689: * 0 OK ! 690: * ENOBUFS ! 691: * E* from net layer datagram output routine ! 692: * SIDE EFFECTS: ! 693: * ! 694: * NOTES: ! 695: */ ! 696: ! 697: int ! 698: tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel, ! 699: dgout_routine) ! 700: int error; ! 701: u_long sref; ! 702: struct sockaddr_iso *faddr, *laddr; ! 703: struct mbuf *erdata; ! 704: int erlen; ! 705: struct tp_pcb *tpcb; ! 706: int cons_channel; ! 707: int (*dgout_routine)(); ! 708: { ! 709: int dutype; ! 710: int datalen = 0; ! 711: register struct tpdu *hdr; ! 712: register struct mbuf *m; ! 713: int csum_offset; ! 714: ! 715: IFTRACE(D_ERROR_EMIT) ! 716: tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen", ! 717: error, sref, tpcb, erlen); ! 718: ENDTRACE ! 719: IFDEBUG(D_ERROR_EMIT) ! 720: printf( ! 721: "tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n", ! 722: error, sref, tpcb, erlen, cons_channel); ! 723: ENDDEBUG ! 724: ! 725: MGET(m, M_DONTWAIT, TPMT_TPHDR); ! 726: if (m == NULL) { ! 727: return ENOBUFS; ! 728: } ! 729: m->m_len = sizeof(struct tpdu); ! 730: m->m_act = MNULL; ! 731: ! 732: hdr = mtod(m, struct tpdu *); ! 733: ! 734: IFDEBUG(D_ERROR_EMIT) ! 735: printf("[error 0x%x] [error&0xff 0x%x] [(char)error 0x%x]\n", ! 736: error, error&0xff, (char)error); ! 737: ENDDEBUG ! 738: ! 739: ! 740: if (error & TP_ERROR_SNDC) ! 741: dutype = DC_TPDU_type; ! 742: else if (error & 0x40) { ! 743: error &= ~0x40; ! 744: dutype = ER_TPDU_type; ! 745: } else ! 746: dutype = DR_TPDU_type; ! 747: error &= 0xff; ! 748: ! 749: hdr->tpdu_type = dutype; ! 750: hdr->tpdu_cdt = 0; ! 751: ! 752: switch( dutype ) { ! 753: ! 754: case DC_TPDU_type: ! 755: IncStat(ts_DC_sent); ! 756: hdr->tpdu_li = 6; ! 757: hdr->tpdu_DCdref = htons(sref); ! 758: hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0; ! 759: IFDEBUG(D_ERROR_EMIT) ! 760: printf("DC case:\n"); ! 761: dump_buf( hdr, 6); ! 762: ENDDEBUG ! 763: /* forget the add'l information variable part */ ! 764: break; ! 765: ! 766: case DR_TPDU_type: ! 767: IncStat(ts_DR_sent); ! 768: hdr->tpdu_li = 7; ! 769: hdr->tpdu_DRdref = htons(sref); ! 770: hdr->tpdu_DRsref = 0; ! 771: hdr->tpdu_DRreason = (char)error; ! 772: IFDEBUG(D_ERROR_EMIT) ! 773: printf("DR case:\n"); ! 774: dump_buf( hdr, 7); ! 775: ENDDEBUG ! 776: /* forget the add'l information variable part */ ! 777: break; ! 778: ! 779: case ER_TPDU_type: ! 780: IncStat(ts_ER_sent); ! 781: hdr->tpdu_li = 5; ! 782: hdr->tpdu_ERreason = (char)error; ! 783: break; ! 784: ! 785: default: ! 786: ASSERT(0); ! 787: printf("TP PANIC: bad dutype 0x%x\n", dutype); ! 788: } ! 789: ! 790: if(tpcb) ! 791: if( tpcb->tp_use_checksum ) { ! 792: ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */); ! 793: csum_offset = hdr->tpdu_li - 2; ! 794: } ! 795: ! 796: ASSERT( hdr->tpdu_li < MLEN ); ! 797: ! 798: if (dutype == ER_TPDU_type) { ! 799: /* copy the errant tpdu into another 'variable part' */ ! 800: register caddr_t P; ! 801: ! 802: IFTRACE(D_ERROR_EMIT) ! 803: tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li, ! 804: 0,0); ! 805: ENDTRACE ! 806: IFDEBUG(D_ERROR_EMIT) ! 807: printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li); ! 808: ENDDEBUG ! 809: ! 810: /* copy at most as many octets for which you have room */ ! 811: if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN) ! 812: erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2; ! 813: ! 814: /* add the "invalid tpdu" parameter : required in class 0 */ ! 815: P = (caddr_t)hdr + (int)(hdr->tpdu_li); ! 816: vbptr(P)->tpv_code = TPP_invalid_tpdu; /* parameter code */ ! 817: vbptr(P)->tpv_len = erlen; /* parameter length */ ! 818: m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */ ! 819: ! 820: /* tp_input very likely handed us an mbuf chain w/ nothing in ! 821: * the first mbuf and the data following the empty mbuf ! 822: */ ! 823: if(erdata->m_len == 0) { ! 824: erdata = m_free(erdata); /* returns the next mbuf on the chain */ ! 825: } ! 826: /* ! 827: * copy only up to the bad octet ! 828: * (or max that will fit in a header ! 829: */ ! 830: m->m_next = m_copy(erdata, 0, erlen); ! 831: hdr->tpdu_li += erlen + 2; ! 832: m_freem(erdata); ! 833: } else { ! 834: IFDEBUG(D_ERROR_EMIT) ! 835: printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li); ! 836: dump_buf( (char *)hdr, hdr->tpdu_li ); ! 837: ENDDEBUG ! 838: m->m_len = hdr->tpdu_li ; ! 839: m_freem(erdata); ! 840: } ! 841: ! 842: hdr->tpdu_li --; ! 843: IFTRACE(D_ERROR_EMIT) ! 844: tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0); ! 845: ENDTRACE ! 846: ! 847: datalen = m_datalen( m); ! 848: ! 849: if(tpcb) { ! 850: if( tpcb->tp_use_checksum ) { ! 851: IFTRACE(D_ERROR_EMIT) ! 852: tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0); ! 853: ENDTRACE ! 854: IFDEBUG(D_ERROR_EMIT) ! 855: printf("before gen csum datalen 0x%x, csum_offset 0x%x\n", ! 856: datalen, csum_offset); ! 857: ENDDEBUG ! 858: ! 859: iso_gen_csum(m, csum_offset, datalen); ! 860: } ! 861: ! 862: IFDEBUG(D_ERROR_EMIT) ! 863: printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n", ! 864: tpcb, tpcb->tp_npcb, tpcb->tp_sock); ! 865: ENDDEBUG ! 866: /* Problem: if packet comes in on ISO but sock is listening ! 867: * in INET, this assertion will fail. ! 868: * Have to believe the argument, not the nlp_proto. ! 869: ASSERT( tpcb->tp_nlproto->nlp_dgoutput == dgout_routine ); ! 870: */ ! 871: ! 872: IFDEBUG(D_ERROR_EMIT) ! 873: printf("tp_error_emit 1 sending DG: Laddr\n"); ! 874: dump_addr((struct sockaddr *)laddr); ! 875: printf("Faddr\n"); ! 876: dump_addr((struct sockaddr *)faddr); ! 877: ENDDEBUG ! 878: return (tpcb->tp_nlproto->nlp_dgoutput)( ! 879: &laddr->siso_addr, ! 880: &faddr->siso_addr, ! 881: m, datalen, ! 882: /* no route */ (caddr_t)0, !tpcb->tp_use_checksum); ! 883: } else { ! 884: if( cons_channel ) { ! 885: #if NARGOXTWENTYFIVE > 0 ! 886: #include "cons.h" ! 887: /* This is unfortunate... ! 888: cons_send_on_vc(cons_channel, m, datalen); ! 889: */ ! 890: cons_netcmd( CONN_CLOSE, (struct isopcb *)0, ! 891: cons_channel, CONS_NOT_DGM); ! 892: IFDEBUG(D_ERROR_EMIT) ! 893: printf("OUTPUT: dutype 0x%x channel 0x%x\n", ! 894: dutype, cons_channel); ! 895: ENDDEBUG ! 896: #else NARGOXTWENTYFIVE ! 897: printf("TP panic! cons channel 0x%x but not cons configured\n", ! 898: cons_channel); ! 899: #endif NARGOXTWENTYFIVE > 0 ! 900: } else { ! 901: #ifndef notdef ! 902: IFDEBUG(D_ERROR_EMIT) ! 903: printf("tp_error_emit sending DG: Laddr\n"); ! 904: dump_addr((struct sockaddr *)laddr); ! 905: printf("Faddr\n"); ! 906: dump_addr((struct sockaddr *)faddr); ! 907: ENDDEBUG ! 908: return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr, ! 909: m, datalen, /* no route */ ! 910: (caddr_t)0, /* nochecksum==false */0); ! 911: #else notdef ! 912: IFDEBUG(D_ERROR_EMIT) ! 913: printf("tp_error_emit DROPPING \n", m); ! 914: ENDDEBUG ! 915: IncStat(ts_send_drop); ! 916: m_freem(m); ! 917: return 0; ! 918: #endif notdef ! 919: } ! 920: } ! 921: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.