xref: /csrg-svn/sys/netiso/tp_inet.c (revision 50435)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*50435Ssklower  *	@(#)tp_inet.c	7.9 (Berkeley) 07/18/91
849268Sbostic  */
949268Sbostic 
1036400Ssklower /***********************************************************
1136400Ssklower 		Copyright IBM Corporation 1987
1236400Ssklower 
1336400Ssklower                       All Rights Reserved
1436400Ssklower 
1536400Ssklower Permission to use, copy, modify, and distribute this software and its
1636400Ssklower documentation for any purpose and without fee is hereby granted,
1736400Ssklower provided that the above copyright notice appear in all copies and that
1836400Ssklower both that copyright notice and this permission notice appear in
1936400Ssklower supporting documentation, and that the name of IBM not be
2036400Ssklower used in advertising or publicity pertaining to distribution of the
2136400Ssklower software without specific, written prior permission.
2236400Ssklower 
2336400Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436400Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536400Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636400Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736400Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836400Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936400Ssklower SOFTWARE.
3036400Ssklower 
3136400Ssklower ******************************************************************/
3236400Ssklower 
3336400Ssklower /*
3436400Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536400Ssklower  */
3636400Ssklower /*
3736400Ssklower  * ARGO TP
3836400Ssklower  * $Header: tp_inet.c,v 5.3 88/11/18 17:27:29 nhall Exp $
3936400Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_inet.c,v $
4036400Ssklower  *
4136400Ssklower  * Here is where you find the inet-dependent code.  We've tried
4236400Ssklower  * keep all net-level and (primarily) address-family-dependent stuff
4336400Ssklower  * out of the tp source, and everthing here is reached indirectly
4436400Ssklower  * through a switch table (struct nl_protosw *) tpcb->tp_nlproto
4536400Ssklower  * (see tp_pcb.c).
4636400Ssklower  * The routines here are:
4749268Sbostic  * 	in_getsufx: gets transport suffix out of an inpcb structure.
4849268Sbostic  * 	in_putsufx: put transport suffix into an inpcb structure.
4949268Sbostic  *	in_putnetaddr: put a whole net addr into an inpcb.
5049268Sbostic  *	in_getnetaddr: get a whole net addr from an inpcb.
5149268Sbostic  *	in_cmpnetaddr: compare a whole net addr from an isopcb.
5249268Sbostic  *	in_recycle_suffix: clear suffix for reuse in inpcb
5349268Sbostic  *	tpip_mtu: figure out what size tpdu to use
5449268Sbostic  *	tpip_input: take a pkt from ip, strip off its ip header, give to tp
5549268Sbostic  *	tpip_output_dg: package a pkt for ip given 2 addresses & some data
5649268Sbostic  *	tpip_output: package a pkt for ip given an inpcb & some data
5736400Ssklower  */
5836400Ssklower 
5936400Ssklower #ifdef INET
6036400Ssklower 
6137469Ssklower #include "param.h"
6236400Ssklower #include "socket.h"
6336400Ssklower #include "socketvar.h"
6436400Ssklower #include "mbuf.h"
6536400Ssklower #include "errno.h"
6636400Ssklower #include "time.h"
6736400Ssklower #include "../net/if.h"
6837469Ssklower #include "tp_param.h"
6937469Ssklower #include "argo_debug.h"
7037469Ssklower #include "tp_stat.h"
7137469Ssklower #include "tp_ip.h"
7237469Ssklower #include "tp_pcb.h"
7337469Ssklower #include "tp_trace.h"
7437469Ssklower #include "tp_stat.h"
7537469Ssklower #include "tp_tpdu.h"
7636400Ssklower #include "../netinet/in_var.h"
7736400Ssklower 
7837469Ssklower #ifndef ISO
7937469Ssklower #include "iso_chksum.c"
8037469Ssklower #endif
8136400Ssklower 
8236400Ssklower /*
8336400Ssklower  * NAME:			in_getsufx()
8436400Ssklower 
8536400Ssklower  * CALLED FROM: 	pr_usrreq() on PRU_BIND,
8636400Ssklower  *					PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
8736400Ssklower  *
8836400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
8936400Ssklower  * 	Get a transport suffix from an inpcb structure (inp).
9036400Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
9136400Ssklower  *
9236400Ssklower  * RETURNS:		internet port / transport suffix
9336400Ssklower  *  			(CAST TO AN INT)
9436400Ssklower  *
9536400Ssklower  * SIDE EFFECTS:
9636400Ssklower  *
9736400Ssklower  * NOTES:
9836400Ssklower  */
9937469Ssklower in_getsufx(inp, lenp, data_out, which)
10036400Ssklower 	struct inpcb *inp;
10137469Ssklower 	u_short *lenp;
10237469Ssklower 	caddr_t data_out;
10336400Ssklower 	int which;
10436400Ssklower {
10537469Ssklower 	*lenp = sizeof(u_short);
10636400Ssklower 	switch (which) {
10736400Ssklower 	case TP_LOCAL:
10837469Ssklower 		*(u_short *)data_out = inp->inp_lport;
10937469Ssklower 		return;
11036400Ssklower 
11136400Ssklower 	case TP_FOREIGN:
11237469Ssklower 		*(u_short *)data_out = inp->inp_fport;
11336400Ssklower 	}
11437469Ssklower 
11536400Ssklower }
11636400Ssklower 
11736400Ssklower /*
11836400Ssklower  * NAME:		in_putsufx()
11936400Ssklower  *
12036400Ssklower  * CALLED FROM: tp_newsocket(); i.e., when a connection
12136400Ssklower  *		is being established by an incoming CR_TPDU.
12236400Ssklower  *
12336400Ssklower  * FUNCTION, ARGUMENTS:
12436400Ssklower  * 	Put a transport suffix (found in name) into an inpcb structure (inp).
12536400Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
12636400Ssklower  *
12736400Ssklower  * RETURNS:		Nada
12836400Ssklower  *
12936400Ssklower  * SIDE EFFECTS:
13036400Ssklower  *
13136400Ssklower  * NOTES:
13236400Ssklower  */
13337469Ssklower /*ARGSUSED*/
13436400Ssklower void
13537469Ssklower in_putsufx(inp, sufxloc, sufxlen, which)
13636400Ssklower 	struct inpcb *inp;
13737469Ssklower 	caddr_t sufxloc;
13836400Ssklower 	int which;
13936400Ssklower {
14037469Ssklower 	if (which == TP_FOREIGN) {
14137469Ssklower 		bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport));
14236400Ssklower 	}
14336400Ssklower }
14436400Ssklower 
14536400Ssklower /*
14636400Ssklower  * NAME:	in_recycle_tsuffix()
14736400Ssklower  *
14836400Ssklower  * CALLED FROM:	tp.trans whenever we go into REFWAIT state.
14936400Ssklower  *
15036400Ssklower  * FUNCTION and ARGUMENT:
15136400Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
15236400Ssklower  * 	(inp) is the net level pcb.
15336400Ssklower  *
15436400Ssklower  * RETURNS:			Nada
15536400Ssklower  *
15636400Ssklower  * SIDE EFFECTS:
15736400Ssklower  *
15836400Ssklower  * NOTES:	This really shouldn't have to be done in a NET level pcb
15936400Ssklower  *	but... for the internet world that just the way it is done in BSD...
16036400Ssklower  * 	The alternative is to have the port unusable until the reference
16136400Ssklower  * 	timer goes off.
16236400Ssklower  */
16336400Ssklower void
16436400Ssklower in_recycle_tsuffix(inp)
16536400Ssklower 	struct inpcb	*inp;
16636400Ssklower {
16736400Ssklower 	inp->inp_fport = inp->inp_lport = 0;
16836400Ssklower }
16936400Ssklower 
17036400Ssklower /*
17136400Ssklower  * NAME:	in_putnetaddr()
17236400Ssklower  *
17336400Ssklower  * CALLED FROM:
17436400Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
17536400Ssklower  * 	incoming CR_TPDU.
17636400Ssklower  *
17736400Ssklower  * FUNCTION and ARGUMENTS:
17836400Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
17936400Ssklower  * 	into an inpcb (inp).
18036400Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
18136400Ssklower  *
18236400Ssklower  * RETURNS:		Nada
18336400Ssklower  *
18436400Ssklower  * SIDE EFFECTS:
18536400Ssklower  *
18636400Ssklower  * NOTES:
18736400Ssklower  */
18836400Ssklower void
18936400Ssklower in_putnetaddr(inp, name, which)
19036400Ssklower 	register struct inpcb	*inp;
19136400Ssklower 	struct sockaddr_in	*name;
19236400Ssklower 	int which;
19336400Ssklower {
19436400Ssklower 	switch (which) {
19536400Ssklower 	case TP_LOCAL:
19636400Ssklower 		bcopy((caddr_t)&name->sin_addr,
19736400Ssklower 			(caddr_t)&inp->inp_laddr, sizeof(struct in_addr));
19836400Ssklower 			/* won't work if the dst address (name) is INADDR_ANY */
19936400Ssklower 
20036400Ssklower 		break;
20136400Ssklower 	case TP_FOREIGN:
20236400Ssklower 		if( name != (struct sockaddr_in *)0 ) {
20336400Ssklower 			bcopy((caddr_t)&name->sin_addr,
20436400Ssklower 				(caddr_t)&inp->inp_faddr, sizeof(struct in_addr));
20536400Ssklower 		}
20636400Ssklower 	}
20736400Ssklower }
20836400Ssklower 
20936400Ssklower /*
21044422Ssklower  * NAME:	in_putnetaddr()
21144422Ssklower  *
21244422Ssklower  * CALLED FROM:
21344422Ssklower  * 	tp_input() when a connection is being established by an
21444422Ssklower  * 	incoming CR_TPDU, and considered for interception.
21544422Ssklower  *
21644422Ssklower  * FUNCTION and ARGUMENTS:
21744422Ssklower  * 	Compare a whole net addr from a struct sockaddr (name),
21844422Ssklower  * 	with that implicitly stored in an inpcb (inp).
21944422Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
22044422Ssklower  *
22144422Ssklower  * RETURNS:		Nada
22244422Ssklower  *
22344422Ssklower  * SIDE EFFECTS:
22444422Ssklower  *
22544422Ssklower  * NOTES:
22644422Ssklower  */
22744422Ssklower in_cmpnetaddr(inp, name, which)
22844422Ssklower 	register struct inpcb	*inp;
22944422Ssklower 	register struct sockaddr_in	*name;
23044422Ssklower 	int which;
23144422Ssklower {
23244422Ssklower 	if (which == TP_LOCAL) {
23344422Ssklower 		if (name->sin_port && name->sin_port != inp->inp_lport)
23444422Ssklower 			return 0;
23544422Ssklower 		return (name->sin_addr.s_addr == inp->inp_laddr.s_addr);
23644422Ssklower 	}
23744422Ssklower 	if (name->sin_port && name->sin_port != inp->inp_fport)
23844422Ssklower 		return 0;
23944422Ssklower 	return (name->sin_addr.s_addr == inp->inp_faddr.s_addr);
24044422Ssklower }
24144422Ssklower 
24244422Ssklower /*
24336400Ssklower  * NAME:	in_getnetaddr()
24436400Ssklower  *
24536400Ssklower  * CALLED FROM:
24636400Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
24736400Ssklower  * FUNCTION and ARGUMENTS:
24836400Ssklower  * 	Copy a whole net addr from an inpcb (inp) into
24937469Ssklower  * 	an mbuf (name);
25036400Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
25136400Ssklower  *
25236400Ssklower  * RETURNS:		Nada
25336400Ssklower  *
25436400Ssklower  * SIDE EFFECTS:
25536400Ssklower  *
25636400Ssklower  * NOTES:
25736400Ssklower  */
25836400Ssklower 
25936400Ssklower void
26036400Ssklower in_getnetaddr( inp, name, which)
26137469Ssklower 	register struct mbuf *name;
26236400Ssklower 	struct inpcb *inp;
26336400Ssklower 	int which;
26436400Ssklower {
26537469Ssklower 	register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *);
26637469Ssklower 	bzero((caddr_t)sin, sizeof(*sin));
26736400Ssklower 	switch (which) {
26836400Ssklower 	case TP_LOCAL:
26937469Ssklower 		sin->sin_addr = inp->inp_laddr;
27037469Ssklower 		sin->sin_port = inp->inp_lport;
27136400Ssklower 		break;
27236400Ssklower 	case TP_FOREIGN:
27337469Ssklower 		sin->sin_addr = inp->inp_faddr;
27437469Ssklower 		sin->sin_port = inp->inp_fport;
27536400Ssklower 		break;
27637469Ssklower 	default:
27737469Ssklower 		return;
27836400Ssklower 	}
27937469Ssklower 	name->m_len = sin->sin_len = sizeof (*sin);
28037469Ssklower 	sin->sin_family = AF_INET;
28136400Ssklower }
28236400Ssklower 
28336400Ssklower /*
28436400Ssklower  * NAME: 	tpip_mtu()
28536400Ssklower  *
28636400Ssklower  * CALLED FROM:
28736400Ssklower  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
28836400Ssklower  *
28936400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
29036400Ssklower  *
29136400Ssklower  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
29236400Ssklower  * a) the header size for the network protocol and the max transmission
29336400Ssklower  *	  unit on the subnet interface, determined from the information in (inp),
29436400Ssklower  * b) the max size negotiated so far (negot)
29536400Ssklower  * c) the window size used by the tp connection (found in so),
29636400Ssklower  *
29736400Ssklower  * The result is put in the integer *size in its integer form and in
29836400Ssklower  * *negot in its logarithmic form.
29936400Ssklower  *
30036400Ssklower  * The rules are:
30136400Ssklower  * a) can only negotiate down from the value found in *negot.
30236400Ssklower  * b) the MTU must be < the windowsize,
30336400Ssklower  * c) If src and dest are on the same net,
30436400Ssklower  * 	  we will negotiate the closest size larger than  MTU but really USE
30536400Ssklower  *    the actual device mtu - ll hdr sizes.
30636400Ssklower  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
30736400Ssklower  *
30836400Ssklower  * SIDE EFFECTS:
30936400Ssklower  *	changes the values addressed by the arguments (size) and (negot)
31036400Ssklower  *  and
31136400Ssklower  *  when the peer is not on one of our directly connected subnets, it
31236400Ssklower  *  looks up a route, leaving the route in the inpcb addressed by (inp)
31336400Ssklower  *
31436400Ssklower  * NOTES:
31536400Ssklower  */
31636400Ssklower 
31736400Ssklower void
31836400Ssklower tpip_mtu(so, inp, size, negot)
31936400Ssklower 	struct socket *so;
32036400Ssklower 	struct inpcb *inp;
32136400Ssklower 	int *size;
32236400Ssklower 	u_char *negot;
32336400Ssklower {
32436400Ssklower 	register struct ifnet	*ifp;
32536400Ssklower 	struct ifnet			*tpip_route();
32636400Ssklower 	struct in_ifaddr		*ia;
32736400Ssklower 	register int			i;
32836400Ssklower 	int						windowsize = so->so_rcv.sb_hiwat;
32936400Ssklower 
33036400Ssklower 	IFDEBUG(D_CONN)
33136400Ssklower 		printf("tpip_mtu(0x%x,0x%x,0x%x,0x%x)\n",
33236400Ssklower 			so, inp, size, negot);
33336400Ssklower 		printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr);
33436400Ssklower 	ENDDEBUG
33536400Ssklower 	IFTRACE(D_CONN)
33636400Ssklower 		tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
33736400Ssklower 	ENDTRACE
33836400Ssklower 
33936400Ssklower 	*size = 1 << *negot;
34036400Ssklower 
34136400Ssklower 	if( *size > windowsize ) {
34236400Ssklower 		*size = windowsize;
34336400Ssklower 	}
34436400Ssklower 
34536400Ssklower 	ia = in_iaonnetof(in_netof(inp->inp_faddr));
34636400Ssklower 	if ( ia == (struct in_ifaddr *)0 ) {
34736400Ssklower 		ifp = tpip_route(&inp->inp_faddr);
34836400Ssklower 		if( ifp == (struct ifnet *)0 )
34936400Ssklower 			return ;
35036400Ssklower 	} else
35136400Ssklower 		ifp = ia->ia_ifp;
35236400Ssklower 
35336400Ssklower 
35436400Ssklower 	/****************************************************************
35536400Ssklower 	 * TODO - make this indirect off the socket structure to the
35636400Ssklower 	 * network layer to get headersize
35736400Ssklower 	 * After all, who knows what lies below the IP layer?
35836400Ssklower 	 * Who knows how big the NL header will be?
35936400Ssklower 	 ***************************************************************/
36036400Ssklower 
36136400Ssklower 	if( *size > ifp->if_mtu - sizeof(struct ip)) {
36236400Ssklower 		*size = ifp->if_mtu - sizeof(struct ip);
36336400Ssklower 	}
36436400Ssklower 	for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i)<*size)) ; i++)
36536400Ssklower 		;
36636400Ssklower 	i--;
36736400Ssklower 
36836400Ssklower 	if (in_netof(inp->inp_laddr) != in_netof(inp->inp_faddr)) {
36936400Ssklower 		i++;
37036400Ssklower 	} else {
37136400Ssklower 		*size = 1<<i;
37236400Ssklower 	}
37336400Ssklower 	*negot = i;
37436400Ssklower 
37536400Ssklower 	IFDEBUG(D_CONN)
37636400Ssklower 		printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
37736400Ssklower 		ifp->if_name,	*size, *negot);
37836400Ssklower 	ENDDEBUG
37936400Ssklower 	IFTRACE(D_CONN)
38036400Ssklower 		tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
38136400Ssklower 		*size, *negot, 0, 0);
38236400Ssklower 	ENDTRACE
38336400Ssklower 
38436400Ssklower }
38536400Ssklower 
38636400Ssklower /*
38736400Ssklower  * NAME:	tpip_output()
38836400Ssklower  *
38936400Ssklower  * CALLED FROM:  tp_emit()
39036400Ssklower  *
39136400Ssklower  * FUNCTION and ARGUMENTS:
39236400Ssklower  *  Take a packet(m0) from tp and package it so that ip will accept it.
39336400Ssklower  *  This means prepending space for the ip header and filling in a few
39436400Ssklower  *  of the fields.
39536400Ssklower  *  inp is the inpcb structure; datalen is the length of the data in the
39636400Ssklower  *  mbuf string m0.
39736400Ssklower  * RETURNS:
39836400Ssklower  *  whatever (E*) is returned form the net layer output routine.
39936400Ssklower  *
40036400Ssklower  * SIDE EFFECTS:
40136400Ssklower  *
40236400Ssklower  * NOTES:
40336400Ssklower  */
40436400Ssklower 
40536400Ssklower int
40636400Ssklower tpip_output(inp, m0, datalen, nochksum)
40736400Ssklower 	struct inpcb		*inp;
40836400Ssklower 	struct mbuf 		*m0;
40936400Ssklower 	int 				datalen;
41036400Ssklower 	int					nochksum;
41136400Ssklower {
41236400Ssklower 	return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen,
41336400Ssklower 		&inp->inp_route, nochksum);
41436400Ssklower }
41536400Ssklower 
41636400Ssklower /*
41736400Ssklower  * NAME:	tpip_output_dg()
41836400Ssklower  *
41936400Ssklower  * CALLED FROM:  tp_error_emit()
42036400Ssklower  *
42136400Ssklower  * FUNCTION and ARGUMENTS:
42236400Ssklower  *  This is a copy of tpip_output that takes the addresses
42336400Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
42436400Ssklower  *  don't have an in_pcb with which to call the normal output rtn.
42536400Ssklower  *
42636400Ssklower  * RETURNS:	 ENOBUFS or  whatever (E*) is
42736400Ssklower  *	returned form the net layer output routine.
42836400Ssklower  *
42936400Ssklower  * SIDE EFFECTS:
43036400Ssklower  *
43136400Ssklower  * NOTES:
43236400Ssklower  */
43336400Ssklower 
43437469Ssklower /*ARGSUSED*/
43536400Ssklower int
43636400Ssklower tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
43736400Ssklower 	struct in_addr		*laddr, *faddr;
43836400Ssklower 	struct mbuf 		*m0;
43936400Ssklower 	int 				datalen;
44036400Ssklower 	struct route 		*ro;
44136400Ssklower 	int					nochksum;
44236400Ssklower {
44336400Ssklower 	register struct mbuf 	*m;
44436400Ssklower 	register struct ip *ip;
44536400Ssklower 	int 					error;
44636400Ssklower 
44736400Ssklower 	IFDEBUG(D_EMIT)
44836400Ssklower 		printf("tpip_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
44936400Ssklower 	ENDDEBUG
45036400Ssklower 
45136400Ssklower 
45237469Ssklower 	MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
45336400Ssklower 	if (m == 0) {
45436400Ssklower 		error = ENOBUFS;
45536400Ssklower 		goto bad;
45636400Ssklower 	}
45736400Ssklower 	m->m_next = m0;
45837469Ssklower 	MH_ALIGN(m, sizeof(struct ip));
45936400Ssklower 	m->m_len = sizeof(struct ip);
46036400Ssklower 
46136400Ssklower 	ip = mtod(m, struct ip *);
46237469Ssklower 	bzero((caddr_t)ip, sizeof *ip);
46336400Ssklower 
46436400Ssklower 	ip->ip_p = IPPROTO_TP;
46537469Ssklower 	m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
46636400Ssklower 	ip->ip_ttl = MAXTTL;
46736400Ssklower 		/* don't know why you need to set ttl;
46836400Ssklower 		 * overlay doesn't even make this available
46936400Ssklower 		 */
47036400Ssklower 
47136400Ssklower 	ip->ip_src = *laddr;
47236400Ssklower 	ip->ip_dst = *faddr;
47336400Ssklower 
47436400Ssklower 	IncStat(ts_tpdu_sent);
47536400Ssklower 	IFDEBUG(D_EMIT)
47636400Ssklower 		dump_mbuf(m, "tpip_output_dg before ip_output\n");
47736400Ssklower 	ENDDEBUG
47836400Ssklower 
47936400Ssklower 	error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST);
48036400Ssklower 
48136400Ssklower 	IFDEBUG(D_EMIT)
48236400Ssklower 		printf("tpip_output_dg after ip_output\n");
48336400Ssklower 	ENDDEBUG
48436400Ssklower 
48536400Ssklower 	return error;
48636400Ssklower 
48736400Ssklower bad:
48836400Ssklower 	m_freem(m);
48936400Ssklower 	IncStat(ts_send_drop);
49036400Ssklower 	return error;
49136400Ssklower }
49236400Ssklower 
49336400Ssklower /*
49436400Ssklower  * NAME:  tpip_input()
49536400Ssklower  *
49636400Ssklower  * CALLED FROM:
49736400Ssklower  * 	ip's input routine, indirectly through the protosw.
49836400Ssklower  *
49936400Ssklower  * FUNCTION and ARGUMENTS:
50036400Ssklower  * Take a packet (m) from ip, strip off the ip header and give it to tp
50136400Ssklower  *
50236400Ssklower  * RETURNS:  No return value.
50336400Ssklower  *
50436400Ssklower  * SIDE EFFECTS:
50536400Ssklower  *
50636400Ssklower  * NOTES:
50736400Ssklower  */
50836400Ssklower ProtoHook
50937469Ssklower tpip_input(m, iplen)
51036400Ssklower 	struct mbuf *m;
51137469Ssklower 	int iplen;
51236400Ssklower {
51336400Ssklower 	struct sockaddr_in 	src, dst;
51436400Ssklower 	register struct ip 		*ip;
51537469Ssklower 	int						s = splnet(), hdrlen;
51636400Ssklower 
51736400Ssklower 	IncStat(ts_pkt_rcvd);
51836400Ssklower 
51937469Ssklower 	/*
52037469Ssklower 	 * IP layer has already pulled up the IP header,
52137469Ssklower 	 * but the first byte after the IP header may not be there,
52237469Ssklower 	 * e.g. if you came in via loopback, so you have to do an
52337469Ssklower 	 * m_pullup to before you can even look to see how much you
52437469Ssklower 	 * really need.  The good news is that m_pullup will round
52537469Ssklower 	 * up to almost the next mbuf's worth.
52637469Ssklower 	 */
52736400Ssklower 
52837469Ssklower 
52937469Ssklower 	if((m = m_pullup(m, iplen + 1)) == MNULL)
53037469Ssklower 		goto discard;
53136400Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
53236400Ssklower 
53336400Ssklower 	/*
53437469Ssklower 	 * Now pull up the whole tp header:
53537469Ssklower 	 * Unfortunately, there may be IP options to skip past so we
53637469Ssklower 	 * just fetch it as an unsigned char.
53736400Ssklower 	 */
53837469Ssklower 	hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
53936400Ssklower 
54037469Ssklower 	if( m->m_len < hdrlen ) {
54137469Ssklower 		if((m = m_pullup(m, hdrlen)) == MNULL){
54236400Ssklower 			IFDEBUG(D_TPINPUT)
54336400Ssklower 				printf("tp_input, pullup 2!\n");
54436400Ssklower 			ENDDEBUG
54536400Ssklower 			goto discard;
54636400Ssklower 		}
54736400Ssklower 	}
54836400Ssklower 	/*
54936400Ssklower 	 * cannot use tp_inputprep() here 'cause you don't
55036400Ssklower 	 * have quite the same situation
55136400Ssklower 	 */
55236400Ssklower 
55336400Ssklower 	IFDEBUG(D_TPINPUT)
55436400Ssklower 		dump_mbuf(m, "after tpip_input both pullups");
55536400Ssklower 	ENDDEBUG
55636400Ssklower 	/*
55736400Ssklower 	 * m_pullup may have returned a different mbuf
55836400Ssklower 	 */
55937469Ssklower 	ip = mtod(m, struct ip *);
56036400Ssklower 
56136400Ssklower 	/*
56236400Ssklower 	 * drop the ip header from the front of the mbuf
56336400Ssklower 	 * this is necessary for the tp checksum
56436400Ssklower 	 */
56537469Ssklower 	m->m_len -= iplen;
56637469Ssklower 	m->m_data += iplen;
56736400Ssklower 
56836400Ssklower 	src.sin_addr = *(struct in_addr *)&(ip->ip_src);
56936400Ssklower 	src.sin_family  = AF_INET;
57037469Ssklower 	src.sin_len  = sizeof(src);
57136400Ssklower 	dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
57236400Ssklower 	dst.sin_family  = AF_INET;
57337469Ssklower 	dst.sin_len  = sizeof(dst);
57436400Ssklower 
57537469Ssklower 	(void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
57639928Ssklower 				0, tpip_output_dg, 0);
57736400Ssklower 	return 0;
57836400Ssklower 
57936400Ssklower discard:
58036400Ssklower 	IFDEBUG(D_TPINPUT)
58136400Ssklower 		printf("tpip_input DISCARD\n");
58236400Ssklower 	ENDDEBUG
58336400Ssklower 	IFTRACE(D_TPINPUT)
58436400Ssklower 		tptrace(TPPTmisc, "tpip_input DISCARD m",  m,0,0,0);
58536400Ssklower 	ENDTRACE
58636400Ssklower 	m_freem(m);
58736400Ssklower 	IncStat(ts_recv_drop);
58837469Ssklower 	splx(s);
58936400Ssklower 	return 0;
59036400Ssklower }
59136400Ssklower 
59236400Ssklower 
59337536Smckusick #include "protosw.h"
59436400Ssklower #include "../netinet/ip_icmp.h"
59536400Ssklower 
59637469Ssklower extern void tp_quench();
59736400Ssklower /*
59836400Ssklower  * NAME:	tpin_quench()
59936400Ssklower  *
60036400Ssklower  * CALLED FROM: tpip_ctlinput()
60136400Ssklower  *
60236400Ssklower  * FUNCTION and ARGUMENTS:  find the tpcb pointer and pass it to tp_quench
60336400Ssklower  *
60436400Ssklower  * RETURNS:	Nada
60536400Ssklower  *
60636400Ssklower  * SIDE EFFECTS:
60736400Ssklower  *
60836400Ssklower  * NOTES:
60936400Ssklower  */
61036400Ssklower 
61136400Ssklower void
61236400Ssklower tpin_quench(inp)
61336400Ssklower 	struct inpcb *inp;
61436400Ssklower {
615*50435Ssklower 	tp_quench((struct tp_pcb *)inp->inp_socket->so_pcb, PRC_QUENCH);
61636400Ssklower }
61736400Ssklower 
61836400Ssklower /*
61936400Ssklower  * NAME:	tpip_ctlinput()
62036400Ssklower  *
62136400Ssklower  * CALLED FROM:
62236400Ssklower  *  The network layer through the protosw table.
62336400Ssklower  *
62436400Ssklower  * FUNCTION and ARGUMENTS:
62536400Ssklower  *	When clnp gets an ICMP msg this gets called.
62636400Ssklower  *	It either returns an error status to the user or
62736400Ssklower  *	causes all connections on this address to be aborted
62836400Ssklower  *	by calling the appropriate xx_notify() routine.
62936400Ssklower  *	(cmd) is the type of ICMP error.
63036400Ssklower  * 	(sa) the address of the sender
63136400Ssklower  *
63236400Ssklower  * RETURNS:	 Nothing
63336400Ssklower  *
63436400Ssklower  * SIDE EFFECTS:
63536400Ssklower  *
63636400Ssklower  * NOTES:
63736400Ssklower  */
63836400Ssklower ProtoHook
63936400Ssklower tpip_ctlinput(cmd, sin)
64036400Ssklower 	int cmd;
64136400Ssklower 	struct sockaddr_in *sin;
64236400Ssklower {
64336400Ssklower 	extern u_char inetctlerrmap[];
64436400Ssklower 	extern ProtoHook tpin_abort();
64536400Ssklower 	extern ProtoHook in_rtchange();
64645630Ssklower 	extern struct in_addr zeroin_addr;
64736400Ssklower 
64836400Ssklower 	if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK)
64936400Ssklower 		return 0;
65036400Ssklower 	if (sin->sin_addr.s_addr == INADDR_ANY)
65136400Ssklower 		return 0;
65236400Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
65336400Ssklower 		return 0;
65436400Ssklower 	switch (cmd) {
65536400Ssklower 
65636400Ssklower 		case	PRC_QUENCH:
65745630Ssklower 			in_pcbnotify(&tp_inpcb, sin, 0,
65845630Ssklower 				zeroin_addr, 0, cmd, (int (*)())tp_quench);
65936400Ssklower 			break;
66036400Ssklower 
66136400Ssklower 		case	PRC_ROUTEDEAD:
66236400Ssklower 		case	PRC_HOSTUNREACH:
66336400Ssklower 		case	PRC_UNREACH_NET:
66436400Ssklower 		case	PRC_IFDOWN:
66536400Ssklower 		case	PRC_HOSTDEAD:
66645630Ssklower 			in_pcbnotify(&tp_inpcb, sin, 0,
66745630Ssklower 				zeroin_addr, 0, cmd, in_rtchange);
66836400Ssklower 			break;
66936400Ssklower 
67036400Ssklower 		default:
67136400Ssklower 		/*
67236400Ssklower 		case	PRC_MSGSIZE:
67336400Ssklower 		case	PRC_UNREACH_HOST:
67436400Ssklower 		case	PRC_UNREACH_PROTOCOL:
67536400Ssklower 		case	PRC_UNREACH_PORT:
67636400Ssklower 		case	PRC_UNREACH_NEEDFRAG:
67736400Ssklower 		case	PRC_UNREACH_SRCFAIL:
67836400Ssklower 		case	PRC_REDIRECT_NET:
67936400Ssklower 		case	PRC_REDIRECT_HOST:
68036400Ssklower 		case	PRC_REDIRECT_TOSNET:
68136400Ssklower 		case	PRC_REDIRECT_TOSHOST:
68236400Ssklower 		case	PRC_TIMXCEED_INTRANS:
68336400Ssklower 		case	PRC_TIMXCEED_REASS:
68436400Ssklower 		case	PRC_PARAMPROB:
68536400Ssklower 		*/
68645630Ssklower 		in_pcbnotify(&tp_inpcb, sin, 0, zeroin_addr, 0,
68745630Ssklower 				cmd, tpin_abort);
68836400Ssklower 	}
68936400Ssklower 	return 0;
69036400Ssklower }
69136400Ssklower 
69236400Ssklower /*
69336400Ssklower  * NAME:	tpin_abort()
69436400Ssklower  *
69536400Ssklower  * CALLED FROM:
69636400Ssklower  *	xxx_notify() from tp_ctlinput() when
69736400Ssklower  *  net level gets some ICMP-equiv. type event.
69836400Ssklower  *
69936400Ssklower  * FUNCTION and ARGUMENTS:
70036400Ssklower  *  Cause the connection to be aborted with some sort of error
70136400Ssklower  *  reason indicating that the network layer caused the abort.
70236400Ssklower  *  Fakes an ER TPDU so we can go through the driver.
70336400Ssklower  *
70436400Ssklower  * RETURNS:	 Nothing
70536400Ssklower  *
70636400Ssklower  * SIDE EFFECTS:
70736400Ssklower  *
70836400Ssklower  * NOTES:
70936400Ssklower  */
71036400Ssklower 
71136400Ssklower ProtoHook
71236400Ssklower tpin_abort(inp)
71336400Ssklower 	struct inpcb *inp;
71436400Ssklower {
71536400Ssklower 	struct tp_event e;
71636400Ssklower 
71736400Ssklower 	e.ev_number = ER_TPDU;
71836400Ssklower 	e.ATTR(ER_TPDU).e_reason = ENETRESET;
71937469Ssklower 	(void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
72036400Ssklower 	return 0;
72136400Ssklower }
72236400Ssklower 
72336400Ssklower #ifdef ARGO_DEBUG
72436400Ssklower dump_inaddr(addr)
72536400Ssklower 	register struct sockaddr_in *addr;
72636400Ssklower {
72736400Ssklower 	printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr);
72836400Ssklower }
72936400Ssklower #endif ARGO_DEBUG
73036400Ssklower 
73136400Ssklower /*
73236400Ssklower  * NAME:	tpip_route()
73336400Ssklower  *
73436400Ssklower  * CALLED FROM: tpip_mtu()
73536400Ssklower  *
73636400Ssklower  * FUNCTION and ARGUMENTS:	given a destination addresss,
73736400Ssklower  *	find the interface that would be used to send something to this address.
73836400Ssklower  *
73936400Ssklower  * RETURNS:	 pointer to an ifnet structure
74036400Ssklower  *
74136400Ssklower  * SIDE EFFECTS:
74236400Ssklower  *
74336400Ssklower  * NOTES:
74436400Ssklower  */
74536400Ssklower struct ifnet *
74636400Ssklower tpip_route(dst)
74736400Ssklower 	struct in_addr *dst;
74836400Ssklower {
74937469Ssklower 	struct ifnet 		*ifp = (struct ifnet *)0;
75037469Ssklower 	struct sockaddr_in	insock;
75137469Ssklower 	struct sockaddr_in	*sin = &insock;
75237469Ssklower 	struct rtentry 		*rt;
75337469Ssklower 	struct ifaddr	*ia;
75436400Ssklower 
75536400Ssklower 	IFDEBUG(D_CONN)
75636400Ssklower 		printf("tpip_route: dst is x%x\n", *dst);
75736400Ssklower 	ENDDEBUG
75836400Ssklower 
75937469Ssklower 	bzero((caddr_t)sin, sizeof (*sin));
76037469Ssklower 	sin->sin_family = AF_INET;
76137469Ssklower 	sin->sin_len = sizeof(*sin);
76237469Ssklower 	sin->sin_addr = *dst;
76336400Ssklower 
76437469Ssklower 	ia = ifa_ifwithdstaddr((struct sockaddr *)sin);
76536400Ssklower 	if (ia == 0)
76637469Ssklower 		ia = ifa_ifwithnet((struct sockaddr *)sin);
76736400Ssklower 	if (ia != 0) {
76837469Ssklower 		ifp = ia->ifa_ifp;
76936400Ssklower 		IFDEBUG(D_CONN)
77036400Ssklower 			printf("tpip_route: ifp from ia:0x%x\n", ia);
77136400Ssklower 		ENDDEBUG
77236400Ssklower 	} else {
77337469Ssklower 		rt = rtalloc1((struct sockaddr *)sin, 0);
77437469Ssklower 		if (rt != 0) {
77537469Ssklower 			ifp = rt->rt_ifp;
77636400Ssklower 			IFDEBUG(D_CONN)
77737469Ssklower 				printf("tpip_route: ifp from rentry: 0x%x\n", rt);
77836400Ssklower 			ENDDEBUG
77937469Ssklower 			rtfree(rt);
78036400Ssklower 		}
78136400Ssklower 	}
78236400Ssklower 	IFDEBUG(D_CONN)
78336400Ssklower 		printf("tpip_route: returning 0x%x\n", ifp);
78436400Ssklower 		if (ifp)
78536400Ssklower 			printf("tpip_route: if name %s unit 0x%x, mtu 0x%x\n",
78636400Ssklower 				ifp->if_name, ifp->if_unit, ifp->if_mtu);
78736400Ssklower 	ENDDEBUG
78836400Ssklower 	return ifp;
78936400Ssklower }
79036400Ssklower 
79136400Ssklower #endif INET
792