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