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