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