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