xref: /csrg-svn/sys/netiso/tp_inet.c (revision 36400)
1*36400Ssklower /***********************************************************
2*36400Ssklower 		Copyright IBM Corporation 1987
3*36400Ssklower 
4*36400Ssklower                       All Rights Reserved
5*36400Ssklower 
6*36400Ssklower Permission to use, copy, modify, and distribute this software and its
7*36400Ssklower documentation for any purpose and without fee is hereby granted,
8*36400Ssklower provided that the above copyright notice appear in all copies and that
9*36400Ssklower both that copyright notice and this permission notice appear in
10*36400Ssklower supporting documentation, and that the name of IBM not be
11*36400Ssklower used in advertising or publicity pertaining to distribution of the
12*36400Ssklower software without specific, written prior permission.
13*36400Ssklower 
14*36400Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36400Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36400Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36400Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36400Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36400Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36400Ssklower SOFTWARE.
21*36400Ssklower 
22*36400Ssklower ******************************************************************/
23*36400Ssklower 
24*36400Ssklower /*
25*36400Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36400Ssklower  */
27*36400Ssklower /*
28*36400Ssklower  * ARGO TP
29*36400Ssklower  * $Header: tp_inet.c,v 5.3 88/11/18 17:27:29 nhall Exp $
30*36400Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_inet.c,v $
31*36400Ssklower  *
32*36400Ssklower  * Here is where you find the inet-dependent code.  We've tried
33*36400Ssklower  * keep all net-level and (primarily) address-family-dependent stuff
34*36400Ssklower  * out of the tp source, and everthing here is reached indirectly
35*36400Ssklower  * through a switch table (struct nl_protosw *) tpcb->tp_nlproto
36*36400Ssklower  * (see tp_pcb.c).
37*36400Ssklower  * The routines here are:
38*36400Ssklower  * 		in_getsufx: gets transport suffix out of an inpcb structure.
39*36400Ssklower  * 		in_putsufx: put transport suffix into an inpcb structure.
40*36400Ssklower  *		in_putnetaddr: put a whole net addr into an inpcb.
41*36400Ssklower  *		in_getnetaddr: get a whole net addr from an inpcb.
42*36400Ssklower  *		in_recycle_suffix: clear suffix for reuse in inpcb
43*36400Ssklower  *		tpip_mtu: figure out what size tpdu to use
44*36400Ssklower  *		tpip_input: take a pkt from ip, strip off its ip header, give to tp
45*36400Ssklower  *		tpip_output_dg: package a pkt for ip given 2 addresses & some data
46*36400Ssklower  *		tpip_output: package a pkt for ip given an inpcb & some data
47*36400Ssklower  */
48*36400Ssklower 
49*36400Ssklower #ifndef lint
50*36400Ssklower static char *rcsid = "$Header: tp_inet.c,v 5.3 88/11/18 17:27:29 nhall Exp $";
51*36400Ssklower #endif lint
52*36400Ssklower 
53*36400Ssklower #ifdef INET
54*36400Ssklower 
55*36400Ssklower #include "types.h"
56*36400Ssklower #include "socket.h"
57*36400Ssklower #include "socketvar.h"
58*36400Ssklower #include "mbuf.h"
59*36400Ssklower #include "errno.h"
60*36400Ssklower #include "time.h"
61*36400Ssklower #include "../net/if.h"
62*36400Ssklower #include "../netiso/tp_param.h"
63*36400Ssklower #include "../netiso/argo_debug.h"
64*36400Ssklower #include "../netiso/tp_stat.h"
65*36400Ssklower #include "../netiso/tp_ip.h"
66*36400Ssklower #include "../netiso/tp_pcb.h"
67*36400Ssklower #include "../netiso/tp_trace.h"
68*36400Ssklower #include "../netiso/tp_stat.h"
69*36400Ssklower #include "../netiso/tp_tpdu.h"
70*36400Ssklower #include "../netinet/in_var.h"
71*36400Ssklower 
72*36400Ssklower 
73*36400Ssklower /*
74*36400Ssklower  * NAME:			in_getsufx()
75*36400Ssklower 
76*36400Ssklower  * CALLED FROM: 	pr_usrreq() on PRU_BIND,
77*36400Ssklower  *					PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
78*36400Ssklower  *
79*36400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
80*36400Ssklower  * 	Get a transport suffix from an inpcb structure (inp).
81*36400Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
82*36400Ssklower  *
83*36400Ssklower  * RETURNS:		internet port / transport suffix
84*36400Ssklower  *  			(CAST TO AN INT)
85*36400Ssklower  *
86*36400Ssklower  * SIDE EFFECTS:
87*36400Ssklower  *
88*36400Ssklower  * NOTES:
89*36400Ssklower  */
90*36400Ssklower 
91*36400Ssklower int
92*36400Ssklower in_getsufx(inp,  which)
93*36400Ssklower 	struct inpcb *inp;
94*36400Ssklower 	int which;
95*36400Ssklower {
96*36400Ssklower 	switch (which) {
97*36400Ssklower 	case TP_LOCAL:
98*36400Ssklower 		return (int) inp->inp_lport;
99*36400Ssklower 
100*36400Ssklower 	case TP_FOREIGN:
101*36400Ssklower 		return (int) inp->inp_fport;
102*36400Ssklower 	}
103*36400Ssklower }
104*36400Ssklower 
105*36400Ssklower /*
106*36400Ssklower  * NAME:		in_putsufx()
107*36400Ssklower  *
108*36400Ssklower  * CALLED FROM: tp_newsocket(); i.e., when a connection
109*36400Ssklower  *		is being established by an incoming CR_TPDU.
110*36400Ssklower  *
111*36400Ssklower  * FUNCTION, ARGUMENTS:
112*36400Ssklower  * 	Put a transport suffix (found in name) into an inpcb structure (inp).
113*36400Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
114*36400Ssklower  *
115*36400Ssklower  * RETURNS:		Nada
116*36400Ssklower  *
117*36400Ssklower  * SIDE EFFECTS:
118*36400Ssklower  *
119*36400Ssklower  * NOTES:
120*36400Ssklower  */
121*36400Ssklower void
122*36400Ssklower in_putsufx(inp, name, which)
123*36400Ssklower 	struct inpcb *inp;
124*36400Ssklower 	struct sockaddr_in *name;
125*36400Ssklower 	int which;
126*36400Ssklower {
127*36400Ssklower 	switch (which) {
128*36400Ssklower 	case TP_LOCAL:
129*36400Ssklower 		inp->inp_lport = name->sin_port;
130*36400Ssklower 		break;
131*36400Ssklower 	case TP_FOREIGN:
132*36400Ssklower 		inp->inp_fport = name->sin_port;
133*36400Ssklower 		break;
134*36400Ssklower 	}
135*36400Ssklower }
136*36400Ssklower 
137*36400Ssklower /*
138*36400Ssklower  * NAME:	in_recycle_tsuffix()
139*36400Ssklower  *
140*36400Ssklower  * CALLED FROM:	tp.trans whenever we go into REFWAIT state.
141*36400Ssklower  *
142*36400Ssklower  * FUNCTION and ARGUMENT:
143*36400Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
144*36400Ssklower  * 	(inp) is the net level pcb.
145*36400Ssklower  *
146*36400Ssklower  * RETURNS:			Nada
147*36400Ssklower  *
148*36400Ssklower  * SIDE EFFECTS:
149*36400Ssklower  *
150*36400Ssklower  * NOTES:	This really shouldn't have to be done in a NET level pcb
151*36400Ssklower  *	but... for the internet world that just the way it is done in BSD...
152*36400Ssklower  * 	The alternative is to have the port unusable until the reference
153*36400Ssklower  * 	timer goes off.
154*36400Ssklower  */
155*36400Ssklower void
156*36400Ssklower in_recycle_tsuffix(inp)
157*36400Ssklower 	struct inpcb	*inp;
158*36400Ssklower {
159*36400Ssklower 	inp->inp_fport = inp->inp_lport = 0;
160*36400Ssklower }
161*36400Ssklower 
162*36400Ssklower /*
163*36400Ssklower  * NAME:	in_putnetaddr()
164*36400Ssklower  *
165*36400Ssklower  * CALLED FROM:
166*36400Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
167*36400Ssklower  * 	incoming CR_TPDU.
168*36400Ssklower  *
169*36400Ssklower  * FUNCTION and ARGUMENTS:
170*36400Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
171*36400Ssklower  * 	into an inpcb (inp).
172*36400Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
173*36400Ssklower  *
174*36400Ssklower  * RETURNS:		Nada
175*36400Ssklower  *
176*36400Ssklower  * SIDE EFFECTS:
177*36400Ssklower  *
178*36400Ssklower  * NOTES:
179*36400Ssklower  */
180*36400Ssklower void
181*36400Ssklower in_putnetaddr(inp, name, which)
182*36400Ssklower 	register struct inpcb	*inp;
183*36400Ssklower 	struct sockaddr_in	*name;
184*36400Ssklower 	int which;
185*36400Ssklower {
186*36400Ssklower 	switch (which) {
187*36400Ssklower 	case TP_LOCAL:
188*36400Ssklower 		bcopy((caddr_t)&name->sin_addr,
189*36400Ssklower 			(caddr_t)&inp->inp_laddr, sizeof(struct in_addr));
190*36400Ssklower 			/* won't work if the dst address (name) is INADDR_ANY */
191*36400Ssklower 
192*36400Ssklower 		break;
193*36400Ssklower 	case TP_FOREIGN:
194*36400Ssklower 		if( name != (struct sockaddr_in *)0 ) {
195*36400Ssklower 			bcopy((caddr_t)&name->sin_addr,
196*36400Ssklower 				(caddr_t)&inp->inp_faddr, sizeof(struct in_addr));
197*36400Ssklower 		}
198*36400Ssklower 	}
199*36400Ssklower }
200*36400Ssklower 
201*36400Ssklower /*
202*36400Ssklower  * NAME:	in_getnetaddr()
203*36400Ssklower  *
204*36400Ssklower  * CALLED FROM:
205*36400Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
206*36400Ssklower  * FUNCTION and ARGUMENTS:
207*36400Ssklower  * 	Copy a whole net addr from an inpcb (inp) into
208*36400Ssklower  * 	a struct sockaddr (name).
209*36400Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
210*36400Ssklower  *
211*36400Ssklower  * RETURNS:		Nada
212*36400Ssklower  *
213*36400Ssklower  * SIDE EFFECTS:
214*36400Ssklower  *
215*36400Ssklower  * NOTES:
216*36400Ssklower  */
217*36400Ssklower 
218*36400Ssklower void
219*36400Ssklower in_getnetaddr( inp, name, which)
220*36400Ssklower 	struct inpcb *inp;
221*36400Ssklower 	struct sockaddr_in *name;
222*36400Ssklower 	int which;
223*36400Ssklower {
224*36400Ssklower 	switch (which) {
225*36400Ssklower 	case TP_LOCAL:
226*36400Ssklower 		bcopy( (caddr_t)&inp->inp_laddr, (caddr_t)&name->sin_addr,
227*36400Ssklower 				sizeof(struct in_addr));
228*36400Ssklower 			/* won't work if the dst address (name) is INADDR_ANY */
229*36400Ssklower 		break;
230*36400Ssklower 
231*36400Ssklower 	case TP_FOREIGN:
232*36400Ssklower 		bcopy( (caddr_t)&inp->inp_faddr, (caddr_t)&name->sin_addr,
233*36400Ssklower 				sizeof(struct in_addr));
234*36400Ssklower 			/* won't work if the dst address (name) is INADDR_ANY */
235*36400Ssklower 		break;
236*36400Ssklower 	}
237*36400Ssklower }
238*36400Ssklower 
239*36400Ssklower /*
240*36400Ssklower  * NAME: 	tpip_mtu()
241*36400Ssklower  *
242*36400Ssklower  * CALLED FROM:
243*36400Ssklower  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
244*36400Ssklower  *
245*36400Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
246*36400Ssklower  *
247*36400Ssklower  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
248*36400Ssklower  * a) the header size for the network protocol and the max transmission
249*36400Ssklower  *	  unit on the subnet interface, determined from the information in (inp),
250*36400Ssklower  * b) the max size negotiated so far (negot)
251*36400Ssklower  * c) the window size used by the tp connection (found in so),
252*36400Ssklower  *
253*36400Ssklower  * The result is put in the integer *size in its integer form and in
254*36400Ssklower  * *negot in its logarithmic form.
255*36400Ssklower  *
256*36400Ssklower  * The rules are:
257*36400Ssklower  * a) can only negotiate down from the value found in *negot.
258*36400Ssklower  * b) the MTU must be < the windowsize,
259*36400Ssklower  * c) If src and dest are on the same net,
260*36400Ssklower  * 	  we will negotiate the closest size larger than  MTU but really USE
261*36400Ssklower  *    the actual device mtu - ll hdr sizes.
262*36400Ssklower  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
263*36400Ssklower  *
264*36400Ssklower  * SIDE EFFECTS:
265*36400Ssklower  *	changes the values addressed by the arguments (size) and (negot)
266*36400Ssklower  *  and
267*36400Ssklower  *  when the peer is not on one of our directly connected subnets, it
268*36400Ssklower  *  looks up a route, leaving the route in the inpcb addressed by (inp)
269*36400Ssklower  *
270*36400Ssklower  * NOTES:
271*36400Ssklower  */
272*36400Ssklower 
273*36400Ssklower void
274*36400Ssklower tpip_mtu(so, inp, size, negot)
275*36400Ssklower 	struct socket *so;
276*36400Ssklower 	struct inpcb *inp;
277*36400Ssklower 	int *size;
278*36400Ssklower 	u_char *negot;
279*36400Ssklower {
280*36400Ssklower 	register struct ifnet	*ifp;
281*36400Ssklower 	struct ifnet			*tpip_route();
282*36400Ssklower 	struct in_ifaddr		*ia;
283*36400Ssklower 	register int			i;
284*36400Ssklower 	int						windowsize = so->so_rcv.sb_hiwat;
285*36400Ssklower 
286*36400Ssklower 	IFDEBUG(D_CONN)
287*36400Ssklower 		printf("tpip_mtu(0x%x,0x%x,0x%x,0x%x)\n",
288*36400Ssklower 			so, inp, size, negot);
289*36400Ssklower 		printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr);
290*36400Ssklower 	ENDDEBUG
291*36400Ssklower 	IFTRACE(D_CONN)
292*36400Ssklower 		tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
293*36400Ssklower 	ENDTRACE
294*36400Ssklower 
295*36400Ssklower 	*size = 1 << *negot;
296*36400Ssklower 
297*36400Ssklower 	if( *size > windowsize ) {
298*36400Ssklower 		*size = windowsize;
299*36400Ssklower 	}
300*36400Ssklower 
301*36400Ssklower 	ia = in_iaonnetof(in_netof(inp->inp_faddr));
302*36400Ssklower 	if ( ia == (struct in_ifaddr *)0 ) {
303*36400Ssklower 		ifp = tpip_route(&inp->inp_faddr);
304*36400Ssklower 		if( ifp == (struct ifnet *)0 )
305*36400Ssklower 			return ;
306*36400Ssklower 	} else
307*36400Ssklower 		ifp = ia->ia_ifp;
308*36400Ssklower 
309*36400Ssklower 
310*36400Ssklower 	/****************************************************************
311*36400Ssklower 	 * TODO - make this indirect off the socket structure to the
312*36400Ssklower 	 * network layer to get headersize
313*36400Ssklower 	 * After all, who knows what lies below the IP layer?
314*36400Ssklower 	 * Who knows how big the NL header will be?
315*36400Ssklower 	 ***************************************************************/
316*36400Ssklower 
317*36400Ssklower 	if( *size > ifp->if_mtu - sizeof(struct ip)) {
318*36400Ssklower 		*size = ifp->if_mtu - sizeof(struct ip);
319*36400Ssklower 	}
320*36400Ssklower 	for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i)<*size)) ; i++)
321*36400Ssklower 		;
322*36400Ssklower 	i--;
323*36400Ssklower 
324*36400Ssklower 	if (in_netof(inp->inp_laddr) != in_netof(inp->inp_faddr)) {
325*36400Ssklower 		i++;
326*36400Ssklower 	} else {
327*36400Ssklower 		*size = 1<<i;
328*36400Ssklower 	}
329*36400Ssklower 	*negot = i;
330*36400Ssklower 
331*36400Ssklower 	IFDEBUG(D_CONN)
332*36400Ssklower 		printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
333*36400Ssklower 		ifp->if_name,	*size, *negot);
334*36400Ssklower 	ENDDEBUG
335*36400Ssklower 	IFTRACE(D_CONN)
336*36400Ssklower 		tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
337*36400Ssklower 		*size, *negot, 0, 0);
338*36400Ssklower 	ENDTRACE
339*36400Ssklower 
340*36400Ssklower }
341*36400Ssklower 
342*36400Ssklower /*
343*36400Ssklower  * NAME:	tpip_output()
344*36400Ssklower  *
345*36400Ssklower  * CALLED FROM:  tp_emit()
346*36400Ssklower  *
347*36400Ssklower  * FUNCTION and ARGUMENTS:
348*36400Ssklower  *  Take a packet(m0) from tp and package it so that ip will accept it.
349*36400Ssklower  *  This means prepending space for the ip header and filling in a few
350*36400Ssklower  *  of the fields.
351*36400Ssklower  *  inp is the inpcb structure; datalen is the length of the data in the
352*36400Ssklower  *  mbuf string m0.
353*36400Ssklower  * RETURNS:
354*36400Ssklower  *  whatever (E*) is returned form the net layer output routine.
355*36400Ssklower  *
356*36400Ssklower  * SIDE EFFECTS:
357*36400Ssklower  *
358*36400Ssklower  * NOTES:
359*36400Ssklower  */
360*36400Ssklower 
361*36400Ssklower int
362*36400Ssklower tpip_output(inp, m0, datalen, nochksum)
363*36400Ssklower 	struct inpcb		*inp;
364*36400Ssklower 	struct mbuf 		*m0;
365*36400Ssklower 	int 				datalen;
366*36400Ssklower 	int					nochksum;
367*36400Ssklower {
368*36400Ssklower 	return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen,
369*36400Ssklower 		&inp->inp_route, nochksum);
370*36400Ssklower }
371*36400Ssklower 
372*36400Ssklower /*
373*36400Ssklower  * NAME:	tpip_output_dg()
374*36400Ssklower  *
375*36400Ssklower  * CALLED FROM:  tp_error_emit()
376*36400Ssklower  *
377*36400Ssklower  * FUNCTION and ARGUMENTS:
378*36400Ssklower  *  This is a copy of tpip_output that takes the addresses
379*36400Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
380*36400Ssklower  *  don't have an in_pcb with which to call the normal output rtn.
381*36400Ssklower  *
382*36400Ssklower  * RETURNS:	 ENOBUFS or  whatever (E*) is
383*36400Ssklower  *	returned form the net layer output routine.
384*36400Ssklower  *
385*36400Ssklower  * SIDE EFFECTS:
386*36400Ssklower  *
387*36400Ssklower  * NOTES:
388*36400Ssklower  */
389*36400Ssklower 
390*36400Ssklower int
391*36400Ssklower tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
392*36400Ssklower 	struct in_addr		*laddr, *faddr;
393*36400Ssklower 	struct mbuf 		*m0;
394*36400Ssklower 	int 				datalen;
395*36400Ssklower 	struct route 		*ro;
396*36400Ssklower 	int					nochksum;
397*36400Ssklower {
398*36400Ssklower 	register struct mbuf 	*m;
399*36400Ssklower 	register struct ip *ip;
400*36400Ssklower 	int 					error;
401*36400Ssklower 
402*36400Ssklower 	IFDEBUG(D_EMIT)
403*36400Ssklower 		printf("tpip_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
404*36400Ssklower 	ENDDEBUG
405*36400Ssklower 
406*36400Ssklower 
407*36400Ssklower 	MGET(m, M_DONTWAIT, TPMT_IPHDR);
408*36400Ssklower 	if (m == 0) {
409*36400Ssklower 		error = ENOBUFS;
410*36400Ssklower 		goto bad;
411*36400Ssklower 	}
412*36400Ssklower 	bzero(mtod(m, caddr_t), MLEN);
413*36400Ssklower 	m->m_next = m0;
414*36400Ssklower 	m->m_off = MMAXOFF - sizeof(struct ip);
415*36400Ssklower 	m->m_len = sizeof(struct ip);
416*36400Ssklower 	m->m_act = MNULL;
417*36400Ssklower 
418*36400Ssklower 	ip = mtod(m, struct ip *);
419*36400Ssklower 
420*36400Ssklower 	ip->ip_p = IPPROTO_TP;
421*36400Ssklower 	ip->ip_len = sizeof(struct ip) + datalen;
422*36400Ssklower 	ip->ip_ttl = MAXTTL;
423*36400Ssklower 		/* don't know why you need to set ttl;
424*36400Ssklower 		 * overlay doesn't even make this available
425*36400Ssklower 		 */
426*36400Ssklower 
427*36400Ssklower 	ip->ip_src = *laddr;
428*36400Ssklower 	ip->ip_dst = *faddr;
429*36400Ssklower 
430*36400Ssklower 	IncStat(ts_tpdu_sent);
431*36400Ssklower 	IFDEBUG(D_EMIT)
432*36400Ssklower 		dump_mbuf(m, "tpip_output_dg before ip_output\n");
433*36400Ssklower 	ENDDEBUG
434*36400Ssklower 
435*36400Ssklower 	error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST);
436*36400Ssklower 
437*36400Ssklower 	IFDEBUG(D_EMIT)
438*36400Ssklower 		printf("tpip_output_dg after ip_output\n");
439*36400Ssklower 	ENDDEBUG
440*36400Ssklower 
441*36400Ssklower 	return error;
442*36400Ssklower 
443*36400Ssklower bad:
444*36400Ssklower 	m_freem(m);
445*36400Ssklower 	IncStat(ts_send_drop);
446*36400Ssklower 	return error;
447*36400Ssklower }
448*36400Ssklower 
449*36400Ssklower /*
450*36400Ssklower  * NAME:  tpip_input()
451*36400Ssklower  *
452*36400Ssklower  * CALLED FROM:
453*36400Ssklower  * 	ip's input routine, indirectly through the protosw.
454*36400Ssklower  *
455*36400Ssklower  * FUNCTION and ARGUMENTS:
456*36400Ssklower  * Take a packet (m) from ip, strip off the ip header and give it to tp
457*36400Ssklower  *
458*36400Ssklower  * RETURNS:  No return value.
459*36400Ssklower  *
460*36400Ssklower  * SIDE EFFECTS:
461*36400Ssklower  *
462*36400Ssklower  * NOTES:
463*36400Ssklower  */
464*36400Ssklower ProtoHook
465*36400Ssklower tpip_input(m)
466*36400Ssklower 	struct mbuf *m;
467*36400Ssklower {
468*36400Ssklower 	typedef struct {
469*36400Ssklower 		struct ip	 tpip_i;
470*36400Ssklower 		struct tpdu  tpip_d;
471*36400Ssklower 	} tpiphdr;
472*36400Ssklower 	register struct tpdu 	*hdr = mtod(m, struct tpdu *);
473*36400Ssklower 	struct sockaddr_in 	src, dst;
474*36400Ssklower 	register struct ip 		*ip;
475*36400Ssklower 	int						s = splnet();
476*36400Ssklower 
477*36400Ssklower 	IncStat(ts_pkt_rcvd);
478*36400Ssklower 
479*36400Ssklower 	/* IP layer has already pulled up the IP header */
480*36400Ssklower 
481*36400Ssklower 	while( m->m_len < 1 ) {
482*36400Ssklower 		struct mbuf *n;
483*36400Ssklower 		n = m_free(m);
484*36400Ssklower 		if( n == MNULL ) {
485*36400Ssklower 			splx(s);
486*36400Ssklower 			return 0;
487*36400Ssklower 		}
488*36400Ssklower 	}
489*36400Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
490*36400Ssklower 
491*36400Ssklower 	/*
492*36400Ssklower 	 * now pull up the whole tp header : we stripped all leading mbufs
493*36400Ssklower 	 * w/o at least one byte, so we know we can read the tpdu_li field.
494*36400Ssklower 	 */
495*36400Ssklower 	hdr = &(mtod(m, tpiphdr *))->tpip_d;
496*36400Ssklower 
497*36400Ssklower 	if( m->m_len < hdr->tpdu_li + 1 + sizeof(struct ip) ) {
498*36400Ssklower 		if((m = m_pullup(m, sizeof(struct ip) + (int)(hdr->tpdu_li)+1))==MNULL){
499*36400Ssklower 			IFDEBUG(D_TPINPUT)
500*36400Ssklower 				printf("tp_input, pullup 2!\n");
501*36400Ssklower 			ENDDEBUG
502*36400Ssklower 			goto discard;
503*36400Ssklower 		}
504*36400Ssklower 	}
505*36400Ssklower 	/*
506*36400Ssklower 	 * cannot use tp_inputprep() here 'cause you don't
507*36400Ssklower 	 * have quite the same situation
508*36400Ssklower 	 */
509*36400Ssklower 
510*36400Ssklower 	IFDEBUG(D_TPINPUT)
511*36400Ssklower 		dump_mbuf(m, "after tpip_input both pullups");
512*36400Ssklower 	ENDDEBUG
513*36400Ssklower 	/*
514*36400Ssklower 	 * m_pullup may have returned a different mbuf
515*36400Ssklower 	 */
516*36400Ssklower 	ip = &(mtod(m, tpiphdr *))->tpip_i;
517*36400Ssklower 
518*36400Ssklower 	/*
519*36400Ssklower 	 * drop the ip header from the front of the mbuf
520*36400Ssklower 	 * this is necessary for the tp checksum
521*36400Ssklower 	 */
522*36400Ssklower 	m->m_len -= sizeof(struct ip);
523*36400Ssklower 	m->m_off += sizeof(struct ip);
524*36400Ssklower 
525*36400Ssklower 	src.sin_addr = *(struct in_addr *)&(ip->ip_src);
526*36400Ssklower 	src.sin_family  = AF_INET;
527*36400Ssklower 	dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
528*36400Ssklower 	dst.sin_family  = AF_INET;
529*36400Ssklower 
530*36400Ssklower 	(void) tp_input(m, &src, &dst, 0, tpip_output_dg);
531*36400Ssklower 	splx(s);
532*36400Ssklower 	return 0;
533*36400Ssklower 
534*36400Ssklower discard:
535*36400Ssklower 	IFDEBUG(D_TPINPUT)
536*36400Ssklower 		printf("tpip_input DISCARD\n");
537*36400Ssklower 	ENDDEBUG
538*36400Ssklower 	IFTRACE(D_TPINPUT)
539*36400Ssklower 		tptrace(TPPTmisc, "tpip_input DISCARD m",  m,0,0,0);
540*36400Ssklower 	ENDTRACE
541*36400Ssklower 	m_freem(m);
542*36400Ssklower 	IncStat(ts_recv_drop);
543*36400Ssklower 
544*36400Ssklower 	return 0;
545*36400Ssklower }
546*36400Ssklower 
547*36400Ssklower 
548*36400Ssklower #include "../h/protosw.h"
549*36400Ssklower #include "../netinet/ip_icmp.h"
550*36400Ssklower 
551*36400Ssklower /*
552*36400Ssklower  * NAME:	tpin_quench()
553*36400Ssklower  *
554*36400Ssklower  * CALLED FROM: tpip_ctlinput()
555*36400Ssklower  *
556*36400Ssklower  * FUNCTION and ARGUMENTS:  find the tpcb pointer and pass it to tp_quench
557*36400Ssklower  *
558*36400Ssklower  * RETURNS:	Nada
559*36400Ssklower  *
560*36400Ssklower  * SIDE EFFECTS:
561*36400Ssklower  *
562*36400Ssklower  * NOTES:
563*36400Ssklower  */
564*36400Ssklower 
565*36400Ssklower void
566*36400Ssklower tpin_quench(inp)
567*36400Ssklower 	struct inpcb *inp;
568*36400Ssklower {
569*36400Ssklower 	tp_quench( inp->inp_socket->so_tpcb );
570*36400Ssklower }
571*36400Ssklower 
572*36400Ssklower /*
573*36400Ssklower  * NAME:	tpip_ctlinput()
574*36400Ssklower  *
575*36400Ssklower  * CALLED FROM:
576*36400Ssklower  *  The network layer through the protosw table.
577*36400Ssklower  *
578*36400Ssklower  * FUNCTION and ARGUMENTS:
579*36400Ssklower  *	When clnp gets an ICMP msg this gets called.
580*36400Ssklower  *	It either returns an error status to the user or
581*36400Ssklower  *	causes all connections on this address to be aborted
582*36400Ssklower  *	by calling the appropriate xx_notify() routine.
583*36400Ssklower  *	(cmd) is the type of ICMP error.
584*36400Ssklower  * 	(sa) the address of the sender
585*36400Ssklower  *
586*36400Ssklower  * RETURNS:	 Nothing
587*36400Ssklower  *
588*36400Ssklower  * SIDE EFFECTS:
589*36400Ssklower  *
590*36400Ssklower  * NOTES:
591*36400Ssklower  */
592*36400Ssklower ProtoHook
593*36400Ssklower tpip_ctlinput(cmd, sin)
594*36400Ssklower 	int cmd;
595*36400Ssklower 	struct sockaddr_in *sin;
596*36400Ssklower {
597*36400Ssklower 	extern u_char inetctlerrmap[];
598*36400Ssklower 	extern ProtoHook tpin_abort();
599*36400Ssklower 	extern ProtoHook in_rtchange();
600*36400Ssklower 
601*36400Ssklower 	if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK)
602*36400Ssklower 		return 0;
603*36400Ssklower 	if (sin->sin_addr.s_addr == INADDR_ANY)
604*36400Ssklower 		return 0;
605*36400Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
606*36400Ssklower 		return 0;
607*36400Ssklower 	switch (cmd) {
608*36400Ssklower 
609*36400Ssklower 		case	PRC_QUENCH:
610*36400Ssklower 			in_pcbnotify(&tp_inpcb, &sin->sin_addr, 0, tp_quench);
611*36400Ssklower 			break;
612*36400Ssklower 
613*36400Ssklower 		case	PRC_ROUTEDEAD:
614*36400Ssklower 		case	PRC_HOSTUNREACH:
615*36400Ssklower 		case	PRC_UNREACH_NET:
616*36400Ssklower 		case	PRC_IFDOWN:
617*36400Ssklower 		case	PRC_HOSTDEAD:
618*36400Ssklower 			in_pcbnotify(&tp_inpcb, &sin->sin_addr,
619*36400Ssklower 					(int)inetctlerrmap[cmd], in_rtchange);
620*36400Ssklower 			break;
621*36400Ssklower 
622*36400Ssklower 		default:
623*36400Ssklower 		/*
624*36400Ssklower 		case	PRC_MSGSIZE:
625*36400Ssklower 		case	PRC_UNREACH_HOST:
626*36400Ssklower 		case	PRC_UNREACH_PROTOCOL:
627*36400Ssklower 		case	PRC_UNREACH_PORT:
628*36400Ssklower 		case	PRC_UNREACH_NEEDFRAG:
629*36400Ssklower 		case	PRC_UNREACH_SRCFAIL:
630*36400Ssklower 		case	PRC_REDIRECT_NET:
631*36400Ssklower 		case	PRC_REDIRECT_HOST:
632*36400Ssklower 		case	PRC_REDIRECT_TOSNET:
633*36400Ssklower 		case	PRC_REDIRECT_TOSHOST:
634*36400Ssklower 		case	PRC_TIMXCEED_INTRANS:
635*36400Ssklower 		case	PRC_TIMXCEED_REASS:
636*36400Ssklower 		case	PRC_PARAMPROB:
637*36400Ssklower 		*/
638*36400Ssklower 		in_pcbnotify(&tp_inpcb, sin, (int)inetctlerrmap[cmd], tpin_abort);
639*36400Ssklower 	}
640*36400Ssklower 	return 0;
641*36400Ssklower }
642*36400Ssklower 
643*36400Ssklower /*
644*36400Ssklower  * NAME:	tpin_abort()
645*36400Ssklower  *
646*36400Ssklower  * CALLED FROM:
647*36400Ssklower  *	xxx_notify() from tp_ctlinput() when
648*36400Ssklower  *  net level gets some ICMP-equiv. type event.
649*36400Ssklower  *
650*36400Ssklower  * FUNCTION and ARGUMENTS:
651*36400Ssklower  *  Cause the connection to be aborted with some sort of error
652*36400Ssklower  *  reason indicating that the network layer caused the abort.
653*36400Ssklower  *  Fakes an ER TPDU so we can go through the driver.
654*36400Ssklower  *
655*36400Ssklower  * RETURNS:	 Nothing
656*36400Ssklower  *
657*36400Ssklower  * SIDE EFFECTS:
658*36400Ssklower  *
659*36400Ssklower  * NOTES:
660*36400Ssklower  */
661*36400Ssklower 
662*36400Ssklower ProtoHook
663*36400Ssklower tpin_abort(inp)
664*36400Ssklower 	struct inpcb *inp;
665*36400Ssklower {
666*36400Ssklower 	struct tp_event e;
667*36400Ssklower 
668*36400Ssklower 	e.ev_number = ER_TPDU;
669*36400Ssklower 	e.ATTR(ER_TPDU).e_reason = ENETRESET;
670*36400Ssklower 	(void) tp_driver(inp->inp_ppcb, &e);
671*36400Ssklower 	return 0;
672*36400Ssklower }
673*36400Ssklower 
674*36400Ssklower #ifdef ARGO_DEBUG
675*36400Ssklower dump_inaddr(addr)
676*36400Ssklower 	register struct sockaddr_in *addr;
677*36400Ssklower {
678*36400Ssklower 	printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr);
679*36400Ssklower }
680*36400Ssklower #endif ARGO_DEBUG
681*36400Ssklower 
682*36400Ssklower /*
683*36400Ssklower  * NAME:	tpip_route()
684*36400Ssklower  *
685*36400Ssklower  * CALLED FROM: tpip_mtu()
686*36400Ssklower  *
687*36400Ssklower  * FUNCTION and ARGUMENTS:	given a destination addresss,
688*36400Ssklower  *	find the interface that would be used to send something to this address.
689*36400Ssklower  *
690*36400Ssklower  * RETURNS:	 pointer to an ifnet structure
691*36400Ssklower  *
692*36400Ssklower  * SIDE EFFECTS:
693*36400Ssklower  *
694*36400Ssklower  * NOTES:
695*36400Ssklower  */
696*36400Ssklower struct ifnet *
697*36400Ssklower tpip_route(dst)
698*36400Ssklower 	struct in_addr *dst;
699*36400Ssklower {
700*36400Ssklower 	struct	ifnet 		*ifp = (struct ifnet *)0;
701*36400Ssklower 	struct	sockaddr_in	*dst_in;
702*36400Ssklower 	struct route		iproute;
703*36400Ssklower 	struct route		*ro = (struct route *)0;
704*36400Ssklower 	struct in_ifaddr	*ia;
705*36400Ssklower 
706*36400Ssklower 	IFDEBUG(D_CONN)
707*36400Ssklower 		printf("tpip_route: dst is x%x\n", *dst);
708*36400Ssklower 	ENDDEBUG
709*36400Ssklower 
710*36400Ssklower 	ro = &iproute;
711*36400Ssklower 	bzero((caddr_t)ro, sizeof (*ro));
712*36400Ssklower 	dst_in = (struct sockaddr_in *)&ro->ro_dst;
713*36400Ssklower 	dst_in->sin_family = AF_INET;
714*36400Ssklower 	dst_in->sin_addr = *dst;
715*36400Ssklower 
716*36400Ssklower 	ia = (struct in_ifaddr *)ifa_ifwithdstaddr(dst_in);
717*36400Ssklower 	if (ia == 0)
718*36400Ssklower 		ia = in_iaonnetof(in_netof(dst_in));
719*36400Ssklower 	if (ia != 0) {
720*36400Ssklower 		ifp = ia->ia_ifp;
721*36400Ssklower 		IFDEBUG(D_CONN)
722*36400Ssklower 			printf("tpip_route: ifp from ia:0x%x\n", ia);
723*36400Ssklower 		ENDDEBUG
724*36400Ssklower 	} else {
725*36400Ssklower 		rtalloc(ro);
726*36400Ssklower 		if (ro->ro_rt != 0) {
727*36400Ssklower 			ifp = ro->ro_rt->rt_ifp;
728*36400Ssklower 			IFDEBUG(D_CONN)
729*36400Ssklower 				printf("tpip_route: ifp from route:0x%x ro_rt 0x%x\n", ro,
730*36400Ssklower 					ro->ro_rt);
731*36400Ssklower 			ENDDEBUG
732*36400Ssklower 			rtfree(ro->ro_rt);
733*36400Ssklower 		}
734*36400Ssklower 	}
735*36400Ssklower 	IFDEBUG(D_CONN)
736*36400Ssklower 		printf("tpip_route: returning 0x%x\n", ifp);
737*36400Ssklower 		if (ifp)
738*36400Ssklower 			printf("tpip_route: if name %s unit 0x%x, mtu 0x%x\n",
739*36400Ssklower 				ifp->if_name, ifp->if_unit, ifp->if_mtu);
740*36400Ssklower 	ENDDEBUG
741*36400Ssklower 	return ifp;
742*36400Ssklower }
743*36400Ssklower 
744*36400Ssklower #endif INET
745