xref: /csrg-svn/sys/netiso/tp_iso.c (revision 37469)
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