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