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