xref: /csrg-svn/sys/netiso/tp_inet.c (revision 51246)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51246Ssklower  *	@(#)tp_inet.c	7.10 (Berkeley) 10/02/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:
287*51246Ssklower  *  tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
28836400Ssklower  *
28936400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
29036400Ssklower  *
291*51246Ssklower  * Perform subnetwork dependent part of determining MTU information.
292*51246Ssklower  * It appears that setting a double pointer to the rtentry associated with
293*51246Ssklower  * the destination, and returning the header size for the network protocol
294*51246Ssklower  * suffices.
29536400Ssklower  *
29636400Ssklower  * SIDE EFFECTS:
297*51246Ssklower  * Sets tp_routep pointer in pcb.
29836400Ssklower  *
29936400Ssklower  * NOTES:
30036400Ssklower  */
30136400Ssklower 
302*51246Ssklower tpip_mtu(tpcb)
303*51246Ssklower register struct tp_pcb *tpcb;
30436400Ssklower {
305*51246Ssklower 	struct inpcb			*inp = (struct inpcb *)tpcb->tp_npcb;
30636400Ssklower 
30736400Ssklower 	IFDEBUG(D_CONN)
308*51246Ssklower 		printf("tpip_mtu(tpcb)\n", tpcb);
309*51246Ssklower 		printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr.s_addr);
31036400Ssklower 	ENDDEBUG
311*51246Ssklower 	tpcb->tp_routep = &(inp->inp_route.ro_rt);
312*51246Ssklower 	return (sizeof (struct ip));
31336400Ssklower 
31436400Ssklower }
31536400Ssklower 
31636400Ssklower /*
31736400Ssklower  * NAME:	tpip_output()
31836400Ssklower  *
31936400Ssklower  * CALLED FROM:  tp_emit()
32036400Ssklower  *
32136400Ssklower  * FUNCTION and ARGUMENTS:
32236400Ssklower  *  Take a packet(m0) from tp and package it so that ip will accept it.
32336400Ssklower  *  This means prepending space for the ip header and filling in a few
32436400Ssklower  *  of the fields.
32536400Ssklower  *  inp is the inpcb structure; datalen is the length of the data in the
32636400Ssklower  *  mbuf string m0.
32736400Ssklower  * RETURNS:
32836400Ssklower  *  whatever (E*) is returned form the net layer output routine.
32936400Ssklower  *
33036400Ssklower  * SIDE EFFECTS:
33136400Ssklower  *
33236400Ssklower  * NOTES:
33336400Ssklower  */
33436400Ssklower 
33536400Ssklower int
33636400Ssklower tpip_output(inp, m0, datalen, nochksum)
33736400Ssklower 	struct inpcb		*inp;
33836400Ssklower 	struct mbuf 		*m0;
33936400Ssklower 	int 				datalen;
34036400Ssklower 	int					nochksum;
34136400Ssklower {
34236400Ssklower 	return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen,
34336400Ssklower 		&inp->inp_route, nochksum);
34436400Ssklower }
34536400Ssklower 
34636400Ssklower /*
34736400Ssklower  * NAME:	tpip_output_dg()
34836400Ssklower  *
34936400Ssklower  * CALLED FROM:  tp_error_emit()
35036400Ssklower  *
35136400Ssklower  * FUNCTION and ARGUMENTS:
35236400Ssklower  *  This is a copy of tpip_output that takes the addresses
35336400Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
35436400Ssklower  *  don't have an in_pcb with which to call the normal output rtn.
35536400Ssklower  *
35636400Ssklower  * RETURNS:	 ENOBUFS or  whatever (E*) is
35736400Ssklower  *	returned form the net layer output routine.
35836400Ssklower  *
35936400Ssklower  * SIDE EFFECTS:
36036400Ssklower  *
36136400Ssklower  * NOTES:
36236400Ssklower  */
36336400Ssklower 
36437469Ssklower /*ARGSUSED*/
36536400Ssklower int
36636400Ssklower tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
36736400Ssklower 	struct in_addr		*laddr, *faddr;
36836400Ssklower 	struct mbuf 		*m0;
36936400Ssklower 	int 				datalen;
37036400Ssklower 	struct route 		*ro;
37136400Ssklower 	int					nochksum;
37236400Ssklower {
37336400Ssklower 	register struct mbuf 	*m;
37436400Ssklower 	register struct ip *ip;
37536400Ssklower 	int 					error;
37636400Ssklower 
37736400Ssklower 	IFDEBUG(D_EMIT)
37836400Ssklower 		printf("tpip_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
37936400Ssklower 	ENDDEBUG
38036400Ssklower 
38136400Ssklower 
38237469Ssklower 	MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
38336400Ssklower 	if (m == 0) {
38436400Ssklower 		error = ENOBUFS;
38536400Ssklower 		goto bad;
38636400Ssklower 	}
38736400Ssklower 	m->m_next = m0;
38837469Ssklower 	MH_ALIGN(m, sizeof(struct ip));
38936400Ssklower 	m->m_len = sizeof(struct ip);
39036400Ssklower 
39136400Ssklower 	ip = mtod(m, struct ip *);
39237469Ssklower 	bzero((caddr_t)ip, sizeof *ip);
39336400Ssklower 
39436400Ssklower 	ip->ip_p = IPPROTO_TP;
39537469Ssklower 	m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
39636400Ssklower 	ip->ip_ttl = MAXTTL;
39736400Ssklower 		/* don't know why you need to set ttl;
39836400Ssklower 		 * overlay doesn't even make this available
39936400Ssklower 		 */
40036400Ssklower 
40136400Ssklower 	ip->ip_src = *laddr;
40236400Ssklower 	ip->ip_dst = *faddr;
40336400Ssklower 
40436400Ssklower 	IncStat(ts_tpdu_sent);
40536400Ssklower 	IFDEBUG(D_EMIT)
40636400Ssklower 		dump_mbuf(m, "tpip_output_dg before ip_output\n");
40736400Ssklower 	ENDDEBUG
40836400Ssklower 
40936400Ssklower 	error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST);
41036400Ssklower 
41136400Ssklower 	IFDEBUG(D_EMIT)
41236400Ssklower 		printf("tpip_output_dg after ip_output\n");
41336400Ssklower 	ENDDEBUG
41436400Ssklower 
41536400Ssklower 	return error;
41636400Ssklower 
41736400Ssklower bad:
41836400Ssklower 	m_freem(m);
41936400Ssklower 	IncStat(ts_send_drop);
42036400Ssklower 	return error;
42136400Ssklower }
42236400Ssklower 
42336400Ssklower /*
42436400Ssklower  * NAME:  tpip_input()
42536400Ssklower  *
42636400Ssklower  * CALLED FROM:
42736400Ssklower  * 	ip's input routine, indirectly through the protosw.
42836400Ssklower  *
42936400Ssklower  * FUNCTION and ARGUMENTS:
43036400Ssklower  * Take a packet (m) from ip, strip off the ip header and give it to tp
43136400Ssklower  *
43236400Ssklower  * RETURNS:  No return value.
43336400Ssklower  *
43436400Ssklower  * SIDE EFFECTS:
43536400Ssklower  *
43636400Ssklower  * NOTES:
43736400Ssklower  */
43836400Ssklower ProtoHook
43937469Ssklower tpip_input(m, iplen)
44036400Ssklower 	struct mbuf *m;
44137469Ssklower 	int iplen;
44236400Ssklower {
44336400Ssklower 	struct sockaddr_in 	src, dst;
44436400Ssklower 	register struct ip 		*ip;
44537469Ssklower 	int						s = splnet(), hdrlen;
44636400Ssklower 
44736400Ssklower 	IncStat(ts_pkt_rcvd);
44836400Ssklower 
44937469Ssklower 	/*
45037469Ssklower 	 * IP layer has already pulled up the IP header,
45137469Ssklower 	 * but the first byte after the IP header may not be there,
45237469Ssklower 	 * e.g. if you came in via loopback, so you have to do an
45337469Ssklower 	 * m_pullup to before you can even look to see how much you
45437469Ssklower 	 * really need.  The good news is that m_pullup will round
45537469Ssklower 	 * up to almost the next mbuf's worth.
45637469Ssklower 	 */
45736400Ssklower 
45837469Ssklower 
45937469Ssklower 	if((m = m_pullup(m, iplen + 1)) == MNULL)
46037469Ssklower 		goto discard;
46136400Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
46236400Ssklower 
46336400Ssklower 	/*
46437469Ssklower 	 * Now pull up the whole tp header:
46537469Ssklower 	 * Unfortunately, there may be IP options to skip past so we
46637469Ssklower 	 * just fetch it as an unsigned char.
46736400Ssklower 	 */
46837469Ssklower 	hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
46936400Ssklower 
47037469Ssklower 	if( m->m_len < hdrlen ) {
47137469Ssklower 		if((m = m_pullup(m, hdrlen)) == MNULL){
47236400Ssklower 			IFDEBUG(D_TPINPUT)
47336400Ssklower 				printf("tp_input, pullup 2!\n");
47436400Ssklower 			ENDDEBUG
47536400Ssklower 			goto discard;
47636400Ssklower 		}
47736400Ssklower 	}
47836400Ssklower 	/*
47936400Ssklower 	 * cannot use tp_inputprep() here 'cause you don't
48036400Ssklower 	 * have quite the same situation
48136400Ssklower 	 */
48236400Ssklower 
48336400Ssklower 	IFDEBUG(D_TPINPUT)
48436400Ssklower 		dump_mbuf(m, "after tpip_input both pullups");
48536400Ssklower 	ENDDEBUG
48636400Ssklower 	/*
48736400Ssklower 	 * m_pullup may have returned a different mbuf
48836400Ssklower 	 */
48937469Ssklower 	ip = mtod(m, struct ip *);
49036400Ssklower 
49136400Ssklower 	/*
49236400Ssklower 	 * drop the ip header from the front of the mbuf
49336400Ssklower 	 * this is necessary for the tp checksum
49436400Ssklower 	 */
49537469Ssklower 	m->m_len -= iplen;
49637469Ssklower 	m->m_data += iplen;
49736400Ssklower 
49836400Ssklower 	src.sin_addr = *(struct in_addr *)&(ip->ip_src);
49936400Ssklower 	src.sin_family  = AF_INET;
50037469Ssklower 	src.sin_len  = sizeof(src);
50136400Ssklower 	dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
50236400Ssklower 	dst.sin_family  = AF_INET;
50337469Ssklower 	dst.sin_len  = sizeof(dst);
50436400Ssklower 
50537469Ssklower 	(void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
50639928Ssklower 				0, tpip_output_dg, 0);
50736400Ssklower 	return 0;
50836400Ssklower 
50936400Ssklower discard:
51036400Ssklower 	IFDEBUG(D_TPINPUT)
51136400Ssklower 		printf("tpip_input DISCARD\n");
51236400Ssklower 	ENDDEBUG
51336400Ssklower 	IFTRACE(D_TPINPUT)
51436400Ssklower 		tptrace(TPPTmisc, "tpip_input DISCARD m",  m,0,0,0);
51536400Ssklower 	ENDTRACE
51636400Ssklower 	m_freem(m);
51736400Ssklower 	IncStat(ts_recv_drop);
51837469Ssklower 	splx(s);
51936400Ssklower 	return 0;
52036400Ssklower }
52136400Ssklower 
52236400Ssklower 
52337536Smckusick #include "protosw.h"
52436400Ssklower #include "../netinet/ip_icmp.h"
52536400Ssklower 
52637469Ssklower extern void tp_quench();
52736400Ssklower /*
52836400Ssklower  * NAME:	tpin_quench()
52936400Ssklower  *
53036400Ssklower  * CALLED FROM: tpip_ctlinput()
53136400Ssklower  *
53236400Ssklower  * FUNCTION and ARGUMENTS:  find the tpcb pointer and pass it to tp_quench
53336400Ssklower  *
53436400Ssklower  * RETURNS:	Nada
53536400Ssklower  *
53636400Ssklower  * SIDE EFFECTS:
53736400Ssklower  *
53836400Ssklower  * NOTES:
53936400Ssklower  */
54036400Ssklower 
54136400Ssklower void
54236400Ssklower tpin_quench(inp)
54336400Ssklower 	struct inpcb *inp;
54436400Ssklower {
54550435Ssklower 	tp_quench((struct tp_pcb *)inp->inp_socket->so_pcb, PRC_QUENCH);
54636400Ssklower }
54736400Ssklower 
54836400Ssklower /*
54936400Ssklower  * NAME:	tpip_ctlinput()
55036400Ssklower  *
55136400Ssklower  * CALLED FROM:
55236400Ssklower  *  The network layer through the protosw table.
55336400Ssklower  *
55436400Ssklower  * FUNCTION and ARGUMENTS:
55536400Ssklower  *	When clnp gets an ICMP msg this gets called.
55636400Ssklower  *	It either returns an error status to the user or
55736400Ssklower  *	causes all connections on this address to be aborted
55836400Ssklower  *	by calling the appropriate xx_notify() routine.
55936400Ssklower  *	(cmd) is the type of ICMP error.
56036400Ssklower  * 	(sa) the address of the sender
56136400Ssklower  *
56236400Ssklower  * RETURNS:	 Nothing
56336400Ssklower  *
56436400Ssklower  * SIDE EFFECTS:
56536400Ssklower  *
56636400Ssklower  * NOTES:
56736400Ssklower  */
56836400Ssklower ProtoHook
56936400Ssklower tpip_ctlinput(cmd, sin)
57036400Ssklower 	int cmd;
57136400Ssklower 	struct sockaddr_in *sin;
57236400Ssklower {
57336400Ssklower 	extern u_char inetctlerrmap[];
57436400Ssklower 	extern ProtoHook tpin_abort();
57536400Ssklower 	extern ProtoHook in_rtchange();
57645630Ssklower 	extern struct in_addr zeroin_addr;
57736400Ssklower 
57836400Ssklower 	if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK)
57936400Ssklower 		return 0;
58036400Ssklower 	if (sin->sin_addr.s_addr == INADDR_ANY)
58136400Ssklower 		return 0;
58236400Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
58336400Ssklower 		return 0;
58436400Ssklower 	switch (cmd) {
58536400Ssklower 
58636400Ssklower 		case	PRC_QUENCH:
58745630Ssklower 			in_pcbnotify(&tp_inpcb, sin, 0,
58845630Ssklower 				zeroin_addr, 0, cmd, (int (*)())tp_quench);
58936400Ssklower 			break;
59036400Ssklower 
59136400Ssklower 		case	PRC_ROUTEDEAD:
59236400Ssklower 		case	PRC_HOSTUNREACH:
59336400Ssklower 		case	PRC_UNREACH_NET:
59436400Ssklower 		case	PRC_IFDOWN:
59536400Ssklower 		case	PRC_HOSTDEAD:
59645630Ssklower 			in_pcbnotify(&tp_inpcb, sin, 0,
59745630Ssklower 				zeroin_addr, 0, cmd, in_rtchange);
59836400Ssklower 			break;
59936400Ssklower 
60036400Ssklower 		default:
60136400Ssklower 		/*
60236400Ssklower 		case	PRC_MSGSIZE:
60336400Ssklower 		case	PRC_UNREACH_HOST:
60436400Ssklower 		case	PRC_UNREACH_PROTOCOL:
60536400Ssklower 		case	PRC_UNREACH_PORT:
60636400Ssklower 		case	PRC_UNREACH_NEEDFRAG:
60736400Ssklower 		case	PRC_UNREACH_SRCFAIL:
60836400Ssklower 		case	PRC_REDIRECT_NET:
60936400Ssklower 		case	PRC_REDIRECT_HOST:
61036400Ssklower 		case	PRC_REDIRECT_TOSNET:
61136400Ssklower 		case	PRC_REDIRECT_TOSHOST:
61236400Ssklower 		case	PRC_TIMXCEED_INTRANS:
61336400Ssklower 		case	PRC_TIMXCEED_REASS:
61436400Ssklower 		case	PRC_PARAMPROB:
61536400Ssklower 		*/
61645630Ssklower 		in_pcbnotify(&tp_inpcb, sin, 0, zeroin_addr, 0,
61745630Ssklower 				cmd, tpin_abort);
61836400Ssklower 	}
61936400Ssklower 	return 0;
62036400Ssklower }
62136400Ssklower 
62236400Ssklower /*
62336400Ssklower  * NAME:	tpin_abort()
62436400Ssklower  *
62536400Ssklower  * CALLED FROM:
62636400Ssklower  *	xxx_notify() from tp_ctlinput() when
62736400Ssklower  *  net level gets some ICMP-equiv. type event.
62836400Ssklower  *
62936400Ssklower  * FUNCTION and ARGUMENTS:
63036400Ssklower  *  Cause the connection to be aborted with some sort of error
63136400Ssklower  *  reason indicating that the network layer caused the abort.
63236400Ssklower  *  Fakes an ER TPDU so we can go through the driver.
63336400Ssklower  *
63436400Ssklower  * RETURNS:	 Nothing
63536400Ssklower  *
63636400Ssklower  * SIDE EFFECTS:
63736400Ssklower  *
63836400Ssklower  * NOTES:
63936400Ssklower  */
64036400Ssklower 
64136400Ssklower ProtoHook
64236400Ssklower tpin_abort(inp)
64336400Ssklower 	struct inpcb *inp;
64436400Ssklower {
64536400Ssklower 	struct tp_event e;
64636400Ssklower 
64736400Ssklower 	e.ev_number = ER_TPDU;
64836400Ssklower 	e.ATTR(ER_TPDU).e_reason = ENETRESET;
64937469Ssklower 	(void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
65036400Ssklower 	return 0;
65136400Ssklower }
65236400Ssklower 
65336400Ssklower #ifdef ARGO_DEBUG
65436400Ssklower dump_inaddr(addr)
65536400Ssklower 	register struct sockaddr_in *addr;
65636400Ssklower {
65736400Ssklower 	printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr);
65836400Ssklower }
65936400Ssklower #endif ARGO_DEBUG
66036400Ssklower #endif INET
661