1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)tp_iso.c 8.2 (Berkeley) 09/22/94
8 */
9
10 /***********************************************************
11 Copyright IBM Corporation 1987
12
13 All Rights Reserved
14
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30
31 ******************************************************************/
32
33 /*
34 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35 */
36 /*
37 * ARGO TP
38 * $Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $
39 * $Source: /var/src/sys/netiso/RCS/tp_iso.c,v $
40 *
41 * Here is where you find the iso-dependent code. We've tried
42 * keep all net-level and (primarily) address-family-dependent stuff
43 * out of the tp source, and everthing here is reached indirectly
44 * through a switch table (struct nl_protosw *) tpcb->tp_nlproto
45 * (see tp_pcb.c).
46 * The routines here are:
47 * iso_getsufx: gets transport suffix out of an isopcb structure.
48 * iso_putsufx: put transport suffix into an isopcb structure.
49 * iso_putnetaddr: put a whole net addr into an isopcb.
50 * iso_getnetaddr: get a whole net addr from an isopcb.
51 * iso_cmpnetaddr: compare a whole net addr from an isopcb.
52 * iso_recycle_suffix: clear suffix for reuse in isopcb
53 * tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff
54 * tpclnp_mtu: figure out what size tpdu to use
55 * tpclnp_input: take a pkt from clnp, strip off its clnp header,
56 * give to tp
57 * tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data
58 * tpclnp_output: package a pkt for clnp given an isopcb & some data
59 */
60
61 #ifdef ISO
62
63 #include <sys/param.h>
64 #include <sys/socket.h>
65 #include <sys/socketvar.h>
66 #include <sys/domain.h>
67 #include <sys/malloc.h>
68 #include <sys/mbuf.h>
69 #include <sys/errno.h>
70 #include <sys/time.h>
71 #include <sys/protosw.h>
72 #include <sys/kernel.h>
73
74 #include <net/if.h>
75 #include <net/route.h>
76
77 #include <netiso/argo_debug.h>
78 #include <netiso/tp_param.h>
79 #include <netiso/tp_stat.h>
80 #include <netiso/tp_pcb.h>
81 #include <netiso/tp_trace.h>
82 #include <netiso/tp_stat.h>
83 #include <netiso/tp_tpdu.h>
84 #include <netiso/tp_clnp.h>
85 #include <netiso/cltp_var.h>
86
87 /*
88 * CALLED FROM:
89 * pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
90 * FUNCTION, ARGUMENTS:
91 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
92 */
93
94 iso_getsufx(isop, lenp, data_out, which)
95 struct isopcb *isop;
96 u_short *lenp;
97 caddr_t data_out;
98 int which;
99 {
100 register struct sockaddr_iso *addr = 0;
101
102 switch (which) {
103 case TP_LOCAL:
104 addr = isop->isop_laddr;
105 break;
106
107 case TP_FOREIGN:
108 addr = isop->isop_faddr;
109 }
110 if (addr)
111 bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tlen));
112 }
113
114 /* CALLED FROM:
115 * tp_newsocket(); i.e., when a connection is being established by an
116 * incoming CR_TPDU.
117 *
118 * FUNCTION, ARGUMENTS:
119 * Put a transport suffix (found in name) into an isopcb structure (isop).
120 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
121 */
122 void
iso_putsufx(isop,sufxloc,sufxlen,which)123 iso_putsufx(isop, sufxloc, sufxlen, which)
124 struct isopcb *isop;
125 caddr_t sufxloc;
126 int sufxlen, which;
127 {
128 struct sockaddr_iso **dst, *backup;
129 register struct sockaddr_iso *addr;
130 struct mbuf *m;
131 int len;
132
133 switch (which) {
134 default:
135 return;
136
137 case TP_LOCAL:
138 dst = &isop->isop_laddr;
139 backup = &isop->isop_sladdr;
140 break;
141
142 case TP_FOREIGN:
143 dst = &isop->isop_faddr;
144 backup = &isop->isop_sfaddr;
145 }
146 if ((addr = *dst) == 0) {
147 addr = *dst = backup;
148 addr->siso_nlen = 0;
149 addr->siso_slen = 0;
150 addr->siso_plen = 0;
151 printf("iso_putsufx on un-initialized isopcb\n");
152 }
153 len = sufxlen + addr->siso_nlen +
154 (sizeof(*addr) - sizeof(addr->siso_data));
155 if (addr == backup) {
156 if (len > sizeof(*addr)) {
157 m = m_getclr(M_DONTWAIT, MT_SONAME);
158 if (m == 0)
159 return;
160 addr = *dst = mtod(m, struct sockaddr_iso *);
161 *addr = *backup;
162 m->m_len = len;
163 }
164 }
165 bcopy(sufxloc, TSEL(addr), sufxlen);
166 addr->siso_tlen = sufxlen;
167 addr->siso_len = len;
168 }
169
170 /*
171 * CALLED FROM:
172 * tp.trans whenever we go into REFWAIT state.
173 * FUNCTION and ARGUMENT:
174 * Called when a ref is frozen, to allow the suffix to be reused.
175 * (isop) is the net level pcb. This really shouldn't have to be
176 * done in a NET level pcb but... for the internet world that just
177 * the way it is done in BSD...
178 * The alternative is to have the port unusable until the reference
179 * timer goes off.
180 */
181 void
iso_recycle_tsuffix(isop)182 iso_recycle_tsuffix(isop)
183 struct isopcb *isop;
184 {
185 isop->isop_laddr->siso_tlen = isop->isop_faddr->siso_tlen = 0;
186 }
187
188 /*
189 * CALLED FROM:
190 * tp_newsocket(); i.e., when a connection is being established by an
191 * incoming CR_TPDU.
192 *
193 * FUNCTION and ARGUMENTS:
194 * Copy a whole net addr from a struct sockaddr (name).
195 * into an isopcb (isop).
196 * The argument (which) takes values TP_LOCAL or TP_FOREIGN
197 */
198 void
iso_putnetaddr(isop,name,which)199 iso_putnetaddr(isop, name, which)
200 register struct isopcb *isop;
201 struct sockaddr_iso *name;
202 int which;
203 {
204 struct sockaddr_iso **sisop, *backup;
205 register struct sockaddr_iso *siso;
206
207 switch (which) {
208 default:
209 printf("iso_putnetaddr: should panic\n");
210 return;
211 case TP_LOCAL:
212 sisop = &isop->isop_laddr;
213 backup = &isop->isop_sladdr;
214 break;
215 case TP_FOREIGN:
216 sisop = &isop->isop_faddr;
217 backup = &isop->isop_sfaddr;
218 }
219 siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
220 IFDEBUG(D_TPISO)
221 printf("ISO_PUTNETADDR\n");
222 dump_isoaddr(isop->isop_faddr);
223 ENDDEBUG
224 siso->siso_addr = name->siso_addr;
225 }
226
227 /*
228 * CALLED FROM:
229 * tp_input() when a connection is being established by an
230 * incoming CR_TPDU, and considered for interception.
231 *
232 * FUNCTION and ARGUMENTS:
233 * compare a whole net addr from a struct sockaddr (name),
234 * with that implicitly stored in an isopcb (isop).
235 * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
236 */
iso_cmpnetaddr(isop,name,which)237 iso_cmpnetaddr(isop, name, which)
238 register struct isopcb *isop;
239 register struct sockaddr_iso *name;
240 int which;
241 {
242 struct sockaddr_iso **sisop, *backup;
243 register struct sockaddr_iso *siso;
244
245 switch (which) {
246 default:
247 printf("iso_cmpnetaddr: should panic\n");
248 return 0;
249 case TP_LOCAL:
250 sisop = &isop->isop_laddr;
251 backup = &isop->isop_sladdr;
252 break;
253 case TP_FOREIGN:
254 sisop = &isop->isop_faddr;
255 backup = &isop->isop_sfaddr;
256 }
257 siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
258 IFDEBUG(D_TPISO)
259 printf("ISO_CMPNETADDR\n");
260 dump_isoaddr(siso);
261 ENDDEBUG
262 if (name->siso_tlen && bcmp(TSEL(name), TSEL(siso), name->siso_tlen))
263 return (0);
264 return (bcmp((caddr_t)name->siso_data,
265 (caddr_t)siso->siso_data, name->siso_nlen) == 0);
266 }
267
268 /*
269 * CALLED FROM:
270 * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
271 * FUNCTION and ARGUMENTS:
272 * Copy a whole net addr from an isopcb (isop) into
273 * a struct sockaddr (name).
274 * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
275 */
276
277 void
iso_getnetaddr(isop,name,which)278 iso_getnetaddr( isop, name, which)
279 struct isopcb *isop;
280 struct mbuf *name;
281 int which;
282 {
283 struct sockaddr_iso *siso =
284 (which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr);
285 if (siso)
286 bcopy((caddr_t)siso, mtod(name, caddr_t),
287 (unsigned)(name->m_len = siso->siso_len));
288 else
289 name->m_len = 0;
290 }
291 /*
292 * NAME: tpclnp_mtu()
293 *
294 * CALLED FROM:
295 * tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
296 *
297 * FUNCTION, ARGUMENTS, and RETURN VALUE:
298 *
299 * Perform subnetwork dependent part of determining MTU information.
300 * It appears that setting a double pointer to the rtentry associated with
301 * the destination, and returning the header size for the network protocol
302 * suffices.
303 *
304 * SIDE EFFECTS:
305 * Sets tp_routep pointer in pcb.
306 *
307 * NOTES:
308 */
tpclnp_mtu(tpcb)309 tpclnp_mtu(tpcb)
310 register struct tp_pcb *tpcb;
311 {
312 struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
313
314 IFDEBUG(D_CONN)
315 printf("tpclnp_mtu(tpcb)\n", tpcb);
316 ENDDEBUG
317 tpcb->tp_routep = &(isop->isop_route.ro_rt);
318 if (tpcb->tp_netservice == ISO_CONS)
319 return 0;
320 else
321 return (sizeof(struct clnp_fixed) + sizeof(struct clnp_segment) +
322 2 * sizeof(struct iso_addr));
323
324 }
325
326 /*
327 * CALLED FROM:
328 * tp_emit()
329 * FUNCTION and ARGUMENTS:
330 * Take a packet(m0) from tp and package it so that clnp will accept it.
331 * This means prepending space for the clnp header and filling in a few
332 * of the fields.
333 * isop is the isopcb structure; datalen is the length of the data in the
334 * mbuf string m0.
335 * RETURN VALUE:
336 * whatever (E*) is returned form the net layer output routine.
337 */
338
339 int
tpclnp_output(isop,m0,datalen,nochksum)340 tpclnp_output(isop, m0, datalen, nochksum)
341 struct isopcb *isop;
342 struct mbuf *m0;
343 int datalen;
344 int nochksum;
345 {
346 register struct mbuf *m = m0;
347 IncStat(ts_tpdu_sent);
348
349 IFDEBUG(D_TPISO)
350 struct tpdu *hdr = mtod(m0, struct tpdu *);
351
352 printf(
353 "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n",
354 datalen,
355 (int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum);
356 dump_isoaddr(isop->isop_faddr);
357 printf("\nsrc addr:\n");
358 dump_isoaddr(isop->isop_laddr);
359 dump_mbuf(m0, "at tpclnp_output");
360 ENDDEBUG
361
362 return
363 clnp_output(m0, isop, datalen, /* flags */nochksum ? CLNP_NO_CKSUM : 0);
364 }
365
366 /*
367 * CALLED FROM:
368 * tp_error_emit()
369 * FUNCTION and ARGUMENTS:
370 * This is a copy of tpclnp_output that takes the addresses
371 * instead of a pcb. It's used by the tp_error_emit, when we
372 * don't have an iso_pcb with which to call the normal output rtn.
373 * RETURN VALUE:
374 * ENOBUFS or
375 * whatever (E*) is returned form the net layer output routine.
376 */
377
378 int
tpclnp_output_dg(laddr,faddr,m0,datalen,ro,nochksum)379 tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
380 struct iso_addr *laddr, *faddr;
381 struct mbuf *m0;
382 int datalen;
383 struct route *ro;
384 int nochksum;
385 {
386 struct isopcb tmppcb;
387 int err;
388 int flags;
389 register struct mbuf *m = m0;
390
391 IFDEBUG(D_TPISO)
392 printf("tpclnp_output_dg datalen 0x%x m0 0x%x\n", datalen, m0);
393 ENDDEBUG
394
395 /*
396 * Fill in minimal portion of isopcb so that clnp can send the
397 * packet.
398 */
399 bzero((caddr_t)&tmppcb, sizeof(tmppcb));
400 tmppcb.isop_laddr = &tmppcb.isop_sladdr;
401 tmppcb.isop_laddr->siso_addr = *laddr;
402 tmppcb.isop_faddr = &tmppcb.isop_sfaddr;
403 tmppcb.isop_faddr->siso_addr = *faddr;
404
405 IFDEBUG(D_TPISO)
406 printf("tpclnp_output_dg faddr: \n");
407 dump_isoaddr(&tmppcb.isop_sfaddr);
408 printf("\ntpclnp_output_dg laddr: \n");
409 dump_isoaddr(&tmppcb.isop_sladdr);
410 printf("\n");
411 ENDDEBUG
412
413 /*
414 * Do not use packet cache since this is a one shot error packet
415 */
416 flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0));
417
418 IncStat(ts_tpdu_sent);
419
420 err = clnp_output(m0, &tmppcb, datalen, flags);
421
422 /*
423 * Free route allocated by clnp (if the route was indeed allocated)
424 */
425 if (tmppcb.isop_route.ro_rt)
426 RTFREE(tmppcb.isop_route.ro_rt);
427
428 return(err);
429 }
430 /*
431 * CALLED FROM:
432 * clnp's input routine, indirectly through the protosw.
433 * FUNCTION and ARGUMENTS:
434 * Take a packet (m) from clnp, strip off the clnp header and give it to tp
435 * No return value.
436 */
437 ProtoHook
tpclnp_input(m,src,dst,clnp_len,ce_bit)438 tpclnp_input(m, src, dst, clnp_len, ce_bit)
439 register struct mbuf *m;
440 struct sockaddr_iso *src, *dst;
441 int clnp_len, ce_bit;
442 {
443 struct mbuf *tp_inputprep();
444 int tp_input(), cltp_input(), (*input)() = tp_input;
445
446 IncStat(ts_pkt_rcvd);
447
448 IFDEBUG(D_TPINPUT)
449 printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len);
450 dump_mbuf(m, "at tpclnp_input");
451 ENDDEBUG
452 /*
453 * CLNP gives us an mbuf chain WITH the clnp header pulled up,
454 * and the length of the clnp header.
455 * First, strip off the Clnp header. leave the mbuf there for the
456 * pullup that follows.
457 */
458 m->m_len -= clnp_len;
459 m->m_data += clnp_len;
460 m->m_pkthdr.len -= clnp_len;
461 /* XXXX: should probably be in clnp_input */
462 switch (dst->siso_data[dst->siso_nlen - 1]) {
463 #ifdef TUBA
464 case ISOPROTO_TCP:
465 return (tuba_tcpinput(m, src, dst));
466 #endif
467 case 0:
468 if (m->m_len == 0 && (m = m_pullup(m, 1)) == 0)
469 return 0;
470 if (*(mtod(m, u_char *)) == ISO10747_IDRP)
471 return (idrp_input(m, src, dst));
472 }
473 m = tp_inputprep(m);
474 if (m == 0)
475 return 0;
476 if (mtod(m, u_char *)[1] == UD_TPDU_type)
477 input = cltp_input;
478
479 IFDEBUG(D_TPINPUT)
480 dump_mbuf(m, "after tpclnp_input both pullups");
481 ENDDEBUG
482
483 IFDEBUG(D_TPISO)
484 printf("calling %sinput : src 0x%x, dst 0x%x, src addr:\n",
485 (input == tp_input ? "tp_" : "clts_"), src, dst);
486 dump_isoaddr(src);
487 printf(" dst addr:\n");
488 dump_isoaddr(dst);
489 ENDDEBUG
490
491 (void) (*input)(m, (struct sockaddr *)src, (struct sockaddr *)dst,
492 0, tpclnp_output_dg, ce_bit);
493
494 IFDEBUG(D_QUENCH)
495 {
496 if(time.tv_usec & 0x4 && time.tv_usec & 0x40) {
497 printf("tpclnp_input: FAKING %s\n",
498 tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2");
499 if(tp_stat.ts_pkt_rcvd & 0x1) {
500 tpclnp_ctlinput(PRC_QUENCH, &src);
501 } else {
502 tpclnp_ctlinput(PRC_QUENCH2, &src);
503 }
504 }
505 }
506 ENDDEBUG
507
508 return 0;
509 }
510
511 ProtoHook
iso_rtchange()512 iso_rtchange()
513 {
514 return 0;
515 }
516
517 /*
518 * CALLED FROM:
519 * tpclnp_ctlinput()
520 * FUNCTION and ARGUMENTS:
521 * find the tpcb pointer and pass it to tp_quench
522 */
523 void
tpiso_decbit(isop)524 tpiso_decbit(isop)
525 struct isopcb *isop;
526 {
527 tp_quench((struct tp_pcb *)isop->isop_socket->so_pcb, PRC_QUENCH2);
528 }
529 /*
530 * CALLED FROM:
531 * tpclnp_ctlinput()
532 * FUNCTION and ARGUMENTS:
533 * find the tpcb pointer and pass it to tp_quench
534 */
535 void
tpiso_quench(isop)536 tpiso_quench(isop)
537 struct isopcb *isop;
538 {
539 tp_quench((struct tp_pcb *)isop->isop_socket->so_pcb, PRC_QUENCH);
540 }
541
542 /*
543 * CALLED FROM:
544 * The network layer through the protosw table.
545 * FUNCTION and ARGUMENTS:
546 * When clnp an ICMP-like msg this gets called.
547 * It either returns an error status to the user or
548 * it causes all connections on this address to be aborted
549 * by calling the appropriate xx_notify() routine.
550 * (cmd) is the type of ICMP error.
551 * (siso) is the address of the guy who sent the ER CLNPDU
552 */
553 ProtoHook
tpclnp_ctlinput(cmd,siso)554 tpclnp_ctlinput(cmd, siso)
555 int cmd;
556 struct sockaddr_iso *siso;
557 {
558 extern u_char inetctlerrmap[];
559 extern ProtoHook tpiso_abort();
560 extern ProtoHook iso_rtchange();
561 extern ProtoHook tpiso_reset();
562 void iso_pcbnotify();
563
564 IFDEBUG(D_TPINPUT)
565 printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd);
566 dump_isoaddr(siso);
567 ENDDEBUG
568
569 if (cmd < 0 || cmd > PRC_NCMDS)
570 return 0;
571 if (siso->siso_family != AF_ISO)
572 return 0;
573 switch (cmd) {
574
575 case PRC_QUENCH2:
576 iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_decbit);
577 break;
578
579 case PRC_QUENCH:
580 iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_quench);
581 break;
582
583 case PRC_TIMXCEED_REASS:
584 case PRC_ROUTEDEAD:
585 iso_pcbnotify(&tp_isopcb, siso, 0, tpiso_reset);
586 break;
587
588 case PRC_HOSTUNREACH:
589 case PRC_UNREACH_NET:
590 case PRC_IFDOWN:
591 case PRC_HOSTDEAD:
592 iso_pcbnotify(&tp_isopcb, siso,
593 (int)inetctlerrmap[cmd], iso_rtchange);
594 break;
595
596 default:
597 /*
598 case PRC_MSGSIZE:
599 case PRC_UNREACH_HOST:
600 case PRC_UNREACH_PROTOCOL:
601 case PRC_UNREACH_PORT:
602 case PRC_UNREACH_NEEDFRAG:
603 case PRC_UNREACH_SRCFAIL:
604 case PRC_REDIRECT_NET:
605 case PRC_REDIRECT_HOST:
606 case PRC_REDIRECT_TOSNET:
607 case PRC_REDIRECT_TOSHOST:
608 case PRC_TIMXCEED_INTRANS:
609 case PRC_PARAMPROB:
610 */
611 iso_pcbnotify(&tp_isopcb, siso, (int)inetctlerrmap[cmd], tpiso_abort);
612 break;
613 }
614 return 0;
615 }
616 /*
617 * XXX - Variant which is called by clnp_er.c with an isoaddr rather
618 * than a sockaddr_iso.
619 */
620
621 static struct sockaddr_iso siso = {sizeof(siso), AF_ISO};
tpclnp_ctlinput1(cmd,isoa)622 tpclnp_ctlinput1(cmd, isoa)
623 int cmd;
624 struct iso_addr *isoa;
625 {
626 bzero((caddr_t)&siso.siso_addr, sizeof(siso.siso_addr));
627 bcopy((caddr_t)isoa, (caddr_t)&siso.siso_addr, isoa->isoa_len);
628 tpclnp_ctlinput(cmd, &siso);
629 }
630
631 /*
632 * These next 2 routines are
633 * CALLED FROM:
634 * xxx_notify() from tp_ctlinput() when
635 * net level gets some ICMP-equiv. type event.
636 * FUNCTION and ARGUMENTS:
637 * Cause the connection to be aborted with some sort of error
638 * reason indicating that the network layer caused the abort.
639 * Fakes an ER TPDU so we can go through the driver.
640 * abort always aborts the TP connection.
641 * reset may or may not, depending on the TP class that's in use.
642 */
643 ProtoHook
tpiso_abort(isop)644 tpiso_abort(isop)
645 struct isopcb *isop;
646 {
647 struct tp_event e;
648
649 IFDEBUG(D_CONN)
650 printf("tpiso_abort 0x%x\n", isop);
651 ENDDEBUG
652 e.ev_number = ER_TPDU;
653 e.ATTR(ER_TPDU).e_reason = ECONNABORTED;
654 return tp_driver((struct tp_pcb *)isop->isop_socket->so_pcb, &e);
655 }
656
657 ProtoHook
tpiso_reset(isop)658 tpiso_reset(isop)
659 struct isopcb *isop;
660 {
661 struct tp_event e;
662
663 e.ev_number = T_NETRESET;
664 return tp_driver((struct tp_pcb *)isop->isop_socket->so_pcb, &e);
665
666 }
667
668 #endif /* ISO */
669