xref: /csrg-svn/sys/netiso/tp_inet.c (revision 37469)
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 $
3136400Ssklower  *
3236400Ssklower  * Here is where you find the inet-dependent code.  We've tried
3336400Ssklower  * keep all net-level and (primarily) address-family-dependent stuff
3436400Ssklower  * out of the tp source, and everthing here is reached indirectly
3536400Ssklower  * through a switch table (struct nl_protosw *) tpcb->tp_nlproto
3636400Ssklower  * (see tp_pcb.c).
3736400Ssklower  * The routines here are:
3836400Ssklower  * 		in_getsufx: gets transport suffix out of an inpcb structure.
3936400Ssklower  * 		in_putsufx: put transport suffix into an inpcb structure.
4036400Ssklower  *		in_putnetaddr: put a whole net addr into an inpcb.
4136400Ssklower  *		in_getnetaddr: get a whole net addr from an inpcb.
4236400Ssklower  *		in_recycle_suffix: clear suffix for reuse in inpcb
4336400Ssklower  *		tpip_mtu: figure out what size tpdu to use
4436400Ssklower  *		tpip_input: take a pkt from ip, strip off its ip header, give to tp
4536400Ssklower  *		tpip_output_dg: package a pkt for ip given 2 addresses & some data
4636400Ssklower  *		tpip_output: package a pkt for ip given an inpcb & some data
4736400Ssklower  */
4836400Ssklower 
4936400Ssklower #ifndef lint
5036400Ssklower static char *rcsid = "$Header: tp_inet.c,v 5.3 88/11/18 17:27:29 nhall Exp $";
5136400Ssklower #endif lint
5236400Ssklower 
5336400Ssklower #ifdef INET
5436400Ssklower 
55*37469Ssklower #include "param.h"
5636400Ssklower #include "socket.h"
5736400Ssklower #include "socketvar.h"
5836400Ssklower #include "mbuf.h"
5936400Ssklower #include "errno.h"
6036400Ssklower #include "time.h"
6136400Ssklower #include "../net/if.h"
62*37469Ssklower #include "tp_param.h"
63*37469Ssklower #include "argo_debug.h"
64*37469Ssklower #include "tp_stat.h"
65*37469Ssklower #include "tp_ip.h"
66*37469Ssklower #include "tp_pcb.h"
67*37469Ssklower #include "tp_trace.h"
68*37469Ssklower #include "tp_stat.h"
69*37469Ssklower #include "tp_tpdu.h"
7036400Ssklower #include "../netinet/in_var.h"
7136400Ssklower 
72*37469Ssklower #ifndef ISO
73*37469Ssklower #include "iso_chksum.c"
74*37469Ssklower #endif
7536400Ssklower 
7636400Ssklower /*
7736400Ssklower  * NAME:			in_getsufx()
7836400Ssklower 
7936400Ssklower  * CALLED FROM: 	pr_usrreq() on PRU_BIND,
8036400Ssklower  *					PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
8136400Ssklower  *
8236400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
8336400Ssklower  * 	Get a transport suffix from an inpcb structure (inp).
8436400Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
8536400Ssklower  *
8636400Ssklower  * RETURNS:		internet port / transport suffix
8736400Ssklower  *  			(CAST TO AN INT)
8836400Ssklower  *
8936400Ssklower  * SIDE EFFECTS:
9036400Ssklower  *
9136400Ssklower  * NOTES:
9236400Ssklower  */
93*37469Ssklower in_getsufx(inp, lenp, data_out, which)
9436400Ssklower 	struct inpcb *inp;
95*37469Ssklower 	u_short *lenp;
96*37469Ssklower 	caddr_t data_out;
9736400Ssklower 	int which;
9836400Ssklower {
99*37469Ssklower 	*lenp = sizeof(u_short);
10036400Ssklower 	switch (which) {
10136400Ssklower 	case TP_LOCAL:
102*37469Ssklower 		*(u_short *)data_out = inp->inp_lport;
103*37469Ssklower 		return;
10436400Ssklower 
10536400Ssklower 	case TP_FOREIGN:
106*37469Ssklower 		*(u_short *)data_out = inp->inp_fport;
10736400Ssklower 	}
108*37469Ssklower 
10936400Ssklower }
11036400Ssklower 
11136400Ssklower /*
11236400Ssklower  * NAME:		in_putsufx()
11336400Ssklower  *
11436400Ssklower  * CALLED FROM: tp_newsocket(); i.e., when a connection
11536400Ssklower  *		is being established by an incoming CR_TPDU.
11636400Ssklower  *
11736400Ssklower  * FUNCTION, ARGUMENTS:
11836400Ssklower  * 	Put a transport suffix (found in name) into an inpcb structure (inp).
11936400Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
12036400Ssklower  *
12136400Ssklower  * RETURNS:		Nada
12236400Ssklower  *
12336400Ssklower  * SIDE EFFECTS:
12436400Ssklower  *
12536400Ssklower  * NOTES:
12636400Ssklower  */
127*37469Ssklower /*ARGSUSED*/
12836400Ssklower void
129*37469Ssklower in_putsufx(inp, sufxloc, sufxlen, which)
13036400Ssklower 	struct inpcb *inp;
131*37469Ssklower 	caddr_t sufxloc;
13236400Ssklower 	int which;
13336400Ssklower {
134*37469Ssklower 	if (which == TP_FOREIGN) {
135*37469Ssklower 		bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport));
13636400Ssklower 	}
13736400Ssklower }
13836400Ssklower 
13936400Ssklower /*
14036400Ssklower  * NAME:	in_recycle_tsuffix()
14136400Ssklower  *
14236400Ssklower  * CALLED FROM:	tp.trans whenever we go into REFWAIT state.
14336400Ssklower  *
14436400Ssklower  * FUNCTION and ARGUMENT:
14536400Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
14636400Ssklower  * 	(inp) is the net level pcb.
14736400Ssklower  *
14836400Ssklower  * RETURNS:			Nada
14936400Ssklower  *
15036400Ssklower  * SIDE EFFECTS:
15136400Ssklower  *
15236400Ssklower  * NOTES:	This really shouldn't have to be done in a NET level pcb
15336400Ssklower  *	but... for the internet world that just the way it is done in BSD...
15436400Ssklower  * 	The alternative is to have the port unusable until the reference
15536400Ssklower  * 	timer goes off.
15636400Ssklower  */
15736400Ssklower void
15836400Ssklower in_recycle_tsuffix(inp)
15936400Ssklower 	struct inpcb	*inp;
16036400Ssklower {
16136400Ssklower 	inp->inp_fport = inp->inp_lport = 0;
16236400Ssklower }
16336400Ssklower 
16436400Ssklower /*
16536400Ssklower  * NAME:	in_putnetaddr()
16636400Ssklower  *
16736400Ssklower  * CALLED FROM:
16836400Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
16936400Ssklower  * 	incoming CR_TPDU.
17036400Ssklower  *
17136400Ssklower  * FUNCTION and ARGUMENTS:
17236400Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
17336400Ssklower  * 	into an inpcb (inp).
17436400Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
17536400Ssklower  *
17636400Ssklower  * RETURNS:		Nada
17736400Ssklower  *
17836400Ssklower  * SIDE EFFECTS:
17936400Ssklower  *
18036400Ssklower  * NOTES:
18136400Ssklower  */
18236400Ssklower void
18336400Ssklower in_putnetaddr(inp, name, which)
18436400Ssklower 	register struct inpcb	*inp;
18536400Ssklower 	struct sockaddr_in	*name;
18636400Ssklower 	int which;
18736400Ssklower {
18836400Ssklower 	switch (which) {
18936400Ssklower 	case TP_LOCAL:
19036400Ssklower 		bcopy((caddr_t)&name->sin_addr,
19136400Ssklower 			(caddr_t)&inp->inp_laddr, sizeof(struct in_addr));
19236400Ssklower 			/* won't work if the dst address (name) is INADDR_ANY */
19336400Ssklower 
19436400Ssklower 		break;
19536400Ssklower 	case TP_FOREIGN:
19636400Ssklower 		if( name != (struct sockaddr_in *)0 ) {
19736400Ssklower 			bcopy((caddr_t)&name->sin_addr,
19836400Ssklower 				(caddr_t)&inp->inp_faddr, sizeof(struct in_addr));
19936400Ssklower 		}
20036400Ssklower 	}
20136400Ssklower }
20236400Ssklower 
20336400Ssklower /*
20436400Ssklower  * NAME:	in_getnetaddr()
20536400Ssklower  *
20636400Ssklower  * CALLED FROM:
20736400Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
20836400Ssklower  * FUNCTION and ARGUMENTS:
20936400Ssklower  * 	Copy a whole net addr from an inpcb (inp) into
210*37469Ssklower  * 	an mbuf (name);
21136400Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
21236400Ssklower  *
21336400Ssklower  * RETURNS:		Nada
21436400Ssklower  *
21536400Ssklower  * SIDE EFFECTS:
21636400Ssklower  *
21736400Ssklower  * NOTES:
21836400Ssklower  */
21936400Ssklower 
22036400Ssklower void
22136400Ssklower in_getnetaddr( inp, name, which)
222*37469Ssklower 	register struct mbuf *name;
22336400Ssklower 	struct inpcb *inp;
22436400Ssklower 	int which;
22536400Ssklower {
226*37469Ssklower 	register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *);
227*37469Ssklower 	bzero((caddr_t)sin, sizeof(*sin));
22836400Ssklower 	switch (which) {
22936400Ssklower 	case TP_LOCAL:
230*37469Ssklower 		sin->sin_addr = inp->inp_laddr;
231*37469Ssklower 		sin->sin_port = inp->inp_lport;
23236400Ssklower 		break;
23336400Ssklower 	case TP_FOREIGN:
234*37469Ssklower 		sin->sin_addr = inp->inp_faddr;
235*37469Ssklower 		sin->sin_port = inp->inp_fport;
23636400Ssklower 		break;
237*37469Ssklower 	default:
238*37469Ssklower 		return;
23936400Ssklower 	}
240*37469Ssklower 	name->m_len = sin->sin_len = sizeof (*sin);
241*37469Ssklower 	sin->sin_family = AF_INET;
24236400Ssklower }
24336400Ssklower 
24436400Ssklower /*
24536400Ssklower  * NAME: 	tpip_mtu()
24636400Ssklower  *
24736400Ssklower  * CALLED FROM:
24836400Ssklower  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
24936400Ssklower  *
25036400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
25136400Ssklower  *
25236400Ssklower  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
25336400Ssklower  * a) the header size for the network protocol and the max transmission
25436400Ssklower  *	  unit on the subnet interface, determined from the information in (inp),
25536400Ssklower  * b) the max size negotiated so far (negot)
25636400Ssklower  * c) the window size used by the tp connection (found in so),
25736400Ssklower  *
25836400Ssklower  * The result is put in the integer *size in its integer form and in
25936400Ssklower  * *negot in its logarithmic form.
26036400Ssklower  *
26136400Ssklower  * The rules are:
26236400Ssklower  * a) can only negotiate down from the value found in *negot.
26336400Ssklower  * b) the MTU must be < the windowsize,
26436400Ssklower  * c) If src and dest are on the same net,
26536400Ssklower  * 	  we will negotiate the closest size larger than  MTU but really USE
26636400Ssklower  *    the actual device mtu - ll hdr sizes.
26736400Ssklower  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
26836400Ssklower  *
26936400Ssklower  * SIDE EFFECTS:
27036400Ssklower  *	changes the values addressed by the arguments (size) and (negot)
27136400Ssklower  *  and
27236400Ssklower  *  when the peer is not on one of our directly connected subnets, it
27336400Ssklower  *  looks up a route, leaving the route in the inpcb addressed by (inp)
27436400Ssklower  *
27536400Ssklower  * NOTES:
27636400Ssklower  */
27736400Ssklower 
27836400Ssklower void
27936400Ssklower tpip_mtu(so, inp, size, negot)
28036400Ssklower 	struct socket *so;
28136400Ssklower 	struct inpcb *inp;
28236400Ssklower 	int *size;
28336400Ssklower 	u_char *negot;
28436400Ssklower {
28536400Ssklower 	register struct ifnet	*ifp;
28636400Ssklower 	struct ifnet			*tpip_route();
28736400Ssklower 	struct in_ifaddr		*ia;
28836400Ssklower 	register int			i;
28936400Ssklower 	int						windowsize = so->so_rcv.sb_hiwat;
29036400Ssklower 
29136400Ssklower 	IFDEBUG(D_CONN)
29236400Ssklower 		printf("tpip_mtu(0x%x,0x%x,0x%x,0x%x)\n",
29336400Ssklower 			so, inp, size, negot);
29436400Ssklower 		printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr);
29536400Ssklower 	ENDDEBUG
29636400Ssklower 	IFTRACE(D_CONN)
29736400Ssklower 		tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
29836400Ssklower 	ENDTRACE
29936400Ssklower 
30036400Ssklower 	*size = 1 << *negot;
30136400Ssklower 
30236400Ssklower 	if( *size > windowsize ) {
30336400Ssklower 		*size = windowsize;
30436400Ssklower 	}
30536400Ssklower 
30636400Ssklower 	ia = in_iaonnetof(in_netof(inp->inp_faddr));
30736400Ssklower 	if ( ia == (struct in_ifaddr *)0 ) {
30836400Ssklower 		ifp = tpip_route(&inp->inp_faddr);
30936400Ssklower 		if( ifp == (struct ifnet *)0 )
31036400Ssklower 			return ;
31136400Ssklower 	} else
31236400Ssklower 		ifp = ia->ia_ifp;
31336400Ssklower 
31436400Ssklower 
31536400Ssklower 	/****************************************************************
31636400Ssklower 	 * TODO - make this indirect off the socket structure to the
31736400Ssklower 	 * network layer to get headersize
31836400Ssklower 	 * After all, who knows what lies below the IP layer?
31936400Ssklower 	 * Who knows how big the NL header will be?
32036400Ssklower 	 ***************************************************************/
32136400Ssklower 
32236400Ssklower 	if( *size > ifp->if_mtu - sizeof(struct ip)) {
32336400Ssklower 		*size = ifp->if_mtu - sizeof(struct ip);
32436400Ssklower 	}
32536400Ssklower 	for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i)<*size)) ; i++)
32636400Ssklower 		;
32736400Ssklower 	i--;
32836400Ssklower 
32936400Ssklower 	if (in_netof(inp->inp_laddr) != in_netof(inp->inp_faddr)) {
33036400Ssklower 		i++;
33136400Ssklower 	} else {
33236400Ssklower 		*size = 1<<i;
33336400Ssklower 	}
33436400Ssklower 	*negot = i;
33536400Ssklower 
33636400Ssklower 	IFDEBUG(D_CONN)
33736400Ssklower 		printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
33836400Ssklower 		ifp->if_name,	*size, *negot);
33936400Ssklower 	ENDDEBUG
34036400Ssklower 	IFTRACE(D_CONN)
34136400Ssklower 		tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
34236400Ssklower 		*size, *negot, 0, 0);
34336400Ssklower 	ENDTRACE
34436400Ssklower 
34536400Ssklower }
34636400Ssklower 
34736400Ssklower /*
34836400Ssklower  * NAME:	tpip_output()
34936400Ssklower  *
35036400Ssklower  * CALLED FROM:  tp_emit()
35136400Ssklower  *
35236400Ssklower  * FUNCTION and ARGUMENTS:
35336400Ssklower  *  Take a packet(m0) from tp and package it so that ip will accept it.
35436400Ssklower  *  This means prepending space for the ip header and filling in a few
35536400Ssklower  *  of the fields.
35636400Ssklower  *  inp is the inpcb structure; datalen is the length of the data in the
35736400Ssklower  *  mbuf string m0.
35836400Ssklower  * RETURNS:
35936400Ssklower  *  whatever (E*) is returned form the net layer output routine.
36036400Ssklower  *
36136400Ssklower  * SIDE EFFECTS:
36236400Ssklower  *
36336400Ssklower  * NOTES:
36436400Ssklower  */
36536400Ssklower 
36636400Ssklower int
36736400Ssklower tpip_output(inp, m0, datalen, nochksum)
36836400Ssklower 	struct inpcb		*inp;
36936400Ssklower 	struct mbuf 		*m0;
37036400Ssklower 	int 				datalen;
37136400Ssklower 	int					nochksum;
37236400Ssklower {
37336400Ssklower 	return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen,
37436400Ssklower 		&inp->inp_route, nochksum);
37536400Ssklower }
37636400Ssklower 
37736400Ssklower /*
37836400Ssklower  * NAME:	tpip_output_dg()
37936400Ssklower  *
38036400Ssklower  * CALLED FROM:  tp_error_emit()
38136400Ssklower  *
38236400Ssklower  * FUNCTION and ARGUMENTS:
38336400Ssklower  *  This is a copy of tpip_output that takes the addresses
38436400Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
38536400Ssklower  *  don't have an in_pcb with which to call the normal output rtn.
38636400Ssklower  *
38736400Ssklower  * RETURNS:	 ENOBUFS or  whatever (E*) is
38836400Ssklower  *	returned form the net layer output routine.
38936400Ssklower  *
39036400Ssklower  * SIDE EFFECTS:
39136400Ssklower  *
39236400Ssklower  * NOTES:
39336400Ssklower  */
39436400Ssklower 
395*37469Ssklower /*ARGSUSED*/
39636400Ssklower int
39736400Ssklower tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
39836400Ssklower 	struct in_addr		*laddr, *faddr;
39936400Ssklower 	struct mbuf 		*m0;
40036400Ssklower 	int 				datalen;
40136400Ssklower 	struct route 		*ro;
40236400Ssklower 	int					nochksum;
40336400Ssklower {
40436400Ssklower 	register struct mbuf 	*m;
40536400Ssklower 	register struct ip *ip;
40636400Ssklower 	int 					error;
40736400Ssklower 
40836400Ssklower 	IFDEBUG(D_EMIT)
40936400Ssklower 		printf("tpip_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
41036400Ssklower 	ENDDEBUG
41136400Ssklower 
41236400Ssklower 
413*37469Ssklower 	MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
41436400Ssklower 	if (m == 0) {
41536400Ssklower 		error = ENOBUFS;
41636400Ssklower 		goto bad;
41736400Ssklower 	}
41836400Ssklower 	m->m_next = m0;
419*37469Ssklower 	MH_ALIGN(m, sizeof(struct ip));
42036400Ssklower 	m->m_len = sizeof(struct ip);
42136400Ssklower 
42236400Ssklower 	ip = mtod(m, struct ip *);
423*37469Ssklower 	bzero((caddr_t)ip, sizeof *ip);
42436400Ssklower 
42536400Ssklower 	ip->ip_p = IPPROTO_TP;
426*37469Ssklower 	m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
42736400Ssklower 	ip->ip_ttl = MAXTTL;
42836400Ssklower 		/* don't know why you need to set ttl;
42936400Ssklower 		 * overlay doesn't even make this available
43036400Ssklower 		 */
43136400Ssklower 
43236400Ssklower 	ip->ip_src = *laddr;
43336400Ssklower 	ip->ip_dst = *faddr;
43436400Ssklower 
43536400Ssklower 	IncStat(ts_tpdu_sent);
43636400Ssklower 	IFDEBUG(D_EMIT)
43736400Ssklower 		dump_mbuf(m, "tpip_output_dg before ip_output\n");
43836400Ssklower 	ENDDEBUG
43936400Ssklower 
44036400Ssklower 	error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST);
44136400Ssklower 
44236400Ssklower 	IFDEBUG(D_EMIT)
44336400Ssklower 		printf("tpip_output_dg after ip_output\n");
44436400Ssklower 	ENDDEBUG
44536400Ssklower 
44636400Ssklower 	return error;
44736400Ssklower 
44836400Ssklower bad:
44936400Ssklower 	m_freem(m);
45036400Ssklower 	IncStat(ts_send_drop);
45136400Ssklower 	return error;
45236400Ssklower }
45336400Ssklower 
45436400Ssklower /*
45536400Ssklower  * NAME:  tpip_input()
45636400Ssklower  *
45736400Ssklower  * CALLED FROM:
45836400Ssklower  * 	ip's input routine, indirectly through the protosw.
45936400Ssklower  *
46036400Ssklower  * FUNCTION and ARGUMENTS:
46136400Ssklower  * Take a packet (m) from ip, strip off the ip header and give it to tp
46236400Ssklower  *
46336400Ssklower  * RETURNS:  No return value.
46436400Ssklower  *
46536400Ssklower  * SIDE EFFECTS:
46636400Ssklower  *
46736400Ssklower  * NOTES:
46836400Ssklower  */
46936400Ssklower ProtoHook
470*37469Ssklower tpip_input(m, iplen)
47136400Ssklower 	struct mbuf *m;
472*37469Ssklower 	int iplen;
47336400Ssklower {
47436400Ssklower 	struct sockaddr_in 	src, dst;
47536400Ssklower 	register struct ip 		*ip;
476*37469Ssklower 	int						s = splnet(), hdrlen;
47736400Ssklower 
47836400Ssklower 	IncStat(ts_pkt_rcvd);
47936400Ssklower 
480*37469Ssklower 	/*
481*37469Ssklower 	 * IP layer has already pulled up the IP header,
482*37469Ssklower 	 * but the first byte after the IP header may not be there,
483*37469Ssklower 	 * e.g. if you came in via loopback, so you have to do an
484*37469Ssklower 	 * m_pullup to before you can even look to see how much you
485*37469Ssklower 	 * really need.  The good news is that m_pullup will round
486*37469Ssklower 	 * up to almost the next mbuf's worth.
487*37469Ssklower 	 */
48836400Ssklower 
489*37469Ssklower 
490*37469Ssklower 	if((m = m_pullup(m, iplen + 1)) == MNULL)
491*37469Ssklower 		goto discard;
49236400Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
49336400Ssklower 
49436400Ssklower 	/*
495*37469Ssklower 	 * Now pull up the whole tp header:
496*37469Ssklower 	 * Unfortunately, there may be IP options to skip past so we
497*37469Ssklower 	 * just fetch it as an unsigned char.
49836400Ssklower 	 */
499*37469Ssklower 	hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
50036400Ssklower 
501*37469Ssklower 	if( m->m_len < hdrlen ) {
502*37469Ssklower 		if((m = m_pullup(m, hdrlen)) == MNULL){
50336400Ssklower 			IFDEBUG(D_TPINPUT)
50436400Ssklower 				printf("tp_input, pullup 2!\n");
50536400Ssklower 			ENDDEBUG
50636400Ssklower 			goto discard;
50736400Ssklower 		}
50836400Ssklower 	}
50936400Ssklower 	/*
51036400Ssklower 	 * cannot use tp_inputprep() here 'cause you don't
51136400Ssklower 	 * have quite the same situation
51236400Ssklower 	 */
51336400Ssklower 
51436400Ssklower 	IFDEBUG(D_TPINPUT)
51536400Ssklower 		dump_mbuf(m, "after tpip_input both pullups");
51636400Ssklower 	ENDDEBUG
51736400Ssklower 	/*
51836400Ssklower 	 * m_pullup may have returned a different mbuf
51936400Ssklower 	 */
520*37469Ssklower 	ip = mtod(m, struct ip *);
52136400Ssklower 
52236400Ssklower 	/*
52336400Ssklower 	 * drop the ip header from the front of the mbuf
52436400Ssklower 	 * this is necessary for the tp checksum
52536400Ssklower 	 */
526*37469Ssklower 	m->m_len -= iplen;
527*37469Ssklower 	m->m_data += iplen;
52836400Ssklower 
52936400Ssklower 	src.sin_addr = *(struct in_addr *)&(ip->ip_src);
53036400Ssklower 	src.sin_family  = AF_INET;
531*37469Ssklower 	src.sin_len  = sizeof(src);
53236400Ssklower 	dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
53336400Ssklower 	dst.sin_family  = AF_INET;
534*37469Ssklower 	dst.sin_len  = sizeof(dst);
53536400Ssklower 
536*37469Ssklower 	(void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
537*37469Ssklower 				0, tpip_output_dg);
53836400Ssklower 	splx(s);
53936400Ssklower 	return 0;
54036400Ssklower 
54136400Ssklower discard:
54236400Ssklower 	IFDEBUG(D_TPINPUT)
54336400Ssklower 		printf("tpip_input DISCARD\n");
54436400Ssklower 	ENDDEBUG
54536400Ssklower 	IFTRACE(D_TPINPUT)
54636400Ssklower 		tptrace(TPPTmisc, "tpip_input DISCARD m",  m,0,0,0);
54736400Ssklower 	ENDTRACE
54836400Ssklower 	m_freem(m);
54936400Ssklower 	IncStat(ts_recv_drop);
550*37469Ssklower 	splx(s);
55136400Ssklower 	return 0;
55236400Ssklower }
55336400Ssklower 
55436400Ssklower 
55536400Ssklower #include "../h/protosw.h"
55636400Ssklower #include "../netinet/ip_icmp.h"
55736400Ssklower 
558*37469Ssklower extern void tp_quench();
55936400Ssklower /*
56036400Ssklower  * NAME:	tpin_quench()
56136400Ssklower  *
56236400Ssklower  * CALLED FROM: tpip_ctlinput()
56336400Ssklower  *
56436400Ssklower  * FUNCTION and ARGUMENTS:  find the tpcb pointer and pass it to tp_quench
56536400Ssklower  *
56636400Ssklower  * RETURNS:	Nada
56736400Ssklower  *
56836400Ssklower  * SIDE EFFECTS:
56936400Ssklower  *
57036400Ssklower  * NOTES:
57136400Ssklower  */
57236400Ssklower 
57336400Ssklower void
57436400Ssklower tpin_quench(inp)
57536400Ssklower 	struct inpcb *inp;
57636400Ssklower {
577*37469Ssklower 	tp_quench((struct tp_pcb *)inp->inp_socket->so_tpcb, PRC_QUENCH);
57836400Ssklower }
57936400Ssklower 
58036400Ssklower /*
58136400Ssklower  * NAME:	tpip_ctlinput()
58236400Ssklower  *
58336400Ssklower  * CALLED FROM:
58436400Ssklower  *  The network layer through the protosw table.
58536400Ssklower  *
58636400Ssklower  * FUNCTION and ARGUMENTS:
58736400Ssklower  *	When clnp gets an ICMP msg this gets called.
58836400Ssklower  *	It either returns an error status to the user or
58936400Ssklower  *	causes all connections on this address to be aborted
59036400Ssklower  *	by calling the appropriate xx_notify() routine.
59136400Ssklower  *	(cmd) is the type of ICMP error.
59236400Ssklower  * 	(sa) the address of the sender
59336400Ssklower  *
59436400Ssklower  * RETURNS:	 Nothing
59536400Ssklower  *
59636400Ssklower  * SIDE EFFECTS:
59736400Ssklower  *
59836400Ssklower  * NOTES:
59936400Ssklower  */
60036400Ssklower ProtoHook
60136400Ssklower tpip_ctlinput(cmd, sin)
60236400Ssklower 	int cmd;
60336400Ssklower 	struct sockaddr_in *sin;
60436400Ssklower {
60536400Ssklower 	extern u_char inetctlerrmap[];
60636400Ssklower 	extern ProtoHook tpin_abort();
60736400Ssklower 	extern ProtoHook in_rtchange();
60836400Ssklower 
60936400Ssklower 	if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK)
61036400Ssklower 		return 0;
61136400Ssklower 	if (sin->sin_addr.s_addr == INADDR_ANY)
61236400Ssklower 		return 0;
61336400Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
61436400Ssklower 		return 0;
61536400Ssklower 	switch (cmd) {
61636400Ssklower 
61736400Ssklower 		case	PRC_QUENCH:
618*37469Ssklower 			in_pcbnotify(&tp_inpcb, &sin->sin_addr,
619*37469Ssklower 						0, (int (*)())tp_quench);
62036400Ssklower 			break;
62136400Ssklower 
62236400Ssklower 		case	PRC_ROUTEDEAD:
62336400Ssklower 		case	PRC_HOSTUNREACH:
62436400Ssklower 		case	PRC_UNREACH_NET:
62536400Ssklower 		case	PRC_IFDOWN:
62636400Ssklower 		case	PRC_HOSTDEAD:
62736400Ssklower 			in_pcbnotify(&tp_inpcb, &sin->sin_addr,
62836400Ssklower 					(int)inetctlerrmap[cmd], in_rtchange);
62936400Ssklower 			break;
63036400Ssklower 
63136400Ssklower 		default:
63236400Ssklower 		/*
63336400Ssklower 		case	PRC_MSGSIZE:
63436400Ssklower 		case	PRC_UNREACH_HOST:
63536400Ssklower 		case	PRC_UNREACH_PROTOCOL:
63636400Ssklower 		case	PRC_UNREACH_PORT:
63736400Ssklower 		case	PRC_UNREACH_NEEDFRAG:
63836400Ssklower 		case	PRC_UNREACH_SRCFAIL:
63936400Ssklower 		case	PRC_REDIRECT_NET:
64036400Ssklower 		case	PRC_REDIRECT_HOST:
64136400Ssklower 		case	PRC_REDIRECT_TOSNET:
64236400Ssklower 		case	PRC_REDIRECT_TOSHOST:
64336400Ssklower 		case	PRC_TIMXCEED_INTRANS:
64436400Ssklower 		case	PRC_TIMXCEED_REASS:
64536400Ssklower 		case	PRC_PARAMPROB:
64636400Ssklower 		*/
647*37469Ssklower 		in_pcbnotify(&tp_inpcb, &sin->sin_addr,
648*37469Ssklower 				(int)inetctlerrmap[cmd], tpin_abort);
64936400Ssklower 	}
65036400Ssklower 	return 0;
65136400Ssklower }
65236400Ssklower 
65336400Ssklower /*
65436400Ssklower  * NAME:	tpin_abort()
65536400Ssklower  *
65636400Ssklower  * CALLED FROM:
65736400Ssklower  *	xxx_notify() from tp_ctlinput() when
65836400Ssklower  *  net level gets some ICMP-equiv. type event.
65936400Ssklower  *
66036400Ssklower  * FUNCTION and ARGUMENTS:
66136400Ssklower  *  Cause the connection to be aborted with some sort of error
66236400Ssklower  *  reason indicating that the network layer caused the abort.
66336400Ssklower  *  Fakes an ER TPDU so we can go through the driver.
66436400Ssklower  *
66536400Ssklower  * RETURNS:	 Nothing
66636400Ssklower  *
66736400Ssklower  * SIDE EFFECTS:
66836400Ssklower  *
66936400Ssklower  * NOTES:
67036400Ssklower  */
67136400Ssklower 
67236400Ssklower ProtoHook
67336400Ssklower tpin_abort(inp)
67436400Ssklower 	struct inpcb *inp;
67536400Ssklower {
67636400Ssklower 	struct tp_event e;
67736400Ssklower 
67836400Ssklower 	e.ev_number = ER_TPDU;
67936400Ssklower 	e.ATTR(ER_TPDU).e_reason = ENETRESET;
680*37469Ssklower 	(void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
68136400Ssklower 	return 0;
68236400Ssklower }
68336400Ssklower 
68436400Ssklower #ifdef ARGO_DEBUG
68536400Ssklower dump_inaddr(addr)
68636400Ssklower 	register struct sockaddr_in *addr;
68736400Ssklower {
68836400Ssklower 	printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr);
68936400Ssklower }
69036400Ssklower #endif ARGO_DEBUG
69136400Ssklower 
69236400Ssklower /*
69336400Ssklower  * NAME:	tpip_route()
69436400Ssklower  *
69536400Ssklower  * CALLED FROM: tpip_mtu()
69636400Ssklower  *
69736400Ssklower  * FUNCTION and ARGUMENTS:	given a destination addresss,
69836400Ssklower  *	find the interface that would be used to send something to this address.
69936400Ssklower  *
70036400Ssklower  * RETURNS:	 pointer to an ifnet structure
70136400Ssklower  *
70236400Ssklower  * SIDE EFFECTS:
70336400Ssklower  *
70436400Ssklower  * NOTES:
70536400Ssklower  */
70636400Ssklower struct ifnet *
70736400Ssklower tpip_route(dst)
70836400Ssklower 	struct in_addr *dst;
70936400Ssklower {
710*37469Ssklower 	struct ifnet 		*ifp = (struct ifnet *)0;
711*37469Ssklower 	struct sockaddr_in	insock;
712*37469Ssklower 	struct sockaddr_in	*sin = &insock;
713*37469Ssklower 	struct rtentry 		*rt;
714*37469Ssklower 	struct ifaddr	*ia;
71536400Ssklower 
71636400Ssklower 	IFDEBUG(D_CONN)
71736400Ssklower 		printf("tpip_route: dst is x%x\n", *dst);
71836400Ssklower 	ENDDEBUG
71936400Ssklower 
720*37469Ssklower 	bzero((caddr_t)sin, sizeof (*sin));
721*37469Ssklower 	sin->sin_family = AF_INET;
722*37469Ssklower 	sin->sin_len = sizeof(*sin);
723*37469Ssklower 	sin->sin_addr = *dst;
72436400Ssklower 
725*37469Ssklower 	ia = ifa_ifwithdstaddr((struct sockaddr *)sin);
72636400Ssklower 	if (ia == 0)
727*37469Ssklower 		ia = ifa_ifwithnet((struct sockaddr *)sin);
72836400Ssklower 	if (ia != 0) {
729*37469Ssklower 		ifp = ia->ifa_ifp;
73036400Ssklower 		IFDEBUG(D_CONN)
73136400Ssklower 			printf("tpip_route: ifp from ia:0x%x\n", ia);
73236400Ssklower 		ENDDEBUG
73336400Ssklower 	} else {
734*37469Ssklower 		rt = rtalloc1((struct sockaddr *)sin, 0);
735*37469Ssklower 		if (rt != 0) {
736*37469Ssklower 			ifp = rt->rt_ifp;
73736400Ssklower 			IFDEBUG(D_CONN)
738*37469Ssklower 				printf("tpip_route: ifp from rentry: 0x%x\n", rt);
73936400Ssklower 			ENDDEBUG
740*37469Ssklower 			rtfree(rt);
74136400Ssklower 		}
74236400Ssklower 	}
74336400Ssklower 	IFDEBUG(D_CONN)
74436400Ssklower 		printf("tpip_route: returning 0x%x\n", ifp);
74536400Ssklower 		if (ifp)
74636400Ssklower 			printf("tpip_route: if name %s unit 0x%x, mtu 0x%x\n",
74736400Ssklower 				ifp->if_name, ifp->if_unit, ifp->if_mtu);
74836400Ssklower 	ENDDEBUG
74936400Ssklower 	return ifp;
75036400Ssklower }
75136400Ssklower 
75236400Ssklower #endif INET
753