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