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.13 (Berkeley) 12/17/91 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 if (!tpcb->tp_cebit_off) { 220 tpcb->tp_win_recv = tp_start_win << 8; 221 LOCAL_CREDIT(tpcb); 222 CONG_INIT_SAMPLE(tpcb); 223 } else 224 LOCAL_CREDIT(tpcb); 225 226 227 case CC_TPDU_type: 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 /* ifdef CE_BIT, we did this in tp_input when the CR came in */ 235 if (tpcb->tp_cebit_off) 236 LOCAL_CREDIT( tpcb ); 237 tpcb->tp_sent_uwe = tpcb->tp_lcredit -1; 238 tpcb->tp_sent_rcvnxt = 1; 239 tpcb->tp_sent_lcdt = tpcb->tp_lcredit; 240 hdr->tpdu_cdt = tpcb->tp_lcredit; 241 } else { 242 #ifdef TPCONS 243 if (tpcb->tp_netservice == ISO_CONS) { 244 struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 245 struct pklcd *lcp = (struct pklcd *)(isop->isop_chan); 246 lcp->lcd_flags &= ~X25_DG_CIRCUIT; 247 } 248 #endif 249 hdr->tpdu_cdt = 0; 250 } 251 hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class); 252 hdr->tpdu_CCoptions = 253 (tpcb->tp_xtd_format? TPO_XTD_FMT:0) | 254 (tpcb->tp_use_efc? TPO_USE_EFC:0); 255 256 IFPERF(tpcb) 257 u_char perf_meas = tpcb->tp_perf_on; 258 ADDOPTION(TPP_perf_meas, hdr, sizeof(perf_meas), perf_meas); 259 ENDPERF 260 261 if( dutype == CR_TPDU_type ) { 262 IncStat(ts_CR_sent); 263 264 ASSERT( tpcb->tp_lsuffixlen > 0 ); 265 ASSERT( tpcb->tp_fsuffixlen > 0 ); 266 267 ADDOPTION(TPP_calling_sufx, hdr, 268 tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]); 269 ADDOPTION(TPP_called_sufx, hdr, 270 tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]); 271 } else { 272 IncStat(ts_CC_sent); 273 } 274 275 ADDOPTION(TPP_tpdu_size, hdr, 276 sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize); 277 278 if (tpcb->tp_class != TP_CLASS_0) { 279 short millisec = 500*(tpcb->tp_sendack_ticks); 280 281 millisec = htons(millisec); 282 ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec); 283 284 x = (tpcb->tp_use_nxpd? TPAO_USE_NXPD: 0) 285 | (tpcb->tp_use_rcc? TPAO_USE_RCC : 0) 286 | (tpcb->tp_use_checksum?0: TPAO_NO_CSUM) 287 | (tpcb->tp_xpd_service? TPAO_USE_TXPD: 0); 288 ADDOPTION(TPP_addl_opt, hdr, 1, x); 289 290 if ((tpcb->tp_l_tpdusize ^ (1 << tpcb->tp_tpdusize)) != 0) { 291 u_short size_s = tpcb->tp_l_tpdusize >> 7; 292 u_char size_c = size_s; 293 ASSERT(tpcb->tp_l_tpdusize < 65536 * 128); 294 if (dutype == CR_TPDU_type) 295 tpcb->tp_ptpdusize = size_s; 296 if (size_s < 256) { 297 ADDOPTION(TPP_ptpdu_size, hdr, 1, size_c); 298 } else { 299 size_s = htons(size_s); 300 ADDOPTION(TPP_ptpdu_size, hdr, 2, size_s); 301 } 302 } 303 } 304 305 if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){ 306 307 ASSERT( 1 == sizeof(tpcb->tp_vers) ); 308 ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers); 309 310 /* for each alt protocol class x, 311 * x = x<<4; 312 * option = concat(option, x); 313 * Well, for now we only have TP0 for an 314 * alternative so... this is easy. 315 * 316 * HOWEVER... There should be NO alt protocol 317 * class over CLNS. Need to see if the route suggests 318 * CONS, and iff so add alt class. 319 */ 320 x = 0; 321 ADDOPTION(TPP_alt_class, hdr, 1, x); 322 } 323 324 if( hdr->tpdu_li > MLEN) 325 panic("tp_emit CR/CC"); 326 } 327 break; 328 329 case DR_TPDU_type: 330 if( hdr->tpdu_DRdref == 0 ) { 331 /* don't issue the DR */ 332 goto done; 333 } 334 hdr->tpdu_cdt = 0; 335 hdr->tpdu_DRsref = htons(tpcb->tp_lref); 336 hdr->tpdu_DRreason = (u_char)eot; /* WHICH BYTE OF THIS??? */ 337 338 /* forget the add'l information variable part */ 339 IncStat(ts_DR_sent); 340 break; 341 342 case DC_TPDU_type: /* not used in class 0 */ 343 ASSERT( tpcb->tp_class != TP_CLASS_0); 344 hdr->tpdu_DCsref = htons(tpcb->tp_lref); 345 hdr->tpdu_cdt = 0; 346 data = (struct mbuf *)0; 347 IncStat(ts_DC_sent); 348 break; 349 350 case XAK_TPDU_type: /* xak not used in class 0 */ 351 ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */ 352 hdr->tpdu_cdt = 0; 353 354 IFTRACE(D_XPD) 355 tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0); 356 ENDTRACE 357 data = (struct mbuf *)0; 358 if (tpcb->tp_xtd_format) { 359 #ifdef BYTE_ORDER 360 union seq_type seqeotX; 361 362 seqeotX.s_seq = seq; 363 seqeotX.s_eot = 1; 364 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); 365 #else 366 hdr->tpdu_XAKseqX = seq; 367 #endif BYTE_ORDER 368 } else { 369 hdr->tpdu_XAKseq = seq; 370 } 371 IncStat(ts_XAK_sent); 372 IncPStat(tpcb, tps_XAK_sent); 373 break; 374 375 case XPD_TPDU_type: /* xpd not used in class 0 */ 376 ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */ 377 hdr->tpdu_cdt = 0; 378 if (tpcb->tp_xtd_format) { 379 #ifdef BYTE_ORDER 380 union seq_type seqeotX; 381 382 seqeotX.s_seq = seq; 383 seqeotX.s_eot = 1; 384 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); 385 #else 386 hdr->tpdu_XPDseqX = seq; 387 hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */ 388 #endif BYTE_ORDER 389 } else { 390 hdr->tpdu_XPDseq = seq; 391 hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */ 392 } 393 IncStat(ts_XPD_sent); 394 IncPStat(tpcb, tps_XPD_sent); 395 396 /* kludge to test the input size checking */ 397 IFDEBUG(D_SIZE_CHECK) 398 /*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) { 399 printf("Sending too much data on XPD: 18 bytes\n"); 400 data->m_len = 18; 401 }*/ 402 ENDDEBUG 403 break; 404 405 case DT_TPDU_type: 406 hdr->tpdu_cdt = 0; 407 IFTRACE(D_DATA) 408 tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq, 409 hdr->tpdu_li, 0); 410 ENDTRACE 411 if (tpcb->tp_xtd_format) { 412 #ifdef BYTE_ORDER 413 union seq_type seqeotX; 414 415 seqeotX.s_seq = seq; 416 seqeotX.s_eot = eot; 417 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); 418 #else 419 hdr->tpdu_DTseqX = seq; 420 hdr->tpdu_DTeotX = eot; 421 #endif BYTE_ORDER 422 } else if (tpcb->tp_class == TP_CLASS_0) { 423 IFDEBUG(D_EMIT) 424 printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr); 425 dump_buf( hdr, hdr->tpdu_li + 1 ); 426 ENDDEBUG 427 ((struct tp0du *)hdr)->tp0du_eot = eot; 428 ((struct tp0du *)hdr)->tp0du_mbz = 0; 429 IFDEBUG(D_EMIT) 430 printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr); 431 dump_buf( hdr, hdr->tpdu_li + 1 ); 432 ENDDEBUG 433 } else { 434 hdr->tpdu_DTseq = seq; 435 hdr->tpdu_DTeot = eot; 436 } 437 if(eot) { 438 IncStat(ts_EOT_sent); 439 } 440 IncStat(ts_DT_sent); 441 IncPStat(tpcb, tps_DT_sent); 442 break; 443 444 case AK_TPDU_type:/* ak not used in class 0 */ 445 ASSERT( tpcb->tp_class != TP_CLASS_0); 446 data = (struct mbuf *)0; 447 olduwe = tpcb->tp_sent_uwe; 448 449 if (seq != tpcb->tp_sent_rcvnxt || tpcb->tp_rsycnt == 0) { 450 LOCAL_CREDIT( tpcb ); 451 tpcb->tp_sent_uwe = 452 SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1); 453 tpcb->tp_sent_lcdt = tpcb->tp_lcredit; 454 acking_ooo = 0; 455 } else 456 acking_ooo = 1; 457 458 IFDEBUG(D_RENEG) 459 /* occasionally fake a reneging so 460 you can test subsequencing */ 461 if( olduwe & 0x1 ) { 462 tpcb->tp_reneged = 1; 463 IncStat(ts_ldebug); 464 } 465 ENDDEBUG 466 /* Are we about to reneg on credit? 467 * When might we do so? 468 * a) when using optimistic credit (which we no longer do). 469 * b) when drain() gets implemented (not in the plans). 470 * c) when D_RENEG is on. 471 * d) when DEC BIT response is implemented. 472 * (not- when we do this, we'll need to implement flow control 473 * confirmation) 474 */ 475 if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) { 476 tpcb->tp_reneged = 1; 477 IncStat(ts_lcdt_reduced); 478 IFTRACE(D_CREDIT) 479 tptraceTPCB(TPPTmisc, 480 "RENEG: olduwe newuwe lcredit rcvnxt", 481 olduwe, 482 tpcb->tp_sent_uwe, tpcb->tp_lcredit, 483 tpcb->tp_rcvnxt); 484 ENDTRACE 485 } 486 IFPERF(tpcb) 487 /* new lwe is less than old uwe means we're 488 * acking before we received a whole window full 489 */ 490 if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) { 491 /* tmp1 = number of pkts fewer than the full window */ 492 register int tmp1 = 493 (int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt); 494 495 if(tmp1 > TP_PM_MAX) 496 tmp1 = TP_PM_MAX; 497 IncPStat( tpcb, tps_ack_early[tmp1] ); 498 499 /* tmp1 = amt of new cdt we're advertising */ 500 tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt); 501 if(tmp1 > TP_PM_MAX ) 502 tmp1 = TP_PM_MAX; 503 504 IncPStat( tpcb, 505 tps_cdt_acked [ tmp1 ] 506 [ ((tpcb->tp_lcredit > TP_PM_MAX)? 507 TP_PM_MAX:tpcb->tp_lcredit) ] ); 508 509 } 510 ENDPERF 511 512 IFTRACE(D_ACKSEND) 513 tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe, 514 tpcb->tp_r_subseq, 0); 515 ENDTRACE 516 if (tpcb->tp_xtd_format) { 517 #ifdef BYTE_ORDER 518 union seq_type seqeotX; 519 520 seqeotX.s_seq = seq; 521 seqeotX.s_eot = 0; 522 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); 523 hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit); 524 #else 525 hdr->tpdu_cdt = 0; 526 hdr->tpdu_AKseqX = seq; 527 hdr->tpdu_AKcdtX = tpcb->tp_lcredit; 528 #endif BYTE_ORDER 529 } else { 530 hdr->tpdu_AKseq = seq; 531 hdr->tpdu_AKcdt = tpcb->tp_lcredit; 532 } 533 if ((tpcb->tp_class == TP_CLASS_4) && 534 (tpcb->tp_reneged || acking_ooo)) { 535 /* 536 * Ack subsequence parameter req'd if WE reneged on 537 * credit offered. (ISO 8073, 12.2.3.8.2, p. 74) 538 */ 539 IFDEBUG(D_RENEG) 540 printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq); 541 ENDDEBUG 542 tpcb->tp_s_subseq++; 543 /* 544 * add tmp subseq and do a htons on it. 545 */ 546 ADDOPTION(TPP_subseq, hdr, 547 sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq); 548 } else 549 tpcb->tp_s_subseq = 0; 550 551 if ( tpcb->tp_sendfcc || eot ) /* overloaded to mean SEND FCC */ { 552 /* 553 * Rules for sending FCC ("should" send when) : 554 * %a) received an ack from peer with NO NEWS whatsoever, 555 * and it did not contain an FCC 556 * b) received an ack from peer that opens its closed window. 557 * c) received an ack from peer after it reneged on its 558 * offered credit, AND this ack raises UWE but LWE is same 559 * and below UWE at time of reneging (reduction) 560 * Now, ISO 8073 12.2.3.8.3 says 561 * that a retransmitted AK shall not contain the FCC 562 * parameter. Now, how the hell you tell the difference 563 * between a retransmitted ack and an ack that's sent in 564 * response to a received ack, I don't know, because without 565 * any local activity, and w/o any received DTs, they 566 * will contain exactly the same credit/seq# information. 567 * Anyway, given that the "retransmission of acks" 568 * procedure (ISO 8073 12.2.3.8.3) is optional, and we 569 * don't do it (although the peer can't tell that), we 570 * ignore this last rule. 571 * 572 * We send FCC for reasons a) and b) only. 573 * To add reason c) would require a ridiculous amount of state. 574 * 575 */ 576 u_short bogus[4]; /* lwe(32), subseq(16), cdt(16) */ 577 SeqNum lwe; 578 u_short subseq, fcredit; 579 580 tpcb->tp_sendfcc = 0; 581 582 lwe = (SeqNum) htonl(tpcb->tp_snduna); 583 subseq = htons(tpcb->tp_r_subseq); 584 fcredit = htons(tpcb->tp_fcredit); 585 586 bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum)); 587 bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short)); 588 bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short)); 589 590 IFTRACE(D_ACKSEND) 591 tptraceTPCB(TPPTmisc, 592 "emit w/FCC: snduna r_subseq fcredit", 593 tpcb->tp_snduna, tpcb->tp_r_subseq, 594 tpcb->tp_fcredit, 0); 595 ENDTRACE 596 597 IFDEBUG(D_ACKSEND) 598 printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n", 599 TPP_flow_cntl_conf, 600 hdr, sizeof(bogus), bogus[0]); 601 ENDDEBUG 602 ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]); 603 IFDEBUG(D_ACKSEND) 604 printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n", 605 hdr, hdr->tpdu_li); 606 printf( 607 "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", 608 csum_offset, hdr->tpdu_li); 609 ENDDEBUG 610 611 } 612 tpcb->tp_reneged = 0; 613 tpcb->tp_sent_rcvnxt = seq; 614 if (tpcb->tp_fcredit == 0) { 615 int timo = tpcb->tp_keepalive_ticks; 616 if (tpcb->tp_rxtshift < TP_MAXRXTSHIFT) 617 tpcb->tp_rxtshift++; 618 timo = min(timo, ((int)tpcb->tp_dt_ticks) << tpcb->tp_rxtshift); 619 tp_ctimeout(tpcb, TM_sendack, timo); 620 } else 621 tp_ctimeout(tpcb, TM_sendack, tpcb->tp_keepalive_ticks); 622 IncStat(ts_AK_sent); 623 IncPStat(tpcb, tps_AK_sent); 624 IFDEBUG(D_ACKSEND) 625 printf( 626 "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", 627 csum_offset, hdr->tpdu_li); 628 ENDDEBUG 629 break; 630 631 case ER_TPDU_type: 632 hdr->tpdu_ERreason = eot; 633 hdr->tpdu_cdt = 0; 634 /* no user data */ 635 data = (struct mbuf *)0; 636 IncStat(ts_ER_sent); 637 break; 638 } 639 640 } 641 ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) ); 642 643 m->m_next = data; 644 645 ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */ 646 ASSERT( hdr->tpdu_li != 0 ); /* leave this in */ 647 648 m->m_len = hdr->tpdu_li ; 649 hdr->tpdu_li --; /* doesn't include the li field */ 650 651 datalen = m_datalen( m ); /* total len */ 652 653 ASSERT( datalen <= tpcb->tp_l_tpdusize ); /* may become a problem 654 when CLNP is used; leave in here for the time being */ 655 IFDEBUG(D_ACKSEND) 656 printf( 657 "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", 658 csum_offset, hdr->tpdu_li); 659 ENDDEBUG 660 if( datalen > tpcb->tp_l_tpdusize ) { 661 printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n", 662 datalen, tpcb->tp_l_tpdusize); 663 } 664 IFDEBUG(D_EMIT) 665 printf( 666 "tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n", 667 m->m_len, csum_offset, datalen); 668 ENDDEBUG 669 if( tpcb->tp_use_checksum || 670 (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) { 671 iso_gen_csum(m, csum_offset, datalen); 672 } 673 674 IFDEBUG(D_EMIT) 675 printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n", 676 tpcb, dutype, datalen); 677 dump_buf(mtod(m, caddr_t), datalen); 678 ENDDEBUG 679 680 IFPERF(tpcb) 681 if( dutype == DT_TPDU_type ) { 682 PStat(tpcb, Nb_to_ll) += (datalen - m->m_len); 683 tpmeas( tpcb->tp_lref, TPtime_to_ll, (struct timeval *)0, 684 seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len)); 685 } 686 ENDPERF 687 688 IFTRACE(D_EMIT) 689 tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0); 690 ENDTRACE 691 IFDEBUG(D_EMIT) 692 printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n", 693 tpcb, tpcb->tp_npcb, tpcb->tp_sock); 694 ENDDEBUG 695 696 { extern char tp_delay; 697 698 if( tp_delay ) 699 if( tpcb->tp_use_checksum == 0 ) { 700 register u_int i = tp_delay; 701 for (; i!= 0; i--) 702 (void) iso_check_csum(m, datalen); 703 } 704 } 705 ASSERT( m->m_len > 0 ); 706 error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen, 707 !tpcb->tp_use_checksum); 708 IFDEBUG(D_EMIT) 709 printf("OUTPUT: returned 0x%x\n", error); 710 ENDDEBUG 711 IFTRACE(D_EMIT) 712 tptraceTPCB(TPPTmisc, 713 "tp_emit nlproto->output netservice returns datalen", 714 tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen); 715 ENDTRACE 716 done: 717 if (error) { 718 if (dutype == AK_TPDU_type) 719 tp_ctimeout(tpcb, TM_sendack, 1); 720 if (error == E_CO_QFULL) { 721 tp_quench(tpcb, PRC_QUENCH); 722 return 0; 723 } 724 } 725 return error; 726 } 727 /* 728 * NAME: tp_error_emit() 729 * CALLED FROM: tp_input() when a DR or ER is to be issued in 730 * response to an input error. 731 * FUNCTION and ARGUMENTS: 732 * The error type is the first argument. 733 * The argument (sref) is the source reference on the bad incoming tpdu, 734 * and is used for a destination reference on the outgoing packet. 735 * (faddr) and (laddr) are the foreign and local addresses for this 736 * connection. 737 * (erdata) is a ptr to the errant incoming tpdu, and is copied into the 738 * outgoing ER, if an ER is to be issued. 739 * (erlen) is the number of octets of the errant tpdu that we should 740 * try to copy. 741 * (tpcb) is the pcb that describes the connection for which the bad tpdu 742 * arrived. 743 * RETURN VALUES: 744 * 0 OK 745 * ENOBUFS 746 * E* from net layer datagram output routine 747 * SIDE EFFECTS: 748 * 749 * NOTES: 750 */ 751 752 int 753 tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel, 754 dgout_routine) 755 int error; 756 u_long sref; 757 struct sockaddr_iso *faddr, *laddr; 758 struct mbuf *erdata; 759 int erlen; 760 struct tp_pcb *tpcb; 761 caddr_t cons_channel; 762 int (*dgout_routine)(); 763 { 764 int dutype; 765 int datalen = 0; 766 register struct tpdu *hdr; 767 register struct mbuf *m; 768 int csum_offset; 769 770 IFTRACE(D_ERROR_EMIT) 771 tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen", 772 error, sref, tpcb, erlen); 773 ENDTRACE 774 IFDEBUG(D_ERROR_EMIT) 775 printf( 776 "tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n", 777 error, sref, tpcb, erlen, cons_channel); 778 ENDDEBUG 779 780 MGET(m, M_DONTWAIT, TPMT_TPHDR); 781 if (m == NULL) { 782 return ENOBUFS; 783 } 784 m->m_len = sizeof(struct tpdu); 785 m->m_act = MNULL; 786 787 hdr = mtod(m, struct tpdu *); 788 789 IFDEBUG(D_ERROR_EMIT) 790 printf("[error 0x%x] [error&0xff 0x%x] [(char)error 0x%x]\n", 791 error, error&0xff, (char)error); 792 ENDDEBUG 793 794 795 if (error & TP_ERROR_SNDC) 796 dutype = DC_TPDU_type; 797 else if (error & 0x40) { 798 error &= ~0x40; 799 dutype = ER_TPDU_type; 800 } else 801 dutype = DR_TPDU_type; 802 error &= 0xff; 803 804 hdr->tpdu_type = dutype; 805 hdr->tpdu_cdt = 0; 806 807 switch( dutype ) { 808 809 case DC_TPDU_type: 810 IncStat(ts_DC_sent); 811 hdr->tpdu_li = 6; 812 hdr->tpdu_DCdref = htons(sref); 813 hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0; 814 IFDEBUG(D_ERROR_EMIT) 815 printf("DC case:\n"); 816 dump_buf( hdr, 6); 817 ENDDEBUG 818 /* forget the add'l information variable part */ 819 break; 820 821 case DR_TPDU_type: 822 IncStat(ts_DR_sent); 823 hdr->tpdu_li = 7; 824 hdr->tpdu_DRdref = htons(sref); 825 hdr->tpdu_DRsref = 0; 826 hdr->tpdu_DRreason = (char)error; 827 IFDEBUG(D_ERROR_EMIT) 828 printf("DR case:\n"); 829 dump_buf( hdr, 7); 830 ENDDEBUG 831 /* forget the add'l information variable part */ 832 break; 833 834 case ER_TPDU_type: 835 IncStat(ts_ER_sent); 836 hdr->tpdu_li = 5; 837 hdr->tpdu_ERreason = (char)error; 838 hdr->tpdu_ERdref = htons(sref); 839 break; 840 841 default: 842 ASSERT(0); 843 printf("TP PANIC: bad dutype 0x%x\n", dutype); 844 } 845 846 if(tpcb) 847 if( tpcb->tp_use_checksum ) { 848 ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */); 849 csum_offset = hdr->tpdu_li - 2; 850 } 851 852 ASSERT( hdr->tpdu_li < MLEN ); 853 854 if (dutype == ER_TPDU_type) { 855 /* copy the errant tpdu into another 'variable part' */ 856 register caddr_t P; 857 858 IFTRACE(D_ERROR_EMIT) 859 tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li, 860 0,0); 861 ENDTRACE 862 IFDEBUG(D_ERROR_EMIT) 863 printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li); 864 ENDDEBUG 865 866 /* copy at most as many octets for which you have room */ 867 if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN) 868 erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2; 869 870 /* add the "invalid tpdu" parameter : required in class 0 */ 871 P = (caddr_t)hdr + (int)(hdr->tpdu_li); 872 vbptr(P)->tpv_code = TPP_invalid_tpdu; /* parameter code */ 873 vbptr(P)->tpv_len = erlen; /* parameter length */ 874 m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */ 875 876 /* tp_input very likely handed us an mbuf chain w/ nothing in 877 * the first mbuf and the data following the empty mbuf 878 */ 879 if(erdata->m_len == 0) { 880 erdata = m_free(erdata); /* returns the next mbuf on the chain */ 881 } 882 /* 883 * copy only up to the bad octet 884 * (or max that will fit in a header 885 */ 886 m->m_next = m_copy(erdata, 0, erlen); 887 hdr->tpdu_li += erlen + 2; 888 m_freem(erdata); 889 } else { 890 IFDEBUG(D_ERROR_EMIT) 891 printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li); 892 dump_buf( (char *)hdr, hdr->tpdu_li ); 893 ENDDEBUG 894 m->m_len = hdr->tpdu_li ; 895 m_freem(erdata); 896 } 897 898 hdr->tpdu_li --; 899 IFTRACE(D_ERROR_EMIT) 900 tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0); 901 ENDTRACE 902 903 datalen = m_datalen( m); 904 if (tpcb) { 905 if( tpcb->tp_use_checksum ) { 906 IFTRACE(D_ERROR_EMIT) 907 tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0); 908 ENDTRACE 909 IFDEBUG(D_ERROR_EMIT) 910 printf("before gen csum datalen 0x%x, csum_offset 0x%x\n", 911 datalen, csum_offset); 912 ENDDEBUG 913 914 iso_gen_csum(m, csum_offset, datalen); 915 } 916 917 IFDEBUG(D_ERROR_EMIT) 918 printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n", 919 tpcb, tpcb->tp_npcb, tpcb->tp_sock); 920 ENDDEBUG 921 } 922 if (cons_channel) { 923 #ifdef TPCONS 924 struct pklcd *lcp = (struct pklcd *)cons_channel; 925 struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; 926 927 tpcons_dg_output(cons_channel, m, datalen); 928 /* was if (tpcb == 0) iso_pcbdetach(isop); */ 929 /* but other side may want to try again over same VC, 930 so, we'll depend on him closing it, but in case it gets forgotten 931 we'll mark it for garbage collection */ 932 lcp->lcd_flags |= X25_DG_CIRCUIT; 933 IFDEBUG(D_ERROR_EMIT) 934 printf("OUTPUT: dutype 0x%x channel 0x%x\n", 935 dutype, cons_channel); 936 ENDDEBUG 937 #else 938 printf("TP panic! cons channel 0x%x but not cons configured\n", 939 cons_channel); 940 #endif 941 } else if (tpcb) { 942 943 IFDEBUG(D_ERROR_EMIT) 944 printf("tp_error_emit 1 sending DG: Laddr\n"); 945 dump_addr((struct sockaddr *)laddr); 946 printf("Faddr\n"); 947 dump_addr((struct sockaddr *)faddr); 948 ENDDEBUG 949 return (tpcb->tp_nlproto->nlp_dgoutput)( 950 &laddr->siso_addr, 951 &faddr->siso_addr, 952 m, datalen, 953 /* no route */ (caddr_t)0, !tpcb->tp_use_checksum); 954 } else if (dgout_routine) { 955 IFDEBUG(D_ERROR_EMIT) 956 printf("tp_error_emit sending DG: Laddr\n"); 957 dump_addr((struct sockaddr *)laddr); 958 printf("Faddr\n"); 959 dump_addr((struct sockaddr *)faddr); 960 ENDDEBUG 961 return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr, 962 m, datalen, /* no route */ 963 (caddr_t)0, /* nochecksum==false */0); 964 } else { 965 IFDEBUG(D_ERROR_EMIT) 966 printf("tp_error_emit DROPPING \n", m); 967 ENDDEBUG 968 IncStat(ts_send_drop); 969 m_freem(m); 970 return 0; 971 } 972 } 973