xref: /csrg-svn/sys/netiso/tp_inet.c (revision 63222)
149268Sbostic /*-
2*63222Sbostic  * Copyright (c) 1991, 1993
3*63222Sbostic  *	The Regents of the University of California.  All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*63222Sbostic  *	@(#)tp_inet.c	8.1 (Berkeley) 06/10/93
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 
6156533Sbostic #include <sys/param.h>
6256533Sbostic #include <sys/socket.h>
6356533Sbostic #include <sys/socketvar.h>
6456533Sbostic #include <sys/mbuf.h>
6556533Sbostic #include <sys/errno.h>
6656533Sbostic #include <sys/time.h>
6736400Ssklower 
6856533Sbostic #include <net/if.h>
6956533Sbostic 
7056533Sbostic #include <netiso/tp_param.h>
7156533Sbostic #include <netiso/argo_debug.h>
7256533Sbostic #include <netiso/tp_stat.h>
7356533Sbostic #include <netiso/tp_ip.h>
7456533Sbostic #include <netiso/tp_pcb.h>
7556533Sbostic #include <netiso/tp_trace.h>
7656533Sbostic #include <netiso/tp_stat.h>
7756533Sbostic #include <netiso/tp_tpdu.h>
7856533Sbostic #include <netinet/in_var.h>
7956533Sbostic 
8037469Ssklower #ifndef ISO
8156533Sbostic #include <netiso/iso_chksum.c>
8237469Ssklower #endif
8336400Ssklower 
8436400Ssklower /*
8536400Ssklower  * NAME:			in_getsufx()
8636400Ssklower 
8736400Ssklower  * CALLED FROM: 	pr_usrreq() on PRU_BIND,
8836400Ssklower  *					PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
8936400Ssklower  *
9036400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
9136400Ssklower  * 	Get a transport suffix from an inpcb structure (inp).
9236400Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
9336400Ssklower  *
9436400Ssklower  * RETURNS:		internet port / transport suffix
9536400Ssklower  *  			(CAST TO AN INT)
9636400Ssklower  *
9736400Ssklower  * SIDE EFFECTS:
9836400Ssklower  *
9936400Ssklower  * NOTES:
10036400Ssklower  */
10137469Ssklower in_getsufx(inp, lenp, data_out, which)
10236400Ssklower 	struct inpcb *inp;
10337469Ssklower 	u_short *lenp;
10437469Ssklower 	caddr_t data_out;
10536400Ssklower 	int which;
10636400Ssklower {
10737469Ssklower 	*lenp = sizeof(u_short);
10836400Ssklower 	switch (which) {
10936400Ssklower 	case TP_LOCAL:
11037469Ssklower 		*(u_short *)data_out = inp->inp_lport;
11137469Ssklower 		return;
11236400Ssklower 
11336400Ssklower 	case TP_FOREIGN:
11437469Ssklower 		*(u_short *)data_out = inp->inp_fport;
11536400Ssklower 	}
11637469Ssklower 
11736400Ssklower }
11836400Ssklower 
11936400Ssklower /*
12036400Ssklower  * NAME:		in_putsufx()
12136400Ssklower  *
12236400Ssklower  * CALLED FROM: tp_newsocket(); i.e., when a connection
12336400Ssklower  *		is being established by an incoming CR_TPDU.
12436400Ssklower  *
12536400Ssklower  * FUNCTION, ARGUMENTS:
12636400Ssklower  * 	Put a transport suffix (found in name) into an inpcb structure (inp).
12736400Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
12836400Ssklower  *
12936400Ssklower  * RETURNS:		Nada
13036400Ssklower  *
13136400Ssklower  * SIDE EFFECTS:
13236400Ssklower  *
13336400Ssklower  * NOTES:
13436400Ssklower  */
13537469Ssklower /*ARGSUSED*/
13636400Ssklower void
in_putsufx(inp,sufxloc,sufxlen,which)13737469Ssklower in_putsufx(inp, sufxloc, sufxlen, which)
13836400Ssklower 	struct inpcb *inp;
13937469Ssklower 	caddr_t sufxloc;
14036400Ssklower 	int which;
14136400Ssklower {
14237469Ssklower 	if (which == TP_FOREIGN) {
14337469Ssklower 		bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport));
14436400Ssklower 	}
14536400Ssklower }
14636400Ssklower 
14736400Ssklower /*
14836400Ssklower  * NAME:	in_recycle_tsuffix()
14936400Ssklower  *
15036400Ssklower  * CALLED FROM:	tp.trans whenever we go into REFWAIT state.
15136400Ssklower  *
15236400Ssklower  * FUNCTION and ARGUMENT:
15336400Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
15436400Ssklower  * 	(inp) is the net level pcb.
15536400Ssklower  *
15636400Ssklower  * RETURNS:			Nada
15736400Ssklower  *
15836400Ssklower  * SIDE EFFECTS:
15936400Ssklower  *
16036400Ssklower  * NOTES:	This really shouldn't have to be done in a NET level pcb
16136400Ssklower  *	but... for the internet world that just the way it is done in BSD...
16236400Ssklower  * 	The alternative is to have the port unusable until the reference
16336400Ssklower  * 	timer goes off.
16436400Ssklower  */
16536400Ssklower void
in_recycle_tsuffix(inp)16636400Ssklower in_recycle_tsuffix(inp)
16736400Ssklower 	struct inpcb	*inp;
16836400Ssklower {
16936400Ssklower 	inp->inp_fport = inp->inp_lport = 0;
17036400Ssklower }
17136400Ssklower 
17236400Ssklower /*
17336400Ssklower  * NAME:	in_putnetaddr()
17436400Ssklower  *
17536400Ssklower  * CALLED FROM:
17636400Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
17736400Ssklower  * 	incoming CR_TPDU.
17836400Ssklower  *
17936400Ssklower  * FUNCTION and ARGUMENTS:
18036400Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
18136400Ssklower  * 	into an inpcb (inp).
18236400Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
18336400Ssklower  *
18436400Ssklower  * RETURNS:		Nada
18536400Ssklower  *
18636400Ssklower  * SIDE EFFECTS:
18736400Ssklower  *
18836400Ssklower  * NOTES:
18936400Ssklower  */
19036400Ssklower void
in_putnetaddr(inp,name,which)19136400Ssklower in_putnetaddr(inp, name, which)
19236400Ssklower 	register struct inpcb	*inp;
19336400Ssklower 	struct sockaddr_in	*name;
19436400Ssklower 	int which;
19536400Ssklower {
19636400Ssklower 	switch (which) {
19736400Ssklower 	case TP_LOCAL:
19836400Ssklower 		bcopy((caddr_t)&name->sin_addr,
19936400Ssklower 			(caddr_t)&inp->inp_laddr, sizeof(struct in_addr));
20036400Ssklower 			/* won't work if the dst address (name) is INADDR_ANY */
20136400Ssklower 
20236400Ssklower 		break;
20336400Ssklower 	case TP_FOREIGN:
20436400Ssklower 		if( name != (struct sockaddr_in *)0 ) {
20536400Ssklower 			bcopy((caddr_t)&name->sin_addr,
20636400Ssklower 				(caddr_t)&inp->inp_faddr, sizeof(struct in_addr));
20736400Ssklower 		}
20836400Ssklower 	}
20936400Ssklower }
21036400Ssklower 
21136400Ssklower /*
21244422Ssklower  * NAME:	in_putnetaddr()
21344422Ssklower  *
21444422Ssklower  * CALLED FROM:
21544422Ssklower  * 	tp_input() when a connection is being established by an
21644422Ssklower  * 	incoming CR_TPDU, and considered for interception.
21744422Ssklower  *
21844422Ssklower  * FUNCTION and ARGUMENTS:
21944422Ssklower  * 	Compare a whole net addr from a struct sockaddr (name),
22044422Ssklower  * 	with that implicitly stored in an inpcb (inp).
22144422Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
22244422Ssklower  *
22344422Ssklower  * RETURNS:		Nada
22444422Ssklower  *
22544422Ssklower  * SIDE EFFECTS:
22644422Ssklower  *
22744422Ssklower  * NOTES:
22844422Ssklower  */
in_cmpnetaddr(inp,name,which)22944422Ssklower in_cmpnetaddr(inp, name, which)
23044422Ssklower 	register struct inpcb	*inp;
23144422Ssklower 	register struct sockaddr_in	*name;
23244422Ssklower 	int which;
23344422Ssklower {
23444422Ssklower 	if (which == TP_LOCAL) {
23544422Ssklower 		if (name->sin_port && name->sin_port != inp->inp_lport)
23644422Ssklower 			return 0;
23744422Ssklower 		return (name->sin_addr.s_addr == inp->inp_laddr.s_addr);
23844422Ssklower 	}
23944422Ssklower 	if (name->sin_port && name->sin_port != inp->inp_fport)
24044422Ssklower 		return 0;
24144422Ssklower 	return (name->sin_addr.s_addr == inp->inp_faddr.s_addr);
24244422Ssklower }
24344422Ssklower 
24444422Ssklower /*
24536400Ssklower  * NAME:	in_getnetaddr()
24636400Ssklower  *
24736400Ssklower  * CALLED FROM:
24836400Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
24936400Ssklower  * FUNCTION and ARGUMENTS:
25036400Ssklower  * 	Copy a whole net addr from an inpcb (inp) into
25137469Ssklower  * 	an mbuf (name);
25236400Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
25336400Ssklower  *
25436400Ssklower  * RETURNS:		Nada
25536400Ssklower  *
25636400Ssklower  * SIDE EFFECTS:
25736400Ssklower  *
25836400Ssklower  * NOTES:
25936400Ssklower  */
26036400Ssklower 
26136400Ssklower void
in_getnetaddr(inp,name,which)26236400Ssklower in_getnetaddr( inp, name, which)
26337469Ssklower 	register struct mbuf *name;
26436400Ssklower 	struct inpcb *inp;
26536400Ssklower 	int which;
26636400Ssklower {
26737469Ssklower 	register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *);
26837469Ssklower 	bzero((caddr_t)sin, sizeof(*sin));
26936400Ssklower 	switch (which) {
27036400Ssklower 	case TP_LOCAL:
27137469Ssklower 		sin->sin_addr = inp->inp_laddr;
27237469Ssklower 		sin->sin_port = inp->inp_lport;
27336400Ssklower 		break;
27436400Ssklower 	case TP_FOREIGN:
27537469Ssklower 		sin->sin_addr = inp->inp_faddr;
27637469Ssklower 		sin->sin_port = inp->inp_fport;
27736400Ssklower 		break;
27837469Ssklower 	default:
27937469Ssklower 		return;
28036400Ssklower 	}
28137469Ssklower 	name->m_len = sin->sin_len = sizeof (*sin);
28237469Ssklower 	sin->sin_family = AF_INET;
28336400Ssklower }
28436400Ssklower 
28536400Ssklower /*
28636400Ssklower  * NAME: 	tpip_mtu()
28736400Ssklower  *
28836400Ssklower  * CALLED FROM:
28951246Ssklower  *  tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
29036400Ssklower  *
29136400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
29236400Ssklower  *
29351246Ssklower  * Perform subnetwork dependent part of determining MTU information.
29451246Ssklower  * It appears that setting a double pointer to the rtentry associated with
29551246Ssklower  * the destination, and returning the header size for the network protocol
29651246Ssklower  * suffices.
29736400Ssklower  *
29836400Ssklower  * SIDE EFFECTS:
29951246Ssklower  * Sets tp_routep pointer in pcb.
30036400Ssklower  *
30136400Ssklower  * NOTES:
30236400Ssklower  */
30336400Ssklower 
tpip_mtu(tpcb)30451246Ssklower tpip_mtu(tpcb)
30551246Ssklower register struct tp_pcb *tpcb;
30636400Ssklower {
30751246Ssklower 	struct inpcb			*inp = (struct inpcb *)tpcb->tp_npcb;
30836400Ssklower 
30936400Ssklower 	IFDEBUG(D_CONN)
31051246Ssklower 		printf("tpip_mtu(tpcb)\n", tpcb);
31151246Ssklower 		printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr.s_addr);
31236400Ssklower 	ENDDEBUG
31351246Ssklower 	tpcb->tp_routep = &(inp->inp_route.ro_rt);
31451246Ssklower 	return (sizeof (struct ip));
31536400Ssklower 
31636400Ssklower }
31736400Ssklower 
31836400Ssklower /*
31936400Ssklower  * NAME:	tpip_output()
32036400Ssklower  *
32136400Ssklower  * CALLED FROM:  tp_emit()
32236400Ssklower  *
32336400Ssklower  * FUNCTION and ARGUMENTS:
32436400Ssklower  *  Take a packet(m0) from tp and package it so that ip will accept it.
32536400Ssklower  *  This means prepending space for the ip header and filling in a few
32636400Ssklower  *  of the fields.
32736400Ssklower  *  inp is the inpcb structure; datalen is the length of the data in the
32836400Ssklower  *  mbuf string m0.
32936400Ssklower  * RETURNS:
33036400Ssklower  *  whatever (E*) is returned form the net layer output routine.
33136400Ssklower  *
33236400Ssklower  * SIDE EFFECTS:
33336400Ssklower  *
33436400Ssklower  * NOTES:
33536400Ssklower  */
33636400Ssklower 
33736400Ssklower int
tpip_output(inp,m0,datalen,nochksum)33836400Ssklower tpip_output(inp, m0, datalen, nochksum)
33936400Ssklower 	struct inpcb		*inp;
34036400Ssklower 	struct mbuf 		*m0;
34136400Ssklower 	int 				datalen;
34236400Ssklower 	int					nochksum;
34336400Ssklower {
34436400Ssklower 	return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen,
34536400Ssklower 		&inp->inp_route, nochksum);
34636400Ssklower }
34736400Ssklower 
34836400Ssklower /*
34936400Ssklower  * NAME:	tpip_output_dg()
35036400Ssklower  *
35136400Ssklower  * CALLED FROM:  tp_error_emit()
35236400Ssklower  *
35336400Ssklower  * FUNCTION and ARGUMENTS:
35436400Ssklower  *  This is a copy of tpip_output that takes the addresses
35536400Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
35636400Ssklower  *  don't have an in_pcb with which to call the normal output rtn.
35736400Ssklower  *
35836400Ssklower  * RETURNS:	 ENOBUFS or  whatever (E*) is
35936400Ssklower  *	returned form the net layer output routine.
36036400Ssklower  *
36136400Ssklower  * SIDE EFFECTS:
36236400Ssklower  *
36336400Ssklower  * NOTES:
36436400Ssklower  */
36536400Ssklower 
36637469Ssklower /*ARGSUSED*/
36736400Ssklower int
tpip_output_dg(laddr,faddr,m0,datalen,ro,nochksum)36836400Ssklower tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
36936400Ssklower 	struct in_addr		*laddr, *faddr;
37036400Ssklower 	struct mbuf 		*m0;
37136400Ssklower 	int 				datalen;
37236400Ssklower 	struct route 		*ro;
37336400Ssklower 	int					nochksum;
37436400Ssklower {
37536400Ssklower 	register struct mbuf 	*m;
37636400Ssklower 	register struct ip *ip;
37736400Ssklower 	int 					error;
37836400Ssklower 
37936400Ssklower 	IFDEBUG(D_EMIT)
38036400Ssklower 		printf("tpip_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
38136400Ssklower 	ENDDEBUG
38236400Ssklower 
38336400Ssklower 
38437469Ssklower 	MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
38536400Ssklower 	if (m == 0) {
38636400Ssklower 		error = ENOBUFS;
38736400Ssklower 		goto bad;
38836400Ssklower 	}
38936400Ssklower 	m->m_next = m0;
39037469Ssklower 	MH_ALIGN(m, sizeof(struct ip));
39136400Ssklower 	m->m_len = sizeof(struct ip);
39236400Ssklower 
39336400Ssklower 	ip = mtod(m, struct ip *);
39437469Ssklower 	bzero((caddr_t)ip, sizeof *ip);
39536400Ssklower 
39636400Ssklower 	ip->ip_p = IPPROTO_TP;
39737469Ssklower 	m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
39836400Ssklower 	ip->ip_ttl = MAXTTL;
39936400Ssklower 		/* don't know why you need to set ttl;
40036400Ssklower 		 * overlay doesn't even make this available
40136400Ssklower 		 */
40236400Ssklower 
40336400Ssklower 	ip->ip_src = *laddr;
40436400Ssklower 	ip->ip_dst = *faddr;
40536400Ssklower 
40636400Ssklower 	IncStat(ts_tpdu_sent);
40736400Ssklower 	IFDEBUG(D_EMIT)
40836400Ssklower 		dump_mbuf(m, "tpip_output_dg before ip_output\n");
40936400Ssklower 	ENDDEBUG
41036400Ssklower 
41161657Ssklower 	error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST, NULL);
41236400Ssklower 
41336400Ssklower 	IFDEBUG(D_EMIT)
41436400Ssklower 		printf("tpip_output_dg after ip_output\n");
41536400Ssklower 	ENDDEBUG
41636400Ssklower 
41736400Ssklower 	return error;
41836400Ssklower 
41936400Ssklower bad:
42036400Ssklower 	m_freem(m);
42136400Ssklower 	IncStat(ts_send_drop);
42236400Ssklower 	return error;
42336400Ssklower }
42436400Ssklower 
42536400Ssklower /*
42636400Ssklower  * NAME:  tpip_input()
42736400Ssklower  *
42836400Ssklower  * CALLED FROM:
42936400Ssklower  * 	ip's input routine, indirectly through the protosw.
43036400Ssklower  *
43136400Ssklower  * FUNCTION and ARGUMENTS:
43236400Ssklower  * Take a packet (m) from ip, strip off the ip header and give it to tp
43336400Ssklower  *
43436400Ssklower  * RETURNS:  No return value.
43536400Ssklower  *
43636400Ssklower  * SIDE EFFECTS:
43736400Ssklower  *
43836400Ssklower  * NOTES:
43936400Ssklower  */
44036400Ssklower ProtoHook
tpip_input(m,iplen)44137469Ssklower tpip_input(m, iplen)
44236400Ssklower 	struct mbuf *m;
44337469Ssklower 	int iplen;
44436400Ssklower {
44536400Ssklower 	struct sockaddr_in 	src, dst;
44636400Ssklower 	register struct ip 		*ip;
44737469Ssklower 	int						s = splnet(), hdrlen;
44836400Ssklower 
44936400Ssklower 	IncStat(ts_pkt_rcvd);
45036400Ssklower 
45137469Ssklower 	/*
45237469Ssklower 	 * IP layer has already pulled up the IP header,
45337469Ssklower 	 * but the first byte after the IP header may not be there,
45437469Ssklower 	 * e.g. if you came in via loopback, so you have to do an
45537469Ssklower 	 * m_pullup to before you can even look to see how much you
45637469Ssklower 	 * really need.  The good news is that m_pullup will round
45737469Ssklower 	 * up to almost the next mbuf's worth.
45837469Ssklower 	 */
45936400Ssklower 
46037469Ssklower 
46137469Ssklower 	if((m = m_pullup(m, iplen + 1)) == MNULL)
46237469Ssklower 		goto discard;
46336400Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
46436400Ssklower 
46536400Ssklower 	/*
46637469Ssklower 	 * Now pull up the whole tp header:
46737469Ssklower 	 * Unfortunately, there may be IP options to skip past so we
46837469Ssklower 	 * just fetch it as an unsigned char.
46936400Ssklower 	 */
47037469Ssklower 	hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
47136400Ssklower 
47237469Ssklower 	if( m->m_len < hdrlen ) {
47337469Ssklower 		if((m = m_pullup(m, hdrlen)) == MNULL){
47436400Ssklower 			IFDEBUG(D_TPINPUT)
47536400Ssklower 				printf("tp_input, pullup 2!\n");
47636400Ssklower 			ENDDEBUG
47736400Ssklower 			goto discard;
47836400Ssklower 		}
47936400Ssklower 	}
48036400Ssklower 	/*
48136400Ssklower 	 * cannot use tp_inputprep() here 'cause you don't
48236400Ssklower 	 * have quite the same situation
48336400Ssklower 	 */
48436400Ssklower 
48536400Ssklower 	IFDEBUG(D_TPINPUT)
48636400Ssklower 		dump_mbuf(m, "after tpip_input both pullups");
48736400Ssklower 	ENDDEBUG
48836400Ssklower 	/*
48936400Ssklower 	 * m_pullup may have returned a different mbuf
49036400Ssklower 	 */
49137469Ssklower 	ip = mtod(m, struct ip *);
49236400Ssklower 
49336400Ssklower 	/*
49436400Ssklower 	 * drop the ip header from the front of the mbuf
49536400Ssklower 	 * this is necessary for the tp checksum
49636400Ssklower 	 */
49737469Ssklower 	m->m_len -= iplen;
49837469Ssklower 	m->m_data += iplen;
49936400Ssklower 
50036400Ssklower 	src.sin_addr = *(struct in_addr *)&(ip->ip_src);
50136400Ssklower 	src.sin_family  = AF_INET;
50237469Ssklower 	src.sin_len  = sizeof(src);
50336400Ssklower 	dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
50436400Ssklower 	dst.sin_family  = AF_INET;
50537469Ssklower 	dst.sin_len  = sizeof(dst);
50636400Ssklower 
50737469Ssklower 	(void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
50839928Ssklower 				0, tpip_output_dg, 0);
50936400Ssklower 	return 0;
51036400Ssklower 
51136400Ssklower discard:
51236400Ssklower 	IFDEBUG(D_TPINPUT)
51336400Ssklower 		printf("tpip_input DISCARD\n");
51436400Ssklower 	ENDDEBUG
51536400Ssklower 	IFTRACE(D_TPINPUT)
51636400Ssklower 		tptrace(TPPTmisc, "tpip_input DISCARD m",  m,0,0,0);
51736400Ssklower 	ENDTRACE
51836400Ssklower 	m_freem(m);
51936400Ssklower 	IncStat(ts_recv_drop);
52037469Ssklower 	splx(s);
52136400Ssklower 	return 0;
52236400Ssklower }
52336400Ssklower 
52436400Ssklower 
52556533Sbostic #include <sys/protosw.h>
52656533Sbostic #include <netinet/ip_icmp.h>
52736400Ssklower 
52837469Ssklower extern void tp_quench();
52936400Ssklower /*
53036400Ssklower  * NAME:	tpin_quench()
53136400Ssklower  *
53236400Ssklower  * CALLED FROM: tpip_ctlinput()
53336400Ssklower  *
53436400Ssklower  * FUNCTION and ARGUMENTS:  find the tpcb pointer and pass it to tp_quench
53536400Ssklower  *
53636400Ssklower  * RETURNS:	Nada
53736400Ssklower  *
53836400Ssklower  * SIDE EFFECTS:
53936400Ssklower  *
54036400Ssklower  * NOTES:
54136400Ssklower  */
54236400Ssklower 
54336400Ssklower void
tpin_quench(inp)54436400Ssklower tpin_quench(inp)
54536400Ssklower 	struct inpcb *inp;
54636400Ssklower {
54750435Ssklower 	tp_quench((struct tp_pcb *)inp->inp_socket->so_pcb, PRC_QUENCH);
54836400Ssklower }
54936400Ssklower 
55036400Ssklower /*
55136400Ssklower  * NAME:	tpip_ctlinput()
55236400Ssklower  *
55336400Ssklower  * CALLED FROM:
55436400Ssklower  *  The network layer through the protosw table.
55536400Ssklower  *
55636400Ssklower  * FUNCTION and ARGUMENTS:
55736400Ssklower  *	When clnp gets an ICMP msg this gets called.
55836400Ssklower  *	It either returns an error status to the user or
55936400Ssklower  *	causes all connections on this address to be aborted
56036400Ssklower  *	by calling the appropriate xx_notify() routine.
56136400Ssklower  *	(cmd) is the type of ICMP error.
56236400Ssklower  * 	(sa) the address of the sender
56336400Ssklower  *
56436400Ssklower  * RETURNS:	 Nothing
56536400Ssklower  *
56636400Ssklower  * SIDE EFFECTS:
56736400Ssklower  *
56836400Ssklower  * NOTES:
56936400Ssklower  */
57036400Ssklower ProtoHook
tpip_ctlinput(cmd,sin)57136400Ssklower tpip_ctlinput(cmd, sin)
57236400Ssklower 	int cmd;
57336400Ssklower 	struct sockaddr_in *sin;
57436400Ssklower {
57536400Ssklower 	extern u_char inetctlerrmap[];
57645630Ssklower 	extern struct in_addr zeroin_addr;
57761657Ssklower 	void tp_quench __P((struct inpcb *,int));
57861657Ssklower 	void tpin_abort __P((struct inpcb *,int));
57936400Ssklower 
58036400Ssklower 	if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK)
58136400Ssklower 		return 0;
58236400Ssklower 	if (sin->sin_addr.s_addr == INADDR_ANY)
58336400Ssklower 		return 0;
58436400Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
58536400Ssklower 		return 0;
58636400Ssklower 	switch (cmd) {
58736400Ssklower 
58836400Ssklower 		case	PRC_QUENCH:
58961657Ssklower 			in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0,
59061657Ssklower 				zeroin_addr, 0, cmd, tp_quench);
59136400Ssklower 			break;
59236400Ssklower 
59336400Ssklower 		case	PRC_ROUTEDEAD:
59436400Ssklower 		case	PRC_HOSTUNREACH:
59536400Ssklower 		case	PRC_UNREACH_NET:
59636400Ssklower 		case	PRC_IFDOWN:
59736400Ssklower 		case	PRC_HOSTDEAD:
59861657Ssklower 			in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0,
59945630Ssklower 				zeroin_addr, 0, cmd, in_rtchange);
60036400Ssklower 			break;
60136400Ssklower 
60236400Ssklower 		default:
60336400Ssklower 		/*
60436400Ssklower 		case	PRC_MSGSIZE:
60536400Ssklower 		case	PRC_UNREACH_HOST:
60636400Ssklower 		case	PRC_UNREACH_PROTOCOL:
60736400Ssklower 		case	PRC_UNREACH_PORT:
60836400Ssklower 		case	PRC_UNREACH_NEEDFRAG:
60936400Ssklower 		case	PRC_UNREACH_SRCFAIL:
61036400Ssklower 		case	PRC_REDIRECT_NET:
61136400Ssklower 		case	PRC_REDIRECT_HOST:
61236400Ssklower 		case	PRC_REDIRECT_TOSNET:
61336400Ssklower 		case	PRC_REDIRECT_TOSHOST:
61436400Ssklower 		case	PRC_TIMXCEED_INTRANS:
61536400Ssklower 		case	PRC_TIMXCEED_REASS:
61636400Ssklower 		case	PRC_PARAMPROB:
61736400Ssklower 		*/
61861657Ssklower 		in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0,
61961657Ssklower 			zeroin_addr, 0, cmd, tpin_abort);
62036400Ssklower 	}
62136400Ssklower 	return 0;
62236400Ssklower }
62336400Ssklower 
62436400Ssklower /*
62536400Ssklower  * NAME:	tpin_abort()
62636400Ssklower  *
62736400Ssklower  * CALLED FROM:
62836400Ssklower  *	xxx_notify() from tp_ctlinput() when
62936400Ssklower  *  net level gets some ICMP-equiv. type event.
63036400Ssklower  *
63136400Ssklower  * FUNCTION and ARGUMENTS:
63236400Ssklower  *  Cause the connection to be aborted with some sort of error
63336400Ssklower  *  reason indicating that the network layer caused the abort.
63436400Ssklower  *  Fakes an ER TPDU so we can go through the driver.
63536400Ssklower  *
63636400Ssklower  * RETURNS:	 Nothing
63736400Ssklower  *
63836400Ssklower  * SIDE EFFECTS:
63936400Ssklower  *
64036400Ssklower  * NOTES:
64136400Ssklower  */
64236400Ssklower 
64336400Ssklower ProtoHook
tpin_abort(inp)64436400Ssklower tpin_abort(inp)
64536400Ssklower 	struct inpcb *inp;
64636400Ssklower {
64736400Ssklower 	struct tp_event e;
64836400Ssklower 
64936400Ssklower 	e.ev_number = ER_TPDU;
65036400Ssklower 	e.ATTR(ER_TPDU).e_reason = ENETRESET;
65137469Ssklower 	(void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
65236400Ssklower 	return 0;
65336400Ssklower }
65436400Ssklower 
65536400Ssklower #ifdef ARGO_DEBUG
dump_inaddr(addr)65636400Ssklower dump_inaddr(addr)
65736400Ssklower 	register struct sockaddr_in *addr;
65836400Ssklower {
65936400Ssklower 	printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr);
66036400Ssklower }
66160359Sbostic #endif /* ARGO_DEBUG */
66260359Sbostic #endif /* INET */
663