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