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 * $Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $ 30 * $Source: /var/src/sys/netiso/RCS/tp_iso.c,v $ 31 * 32 * Here is where you find the iso-dependent code. We've tried 33 * keep all net-level and (primarily) address-family-dependent stuff 34 * out of the tp source, and everthing here is reached indirectly 35 * through a switch table (struct nl_protosw *) tpcb->tp_nlproto 36 * (see tp_pcb.c). 37 * The routines here are: 38 * iso_getsufx: gets transport suffix out of an isopcb structure. 39 * iso_putsufx: put transport suffix into an isopcb structure. 40 * iso_putnetaddr: put a whole net addr into an isopcb. 41 * iso_getnetaddr: get a whole net addr from an isopcb. 42 * iso_recycle_suffix: clear suffix for reuse in isopcb 43 * tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff 44 * tpclnp_mtu: figure out what size tpdu to use 45 * tpclnp_input: take a pkt from clnp, strip off its clnp header, 46 * give to tp 47 * tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data 48 * tpclnp_output: package a pkt for clnp given an isopcb & some data 49 */ 50 51 #ifndef lint 52 static char *rcsid = "$Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $"; 53 #endif lint 54 55 #ifdef ISO 56 57 #include "param.h" 58 #include "socket.h" 59 #include "socketvar.h" 60 #include "domain.h" 61 #include "malloc.h" 62 #include "mbuf.h" 63 #include "errno.h" 64 #include "time.h" 65 #include "protosw.h" 66 67 #include "../net/if.h" 68 #include "../net/route.h" 69 70 #include "argo_debug.h" 71 #include "tp_param.h" 72 #include "tp_stat.h" 73 #include "tp_pcb.h" 74 #include "tp_trace.h" 75 #include "tp_stat.h" 76 #include "tp_tpdu.h" 77 #include "tp_clnp.h" 78 79 /* 80 * CALLED FROM: 81 * pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR 82 * FUNCTION, ARGUMENTS: 83 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. 84 */ 85 86 iso_getsufx(isop, lenp, data_out, which) 87 struct isopcb *isop; 88 u_short *lenp; 89 caddr_t data_out; 90 int which; 91 { 92 register struct sockaddr_iso *addr = 0; 93 94 switch (which) { 95 case TP_LOCAL: 96 addr = isop->isop_laddr; 97 break; 98 99 case TP_FOREIGN: 100 addr = isop->isop_faddr; 101 } 102 if (addr) 103 bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tsuffixlen)); 104 } 105 106 /* CALLED FROM: 107 * tp_newsocket(); i.e., when a connection is being established by an 108 * incoming CR_TPDU. 109 * 110 * FUNCTION, ARGUMENTS: 111 * Put a transport suffix (found in name) into an isopcb structure (isop). 112 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. 113 */ 114 void 115 iso_putsufx(isop, sufxloc, sufxlen, which) 116 struct isopcb *isop; 117 caddr_t sufxloc; 118 int sufxlen, which; 119 { 120 struct sockaddr_iso **dst, *backup; 121 register struct sockaddr_iso *addr; 122 struct mbuf *m; 123 int len; 124 125 switch (which) { 126 default: 127 return; 128 129 case TP_LOCAL: 130 dst = &isop->isop_laddr; 131 backup = &isop->isop_sladdr; 132 break; 133 134 case TP_FOREIGN: 135 dst = &isop->isop_faddr; 136 backup = &isop->isop_sfaddr; 137 } 138 if ((addr = *dst) == 0) { 139 addr = *dst = backup; 140 addr->siso_nlen = 0; 141 addr->siso_ssuffixlen = 0; 142 printf("iso_putsufx on un-initialized isopcb\n"); 143 } 144 len = sufxlen + addr->siso_nlen + 145 (sizeof(struct sockaddr_iso) - sizeof(struct iso_addr)); 146 if (addr == backup) { 147 if (len > sizeof(isop->isop_sladdr)) { 148 m = m_getclr(M_DONTWAIT, MT_SONAME); 149 if (m == 0) 150 return; 151 addr = *dst = mtod(m, struct sockaddr_iso *); 152 *addr = *backup; 153 m->m_len = len; 154 } 155 } else 156 dtom(addr)->m_len = len; 157 bcopy(sufxloc, TSEL(addr), sufxlen); 158 addr->siso_tsuffixlen = sufxlen; 159 addr->siso_len = len; 160 } 161 162 /* 163 * CALLED FROM: 164 * tp.trans whenever we go into REFWAIT state. 165 * FUNCTION and ARGUMENT: 166 * Called when a ref is frozen, to allow the suffix to be reused. 167 * (isop) is the net level pcb. This really shouldn't have to be 168 * done in a NET level pcb but... for the internet world that just 169 * the way it is done in BSD... 170 * The alternative is to have the port unusable until the reference 171 * timer goes off. 172 */ 173 void 174 iso_recycle_tsuffix(isop) 175 struct isopcb *isop; 176 { 177 isop->isop_laddr->siso_tsuffixlen = isop->isop_faddr->siso_tsuffixlen = 0; 178 } 179 180 /* 181 * CALLED FROM: 182 * tp_newsocket(); i.e., when a connection is being established by an 183 * incoming CR_TPDU. 184 * 185 * FUNCTION and ARGUMENTS: 186 * Copy a whole net addr from a struct sockaddr (name). 187 * into an isopcb (isop). 188 * The argument (which) takes values TP_LOCAL or TP_FOREIGN 189 */ 190 void 191 iso_putnetaddr(isop, name, which) 192 register struct isopcb *isop; 193 struct sockaddr_iso *name; 194 int which; 195 { 196 struct sockaddr_iso **sisop, *backup; 197 register struct sockaddr_iso *siso; 198 199 switch (which) { 200 case TP_LOCAL: 201 sisop = &isop->isop_laddr; 202 backup = &isop->isop_sladdr; 203 break; 204 case TP_FOREIGN: 205 sisop = &isop->isop_faddr; 206 backup = &isop->isop_sfaddr; 207 } 208 siso = ((*sisop == 0) ? (*sisop = backup) : *sisop); 209 IFDEBUG(D_TPISO) 210 printf("ISO_PUTNETADDR\n"); 211 dump_isoaddr(isop->isop_faddr); 212 ENDDEBUG 213 siso->siso_addr = name->siso_addr; 214 } 215 216 /* 217 * CALLED FROM: 218 * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR 219 * FUNCTION and ARGUMENTS: 220 * Copy a whole net addr from an isopcb (isop) into 221 * a struct sockaddr (name). 222 * The argument (which) takes values TP_LOCAL or TP_FOREIGN. 223 */ 224 225 void 226 iso_getnetaddr( isop, name, which) 227 struct isopcb *isop; 228 struct mbuf *name; 229 int which; 230 { 231 struct sockaddr_iso *siso = 232 (which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr); 233 if (siso) 234 bcopy((caddr_t)siso, mtod(name, caddr_t), 235 (unsigned)(name->m_len = siso->siso_len)); 236 else 237 name->m_len = 0; 238 } 239 240 /* 241 * CALLED FROM: 242 * tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT 243 * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE: 244 * Determine the proper maximum transmission unit, i.e., MTU, to use, given 245 * a) the header size for the network protocol and the max transmission 246 * unit on the subnet interface, determined from the information in (isop), 247 * b) the max size negotiated so far (negot) 248 * c) the window size used by the tp connection (found in so), 249 * 250 * The result is put in the integer *size in its integer form and in 251 * *negot in its logarithmic form. 252 * 253 * The rules are: 254 * a) can only negotiate down from the value found in *negot. 255 * b) the MTU must be < the windowsize, 256 * c) If src and dest are on the same net, 257 * we will negotiate the closest size larger than MTU but really USE 258 * the actual device mtu - ll hdr sizes. 259 * otherwise we negotiate the closest size smaller than MTU - ll hdr sizes. 260 */ 261 262 void 263 tpclnp_mtu(so, isop, size, negot ) 264 struct socket *so; 265 struct isopcb *isop; 266 int *size; 267 u_char *negot; 268 { 269 struct ifnet *ifp; 270 struct iso_ifaddr *ia; 271 register int i; 272 int windowsize = so->so_rcv.sb_hiwat; 273 int clnp_size; 274 int sizeismtu = 0; 275 276 struct iso_ifaddr *iso_routeifa(); 277 278 IFDEBUG(D_CONN) 279 printf("tpclnp_mtu(0x%x,0x%x,0x%x,0x%x)\n", so, isop, size, negot); 280 ENDDEBUG 281 IFTRACE(D_CONN) 282 tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0); 283 ENDTRACE 284 285 *size = 1 << *negot; 286 287 if( *size > windowsize ) { 288 *size = windowsize; 289 } 290 291 if (((ia = iso_routeifa(isop->isop_faddr)) == 0) 292 || (ifp = ia->ia_ifp) == 0) 293 return; 294 295 /* TODO - make this indirect off the socket structure to the 296 * network layer to get headersize 297 */ 298 if (isop->isop_laddr) 299 clnp_size = clnp_hdrsize(isop->isop_laddr->siso_addr.isoa_len); 300 else 301 clnp_size = 20; 302 303 if(*size > ifp->if_mtu - clnp_size) { 304 *size = ifp->if_mtu - clnp_size; 305 sizeismtu = 1; 306 } 307 /* have to transform size to the log2 of size */ 308 for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i) <= *size)) ; i++) 309 ; 310 i--; 311 312 IFTRACE(D_CONN) 313 tptrace(TPPTmisc, "GET MTU MID: tpcb size negot i \n", 314 *size, *negot, i, 0); 315 ENDTRACE 316 317 /* are we on the same LAN? if so, negotiate one tpdu size larger, 318 * and actually send the real mtu size 319 */ 320 if (iso_localifa(isop->isop_faddr)) { 321 i++; 322 } else { 323 *size = 1<<i; 324 } 325 *negot = i; 326 327 IFDEBUG(D_CONN) 328 printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n", 329 ifp->if_name, *size, *negot); 330 ENDDEBUG 331 IFTRACE(D_CONN) 332 tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n", 333 *size, *negot, 0, 0); 334 ENDTRACE 335 } 336 337 338 /* 339 * CALLED FROM: 340 * tp_emit() 341 * FUNCTION and ARGUMENTS: 342 * Take a packet(m0) from tp and package it so that clnp will accept it. 343 * This means prepending space for the clnp header and filling in a few 344 * of the fields. 345 * inp is the isopcb structure; datalen is the length of the data in the 346 * mbuf string m0. 347 * RETURN VALUE: 348 * whatever (E*) is returned form the net layer output routine. 349 */ 350 351 int 352 tpclnp_output(isop, m0, datalen, nochksum) 353 struct isopcb *isop; 354 struct mbuf *m0; 355 int datalen; 356 int nochksum; 357 { 358 register struct mbuf *m = m0; 359 IncStat(ts_tpdu_sent); 360 361 IFDEBUG(D_TPISO) 362 struct tpdu *hdr = mtod(m0, struct tpdu *); 363 364 printf( 365 "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n", 366 datalen, 367 (int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum); 368 dump_isoaddr(isop->isop_faddr); 369 printf("\nsrc addr:\n"); 370 dump_isoaddr(isop->isop_laddr); 371 dump_mbuf(m0, "at tpclnp_output"); 372 ENDDEBUG 373 if ((m->m_flags & M_PKTHDR) == 0) { 374 IFDEBUG(D_TPISO) 375 printf("tpclnp_output: non headered mbuf"); 376 ENDDEBUG 377 MGETHDR(m, M_DONTWAIT, MT_DATA); 378 if (m == 0) { 379 m_freem(m0); 380 return ENOBUFS; 381 } 382 m->m_next = m0; 383 m->m_len = 0; 384 m->m_pkthdr.len = datalen; 385 m0 = m; 386 } 387 388 return 389 clnp_output(m0, isop, /* flags */nochksum ? CLNP_NO_CKSUM : 0); 390 } 391 392 /* 393 * CALLED FROM: 394 * tp_error_emit() 395 * FUNCTION and ARGUMENTS: 396 * This is a copy of tpclnp_output that takes the addresses 397 * instead of a pcb. It's used by the tp_error_emit, when we 398 * don't have an iso_pcb with which to call the normal output rtn. 399 * RETURN VALUE: 400 * ENOBUFS or 401 * whatever (E*) is returned form the net layer output routine. 402 */ 403 404 int 405 tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum) 406 struct iso_addr *laddr, *faddr; 407 struct mbuf *m0; 408 int datalen; 409 struct route *ro; 410 int nochksum; 411 { 412 struct isopcb tmppcb; 413 int err; 414 int flags; 415 register struct mbuf *m = m0; 416 417 IFDEBUG(D_TPISO) 418 printf("tpclnp_output_dg datalen 0x%x m0 0x%x\n", datalen, m0); 419 ENDDEBUG 420 421 /* 422 * Fill in minimal portion of isopcb so that clnp can send the 423 * packet. 424 */ 425 bzero((caddr_t)&tmppcb, sizeof(tmppcb)); 426 tmppcb.isop_laddr = &tmppcb.isop_sladdr; 427 tmppcb.isop_laddr->siso_addr = *laddr; 428 tmppcb.isop_faddr = &tmppcb.isop_sfaddr; 429 tmppcb.isop_faddr->siso_addr = *faddr; 430 431 IFDEBUG(D_TPISO) 432 printf("tpclnp_output_dg faddr: \n"); 433 dump_isoaddr(&tmppcb.isop_sfaddr); 434 printf("\ntpclnp_output_dg laddr: \n"); 435 dump_isoaddr(&tmppcb.isop_sladdr); 436 printf("\n"); 437 ENDDEBUG 438 439 /* 440 * Do not use packet cache since this is a one shot error packet 441 */ 442 flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0)); 443 444 IncStat(ts_tpdu_sent); 445 446 if ((m->m_flags & M_PKTHDR) == 0) { 447 printf("tpclnp_output: non headered mbuf"); 448 MGETHDR(m, M_DONTWAIT, MT_DATA); 449 if (m == 0) { 450 m_freem(m0); 451 return ENOBUFS; 452 } 453 m->m_next = m0; 454 m->m_len = 0; 455 m->m_pkthdr.len = datalen; 456 m0 = m; 457 } 458 err = clnp_output(m0, &tmppcb, flags); 459 460 /* 461 * Free route allocated by clnp (if the route was indeed allocated) 462 */ 463 if (tmppcb.isop_route.ro_rt) 464 RTFREE(tmppcb.isop_route.ro_rt); 465 466 return(err); 467 } 468 extern struct sockaddr_iso blank_siso; 469 /* 470 * CALLED FROM: 471 * clnp's input routine, indirectly through the protosw. 472 * FUNCTION and ARGUMENTS: 473 * Take a packet (m) from clnp, strip off the clnp header and give it to tp 474 * No return value. 475 */ 476 ProtoHook 477 tpclnp_input(m, faddr, laddr, clnp_len) 478 struct mbuf *m; 479 struct iso_addr *faddr, *laddr; 480 int clnp_len; 481 { 482 struct sockaddr_iso src, dst; 483 int s = splnet(); 484 struct mbuf *tp_inputprep(); 485 486 IncStat(ts_pkt_rcvd); 487 488 IFDEBUG(D_TPINPUT) 489 printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len); 490 dump_mbuf(m, "at tpclnp_input"); 491 ENDDEBUG 492 /* 493 * CLNP gives us an mbuf chain WITH the clnp header pulled up, 494 * and the length of the clnp header. 495 * First, strip off the Clnp header. leave the mbuf there for the 496 * pullup that follows. 497 */ 498 499 m->m_len -= clnp_len; 500 m->m_data += clnp_len; 501 502 m = tp_inputprep(m); 503 504 IFDEBUG(D_TPINPUT) 505 dump_mbuf(m, "after tpclnp_input both pullups"); 506 ENDDEBUG 507 508 src = blank_siso; dst = blank_siso; 509 bcopy((caddr_t)faddr, (caddr_t)&src.siso_addr, 1 + faddr->isoa_len); 510 bcopy((caddr_t)laddr, (caddr_t)&dst.siso_addr, 1 + laddr->isoa_len); 511 512 IFDEBUG(D_TPISO) 513 printf("calling tp_input: &src 0x%x &dst 0x%x, src addr:\n", 514 &src, &dst); 515 printf(" dst addr:\n"); 516 dump_isoaddr(&src); 517 dump_isoaddr(&dst); 518 ENDDEBUG 519 520 (void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst, 521 0, tpclnp_output_dg); 522 523 IFDEBUG(D_QUENCH) 524 { 525 if(time.tv_usec & 0x4 && time.tv_usec & 0x40) { 526 printf("tpclnp_input: FAKING %s\n", 527 tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2"); 528 if(tp_stat.ts_pkt_rcvd & 0x1) { 529 tpclnp_ctlinput(PRC_QUENCH, &src); 530 } else { 531 tpclnp_ctlinput(PRC_QUENCH2, &src); 532 } 533 } 534 } 535 ENDDEBUG 536 537 splx(s); 538 return 0; 539 } 540 541 ProtoHook 542 iso_rtchange() 543 { 544 return 0; 545 } 546 547 /* 548 * CALLED FROM: 549 * tpclnp_ctlinput() 550 * FUNCTION and ARGUMENTS: 551 * find the tpcb pointer and pass it to tp_quench 552 */ 553 void 554 tpiso_decbit(isop) 555 struct isopcb *isop; 556 { 557 tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH2); 558 } 559 /* 560 * CALLED FROM: 561 * tpclnp_ctlinput() 562 * FUNCTION and ARGUMENTS: 563 * find the tpcb pointer and pass it to tp_quench 564 */ 565 void 566 tpiso_quench(isop) 567 struct isopcb *isop; 568 { 569 tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH); 570 } 571 572 /* 573 * CALLED FROM: 574 * The network layer through the protosw table. 575 * FUNCTION and ARGUMENTS: 576 * When clnp an ICMP-like msg this gets called. 577 * It either returns an error status to the user or 578 * it causes all connections on this address to be aborted 579 * by calling the appropriate xx_notify() routine. 580 * (cmd) is the type of ICMP error. 581 * (siso) is the address of the guy who sent the ER CLNPDU 582 */ 583 ProtoHook 584 tpclnp_ctlinput(cmd, siso) 585 int cmd; 586 struct sockaddr_iso *siso; 587 { 588 return tpclnp_ctlinput1(cmd, &siso->siso_addr); 589 } 590 591 /* 592 * Entry to ctlinput with argument of an iso_addr rather than a sockaddr 593 */ 594 ProtoHook 595 tpclnp_ctlinput1(cmd, isoa) 596 int cmd; 597 struct iso_addr *isoa; 598 { 599 extern u_char inetctlerrmap[]; 600 extern ProtoHook tpiso_abort(); 601 extern ProtoHook iso_rtchange(); 602 extern ProtoHook tpiso_reset(); 603 void iso_pcbnotify(); 604 605 IFDEBUG(D_TPINPUT) 606 printf("tpclnp_ctlinput1: cmd 0x%x addr: %s\n", cmd, 607 clnp_iso_addrp(isoa)); 608 ENDDEBUG 609 610 if (cmd < 0 || cmd > PRC_NCMDS) 611 return 0; 612 switch (cmd) { 613 614 case PRC_QUENCH2: 615 iso_pcbnotify(&tp_isopcb, isoa, 0, (int (*)())tpiso_decbit); 616 break; 617 618 case PRC_QUENCH: 619 iso_pcbnotify(&tp_isopcb, isoa, 0, (int (*)())tpiso_quench); 620 break; 621 622 case PRC_TIMXCEED_REASS: 623 case PRC_ROUTEDEAD: 624 iso_pcbnotify(&tp_isopcb, isoa, 0, tpiso_reset); 625 break; 626 627 case PRC_HOSTUNREACH: 628 case PRC_UNREACH_NET: 629 case PRC_IFDOWN: 630 case PRC_HOSTDEAD: 631 iso_pcbnotify(&tp_isopcb, isoa, 632 (int)inetctlerrmap[cmd], iso_rtchange); 633 break; 634 635 default: 636 /* 637 case PRC_MSGSIZE: 638 case PRC_UNREACH_HOST: 639 case PRC_UNREACH_PROTOCOL: 640 case PRC_UNREACH_PORT: 641 case PRC_UNREACH_NEEDFRAG: 642 case PRC_UNREACH_SRCFAIL: 643 case PRC_REDIRECT_NET: 644 case PRC_REDIRECT_HOST: 645 case PRC_REDIRECT_TOSNET: 646 case PRC_REDIRECT_TOSHOST: 647 case PRC_TIMXCEED_INTRANS: 648 case PRC_PARAMPROB: 649 */ 650 iso_pcbnotify(&tp_isopcb, isoa, (int)inetctlerrmap[cmd], tpiso_abort); 651 break; 652 } 653 return 0; 654 } 655 656 /* 657 * These next 2 routines are 658 * CALLED FROM: 659 * xxx_notify() from tp_ctlinput() when 660 * net level gets some ICMP-equiv. type event. 661 * FUNCTION and ARGUMENTS: 662 * Cause the connection to be aborted with some sort of error 663 * reason indicating that the network layer caused the abort. 664 * Fakes an ER TPDU so we can go through the driver. 665 * abort always aborts the TP connection. 666 * reset may or may not, depending on the TP class that's in use. 667 */ 668 ProtoHook 669 tpiso_abort(isop) 670 struct isopcb *isop; 671 { 672 struct tp_event e; 673 674 IFDEBUG(D_CONN) 675 printf("tpiso_abort 0x%x\n", isop); 676 ENDDEBUG 677 e.ev_number = ER_TPDU; 678 e.ATTR(ER_TPDU).e_reason = ECONNABORTED; 679 return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e); 680 } 681 682 ProtoHook 683 tpiso_reset(isop) 684 struct isopcb *isop; 685 { 686 struct tp_event e; 687 688 e.ev_number = T_NETRESET; 689 return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e); 690 691 } 692 693 #endif ISO 694