xref: /csrg-svn/sys/netiso/tp_inet.c (revision 44422)
136400Ssklower /***********************************************************
236400Ssklower 		Copyright IBM Corporation 1987
336400Ssklower 
436400Ssklower                       All Rights Reserved
536400Ssklower 
636400Ssklower Permission to use, copy, modify, and distribute this software and its
736400Ssklower documentation for any purpose and without fee is hereby granted,
836400Ssklower provided that the above copyright notice appear in all copies and that
936400Ssklower both that copyright notice and this permission notice appear in
1036400Ssklower supporting documentation, and that the name of IBM not be
1136400Ssklower used in advertising or publicity pertaining to distribution of the
1236400Ssklower software without specific, written prior permission.
1336400Ssklower 
1436400Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536400Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636400Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736400Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836400Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936400Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036400Ssklower SOFTWARE.
2136400Ssklower 
2236400Ssklower ******************************************************************/
2336400Ssklower 
2436400Ssklower /*
2536400Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636400Ssklower  */
2736400Ssklower /*
2836400Ssklower  * ARGO TP
2936400Ssklower  * $Header: tp_inet.c,v 5.3 88/11/18 17:27:29 nhall Exp $
3036400Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_inet.c,v $
31*44422Ssklower  *	@(#)tp_inet.c	7.6 (Berkeley) 06/28/90 *
3236400Ssklower  *
3336400Ssklower  * Here is where you find the inet-dependent code.  We've tried
3436400Ssklower  * keep all net-level and (primarily) address-family-dependent stuff
3536400Ssklower  * out of the tp source, and everthing here is reached indirectly
3636400Ssklower  * through a switch table (struct nl_protosw *) tpcb->tp_nlproto
3736400Ssklower  * (see tp_pcb.c).
3836400Ssklower  * The routines here are:
3936400Ssklower  * 		in_getsufx: gets transport suffix out of an inpcb structure.
4036400Ssklower  * 		in_putsufx: put transport suffix into an inpcb structure.
4136400Ssklower  *		in_putnetaddr: put a whole net addr into an inpcb.
4236400Ssklower  *		in_getnetaddr: get a whole net addr from an inpcb.
43*44422Ssklower  *		in_cmpnetaddr: compare a whole net addr from an isopcb.
4436400Ssklower  *		in_recycle_suffix: clear suffix for reuse in inpcb
4536400Ssklower  *		tpip_mtu: figure out what size tpdu to use
4636400Ssklower  *		tpip_input: take a pkt from ip, strip off its ip header, give to tp
4736400Ssklower  *		tpip_output_dg: package a pkt for ip given 2 addresses & some data
4836400Ssklower  *		tpip_output: package a pkt for ip given an inpcb & some data
4936400Ssklower  */
5036400Ssklower 
5136400Ssklower #ifndef lint
5236400Ssklower static char *rcsid = "$Header: tp_inet.c,v 5.3 88/11/18 17:27:29 nhall Exp $";
5336400Ssklower #endif lint
5436400Ssklower 
5536400Ssklower #ifdef INET
5636400Ssklower 
5737469Ssklower #include "param.h"
5836400Ssklower #include "socket.h"
5936400Ssklower #include "socketvar.h"
6036400Ssklower #include "mbuf.h"
6136400Ssklower #include "errno.h"
6236400Ssklower #include "time.h"
6336400Ssklower #include "../net/if.h"
6437469Ssklower #include "tp_param.h"
6537469Ssklower #include "argo_debug.h"
6637469Ssklower #include "tp_stat.h"
6737469Ssklower #include "tp_ip.h"
6837469Ssklower #include "tp_pcb.h"
6937469Ssklower #include "tp_trace.h"
7037469Ssklower #include "tp_stat.h"
7137469Ssklower #include "tp_tpdu.h"
7236400Ssklower #include "../netinet/in_var.h"
7336400Ssklower 
7437469Ssklower #ifndef ISO
7537469Ssklower #include "iso_chksum.c"
7637469Ssklower #endif
7736400Ssklower 
7836400Ssklower /*
7936400Ssklower  * NAME:			in_getsufx()
8036400Ssklower 
8136400Ssklower  * CALLED FROM: 	pr_usrreq() on PRU_BIND,
8236400Ssklower  *					PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
8336400Ssklower  *
8436400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
8536400Ssklower  * 	Get a transport suffix from an inpcb structure (inp).
8636400Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
8736400Ssklower  *
8836400Ssklower  * RETURNS:		internet port / transport suffix
8936400Ssklower  *  			(CAST TO AN INT)
9036400Ssklower  *
9136400Ssklower  * SIDE EFFECTS:
9236400Ssklower  *
9336400Ssklower  * NOTES:
9436400Ssklower  */
9537469Ssklower in_getsufx(inp, lenp, data_out, which)
9636400Ssklower 	struct inpcb *inp;
9737469Ssklower 	u_short *lenp;
9837469Ssklower 	caddr_t data_out;
9936400Ssklower 	int which;
10036400Ssklower {
10137469Ssklower 	*lenp = sizeof(u_short);
10236400Ssklower 	switch (which) {
10336400Ssklower 	case TP_LOCAL:
10437469Ssklower 		*(u_short *)data_out = inp->inp_lport;
10537469Ssklower 		return;
10636400Ssklower 
10736400Ssklower 	case TP_FOREIGN:
10837469Ssklower 		*(u_short *)data_out = inp->inp_fport;
10936400Ssklower 	}
11037469Ssklower 
11136400Ssklower }
11236400Ssklower 
11336400Ssklower /*
11436400Ssklower  * NAME:		in_putsufx()
11536400Ssklower  *
11636400Ssklower  * CALLED FROM: tp_newsocket(); i.e., when a connection
11736400Ssklower  *		is being established by an incoming CR_TPDU.
11836400Ssklower  *
11936400Ssklower  * FUNCTION, ARGUMENTS:
12036400Ssklower  * 	Put a transport suffix (found in name) into an inpcb structure (inp).
12136400Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
12236400Ssklower  *
12336400Ssklower  * RETURNS:		Nada
12436400Ssklower  *
12536400Ssklower  * SIDE EFFECTS:
12636400Ssklower  *
12736400Ssklower  * NOTES:
12836400Ssklower  */
12937469Ssklower /*ARGSUSED*/
13036400Ssklower void
13137469Ssklower in_putsufx(inp, sufxloc, sufxlen, which)
13236400Ssklower 	struct inpcb *inp;
13337469Ssklower 	caddr_t sufxloc;
13436400Ssklower 	int which;
13536400Ssklower {
13637469Ssklower 	if (which == TP_FOREIGN) {
13737469Ssklower 		bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport));
13836400Ssklower 	}
13936400Ssklower }
14036400Ssklower 
14136400Ssklower /*
14236400Ssklower  * NAME:	in_recycle_tsuffix()
14336400Ssklower  *
14436400Ssklower  * CALLED FROM:	tp.trans whenever we go into REFWAIT state.
14536400Ssklower  *
14636400Ssklower  * FUNCTION and ARGUMENT:
14736400Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
14836400Ssklower  * 	(inp) is the net level pcb.
14936400Ssklower  *
15036400Ssklower  * RETURNS:			Nada
15136400Ssklower  *
15236400Ssklower  * SIDE EFFECTS:
15336400Ssklower  *
15436400Ssklower  * NOTES:	This really shouldn't have to be done in a NET level pcb
15536400Ssklower  *	but... for the internet world that just the way it is done in BSD...
15636400Ssklower  * 	The alternative is to have the port unusable until the reference
15736400Ssklower  * 	timer goes off.
15836400Ssklower  */
15936400Ssklower void
16036400Ssklower in_recycle_tsuffix(inp)
16136400Ssklower 	struct inpcb	*inp;
16236400Ssklower {
16336400Ssklower 	inp->inp_fport = inp->inp_lport = 0;
16436400Ssklower }
16536400Ssklower 
16636400Ssklower /*
16736400Ssklower  * NAME:	in_putnetaddr()
16836400Ssklower  *
16936400Ssklower  * CALLED FROM:
17036400Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
17136400Ssklower  * 	incoming CR_TPDU.
17236400Ssklower  *
17336400Ssklower  * FUNCTION and ARGUMENTS:
17436400Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
17536400Ssklower  * 	into an inpcb (inp).
17636400Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
17736400Ssklower  *
17836400Ssklower  * RETURNS:		Nada
17936400Ssklower  *
18036400Ssklower  * SIDE EFFECTS:
18136400Ssklower  *
18236400Ssklower  * NOTES:
18336400Ssklower  */
18436400Ssklower void
18536400Ssklower in_putnetaddr(inp, name, which)
18636400Ssklower 	register struct inpcb	*inp;
18736400Ssklower 	struct sockaddr_in	*name;
18836400Ssklower 	int which;
18936400Ssklower {
19036400Ssklower 	switch (which) {
19136400Ssklower 	case TP_LOCAL:
19236400Ssklower 		bcopy((caddr_t)&name->sin_addr,
19336400Ssklower 			(caddr_t)&inp->inp_laddr, sizeof(struct in_addr));
19436400Ssklower 			/* won't work if the dst address (name) is INADDR_ANY */
19536400Ssklower 
19636400Ssklower 		break;
19736400Ssklower 	case TP_FOREIGN:
19836400Ssklower 		if( name != (struct sockaddr_in *)0 ) {
19936400Ssklower 			bcopy((caddr_t)&name->sin_addr,
20036400Ssklower 				(caddr_t)&inp->inp_faddr, sizeof(struct in_addr));
20136400Ssklower 		}
20236400Ssklower 	}
20336400Ssklower }
20436400Ssklower 
20536400Ssklower /*
206*44422Ssklower  * NAME:	in_putnetaddr()
207*44422Ssklower  *
208*44422Ssklower  * CALLED FROM:
209*44422Ssklower  * 	tp_input() when a connection is being established by an
210*44422Ssklower  * 	incoming CR_TPDU, and considered for interception.
211*44422Ssklower  *
212*44422Ssklower  * FUNCTION and ARGUMENTS:
213*44422Ssklower  * 	Compare a whole net addr from a struct sockaddr (name),
214*44422Ssklower  * 	with that implicitly stored in an inpcb (inp).
215*44422Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
216*44422Ssklower  *
217*44422Ssklower  * RETURNS:		Nada
218*44422Ssklower  *
219*44422Ssklower  * SIDE EFFECTS:
220*44422Ssklower  *
221*44422Ssklower  * NOTES:
222*44422Ssklower  */
223*44422Ssklower in_cmpnetaddr(inp, name, which)
224*44422Ssklower 	register struct inpcb	*inp;
225*44422Ssklower 	register struct sockaddr_in	*name;
226*44422Ssklower 	int which;
227*44422Ssklower {
228*44422Ssklower 	if (which == TP_LOCAL) {
229*44422Ssklower 		if (name->sin_port && name->sin_port != inp->inp_lport)
230*44422Ssklower 			return 0;
231*44422Ssklower 		return (name->sin_addr.s_addr == inp->inp_laddr.s_addr);
232*44422Ssklower 	}
233*44422Ssklower 	if (name->sin_port && name->sin_port != inp->inp_fport)
234*44422Ssklower 		return 0;
235*44422Ssklower 	return (name->sin_addr.s_addr == inp->inp_faddr.s_addr);
236*44422Ssklower }
237*44422Ssklower 
238*44422Ssklower /*
23936400Ssklower  * NAME:	in_getnetaddr()
24036400Ssklower  *
24136400Ssklower  * CALLED FROM:
24236400Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
24336400Ssklower  * FUNCTION and ARGUMENTS:
24436400Ssklower  * 	Copy a whole net addr from an inpcb (inp) into
24537469Ssklower  * 	an mbuf (name);
24636400Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
24736400Ssklower  *
24836400Ssklower  * RETURNS:		Nada
24936400Ssklower  *
25036400Ssklower  * SIDE EFFECTS:
25136400Ssklower  *
25236400Ssklower  * NOTES:
25336400Ssklower  */
25436400Ssklower 
25536400Ssklower void
25636400Ssklower in_getnetaddr( inp, name, which)
25737469Ssklower 	register struct mbuf *name;
25836400Ssklower 	struct inpcb *inp;
25936400Ssklower 	int which;
26036400Ssklower {
26137469Ssklower 	register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *);
26237469Ssklower 	bzero((caddr_t)sin, sizeof(*sin));
26336400Ssklower 	switch (which) {
26436400Ssklower 	case TP_LOCAL:
26537469Ssklower 		sin->sin_addr = inp->inp_laddr;
26637469Ssklower 		sin->sin_port = inp->inp_lport;
26736400Ssklower 		break;
26836400Ssklower 	case TP_FOREIGN:
26937469Ssklower 		sin->sin_addr = inp->inp_faddr;
27037469Ssklower 		sin->sin_port = inp->inp_fport;
27136400Ssklower 		break;
27237469Ssklower 	default:
27337469Ssklower 		return;
27436400Ssklower 	}
27537469Ssklower 	name->m_len = sin->sin_len = sizeof (*sin);
27637469Ssklower 	sin->sin_family = AF_INET;
27736400Ssklower }
27836400Ssklower 
27936400Ssklower /*
28036400Ssklower  * NAME: 	tpip_mtu()
28136400Ssklower  *
28236400Ssklower  * CALLED FROM:
28336400Ssklower  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
28436400Ssklower  *
28536400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
28636400Ssklower  *
28736400Ssklower  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
28836400Ssklower  * a) the header size for the network protocol and the max transmission
28936400Ssklower  *	  unit on the subnet interface, determined from the information in (inp),
29036400Ssklower  * b) the max size negotiated so far (negot)
29136400Ssklower  * c) the window size used by the tp connection (found in so),
29236400Ssklower  *
29336400Ssklower  * The result is put in the integer *size in its integer form and in
29436400Ssklower  * *negot in its logarithmic form.
29536400Ssklower  *
29636400Ssklower  * The rules are:
29736400Ssklower  * a) can only negotiate down from the value found in *negot.
29836400Ssklower  * b) the MTU must be < the windowsize,
29936400Ssklower  * c) If src and dest are on the same net,
30036400Ssklower  * 	  we will negotiate the closest size larger than  MTU but really USE
30136400Ssklower  *    the actual device mtu - ll hdr sizes.
30236400Ssklower  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
30336400Ssklower  *
30436400Ssklower  * SIDE EFFECTS:
30536400Ssklower  *	changes the values addressed by the arguments (size) and (negot)
30636400Ssklower  *  and
30736400Ssklower  *  when the peer is not on one of our directly connected subnets, it
30836400Ssklower  *  looks up a route, leaving the route in the inpcb addressed by (inp)
30936400Ssklower  *
31036400Ssklower  * NOTES:
31136400Ssklower  */
31236400Ssklower 
31336400Ssklower void
31436400Ssklower tpip_mtu(so, inp, size, negot)
31536400Ssklower 	struct socket *so;
31636400Ssklower 	struct inpcb *inp;
31736400Ssklower 	int *size;
31836400Ssklower 	u_char *negot;
31936400Ssklower {
32036400Ssklower 	register struct ifnet	*ifp;
32136400Ssklower 	struct ifnet			*tpip_route();
32236400Ssklower 	struct in_ifaddr		*ia;
32336400Ssklower 	register int			i;
32436400Ssklower 	int						windowsize = so->so_rcv.sb_hiwat;
32536400Ssklower 
32636400Ssklower 	IFDEBUG(D_CONN)
32736400Ssklower 		printf("tpip_mtu(0x%x,0x%x,0x%x,0x%x)\n",
32836400Ssklower 			so, inp, size, negot);
32936400Ssklower 		printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr);
33036400Ssklower 	ENDDEBUG
33136400Ssklower 	IFTRACE(D_CONN)
33236400Ssklower 		tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
33336400Ssklower 	ENDTRACE
33436400Ssklower 
33536400Ssklower 	*size = 1 << *negot;
33636400Ssklower 
33736400Ssklower 	if( *size > windowsize ) {
33836400Ssklower 		*size = windowsize;
33936400Ssklower 	}
34036400Ssklower 
34136400Ssklower 	ia = in_iaonnetof(in_netof(inp->inp_faddr));
34236400Ssklower 	if ( ia == (struct in_ifaddr *)0 ) {
34336400Ssklower 		ifp = tpip_route(&inp->inp_faddr);
34436400Ssklower 		if( ifp == (struct ifnet *)0 )
34536400Ssklower 			return ;
34636400Ssklower 	} else
34736400Ssklower 		ifp = ia->ia_ifp;
34836400Ssklower 
34936400Ssklower 
35036400Ssklower 	/****************************************************************
35136400Ssklower 	 * TODO - make this indirect off the socket structure to the
35236400Ssklower 	 * network layer to get headersize
35336400Ssklower 	 * After all, who knows what lies below the IP layer?
35436400Ssklower 	 * Who knows how big the NL header will be?
35536400Ssklower 	 ***************************************************************/
35636400Ssklower 
35736400Ssklower 	if( *size > ifp->if_mtu - sizeof(struct ip)) {
35836400Ssklower 		*size = ifp->if_mtu - sizeof(struct ip);
35936400Ssklower 	}
36036400Ssklower 	for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i)<*size)) ; i++)
36136400Ssklower 		;
36236400Ssklower 	i--;
36336400Ssklower 
36436400Ssklower 	if (in_netof(inp->inp_laddr) != in_netof(inp->inp_faddr)) {
36536400Ssklower 		i++;
36636400Ssklower 	} else {
36736400Ssklower 		*size = 1<<i;
36836400Ssklower 	}
36936400Ssklower 	*negot = i;
37036400Ssklower 
37136400Ssklower 	IFDEBUG(D_CONN)
37236400Ssklower 		printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
37336400Ssklower 		ifp->if_name,	*size, *negot);
37436400Ssklower 	ENDDEBUG
37536400Ssklower 	IFTRACE(D_CONN)
37636400Ssklower 		tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
37736400Ssklower 		*size, *negot, 0, 0);
37836400Ssklower 	ENDTRACE
37936400Ssklower 
38036400Ssklower }
38136400Ssklower 
38236400Ssklower /*
38336400Ssklower  * NAME:	tpip_output()
38436400Ssklower  *
38536400Ssklower  * CALLED FROM:  tp_emit()
38636400Ssklower  *
38736400Ssklower  * FUNCTION and ARGUMENTS:
38836400Ssklower  *  Take a packet(m0) from tp and package it so that ip will accept it.
38936400Ssklower  *  This means prepending space for the ip header and filling in a few
39036400Ssklower  *  of the fields.
39136400Ssklower  *  inp is the inpcb structure; datalen is the length of the data in the
39236400Ssklower  *  mbuf string m0.
39336400Ssklower  * RETURNS:
39436400Ssklower  *  whatever (E*) is returned form the net layer output routine.
39536400Ssklower  *
39636400Ssklower  * SIDE EFFECTS:
39736400Ssklower  *
39836400Ssklower  * NOTES:
39936400Ssklower  */
40036400Ssklower 
40136400Ssklower int
40236400Ssklower tpip_output(inp, m0, datalen, nochksum)
40336400Ssklower 	struct inpcb		*inp;
40436400Ssklower 	struct mbuf 		*m0;
40536400Ssklower 	int 				datalen;
40636400Ssklower 	int					nochksum;
40736400Ssklower {
40836400Ssklower 	return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen,
40936400Ssklower 		&inp->inp_route, nochksum);
41036400Ssklower }
41136400Ssklower 
41236400Ssklower /*
41336400Ssklower  * NAME:	tpip_output_dg()
41436400Ssklower  *
41536400Ssklower  * CALLED FROM:  tp_error_emit()
41636400Ssklower  *
41736400Ssklower  * FUNCTION and ARGUMENTS:
41836400Ssklower  *  This is a copy of tpip_output that takes the addresses
41936400Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
42036400Ssklower  *  don't have an in_pcb with which to call the normal output rtn.
42136400Ssklower  *
42236400Ssklower  * RETURNS:	 ENOBUFS or  whatever (E*) is
42336400Ssklower  *	returned form the net layer output routine.
42436400Ssklower  *
42536400Ssklower  * SIDE EFFECTS:
42636400Ssklower  *
42736400Ssklower  * NOTES:
42836400Ssklower  */
42936400Ssklower 
43037469Ssklower /*ARGSUSED*/
43136400Ssklower int
43236400Ssklower tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
43336400Ssklower 	struct in_addr		*laddr, *faddr;
43436400Ssklower 	struct mbuf 		*m0;
43536400Ssklower 	int 				datalen;
43636400Ssklower 	struct route 		*ro;
43736400Ssklower 	int					nochksum;
43836400Ssklower {
43936400Ssklower 	register struct mbuf 	*m;
44036400Ssklower 	register struct ip *ip;
44136400Ssklower 	int 					error;
44236400Ssklower 
44336400Ssklower 	IFDEBUG(D_EMIT)
44436400Ssklower 		printf("tpip_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
44536400Ssklower 	ENDDEBUG
44636400Ssklower 
44736400Ssklower 
44837469Ssklower 	MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
44936400Ssklower 	if (m == 0) {
45036400Ssklower 		error = ENOBUFS;
45136400Ssklower 		goto bad;
45236400Ssklower 	}
45336400Ssklower 	m->m_next = m0;
45437469Ssklower 	MH_ALIGN(m, sizeof(struct ip));
45536400Ssklower 	m->m_len = sizeof(struct ip);
45636400Ssklower 
45736400Ssklower 	ip = mtod(m, struct ip *);
45837469Ssklower 	bzero((caddr_t)ip, sizeof *ip);
45936400Ssklower 
46036400Ssklower 	ip->ip_p = IPPROTO_TP;
46137469Ssklower 	m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
46236400Ssklower 	ip->ip_ttl = MAXTTL;
46336400Ssklower 		/* don't know why you need to set ttl;
46436400Ssklower 		 * overlay doesn't even make this available
46536400Ssklower 		 */
46636400Ssklower 
46736400Ssklower 	ip->ip_src = *laddr;
46836400Ssklower 	ip->ip_dst = *faddr;
46936400Ssklower 
47036400Ssklower 	IncStat(ts_tpdu_sent);
47136400Ssklower 	IFDEBUG(D_EMIT)
47236400Ssklower 		dump_mbuf(m, "tpip_output_dg before ip_output\n");
47336400Ssklower 	ENDDEBUG
47436400Ssklower 
47536400Ssklower 	error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST);
47636400Ssklower 
47736400Ssklower 	IFDEBUG(D_EMIT)
47836400Ssklower 		printf("tpip_output_dg after ip_output\n");
47936400Ssklower 	ENDDEBUG
48036400Ssklower 
48136400Ssklower 	return error;
48236400Ssklower 
48336400Ssklower bad:
48436400Ssklower 	m_freem(m);
48536400Ssklower 	IncStat(ts_send_drop);
48636400Ssklower 	return error;
48736400Ssklower }
48836400Ssklower 
48936400Ssklower /*
49036400Ssklower  * NAME:  tpip_input()
49136400Ssklower  *
49236400Ssklower  * CALLED FROM:
49336400Ssklower  * 	ip's input routine, indirectly through the protosw.
49436400Ssklower  *
49536400Ssklower  * FUNCTION and ARGUMENTS:
49636400Ssklower  * Take a packet (m) from ip, strip off the ip header and give it to tp
49736400Ssklower  *
49836400Ssklower  * RETURNS:  No return value.
49936400Ssklower  *
50036400Ssklower  * SIDE EFFECTS:
50136400Ssklower  *
50236400Ssklower  * NOTES:
50336400Ssklower  */
50436400Ssklower ProtoHook
50537469Ssklower tpip_input(m, iplen)
50636400Ssklower 	struct mbuf *m;
50737469Ssklower 	int iplen;
50836400Ssklower {
50936400Ssklower 	struct sockaddr_in 	src, dst;
51036400Ssklower 	register struct ip 		*ip;
51137469Ssklower 	int						s = splnet(), hdrlen;
51236400Ssklower 
51336400Ssklower 	IncStat(ts_pkt_rcvd);
51436400Ssklower 
51537469Ssklower 	/*
51637469Ssklower 	 * IP layer has already pulled up the IP header,
51737469Ssklower 	 * but the first byte after the IP header may not be there,
51837469Ssklower 	 * e.g. if you came in via loopback, so you have to do an
51937469Ssklower 	 * m_pullup to before you can even look to see how much you
52037469Ssklower 	 * really need.  The good news is that m_pullup will round
52137469Ssklower 	 * up to almost the next mbuf's worth.
52237469Ssklower 	 */
52336400Ssklower 
52437469Ssklower 
52537469Ssklower 	if((m = m_pullup(m, iplen + 1)) == MNULL)
52637469Ssklower 		goto discard;
52736400Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
52836400Ssklower 
52936400Ssklower 	/*
53037469Ssklower 	 * Now pull up the whole tp header:
53137469Ssklower 	 * Unfortunately, there may be IP options to skip past so we
53237469Ssklower 	 * just fetch it as an unsigned char.
53336400Ssklower 	 */
53437469Ssklower 	hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
53536400Ssklower 
53637469Ssklower 	if( m->m_len < hdrlen ) {
53737469Ssklower 		if((m = m_pullup(m, hdrlen)) == MNULL){
53836400Ssklower 			IFDEBUG(D_TPINPUT)
53936400Ssklower 				printf("tp_input, pullup 2!\n");
54036400Ssklower 			ENDDEBUG
54136400Ssklower 			goto discard;
54236400Ssklower 		}
54336400Ssklower 	}
54436400Ssklower 	/*
54536400Ssklower 	 * cannot use tp_inputprep() here 'cause you don't
54636400Ssklower 	 * have quite the same situation
54736400Ssklower 	 */
54836400Ssklower 
54936400Ssklower 	IFDEBUG(D_TPINPUT)
55036400Ssklower 		dump_mbuf(m, "after tpip_input both pullups");
55136400Ssklower 	ENDDEBUG
55236400Ssklower 	/*
55336400Ssklower 	 * m_pullup may have returned a different mbuf
55436400Ssklower 	 */
55537469Ssklower 	ip = mtod(m, struct ip *);
55636400Ssklower 
55736400Ssklower 	/*
55836400Ssklower 	 * drop the ip header from the front of the mbuf
55936400Ssklower 	 * this is necessary for the tp checksum
56036400Ssklower 	 */
56137469Ssklower 	m->m_len -= iplen;
56237469Ssklower 	m->m_data += iplen;
56336400Ssklower 
56436400Ssklower 	src.sin_addr = *(struct in_addr *)&(ip->ip_src);
56536400Ssklower 	src.sin_family  = AF_INET;
56637469Ssklower 	src.sin_len  = sizeof(src);
56736400Ssklower 	dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
56836400Ssklower 	dst.sin_family  = AF_INET;
56937469Ssklower 	dst.sin_len  = sizeof(dst);
57036400Ssklower 
57137469Ssklower 	(void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
57239928Ssklower 				0, tpip_output_dg, 0);
57336400Ssklower 	return 0;
57436400Ssklower 
57536400Ssklower discard:
57636400Ssklower 	IFDEBUG(D_TPINPUT)
57736400Ssklower 		printf("tpip_input DISCARD\n");
57836400Ssklower 	ENDDEBUG
57936400Ssklower 	IFTRACE(D_TPINPUT)
58036400Ssklower 		tptrace(TPPTmisc, "tpip_input DISCARD m",  m,0,0,0);
58136400Ssklower 	ENDTRACE
58236400Ssklower 	m_freem(m);
58336400Ssklower 	IncStat(ts_recv_drop);
58437469Ssklower 	splx(s);
58536400Ssklower 	return 0;
58636400Ssklower }
58736400Ssklower 
58836400Ssklower 
58937536Smckusick #include "protosw.h"
59036400Ssklower #include "../netinet/ip_icmp.h"
59136400Ssklower 
59237469Ssklower extern void tp_quench();
59336400Ssklower /*
59436400Ssklower  * NAME:	tpin_quench()
59536400Ssklower  *
59636400Ssklower  * CALLED FROM: tpip_ctlinput()
59736400Ssklower  *
59836400Ssklower  * FUNCTION and ARGUMENTS:  find the tpcb pointer and pass it to tp_quench
59936400Ssklower  *
60036400Ssklower  * RETURNS:	Nada
60136400Ssklower  *
60236400Ssklower  * SIDE EFFECTS:
60336400Ssklower  *
60436400Ssklower  * NOTES:
60536400Ssklower  */
60636400Ssklower 
60736400Ssklower void
60836400Ssklower tpin_quench(inp)
60936400Ssklower 	struct inpcb *inp;
61036400Ssklower {
61137469Ssklower 	tp_quench((struct tp_pcb *)inp->inp_socket->so_tpcb, PRC_QUENCH);
61236400Ssklower }
61336400Ssklower 
61436400Ssklower /*
61536400Ssklower  * NAME:	tpip_ctlinput()
61636400Ssklower  *
61736400Ssklower  * CALLED FROM:
61836400Ssklower  *  The network layer through the protosw table.
61936400Ssklower  *
62036400Ssklower  * FUNCTION and ARGUMENTS:
62136400Ssklower  *	When clnp gets an ICMP msg this gets called.
62236400Ssklower  *	It either returns an error status to the user or
62336400Ssklower  *	causes all connections on this address to be aborted
62436400Ssklower  *	by calling the appropriate xx_notify() routine.
62536400Ssklower  *	(cmd) is the type of ICMP error.
62636400Ssklower  * 	(sa) the address of the sender
62736400Ssklower  *
62836400Ssklower  * RETURNS:	 Nothing
62936400Ssklower  *
63036400Ssklower  * SIDE EFFECTS:
63136400Ssklower  *
63236400Ssklower  * NOTES:
63336400Ssklower  */
63436400Ssklower ProtoHook
63536400Ssklower tpip_ctlinput(cmd, sin)
63636400Ssklower 	int cmd;
63736400Ssklower 	struct sockaddr_in *sin;
63836400Ssklower {
63936400Ssklower 	extern u_char inetctlerrmap[];
64036400Ssklower 	extern ProtoHook tpin_abort();
64136400Ssklower 	extern ProtoHook in_rtchange();
64236400Ssklower 
64336400Ssklower 	if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK)
64436400Ssklower 		return 0;
64536400Ssklower 	if (sin->sin_addr.s_addr == INADDR_ANY)
64636400Ssklower 		return 0;
64736400Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
64836400Ssklower 		return 0;
64936400Ssklower 	switch (cmd) {
65036400Ssklower 
65136400Ssklower 		case	PRC_QUENCH:
65239928Ssklower 			in_pcbnotify(&tp_inpcb, sin,
65337469Ssklower 						0, (int (*)())tp_quench);
65436400Ssklower 			break;
65536400Ssklower 
65636400Ssklower 		case	PRC_ROUTEDEAD:
65736400Ssklower 		case	PRC_HOSTUNREACH:
65836400Ssklower 		case	PRC_UNREACH_NET:
65936400Ssklower 		case	PRC_IFDOWN:
66036400Ssklower 		case	PRC_HOSTDEAD:
66139928Ssklower 			in_pcbnotify(&tp_inpcb, sin,
66236400Ssklower 					(int)inetctlerrmap[cmd], in_rtchange);
66336400Ssklower 			break;
66436400Ssklower 
66536400Ssklower 		default:
66636400Ssklower 		/*
66736400Ssklower 		case	PRC_MSGSIZE:
66836400Ssklower 		case	PRC_UNREACH_HOST:
66936400Ssklower 		case	PRC_UNREACH_PROTOCOL:
67036400Ssklower 		case	PRC_UNREACH_PORT:
67136400Ssklower 		case	PRC_UNREACH_NEEDFRAG:
67236400Ssklower 		case	PRC_UNREACH_SRCFAIL:
67336400Ssklower 		case	PRC_REDIRECT_NET:
67436400Ssklower 		case	PRC_REDIRECT_HOST:
67536400Ssklower 		case	PRC_REDIRECT_TOSNET:
67636400Ssklower 		case	PRC_REDIRECT_TOSHOST:
67736400Ssklower 		case	PRC_TIMXCEED_INTRANS:
67836400Ssklower 		case	PRC_TIMXCEED_REASS:
67936400Ssklower 		case	PRC_PARAMPROB:
68036400Ssklower 		*/
68139928Ssklower 		in_pcbnotify(&tp_inpcb, sin,
68237469Ssklower 				(int)inetctlerrmap[cmd], tpin_abort);
68336400Ssklower 	}
68436400Ssklower 	return 0;
68536400Ssklower }
68636400Ssklower 
68736400Ssklower /*
68836400Ssklower  * NAME:	tpin_abort()
68936400Ssklower  *
69036400Ssklower  * CALLED FROM:
69136400Ssklower  *	xxx_notify() from tp_ctlinput() when
69236400Ssklower  *  net level gets some ICMP-equiv. type event.
69336400Ssklower  *
69436400Ssklower  * FUNCTION and ARGUMENTS:
69536400Ssklower  *  Cause the connection to be aborted with some sort of error
69636400Ssklower  *  reason indicating that the network layer caused the abort.
69736400Ssklower  *  Fakes an ER TPDU so we can go through the driver.
69836400Ssklower  *
69936400Ssklower  * RETURNS:	 Nothing
70036400Ssklower  *
70136400Ssklower  * SIDE EFFECTS:
70236400Ssklower  *
70336400Ssklower  * NOTES:
70436400Ssklower  */
70536400Ssklower 
70636400Ssklower ProtoHook
70736400Ssklower tpin_abort(inp)
70836400Ssklower 	struct inpcb *inp;
70936400Ssklower {
71036400Ssklower 	struct tp_event e;
71136400Ssklower 
71236400Ssklower 	e.ev_number = ER_TPDU;
71336400Ssklower 	e.ATTR(ER_TPDU).e_reason = ENETRESET;
71437469Ssklower 	(void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
71536400Ssklower 	return 0;
71636400Ssklower }
71736400Ssklower 
71836400Ssklower #ifdef ARGO_DEBUG
71936400Ssklower dump_inaddr(addr)
72036400Ssklower 	register struct sockaddr_in *addr;
72136400Ssklower {
72236400Ssklower 	printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr);
72336400Ssklower }
72436400Ssklower #endif ARGO_DEBUG
72536400Ssklower 
72636400Ssklower /*
72736400Ssklower  * NAME:	tpip_route()
72836400Ssklower  *
72936400Ssklower  * CALLED FROM: tpip_mtu()
73036400Ssklower  *
73136400Ssklower  * FUNCTION and ARGUMENTS:	given a destination addresss,
73236400Ssklower  *	find the interface that would be used to send something to this address.
73336400Ssklower  *
73436400Ssklower  * RETURNS:	 pointer to an ifnet structure
73536400Ssklower  *
73636400Ssklower  * SIDE EFFECTS:
73736400Ssklower  *
73836400Ssklower  * NOTES:
73936400Ssklower  */
74036400Ssklower struct ifnet *
74136400Ssklower tpip_route(dst)
74236400Ssklower 	struct in_addr *dst;
74336400Ssklower {
74437469Ssklower 	struct ifnet 		*ifp = (struct ifnet *)0;
74537469Ssklower 	struct sockaddr_in	insock;
74637469Ssklower 	struct sockaddr_in	*sin = &insock;
74737469Ssklower 	struct rtentry 		*rt;
74837469Ssklower 	struct ifaddr	*ia;
74936400Ssklower 
75036400Ssklower 	IFDEBUG(D_CONN)
75136400Ssklower 		printf("tpip_route: dst is x%x\n", *dst);
75236400Ssklower 	ENDDEBUG
75336400Ssklower 
75437469Ssklower 	bzero((caddr_t)sin, sizeof (*sin));
75537469Ssklower 	sin->sin_family = AF_INET;
75637469Ssklower 	sin->sin_len = sizeof(*sin);
75737469Ssklower 	sin->sin_addr = *dst;
75836400Ssklower 
75937469Ssklower 	ia = ifa_ifwithdstaddr((struct sockaddr *)sin);
76036400Ssklower 	if (ia == 0)
76137469Ssklower 		ia = ifa_ifwithnet((struct sockaddr *)sin);
76236400Ssklower 	if (ia != 0) {
76337469Ssklower 		ifp = ia->ifa_ifp;
76436400Ssklower 		IFDEBUG(D_CONN)
76536400Ssklower 			printf("tpip_route: ifp from ia:0x%x\n", ia);
76636400Ssklower 		ENDDEBUG
76736400Ssklower 	} else {
76837469Ssklower 		rt = rtalloc1((struct sockaddr *)sin, 0);
76937469Ssklower 		if (rt != 0) {
77037469Ssklower 			ifp = rt->rt_ifp;
77136400Ssklower 			IFDEBUG(D_CONN)
77237469Ssklower 				printf("tpip_route: ifp from rentry: 0x%x\n", rt);
77336400Ssklower 			ENDDEBUG
77437469Ssklower 			rtfree(rt);
77536400Ssklower 		}
77636400Ssklower 	}
77736400Ssklower 	IFDEBUG(D_CONN)
77836400Ssklower 		printf("tpip_route: returning 0x%x\n", ifp);
77936400Ssklower 		if (ifp)
78036400Ssklower 			printf("tpip_route: if name %s unit 0x%x, mtu 0x%x\n",
78136400Ssklower 				ifp->if_name, ifp->if_unit, ifp->if_mtu);
78236400Ssklower 	ENDDEBUG
78336400Ssklower 	return ifp;
78436400Ssklower }
78536400Ssklower 
78636400Ssklower #endif INET
787