xref: /original-bsd/sys/netiso/tp_inet.c (revision 08eb28af)
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_inet.c	7.8 (Berkeley) 05/06/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: tp_inet.c,v 5.3 88/11/18 17:27:29 nhall Exp $
39  * $Source: /usr/argo/sys/netiso/RCS/tp_inet.c,v $
40  *
41  * Here is where you find the inet-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  * 	in_getsufx: gets transport suffix out of an inpcb structure.
48  * 	in_putsufx: put transport suffix into an inpcb structure.
49  *	in_putnetaddr: put a whole net addr into an inpcb.
50  *	in_getnetaddr: get a whole net addr from an inpcb.
51  *	in_cmpnetaddr: compare a whole net addr from an isopcb.
52  *	in_recycle_suffix: clear suffix for reuse in inpcb
53  *	tpip_mtu: figure out what size tpdu to use
54  *	tpip_input: take a pkt from ip, strip off its ip header, give to tp
55  *	tpip_output_dg: package a pkt for ip given 2 addresses & some data
56  *	tpip_output: package a pkt for ip given an inpcb & some data
57  */
58 
59 #ifdef INET
60 
61 #include "param.h"
62 #include "socket.h"
63 #include "socketvar.h"
64 #include "mbuf.h"
65 #include "errno.h"
66 #include "time.h"
67 #include "../net/if.h"
68 #include "tp_param.h"
69 #include "argo_debug.h"
70 #include "tp_stat.h"
71 #include "tp_ip.h"
72 #include "tp_pcb.h"
73 #include "tp_trace.h"
74 #include "tp_stat.h"
75 #include "tp_tpdu.h"
76 #include "../netinet/in_var.h"
77 
78 #ifndef ISO
79 #include "iso_chksum.c"
80 #endif
81 
82 /*
83  * NAME:			in_getsufx()
84 
85  * CALLED FROM: 	pr_usrreq() on PRU_BIND,
86  *					PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
87  *
88  * FUNCTION, ARGUMENTS, and RETURN VALUE:
89  * 	Get a transport suffix from an inpcb structure (inp).
90  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
91  *
92  * RETURNS:		internet port / transport suffix
93  *  			(CAST TO AN INT)
94  *
95  * SIDE EFFECTS:
96  *
97  * NOTES:
98  */
99 in_getsufx(inp, lenp, data_out, which)
100 	struct inpcb *inp;
101 	u_short *lenp;
102 	caddr_t data_out;
103 	int which;
104 {
105 	*lenp = sizeof(u_short);
106 	switch (which) {
107 	case TP_LOCAL:
108 		*(u_short *)data_out = inp->inp_lport;
109 		return;
110 
111 	case TP_FOREIGN:
112 		*(u_short *)data_out = inp->inp_fport;
113 	}
114 
115 }
116 
117 /*
118  * NAME:		in_putsufx()
119  *
120  * CALLED FROM: tp_newsocket(); i.e., when a connection
121  *		is being established by an incoming CR_TPDU.
122  *
123  * FUNCTION, ARGUMENTS:
124  * 	Put a transport suffix (found in name) into an inpcb structure (inp).
125  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
126  *
127  * RETURNS:		Nada
128  *
129  * SIDE EFFECTS:
130  *
131  * NOTES:
132  */
133 /*ARGSUSED*/
134 void
135 in_putsufx(inp, sufxloc, sufxlen, which)
136 	struct inpcb *inp;
137 	caddr_t sufxloc;
138 	int which;
139 {
140 	if (which == TP_FOREIGN) {
141 		bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport));
142 	}
143 }
144 
145 /*
146  * NAME:	in_recycle_tsuffix()
147  *
148  * CALLED FROM:	tp.trans whenever we go into REFWAIT state.
149  *
150  * FUNCTION and ARGUMENT:
151  *	 Called when a ref is frozen, to allow the suffix to be reused.
152  * 	(inp) is the net level pcb.
153  *
154  * RETURNS:			Nada
155  *
156  * SIDE EFFECTS:
157  *
158  * NOTES:	This really shouldn't have to be done in a NET level pcb
159  *	but... for the internet world that just the way it is done in BSD...
160  * 	The alternative is to have the port unusable until the reference
161  * 	timer goes off.
162  */
163 void
164 in_recycle_tsuffix(inp)
165 	struct inpcb	*inp;
166 {
167 	inp->inp_fport = inp->inp_lport = 0;
168 }
169 
170 /*
171  * NAME:	in_putnetaddr()
172  *
173  * CALLED FROM:
174  * 	tp_newsocket(); i.e., when a connection is being established by an
175  * 	incoming CR_TPDU.
176  *
177  * FUNCTION and ARGUMENTS:
178  * 	Copy a whole net addr from a struct sockaddr (name).
179  * 	into an inpcb (inp).
180  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
181  *
182  * RETURNS:		Nada
183  *
184  * SIDE EFFECTS:
185  *
186  * NOTES:
187  */
188 void
189 in_putnetaddr(inp, name, which)
190 	register struct inpcb	*inp;
191 	struct sockaddr_in	*name;
192 	int which;
193 {
194 	switch (which) {
195 	case TP_LOCAL:
196 		bcopy((caddr_t)&name->sin_addr,
197 			(caddr_t)&inp->inp_laddr, sizeof(struct in_addr));
198 			/* won't work if the dst address (name) is INADDR_ANY */
199 
200 		break;
201 	case TP_FOREIGN:
202 		if( name != (struct sockaddr_in *)0 ) {
203 			bcopy((caddr_t)&name->sin_addr,
204 				(caddr_t)&inp->inp_faddr, sizeof(struct in_addr));
205 		}
206 	}
207 }
208 
209 /*
210  * NAME:	in_putnetaddr()
211  *
212  * CALLED FROM:
213  * 	tp_input() when a connection is being established by an
214  * 	incoming CR_TPDU, and considered for interception.
215  *
216  * FUNCTION and ARGUMENTS:
217  * 	Compare a whole net addr from a struct sockaddr (name),
218  * 	with that implicitly stored in an inpcb (inp).
219  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
220  *
221  * RETURNS:		Nada
222  *
223  * SIDE EFFECTS:
224  *
225  * NOTES:
226  */
227 in_cmpnetaddr(inp, name, which)
228 	register struct inpcb	*inp;
229 	register struct sockaddr_in	*name;
230 	int which;
231 {
232 	if (which == TP_LOCAL) {
233 		if (name->sin_port && name->sin_port != inp->inp_lport)
234 			return 0;
235 		return (name->sin_addr.s_addr == inp->inp_laddr.s_addr);
236 	}
237 	if (name->sin_port && name->sin_port != inp->inp_fport)
238 		return 0;
239 	return (name->sin_addr.s_addr == inp->inp_faddr.s_addr);
240 }
241 
242 /*
243  * NAME:	in_getnetaddr()
244  *
245  * CALLED FROM:
246  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
247  * FUNCTION and ARGUMENTS:
248  * 	Copy a whole net addr from an inpcb (inp) into
249  * 	an mbuf (name);
250  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
251  *
252  * RETURNS:		Nada
253  *
254  * SIDE EFFECTS:
255  *
256  * NOTES:
257  */
258 
259 void
260 in_getnetaddr( inp, name, which)
261 	register struct mbuf *name;
262 	struct inpcb *inp;
263 	int which;
264 {
265 	register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *);
266 	bzero((caddr_t)sin, sizeof(*sin));
267 	switch (which) {
268 	case TP_LOCAL:
269 		sin->sin_addr = inp->inp_laddr;
270 		sin->sin_port = inp->inp_lport;
271 		break;
272 	case TP_FOREIGN:
273 		sin->sin_addr = inp->inp_faddr;
274 		sin->sin_port = inp->inp_fport;
275 		break;
276 	default:
277 		return;
278 	}
279 	name->m_len = sin->sin_len = sizeof (*sin);
280 	sin->sin_family = AF_INET;
281 }
282 
283 /*
284  * NAME: 	tpip_mtu()
285  *
286  * CALLED FROM:
287  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
288  *
289  * FUNCTION, ARGUMENTS, and RETURN VALUE:
290  *
291  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
292  * a) the header size for the network protocol and the max transmission
293  *	  unit on the subnet interface, determined from the information in (inp),
294  * b) the max size negotiated so far (negot)
295  * c) the window size used by the tp connection (found in so),
296  *
297  * The result is put in the integer *size in its integer form and in
298  * *negot in its logarithmic form.
299  *
300  * The rules are:
301  * a) can only negotiate down from the value found in *negot.
302  * b) the MTU must be < the windowsize,
303  * c) If src and dest are on the same net,
304  * 	  we will negotiate the closest size larger than  MTU but really USE
305  *    the actual device mtu - ll hdr sizes.
306  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
307  *
308  * SIDE EFFECTS:
309  *	changes the values addressed by the arguments (size) and (negot)
310  *  and
311  *  when the peer is not on one of our directly connected subnets, it
312  *  looks up a route, leaving the route in the inpcb addressed by (inp)
313  *
314  * NOTES:
315  */
316 
317 void
318 tpip_mtu(so, inp, size, negot)
319 	struct socket *so;
320 	struct inpcb *inp;
321 	int *size;
322 	u_char *negot;
323 {
324 	register struct ifnet	*ifp;
325 	struct ifnet			*tpip_route();
326 	struct in_ifaddr		*ia;
327 	register int			i;
328 	int						windowsize = so->so_rcv.sb_hiwat;
329 
330 	IFDEBUG(D_CONN)
331 		printf("tpip_mtu(0x%x,0x%x,0x%x,0x%x)\n",
332 			so, inp, size, negot);
333 		printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr);
334 	ENDDEBUG
335 	IFTRACE(D_CONN)
336 		tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
337 	ENDTRACE
338 
339 	*size = 1 << *negot;
340 
341 	if( *size > windowsize ) {
342 		*size = windowsize;
343 	}
344 
345 	ia = in_iaonnetof(in_netof(inp->inp_faddr));
346 	if ( ia == (struct in_ifaddr *)0 ) {
347 		ifp = tpip_route(&inp->inp_faddr);
348 		if( ifp == (struct ifnet *)0 )
349 			return ;
350 	} else
351 		ifp = ia->ia_ifp;
352 
353 
354 	/****************************************************************
355 	 * TODO - make this indirect off the socket structure to the
356 	 * network layer to get headersize
357 	 * After all, who knows what lies below the IP layer?
358 	 * Who knows how big the NL header will be?
359 	 ***************************************************************/
360 
361 	if( *size > ifp->if_mtu - sizeof(struct ip)) {
362 		*size = ifp->if_mtu - sizeof(struct ip);
363 	}
364 	for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i)<*size)) ; i++)
365 		;
366 	i--;
367 
368 	if (in_netof(inp->inp_laddr) != in_netof(inp->inp_faddr)) {
369 		i++;
370 	} else {
371 		*size = 1<<i;
372 	}
373 	*negot = i;
374 
375 	IFDEBUG(D_CONN)
376 		printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
377 		ifp->if_name,	*size, *negot);
378 	ENDDEBUG
379 	IFTRACE(D_CONN)
380 		tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
381 		*size, *negot, 0, 0);
382 	ENDTRACE
383 
384 }
385 
386 /*
387  * NAME:	tpip_output()
388  *
389  * CALLED FROM:  tp_emit()
390  *
391  * FUNCTION and ARGUMENTS:
392  *  Take a packet(m0) from tp and package it so that ip will accept it.
393  *  This means prepending space for the ip header and filling in a few
394  *  of the fields.
395  *  inp is the inpcb structure; datalen is the length of the data in the
396  *  mbuf string m0.
397  * RETURNS:
398  *  whatever (E*) is returned form the net layer output routine.
399  *
400  * SIDE EFFECTS:
401  *
402  * NOTES:
403  */
404 
405 int
406 tpip_output(inp, m0, datalen, nochksum)
407 	struct inpcb		*inp;
408 	struct mbuf 		*m0;
409 	int 				datalen;
410 	int					nochksum;
411 {
412 	return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen,
413 		&inp->inp_route, nochksum);
414 }
415 
416 /*
417  * NAME:	tpip_output_dg()
418  *
419  * CALLED FROM:  tp_error_emit()
420  *
421  * FUNCTION and ARGUMENTS:
422  *  This is a copy of tpip_output that takes the addresses
423  *  instead of a pcb.  It's used by the tp_error_emit, when we
424  *  don't have an in_pcb with which to call the normal output rtn.
425  *
426  * RETURNS:	 ENOBUFS or  whatever (E*) is
427  *	returned form the net layer output routine.
428  *
429  * SIDE EFFECTS:
430  *
431  * NOTES:
432  */
433 
434 /*ARGSUSED*/
435 int
436 tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
437 	struct in_addr		*laddr, *faddr;
438 	struct mbuf 		*m0;
439 	int 				datalen;
440 	struct route 		*ro;
441 	int					nochksum;
442 {
443 	register struct mbuf 	*m;
444 	register struct ip *ip;
445 	int 					error;
446 
447 	IFDEBUG(D_EMIT)
448 		printf("tpip_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
449 	ENDDEBUG
450 
451 
452 	MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
453 	if (m == 0) {
454 		error = ENOBUFS;
455 		goto bad;
456 	}
457 	m->m_next = m0;
458 	MH_ALIGN(m, sizeof(struct ip));
459 	m->m_len = sizeof(struct ip);
460 
461 	ip = mtod(m, struct ip *);
462 	bzero((caddr_t)ip, sizeof *ip);
463 
464 	ip->ip_p = IPPROTO_TP;
465 	m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
466 	ip->ip_ttl = MAXTTL;
467 		/* don't know why you need to set ttl;
468 		 * overlay doesn't even make this available
469 		 */
470 
471 	ip->ip_src = *laddr;
472 	ip->ip_dst = *faddr;
473 
474 	IncStat(ts_tpdu_sent);
475 	IFDEBUG(D_EMIT)
476 		dump_mbuf(m, "tpip_output_dg before ip_output\n");
477 	ENDDEBUG
478 
479 	error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST);
480 
481 	IFDEBUG(D_EMIT)
482 		printf("tpip_output_dg after ip_output\n");
483 	ENDDEBUG
484 
485 	return error;
486 
487 bad:
488 	m_freem(m);
489 	IncStat(ts_send_drop);
490 	return error;
491 }
492 
493 /*
494  * NAME:  tpip_input()
495  *
496  * CALLED FROM:
497  * 	ip's input routine, indirectly through the protosw.
498  *
499  * FUNCTION and ARGUMENTS:
500  * Take a packet (m) from ip, strip off the ip header and give it to tp
501  *
502  * RETURNS:  No return value.
503  *
504  * SIDE EFFECTS:
505  *
506  * NOTES:
507  */
508 ProtoHook
509 tpip_input(m, iplen)
510 	struct mbuf *m;
511 	int iplen;
512 {
513 	struct sockaddr_in 	src, dst;
514 	register struct ip 		*ip;
515 	int						s = splnet(), hdrlen;
516 
517 	IncStat(ts_pkt_rcvd);
518 
519 	/*
520 	 * IP layer has already pulled up the IP header,
521 	 * but the first byte after the IP header may not be there,
522 	 * e.g. if you came in via loopback, so you have to do an
523 	 * m_pullup to before you can even look to see how much you
524 	 * really need.  The good news is that m_pullup will round
525 	 * up to almost the next mbuf's worth.
526 	 */
527 
528 
529 	if((m = m_pullup(m, iplen + 1)) == MNULL)
530 		goto discard;
531 	CHANGE_MTYPE(m, TPMT_DATA);
532 
533 	/*
534 	 * Now pull up the whole tp header:
535 	 * Unfortunately, there may be IP options to skip past so we
536 	 * just fetch it as an unsigned char.
537 	 */
538 	hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
539 
540 	if( m->m_len < hdrlen ) {
541 		if((m = m_pullup(m, hdrlen)) == MNULL){
542 			IFDEBUG(D_TPINPUT)
543 				printf("tp_input, pullup 2!\n");
544 			ENDDEBUG
545 			goto discard;
546 		}
547 	}
548 	/*
549 	 * cannot use tp_inputprep() here 'cause you don't
550 	 * have quite the same situation
551 	 */
552 
553 	IFDEBUG(D_TPINPUT)
554 		dump_mbuf(m, "after tpip_input both pullups");
555 	ENDDEBUG
556 	/*
557 	 * m_pullup may have returned a different mbuf
558 	 */
559 	ip = mtod(m, struct ip *);
560 
561 	/*
562 	 * drop the ip header from the front of the mbuf
563 	 * this is necessary for the tp checksum
564 	 */
565 	m->m_len -= iplen;
566 	m->m_data += iplen;
567 
568 	src.sin_addr = *(struct in_addr *)&(ip->ip_src);
569 	src.sin_family  = AF_INET;
570 	src.sin_len  = sizeof(src);
571 	dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
572 	dst.sin_family  = AF_INET;
573 	dst.sin_len  = sizeof(dst);
574 
575 	(void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
576 				0, tpip_output_dg, 0);
577 	return 0;
578 
579 discard:
580 	IFDEBUG(D_TPINPUT)
581 		printf("tpip_input DISCARD\n");
582 	ENDDEBUG
583 	IFTRACE(D_TPINPUT)
584 		tptrace(TPPTmisc, "tpip_input DISCARD m",  m,0,0,0);
585 	ENDTRACE
586 	m_freem(m);
587 	IncStat(ts_recv_drop);
588 	splx(s);
589 	return 0;
590 }
591 
592 
593 #include "protosw.h"
594 #include "../netinet/ip_icmp.h"
595 
596 extern void tp_quench();
597 /*
598  * NAME:	tpin_quench()
599  *
600  * CALLED FROM: tpip_ctlinput()
601  *
602  * FUNCTION and ARGUMENTS:  find the tpcb pointer and pass it to tp_quench
603  *
604  * RETURNS:	Nada
605  *
606  * SIDE EFFECTS:
607  *
608  * NOTES:
609  */
610 
611 void
612 tpin_quench(inp)
613 	struct inpcb *inp;
614 {
615 	tp_quench((struct tp_pcb *)inp->inp_socket->so_tpcb, PRC_QUENCH);
616 }
617 
618 /*
619  * NAME:	tpip_ctlinput()
620  *
621  * CALLED FROM:
622  *  The network layer through the protosw table.
623  *
624  * FUNCTION and ARGUMENTS:
625  *	When clnp gets an ICMP msg this gets called.
626  *	It either returns an error status to the user or
627  *	causes all connections on this address to be aborted
628  *	by calling the appropriate xx_notify() routine.
629  *	(cmd) is the type of ICMP error.
630  * 	(sa) the address of the sender
631  *
632  * RETURNS:	 Nothing
633  *
634  * SIDE EFFECTS:
635  *
636  * NOTES:
637  */
638 ProtoHook
639 tpip_ctlinput(cmd, sin)
640 	int cmd;
641 	struct sockaddr_in *sin;
642 {
643 	extern u_char inetctlerrmap[];
644 	extern ProtoHook tpin_abort();
645 	extern ProtoHook in_rtchange();
646 	extern struct in_addr zeroin_addr;
647 
648 	if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK)
649 		return 0;
650 	if (sin->sin_addr.s_addr == INADDR_ANY)
651 		return 0;
652 	if (cmd < 0 || cmd > PRC_NCMDS)
653 		return 0;
654 	switch (cmd) {
655 
656 		case	PRC_QUENCH:
657 			in_pcbnotify(&tp_inpcb, sin, 0,
658 				zeroin_addr, 0, cmd, (int (*)())tp_quench);
659 			break;
660 
661 		case	PRC_ROUTEDEAD:
662 		case	PRC_HOSTUNREACH:
663 		case	PRC_UNREACH_NET:
664 		case	PRC_IFDOWN:
665 		case	PRC_HOSTDEAD:
666 			in_pcbnotify(&tp_inpcb, sin, 0,
667 				zeroin_addr, 0, cmd, in_rtchange);
668 			break;
669 
670 		default:
671 		/*
672 		case	PRC_MSGSIZE:
673 		case	PRC_UNREACH_HOST:
674 		case	PRC_UNREACH_PROTOCOL:
675 		case	PRC_UNREACH_PORT:
676 		case	PRC_UNREACH_NEEDFRAG:
677 		case	PRC_UNREACH_SRCFAIL:
678 		case	PRC_REDIRECT_NET:
679 		case	PRC_REDIRECT_HOST:
680 		case	PRC_REDIRECT_TOSNET:
681 		case	PRC_REDIRECT_TOSHOST:
682 		case	PRC_TIMXCEED_INTRANS:
683 		case	PRC_TIMXCEED_REASS:
684 		case	PRC_PARAMPROB:
685 		*/
686 		in_pcbnotify(&tp_inpcb, sin, 0, zeroin_addr, 0,
687 				cmd, tpin_abort);
688 	}
689 	return 0;
690 }
691 
692 /*
693  * NAME:	tpin_abort()
694  *
695  * CALLED FROM:
696  *	xxx_notify() from tp_ctlinput() when
697  *  net level gets some ICMP-equiv. type event.
698  *
699  * FUNCTION and ARGUMENTS:
700  *  Cause the connection to be aborted with some sort of error
701  *  reason indicating that the network layer caused the abort.
702  *  Fakes an ER TPDU so we can go through the driver.
703  *
704  * RETURNS:	 Nothing
705  *
706  * SIDE EFFECTS:
707  *
708  * NOTES:
709  */
710 
711 ProtoHook
712 tpin_abort(inp)
713 	struct inpcb *inp;
714 {
715 	struct tp_event e;
716 
717 	e.ev_number = ER_TPDU;
718 	e.ATTR(ER_TPDU).e_reason = ENETRESET;
719 	(void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
720 	return 0;
721 }
722 
723 #ifdef ARGO_DEBUG
724 dump_inaddr(addr)
725 	register struct sockaddr_in *addr;
726 {
727 	printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr);
728 }
729 #endif ARGO_DEBUG
730 
731 /*
732  * NAME:	tpip_route()
733  *
734  * CALLED FROM: tpip_mtu()
735  *
736  * FUNCTION and ARGUMENTS:	given a destination addresss,
737  *	find the interface that would be used to send something to this address.
738  *
739  * RETURNS:	 pointer to an ifnet structure
740  *
741  * SIDE EFFECTS:
742  *
743  * NOTES:
744  */
745 struct ifnet *
746 tpip_route(dst)
747 	struct in_addr *dst;
748 {
749 	struct ifnet 		*ifp = (struct ifnet *)0;
750 	struct sockaddr_in	insock;
751 	struct sockaddr_in	*sin = &insock;
752 	struct rtentry 		*rt;
753 	struct ifaddr	*ia;
754 
755 	IFDEBUG(D_CONN)
756 		printf("tpip_route: dst is x%x\n", *dst);
757 	ENDDEBUG
758 
759 	bzero((caddr_t)sin, sizeof (*sin));
760 	sin->sin_family = AF_INET;
761 	sin->sin_len = sizeof(*sin);
762 	sin->sin_addr = *dst;
763 
764 	ia = ifa_ifwithdstaddr((struct sockaddr *)sin);
765 	if (ia == 0)
766 		ia = ifa_ifwithnet((struct sockaddr *)sin);
767 	if (ia != 0) {
768 		ifp = ia->ifa_ifp;
769 		IFDEBUG(D_CONN)
770 			printf("tpip_route: ifp from ia:0x%x\n", ia);
771 		ENDDEBUG
772 	} else {
773 		rt = rtalloc1((struct sockaddr *)sin, 0);
774 		if (rt != 0) {
775 			ifp = rt->rt_ifp;
776 			IFDEBUG(D_CONN)
777 				printf("tpip_route: ifp from rentry: 0x%x\n", rt);
778 			ENDDEBUG
779 			rtfree(rt);
780 		}
781 	}
782 	IFDEBUG(D_CONN)
783 		printf("tpip_route: returning 0x%x\n", ifp);
784 		if (ifp)
785 			printf("tpip_route: if name %s unit 0x%x, mtu 0x%x\n",
786 				ifp->if_name, ifp->if_unit, ifp->if_mtu);
787 	ENDDEBUG
788 	return ifp;
789 }
790 
791 #endif INET
792