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