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