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