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