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