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