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