1*25202Skarels /*
2*25202Skarels  $Log:	rdp_usrreq.c,v $
3*25202Skarels  * Revision 2.8  85/05/30  11:54:12  walsh
4*25202Skarels  * initialize r_srtt.
5*25202Skarels  *
6*25202Skarels  * Revision 2.7  85/02/26  08:27:02  walsh
7*25202Skarels  * First pass at using IP source routing information to establish connections
8*25202Skarels  * (possibly with hosts not known by the Internet gateways.)  The hooks with
9*25202Skarels  * TCP could be better done - particularly dealing with IP addresses in the
10*25202Skarels  * header for checksums and tcpdb lookups.
11*25202Skarels  *
12*25202Skarels  * Revision 2.6  84/11/29  12:51:00  walsh
13*25202Skarels  * changed references to currentrtt into references to srtt, a better
14*25202Skarels  * and less misleading mnemonic.
15*25202Skarels  *
16*25202Skarels  * Revision 2.5  84/11/08  16:13:17  walsh
17*25202Skarels  * Added code to gather statistics on RDP traffic.  This makes the RDPCB
18*25202Skarels  * too big unles you make mbufs 512 bytes large.  RDP_CS should be turned off
19*25202Skarels  * unless you do.
20*25202Skarels  *
21*25202Skarels  * Revision 2.4  84/11/05  12:41:29  walsh
22*25202Skarels  * Set things up so can debug RDP connections just like can debug TCP
23*25202Skarels  * connections.
24*25202Skarels  *
25*25202Skarels  * Revision 2.3  84/11/05  11:05:42  walsh
26*25202Skarels  * comment and adjust number for rdp_iss in a mathematically correct way
27*25202Skarels  * as a result of benchmarks (cf. operationally correct).
28*25202Skarels  *
29*25202Skarels  * Revision 2.2  84/11/05  10:49:01  walsh
30*25202Skarels  * More changes to go with NULL messages getting their own sequence
31*25202Skarels  * number.
32*25202Skarels  *
33*25202Skarels  * Revision 2.1  84/11/02  10:16:02  walsh
34*25202Skarels  * Fixed to include RCS comments in checked out source.
35*25202Skarels  *
36*25202Skarels  *
37*25202Skarels  * description:
38*25202Skarels  * The user system call interface to RDP.
39*25202Skarels  *
40*25202Skarels  * revision 1.11
41*25202Skarels  * date: 84/07/20 12:35:26;  author: root;  state: Exp;  lines added/del: 2/2
42*25202Skarels  * fix syntax error.
43*25202Skarels  *
44*25202Skarels  * revision 1.10
45*25202Skarels  * date: 84/07/20 11:25:53;  author: walsh;  state: Exp;  lines added/del: 3/2
46*25202Skarels  * Don't let user use unreasonable (too small) retranmit took too long timers.
47*25202Skarels  *
48*25202Skarels  * revision 1.9
49*25202Skarels  * date: 84/07/19 10:22:59;  author: walsh;  state: Exp;  lines added/del: 2/1
50*25202Skarels  * Organized macros and classified their definitions in rdp_macros.h.
51*25202Skarels  *
52*25202Skarels  * revision 1.8
53*25202Skarels  * date: 84/07/18 18:51:41;  author: walsh;  state: Exp;  lines added/del: 29/1
54*25202Skarels  * Added provision for sending of NULL messages.  These are sent on an idle
55*25202Skarels  * connection to determine that the other side still exists.
56*25202Skarels  *
57*25202Skarels  * revision 1.7
58*25202Skarels  * date: 84/07/18 13:49:19;  author: walsh;  state: Exp;  lines added/del: 19/1
59*25202Skarels  * RTTL timer is now user alterable.
60*25202Skarels  *
61*25202Skarels  * revision 1.6
62*25202Skarels  * date: 84/07/17 22:42:08;  author: walsh;  state: Exp;  lines added/del: 7/3
63*25202Skarels  * Can't connect to port numbers greater than RDP_pMAX.
64*25202Skarels  *
65*25202Skarels  * revision 1.5
66*25202Skarels  * date: 84/07/12 13:48:38;  author: walsh;  state: Exp;  lines added/del: 2/1
67*25202Skarels  * Rather than in-line stuffing of IP/RDP headers, at least half of which are
68*25202Skarels  * constant, copy headers in from a template of what the headers are like.  The
69*25202Skarels  * bcopy() call is turned into a movc3 instruction on the VAX by a sed script
70*25202Skarels  * run over the assembler output of the C compiler.  Marginal speed-up.
71*25202Skarels  *
72*25202Skarels  * revision 1.4
73*25202Skarels  * date: 84/07/10 10:45:38;  author: walsh;  state: Exp;  lines added/del: 20/19
74*25202Skarels  * neatened up some formatting.
75*25202Skarels  *
76*25202Skarels  * revision 1.3
77*25202Skarels  * date: 84/07/06 14:41:15;  author: wjacobso;  state: Exp;  lines added/del: 11/3
78*25202Skarels  * use RSP_ACTION macro instead of rdp_action
79*25202Skarels  *
80*25202Skarels  * revision 1.2
81*25202Skarels  * date: 84/07/06 09:51:35;  author: root;  state: Exp;  lines added/del: 56/17
82*25202Skarels  * This version seems to run bug-free.
83*25202Skarels  *
84*25202Skarels  * revision 1.1
85*25202Skarels  * date: 84/06/26 14:18:47;  author: walsh;  state: Exp;
86*25202Skarels  * Initial revision
87*25202Skarels  */
88*25202Skarels 
89*25202Skarels 
90*25202Skarels 
91*25202Skarels #ifdef RDP
92*25202Skarels #ifdef	RCSIDENT
93*25202Skarels static char rcsident[] = "$Header: rdp_usrreq.c,v 2.8 85/05/30 11:54:12 walsh Exp $";
94*25202Skarels #endif RCSIDENT
95*25202Skarels 
96*25202Skarels #include "../h/param.h"
97*25202Skarels #include "../h/systm.h"
98*25202Skarels #include "../h/mbuf.h"
99*25202Skarels #include "../h/socket.h"
100*25202Skarels #include "../h/socketvar.h"
101*25202Skarels #include "../h/protosw.h"
102*25202Skarels #include "../h/errno.h"
103*25202Skarels #include "../h/ioctl.h"
104*25202Skarels #include "../h/time.h"
105*25202Skarels #include "../h/kernel.h"
106*25202Skarels 
107*25202Skarels #include "../net/if.h"
108*25202Skarels #include "../net/route.h"
109*25202Skarels 
110*25202Skarels #include "../bbnnet/in.h"
111*25202Skarels #include "../bbnnet/net.h"
112*25202Skarels #include "../bbnnet/in_pcb.h"
113*25202Skarels #include "../bbnnet/in_var.h"
114*25202Skarels #include "../bbnnet/ip.h"
115*25202Skarels #include "../bbnnet/icmp.h"
116*25202Skarels #include "../bbnnet/rdp.h"
117*25202Skarels #include "../bbnnet/rdp_macros.h"
118*25202Skarels 
119*25202Skarels /*
120*25202Skarels  * RDP protocol interface to socket abstraction.
121*25202Skarels  */
122*25202Skarels 
123*25202Skarels /*
124*25202Skarels  * misc data structures
125*25202Skarels  */
126*25202Skarels 
127*25202Skarels struct inpcb rdp;
128*25202Skarels struct rdp_stat rdpstat;
129*25202Skarels 
130*25202Skarels struct dfilter	rdp_dfilter;
131*25202Skarels rdpsequence rdp_iss;
132*25202Skarels 
133*25202Skarels /*
134*25202Skarels  * RDP port allocation information
135*25202Skarels  */
136*25202Skarels 
137*25202Skarels extern rdp_binding_used();
138*25202Skarels 
139*25202Skarels struct pr_advice rdp_advice =
140*25202Skarels {
141*25202Skarels     RDP_RESERVED,
142*25202Skarels     RDP_USERRESERVED,
143*25202Skarels     RDP_MAXPORT,
144*25202Skarels     RDP_USERRESERVED+1,
145*25202Skarels     sizeof(u_char),
146*25202Skarels     rdp_binding_used
147*25202Skarels } ;
148*25202Skarels 
149*25202Skarels 
150*25202Skarels /*
151*25202Skarels  * Allocate and initialize a new RDPCB
152*25202Skarels  * rdp_usrreq calls rdp_attach calls us.  rdp_usrreq splnet()'s
153*25202Skarels  *
154*25202Skarels  * Default allocation for kernel receive buffering is
155*25202Skarels  * (rdp_ournbuf * rdp_ourmaxlen) bytes.
156*25202Skarels  */
157*25202Skarels int rdp_ournbuf = 8;
158*25202Skarels int rdp_ourmaxlen = IPMAX - HDRSLOP;
159*25202Skarels 
rdp_newrdpcb(inp)160*25202Skarels rdp_newrdpcb(inp)
161*25202Skarels register INPCB	*inp;
162*25202Skarels {
163*25202Skarels     register RDPCB	*rdpcb;
164*25202Skarels     register MBUF	*m;
165*25202Skarels     MBUF	*mrq, *msq;
166*25202Skarels 
167*25202Skarels     m	= m_getclr(M_WAIT, MT_PCB);
168*25202Skarels     mrq	= m_getclr(M_WAIT, MT_PCB);
169*25202Skarels     msq	= m_getclr(M_WAIT, MT_PCB);
170*25202Skarels     if ((m == NULL) || (mrq == NULL) || (msq == NULL))
171*25202Skarels     {
172*25202Skarels 	if (m)
173*25202Skarels 	    m_free(m);
174*25202Skarels 	if (mrq)
175*25202Skarels 	    m_free(mrq);
176*25202Skarels 	if (msq)
177*25202Skarels 	    m_free(msq);
178*25202Skarels 	return(ENOBUFS);
179*25202Skarels     }
180*25202Skarels 
181*25202Skarels     rdpcb = mtod(m, RDPCB *);
182*25202Skarels 
183*25202Skarels     /* initialize non-zero tcb fields */
184*25202Skarels 
185*25202Skarels     rdpcb->r_sendq.rq_msgs	= mtod(msq, MBUF **);
186*25202Skarels     rdpcb->r_rcvq.rq_msgs	= mtod(mrq, MBUF **);
187*25202Skarels     rdpcb->r_state		= RDP_sUNOPENED;
188*25202Skarels #ifdef RDP_CS
189*25202Skarels     rdpcb->r_entered[RDP_sUNOPENED] = iptime();
190*25202Skarels #endif
191*25202Skarels     rdpcb->r_ournbuf	= MAX(1, MIN(RDP_MAXDGRAMS, rdp_ournbuf));
192*25202Skarels     rdpcb->r_hisnbuf	= 1;
193*25202Skarels /*  rdpcb->r_synrcvd	= FALSE;	*/
194*25202Skarels /*  rdpcb->r_synacked	= FALSE;	*/
195*25202Skarels /*  rdpcb->r_usrclosed	= FALSE;	*/
196*25202Skarels /*  rdpcb->r_rttiming	= FALSE;	*/
197*25202Skarels     rdpcb->r_sequential	= TRUE;
198*25202Skarels     rdpcb->r_closewait	= RDP_tvCLOSEWAIT;
199*25202Skarels     rdpcb->r_rttl	= RDP_tvRTTL;
200*25202Skarels     rdpcb->r_tvnull	= RDP_tvNULL;
201*25202Skarels     rdpcb->r_srtt	= RDP_tvRXMIN; /*###*/
202*25202Skarels     rdpcb->r_rxmitime	= rdpcb->r_srtt + 1;
203*25202Skarels     rdpcb->r_rttlindex	= (-1);
204*25202Skarels     rdpcb->r_iss = rdp_iss;
205*25202Skarels     rdpcb->r_sndnxt = rdpcb->r_snduna = rdpcb->r_iss +1;
206*25202Skarels     rdp_iss += RDP_ISSINCR;
207*25202Skarels 
208*25202Skarels     /* attach the protocol specific pcb to the generic internet pcb */
209*25202Skarels     inp->inp_ppcb = (caddr_t)rdpcb;
210*25202Skarels     rdpcb->r_inpcb = inp;
211*25202Skarels 
212*25202Skarels     /*
213*25202Skarels      * User has until listen(2) or connect(2) to increase max dgram
214*25202Skarels      * size we will accept.  He does this by adjusting his socket's
215*25202Skarels      * amount of receive buffering.
216*25202Skarels      */
217*25202Skarels     sbreserve (&rdpcb->r_inpcb->inp_socket->so_rcv, rdp_ourmaxlen);
218*25202Skarels     pick_ourmaxlen(rdpcb);
219*25202Skarels 
220*25202Skarels     return(0);
221*25202Skarels }
222*25202Skarels 
rdp_pcbdisconnect(inp)223*25202Skarels rdp_pcbdisconnect(inp)
224*25202Skarels INPCB	*inp;
225*25202Skarels {
226*25202Skarels     register RDPCB	*rdpcb;
227*25202Skarels     register MBUF	*m;
228*25202Skarels     register int	 i;
229*25202Skarels 
230*25202Skarels     if (rdpcb = (RDPCB *) inp->inp_ppcb)
231*25202Skarels     {
232*25202Skarels 	inp->inp_ppcb = (caddr_t) NULL;
233*25202Skarels 
234*25202Skarels 	/*
235*25202Skarels 	 * free all data on receive and send qs
236*25202Skarels 	 * Remember, due to EACKS, send q may contain non-NULL
237*25202Skarels 	 * RDP_DELIVERED pointers.
238*25202Skarels 	 * If we close while we're retransmitting a NULL message,
239*25202Skarels 	 * may have one of those on our send queue.
240*25202Skarels 	 */
241*25202Skarels 	for (i=0; i<RDP_MAXDGRAMS; i++)
242*25202Skarels 	{
243*25202Skarels 	    if (m = rdpcb->r_sendq.rq_msgs[i])
244*25202Skarels 		if ((m != RDP_DELIVERED) && (m != RDP_NULLMSG))
245*25202Skarels 		    m_freem(m);
246*25202Skarels 	    if (m = rdpcb->r_rcvq.rq_msgs[i])
247*25202Skarels 		if (m != RDP_DELIVERED)  /* just in case */
248*25202Skarels 		    m_freem(m);
249*25202Skarels 	}
250*25202Skarels 	m_free(dtom(rdpcb->r_sendq.rq_msgs));
251*25202Skarels 	m_free(dtom(rdpcb->r_rcvq.rq_msgs));
252*25202Skarels 
253*25202Skarels 	m_free(dtom(rdpcb));
254*25202Skarels     }
255*25202Skarels }
256*25202Skarels 
257*25202Skarels /*
258*25202Skarels  * Is a rdp port/address pair already in use by some socket on this machine?
259*25202Skarels  * Passed to in_pcbbind() to help it find a port/address binding
260*25202Skarels  * that is unique for rdp.
261*25202Skarels  */
rdp_binding_used(inp,lport,laddr,reuselocal)262*25202Skarels int rdp_binding_used(inp, lport, laddr, reuselocal)
263*25202Skarels INPCB	*inp;
264*25202Skarels rdpportnum lport;
265*25202Skarels u_long laddr;
266*25202Skarels {
267*25202Skarels     register INPCB		*i;
268*25202Skarels 
269*25202Skarels     for(i = rdp.inp_next; i != &rdp; i = i->inp_next)
270*25202Skarels     {
271*25202Skarels 	/*
272*25202Skarels 	 * Since our inpcb is in this linked list, don't want to know
273*25202Skarels 	 * if we, ourselves, are already using this binding.
274*25202Skarels 	 */
275*25202Skarels 	if (i != inp)
276*25202Skarels 	    if (i->inp_lport == lport)
277*25202Skarels 		/*
278*25202Skarels 		 * Our/His address is unbound (INADDR_ANY) iff
279*25202Skarels 		 * not yet connected to foreign host.
280*25202Skarels 		 */
281*25202Skarels 		if ((i->inp_laddr.s_addr == laddr) ||
282*25202Skarels 		    (i->inp_laddr.s_addr == INADDR_ANY) ||
283*25202Skarels 		    (laddr == INADDR_ANY))
284*25202Skarels 		{
285*25202Skarels 		    if (!reuselocal)
286*25202Skarels 			break;
287*25202Skarels 		    if (i->inp_faddr.s_addr == INADDR_ANY)
288*25202Skarels 			/*
289*25202Skarels 			 * We're both waiting for foreign
290*25202Skarels 			 * connection.  Could only re-use if
291*25202Skarels 			 * he was already connected.
292*25202Skarels 			 */
293*25202Skarels 			break;
294*25202Skarels 		}
295*25202Skarels     }
296*25202Skarels     return (i != &rdp);
297*25202Skarels }
298*25202Skarels 
rdp_conn_used(inp,lport,laddr,fport,faddr)299*25202Skarels char *rdp_conn_used(inp, lport, laddr, fport, faddr)
300*25202Skarels INPCB	*inp;
301*25202Skarels rdpportnum lport;
302*25202Skarels u_long laddr;
303*25202Skarels rdpportnum fport;
304*25202Skarels u_long faddr;
305*25202Skarels {
306*25202Skarels     register INPCB		*i;
307*25202Skarels 
308*25202Skarels     for(i = rdp.inp_next; i != &rdp; i = i->inp_next)
309*25202Skarels     {
310*25202Skarels 	/*
311*25202Skarels 	 * Since our inpcb is in this linked list, don't want to know
312*25202Skarels 	 * if we, ourselves, are already using this connetion.
313*25202Skarels 	 */
314*25202Skarels 	if (i != inp)
315*25202Skarels 	    if ((i->inp_lport == lport) &&
316*25202Skarels 	    (i->inp_fport == fport) &&
317*25202Skarels 	    (i->inp_laddr.s_addr == laddr) &&
318*25202Skarels 	    (i->inp_faddr.s_addr == faddr))
319*25202Skarels 
320*25202Skarels 		return((char *)(i->inp_ppcb));
321*25202Skarels     }
322*25202Skarels     return ((char *) NULL);
323*25202Skarels }
324*25202Skarels 
rdp_ioctl(rdpcb,command,data)325*25202Skarels rdp_ioctl (rdpcb, command, data)
326*25202Skarels RDPCB *rdpcb;
327*25202Skarels int command;
328*25202Skarels caddr_t data;
329*25202Skarels {
330*25202Skarels     switch (command)
331*25202Skarels     {
332*25202Skarels       case SIOCGNDGRAMS:
333*25202Skarels 	*((int *) data) = rdpcb->r_ournbuf;
334*25202Skarels 	break;
335*25202Skarels 
336*25202Skarels       case SIOCSNDGRAMS:
337*25202Skarels 	if ((rdpcb->r_state == RDP_sUNOPENED) && (*((int *) data) > 0))
338*25202Skarels 	    rdpcb->r_ournbuf = MIN (*((int *) data), RDP_MAXDGRAMS);
339*25202Skarels 	else
340*25202Skarels 	    return EINVAL;
341*25202Skarels 	break;
342*25202Skarels 
343*25202Skarels 
344*25202Skarels       case SIOCGSEQ:
345*25202Skarels 	*((int *) data) = rdpcb->r_sequential;
346*25202Skarels 	break;
347*25202Skarels 
348*25202Skarels       case SIOCSSEQ:
349*25202Skarels 	if (rdpcb->r_state == RDP_sUNOPENED)
350*25202Skarels 	    rdpcb->r_sequential = *((int *) data) ? TRUE : FALSE;
351*25202Skarels 	else
352*25202Skarels 	    return EINVAL;
353*25202Skarels 	break;
354*25202Skarels 
355*25202Skarels 
356*25202Skarels       case SIOCGRTTL:
357*25202Skarels 	*((int *) data) = rdpcb->r_rttl;
358*25202Skarels 	break;
359*25202Skarels 
360*25202Skarels       case SIOCSRTTL:
361*25202Skarels 	{
362*25202Skarels 	    /*
363*25202Skarels 	     * Allow user to set r_rttl to 0 to disable.
364*25202Skarels 	     */
365*25202Skarels 	    unsigned int	newvalue;
366*25202Skarels 
367*25202Skarels 	    newvalue = *((unsigned int *) data);
368*25202Skarels 	    if ((newvalue > RDP_MAXTIMERVAL) ||
369*25202Skarels 		(newvalue && (newvalue < MIN(rdpcb->r_srtt, rdpcb->r_rxmitime))))
370*25202Skarels 		return EINVAL;
371*25202Skarels 	    else
372*25202Skarels 		rdpcb->r_rttl = newvalue;
373*25202Skarels 	}
374*25202Skarels 	break;
375*25202Skarels 
376*25202Skarels 	/*
377*25202Skarels 	 * Problem with socket level KEEPALIVES is that timer
378*25202Skarels 	 * would be constant for all connections.
379*25202Skarels 	 */
380*25202Skarels       case SIOCGNULL:
381*25202Skarels 	*((int *) data) = rdpcb->r_tvnull;
382*25202Skarels 	break;
383*25202Skarels 
384*25202Skarels       case SIOCSNULL:
385*25202Skarels 	{
386*25202Skarels 	    /*
387*25202Skarels 	     * Allow user to set to 0 to disable.
388*25202Skarels 	     */
389*25202Skarels 	    unsigned int	newvalue;
390*25202Skarels 
391*25202Skarels 	    newvalue = *((unsigned int *) data);
392*25202Skarels 	    if ((newvalue > RDP_MAXTIMERVAL) ||
393*25202Skarels 		(newvalue && (newvalue < rdpcb->r_rttl)))
394*25202Skarels 		return EINVAL;
395*25202Skarels 	    else
396*25202Skarels 		rdpcb->r_tvnull = newvalue;
397*25202Skarels 	}
398*25202Skarels 	break;
399*25202Skarels 
400*25202Skarels       default:
401*25202Skarels 	/* not our ioctl, let lower level try ioctl */
402*25202Skarels 	return ip_ioctl (rdpcb->r_inpcb, command, data);
403*25202Skarels     }
404*25202Skarels 
405*25202Skarels     return (0);
406*25202Skarels }
407*25202Skarels 
408*25202Skarels /*
409*25202Skarels  * Process a RDP user request (system call).
410*25202Skarels  */
411*25202Skarels /*ARGSUSED*/
412*25202Skarels rdp_usrreq(so, req, m, nam, rights)
413*25202Skarels struct socket *so;
414*25202Skarels int req;
415*25202Skarels struct mbuf *m, *nam, *rights;
416*25202Skarels {
417*25202Skarels     register RDPCB	*rdpcb;
418*25202Skarels     register struct inpcb *inp;
419*25202Skarels     register int s;
420*25202Skarels     int error = 0;
421*25202Skarels 
422*25202Skarels     s = splnet();
423*25202Skarels     inp = sotoinpcb(so);
424*25202Skarels 
425*25202Skarels     if (rights && rights->m_len)
426*25202Skarels     {
427*25202Skarels 	splx(s);
428*25202Skarels 	return (EINVAL);
429*25202Skarels     }
430*25202Skarels     /*
431*25202Skarels      * When an RDPCB is attached to a socket, then there will be
432*25202Skarels      * an INPCB pointed at by the socket, and this
433*25202Skarels      * structure will point at a subsidary RDPCB.
434*25202Skarels      */
435*25202Skarels     if (inp == 0 && req != PRU_ATTACH)
436*25202Skarels     {
437*25202Skarels 	splx(s);
438*25202Skarels 	return (EINVAL);	/* XXX */
439*25202Skarels     }
440*25202Skarels     if (inp)
441*25202Skarels 	rdpcb = (RDPCB *) inp->inp_ppcb;
442*25202Skarels 
443*25202Skarels     /*
444*25202Skarels      * This switch becomes a 'caseb', so put common ones at top.
445*25202Skarels      */
446*25202Skarels     switch (req)
447*25202Skarels     {
448*25202Skarels 
449*25202Skarels       case PRU_RCVD:
450*25202Skarels 	/*
451*25202Skarels 	 * After user has received message, ack the message. read(2)
452*25202Skarels 	 */
453*25202Skarels 	{
454*25202Skarels 	    register rdpstate newstate;
455*25202Skarels 
456*25202Skarels 	    RDP_ACTION(RDP_iRCV, rdpcb, 0, newstate);
457*25202Skarels 	}
458*25202Skarels 	break;
459*25202Skarels 
460*25202Skarels       case PRU_SEND:
461*25202Skarels 	/*
462*25202Skarels 	 * Send this message. write(2)
463*25202Skarels 	 */
464*25202Skarels 	{
465*25202Skarels 	    register rdpstate newstate;
466*25202Skarels 
467*25202Skarels 	    RDP_ACTION(RDP_iSEND, rdpcb, ((int) m), newstate);
468*25202Skarels 	}
469*25202Skarels 	break;
470*25202Skarels 
471*25202Skarels       case PRU_ATTACH:
472*25202Skarels 	/*
473*25202Skarels 	 * set up protocol control blocks.  socket(2)
474*25202Skarels 	 */
475*25202Skarels 	if (inp)
476*25202Skarels 	{
477*25202Skarels 	    error = EISCONN;
478*25202Skarels 	    break;
479*25202Skarels 	}
480*25202Skarels 	if (error = rdp_attach(so))
481*25202Skarels 	    break;
482*25202Skarels 
483*25202Skarels 	/*
484*25202Skarels 	 * so_linger doesn't affect anything I know of in the socket level
485*25202Skarels 	 * -- see soclose().  Maybe this is one of those someday things.
486*25202Skarels 	 */
487*25202Skarels 	if ((so->so_options & SO_LINGER) && so->so_linger == 0)
488*25202Skarels 		so->so_linger = 120;
489*25202Skarels 
490*25202Skarels 	rdpcb = (RDPCB *) ((INPCB *) so->so_pcb)->inp_ppcb;
491*25202Skarels 	break;
492*25202Skarels 
493*25202Skarels       case PRU_DETACH:
494*25202Skarels 	/*
495*25202Skarels 	 * close(2) the connection
496*25202Skarels 	 */
497*25202Skarels 	rdp_close(rdpcb);
498*25202Skarels 	break;
499*25202Skarels 
500*25202Skarels       case PRU_BIND:
501*25202Skarels 	/*
502*25202Skarels 	 * Give the socket an address.  bind(2)
503*25202Skarels 	 */
504*25202Skarels 	error = in_pcbbind(inp, nam, &rdp_advice);
505*25202Skarels 	break;
506*25202Skarels 
507*25202Skarels       case PRU_LISTEN:
508*25202Skarels 	/*
509*25202Skarels 	 * Prepare to accept connections.  Passive open.  listen(2)
510*25202Skarels 	 */
511*25202Skarels 	if (inp->inp_lport == 0)
512*25202Skarels 	    if (error = in_pcbbind(inp, (MBUF *)0, &rdp_advice))
513*25202Skarels 		break;
514*25202Skarels 
515*25202Skarels 	pick_ourmaxlen(rdpcb);
516*25202Skarels 	rdp_action(RDP_iLISTEN, rdpcb, 0);
517*25202Skarels 	break;
518*25202Skarels 
519*25202Skarels       case PRU_CONNECT:
520*25202Skarels 	/*
521*25202Skarels 	 * Active open.  connect(2).  Initiate connection to peer.
522*25202Skarels 	 * Bind the local end if not already.  Set the routing.
523*25202Skarels 	 * Crank up the state machine.
524*25202Skarels 	 */
525*25202Skarels 	{
526*25202Skarels 	    struct sockaddr_in *sin;
527*25202Skarels 
528*25202Skarels 	    /*
529*25202Skarels 	     * ensure foreign address might be valid.
530*25202Skarels 	     * Can't connect to broadcast address...
531*25202Skarels 	     */
532*25202Skarels 	    sin = mtod(nam, struct sockaddr_in *);
533*25202Skarels 	    if ((in_broadcast(sin->sin_addr)) ||
534*25202Skarels 		(sin->sin_port > RDP_MAXPORT))
535*25202Skarels 	    {
536*25202Skarels 		error = EADDRNOTAVAIL;
537*25202Skarels 		break;
538*25202Skarels 	    }
539*25202Skarels 
540*25202Skarels 	    if (inp->inp_lport == 0)
541*25202Skarels 		if (error = in_pcbbind(inp, (MBUF *)0, &rdp_advice))
542*25202Skarels 		    break;
543*25202Skarels 	    if (error = in_pcbconnect(inp, nam, rdp_conn_used))
544*25202Skarels 		break;
545*25202Skarels 
546*25202Skarels 	    /*
547*25202Skarels 	     * So can debug connection problems without having to change
548*25202Skarels 	     * every program or apply debugging flag to each program every
549*25202Skarels 	     * time run it.
550*25202Skarels 	     */
551*25202Skarels 	    dowedebug(inp, so, &rdp_dfilter);
552*25202Skarels 
553*25202Skarels 	    soisconnecting(so);
554*25202Skarels 	    pick_ourmaxlen(rdpcb);
555*25202Skarels 	    rdp_template(rdpcb);
556*25202Skarels 	    rdp_action(RDP_iCONNECT, rdpcb, 0);
557*25202Skarels 	}
558*25202Skarels 	break;
559*25202Skarels 
560*25202Skarels 	/*
561*25202Skarels 	 * Create a TCP connection between two sockets.
562*25202Skarels 	 */
563*25202Skarels       case PRU_CONNECT2:
564*25202Skarels 	error = EOPNOTSUPP;
565*25202Skarels 	break;
566*25202Skarels 
567*25202Skarels       case PRU_DISCONNECT:
568*25202Skarels 	/*
569*25202Skarels 	 * close(2)
570*25202Skarels 	 */
571*25202Skarels 	rdp_close(rdpcb);
572*25202Skarels 	break;
573*25202Skarels 
574*25202Skarels       case PRU_ACCEPT:
575*25202Skarels 	/*
576*25202Skarels 	 * accept(2).  Socket code has waited until a new connection
577*25202Skarels 	 * is available for the listener/server.  Now that there is
578*25202Skarels 	 * one, we just tell them who it is.
579*25202Skarels 	 */
580*25202Skarels 	{
581*25202Skarels 	    struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
582*25202Skarels 
583*25202Skarels 	    nam->m_len = sizeof (struct sockaddr_in);
584*25202Skarels 	    sin->sin_family = AF_INET;
585*25202Skarels 	    sin->sin_port = inp->inp_fport;
586*25202Skarels 	    sin->sin_addr = inp->inp_faddr;
587*25202Skarels 	}
588*25202Skarels 	break;
589*25202Skarels 
590*25202Skarels       case PRU_SHUTDOWN:
591*25202Skarels 	/*
592*25202Skarels 	 * user has shutdown(2) for writing.  This is a friendly close;
593*25202Skarels 	 * the user may still want to read.
594*25202Skarels 	 */
595*25202Skarels 	socantsendmore(so);
596*25202Skarels 	break;
597*25202Skarels 
598*25202Skarels       case PRU_ABORT:
599*25202Skarels 	/*
600*25202Skarels 	 * abort un-accept(2)ed connections when close listening socket
601*25202Skarels 	 * act as if it was accepted and closed.  Remove socket from
602*25202Skarels 	 * parent socket's qs so that not hang in soclose()
603*25202Skarels 	 */
604*25202Skarels 
605*25202Skarels 	/* accept */
606*25202Skarels 	if (! soqremque(so, 0)) /* SYNSENT, LSYNRCVD */
607*25202Skarels 	    if (! soqremque(so, 1)) /* ESTAB */
608*25202Skarels 		panic("rdp ABORT");
609*25202Skarels 
610*25202Skarels 	/* close */
611*25202Skarels 	rdp_close(rdpcb);
612*25202Skarels 	break;
613*25202Skarels 
614*25202Skarels       case PRU_CONTROL:
615*25202Skarels 	error = rdp_ioctl(rdpcb, (int) m, (caddr_t) nam);
616*25202Skarels 	break;
617*25202Skarels 
618*25202Skarels /* SOME AS YET UNIMPLEMENTED HOOKS */
619*25202Skarels       case PRU_SENSE:
620*25202Skarels 	error = EOPNOTSUPP;
621*25202Skarels 	break;
622*25202Skarels /* END UNIMPLEMENTED HOOKS */
623*25202Skarels 
624*25202Skarels       case PRU_RCVOOB:
625*25202Skarels       case PRU_SENDOOB:
626*25202Skarels 	error = EOPNOTSUPP;
627*25202Skarels 	break;
628*25202Skarels 
629*25202Skarels       case PRU_SOCKADDR:
630*25202Skarels 	/*
631*25202Skarels 	 * Tell user his (local) address/binding
632*25202Skarels 	 */
633*25202Skarels 	in_setsockaddr(inp, nam);
634*25202Skarels 	break;
635*25202Skarels 
636*25202Skarels       case PRU_PEERADDR:
637*25202Skarels 	in_setpeeraddr(inp, nam);
638*25202Skarels 	break;
639*25202Skarels 
640*25202Skarels #ifdef neverdef
641*25202Skarels       case PRU_SLOWTIMO:
642*25202Skarels 	rdp_timeo();
643*25202Skarels 	break;
644*25202Skarels #endif
645*25202Skarels 
646*25202Skarels       default:
647*25202Skarels 	panic("rdp_usrreq");
648*25202Skarels     }
649*25202Skarels     splx(s);
650*25202Skarels     return (error);
651*25202Skarels }
652*25202Skarels 
653*25202Skarels /*
654*25202Skarels  * get/setsockopt() handler
655*25202Skarels  */
656*25202Skarels 
rdp_ctloutput(req,so,level,optname,optval)657*25202Skarels rdp_ctloutput(req,so,level,optname,optval)
658*25202Skarels int req;
659*25202Skarels struct socket *so;
660*25202Skarels int level, optname;
661*25202Skarels struct mbuf **optval;
662*25202Skarels {
663*25202Skarels     int s = splnet(); /* like PRU/packet/timer entry into net code */
664*25202Skarels     int error;
665*25202Skarels     struct inpcb *inp;
666*25202Skarels 
667*25202Skarels     /*
668*25202Skarels      * See comments by tcp_ctloutput()
669*25202Skarels      */
670*25202Skarels     if (level == IPPROTO_RDP)
671*25202Skarels     {
672*25202Skarels 	inp = sotoinpcb(so);
673*25202Skarels 
674*25202Skarels 	switch(optname)
675*25202Skarels 	{
676*25202Skarels 	  case PRCO_GETOPT:
677*25202Skarels 	    error = rdp_getopt(inp, optname, optval);
678*25202Skarels 	    break;
679*25202Skarels 
680*25202Skarels 	  case PRCO_SETOPT:
681*25202Skarels 	    error = rdp_setopt(inp, optname, optval);
682*25202Skarels 	    break;
683*25202Skarels 
684*25202Skarels 	  default:
685*25202Skarels 	    panic("rdp_ctloutput");
686*25202Skarels 	}
687*25202Skarels     } else
688*25202Skarels         error = ip_ctloutput(req,so,level,optname,optval);
689*25202Skarels 
690*25202Skarels     splx(s);
691*25202Skarels     return (error);
692*25202Skarels }
693*25202Skarels 
694*25202Skarels rdp_setopt (inp, command, data)
695*25202Skarels struct inpcb	*inp;
696*25202Skarels struct mbuf	**data;
697*25202Skarels {
698*25202Skarels     /* no RDP specific options accessed by setsockopt() as yet */
699*25202Skarels     return EOPNOTSUPP;
700*25202Skarels }
701*25202Skarels 
702*25202Skarels rdp_getopt (inp, command, data)
703*25202Skarels struct inpcb	*inp;
704*25202Skarels struct mbuf	**data;
705*25202Skarels {
706*25202Skarels     /* no RDP specific options accessed by getsockopt() as yet */
707*25202Skarels     return EOPNOTSUPP;
708*25202Skarels }
709*25202Skarels 
710*25202Skarels /*
711*25202Skarels  * attach rdp protocol to socket
712*25202Skarels  */
713*25202Skarels rdp_attach(so)
714*25202Skarels struct socket *so;
715*25202Skarels {
716*25202Skarels     struct inpcb *inp;
717*25202Skarels     int error;
718*25202Skarels 
719*25202Skarels     if ((error = in_pcballoc(so,&rdp)) == 0)
720*25202Skarels     {
721*25202Skarels 	inp = sotoinpcb(so);
722*25202Skarels 	if (error = rdp_newrdpcb(inp))
723*25202Skarels 	    in_pcbdetach(inp,(int(*)())0);
724*25202Skarels     }
725*25202Skarels     return(error);
726*25202Skarels }
727*25202Skarels 
728*25202Skarels 
729*25202Skarels 
730*25202Skarels /*
731*25202Skarels  * Initiate (or continue) disconnect.  close(2).
732*25202Skarels  */
rdp_close(rdpcb)733*25202Skarels rdp_close(rdpcb)
734*25202Skarels register RDPCB *rdpcb;
735*25202Skarels {
736*25202Skarels     struct socket *so;
737*25202Skarels 
738*25202Skarels     if (! rdpcb->r_usrclosed)
739*25202Skarels     {
740*25202Skarels 	rdpcb->r_usrclosed = TRUE;
741*25202Skarels 	so = rdpcb->r_inpcb->inp_socket;
742*25202Skarels 	soisdisconnecting(so);
743*25202Skarels 	sbflush(&so->so_rcv);
744*25202Skarels 	rdp_action(RDP_iUCLOSE, rdpcb, 0);
745*25202Skarels     }
746*25202Skarels }
747*25202Skarels 
rdp_init()748*25202Skarels rdp_init()
749*25202Skarels {
750*25202Skarels     /*
751*25202Skarels      * Leave these checks in!  It's a pain in the ass to find out
752*25202Skarels      * problems caused by too small mbufs if someone changes the
753*25202Skarels      * size of an mbuf.
754*25202Skarels      */
755*25202Skarels     if (sizeof(RDPCB) > MLEN)
756*25202Skarels 	panic("rdpcb too big");
757*25202Skarels 
758*25202Skarels     if (sizeof(R_DEBUG) > MLEN)
759*25202Skarels 	panic("r_debug too big");
760*25202Skarels 
761*25202Skarels     if (sizeof(RDPHDR) + sizeof(struct ip) > MLEN)
762*25202Skarels 	panic("rdphdr too big");
763*25202Skarels 
764*25202Skarels     /*
765*25202Skarels      * When send a packet, we allocate an mbuf for options and assume
766*25202Skarels      * they'll always fit.
767*25202Skarels      */
768*25202Skarels     if (sizeof(EACKOPTIONS) * RDP_MAXDGRAMS > MLEN)
769*25202Skarels 	panic("RDP_MAXDGRAMS too big");
770*25202Skarels 
771*25202Skarels     /*
772*25202Skarels      * rq_msgs is assumed to fit within a single mbuf.
773*25202Skarels      */
774*25202Skarels     if (sizeof(MBUF *) * RDP_MAXDGRAMS > MLEN)
775*25202Skarels 	panic("RDP_MAXDGRAMS too big 2");
776*25202Skarels 
777*25202Skarels     /*
778*25202Skarels      * When receive a packet, IP hdr + RDP hdr + RDP options pulled up
779*25202Skarels      * into a single mbuf and later assumed to be contiguous.  We'd like
780*25202Skarels      * to avoid deadlock on a connection leading to a timeout failure of
781*25202Skarels      * the connection.  Also, later just before we pass the packet to the
782*25202Skarels      * user, we trim off the headers assuming they're in one mbuf.
783*25202Skarels      *
784*25202Skarels      * This superceeds a few of the above, but if we change things, the
785*25202Skarels      * separate listing will make things easier.
786*25202Skarels      */
787*25202Skarels     if (sizeof(struct ip)+sizeof(RDPHDR)+(sizeof(EACKOPTIONS)*RDP_MAXDGRAMS)
788*25202Skarels 	> MLEN)
789*25202Skarels 	panic("RDP_MAXDGRAMS too big 3");
790*25202Skarels 
791*25202Skarels     rdp_iss = time.tv_sec;
792*25202Skarels 
793*25202Skarels     rdp.inp_next = rdp.inp_prev = &rdp;
794*25202Skarels 
795*25202Skarels     /* are only 4 things to match. turn off for now */
796*25202Skarels     rdp_dfilter.matches = 5;
797*25202Skarels 
798*25202Skarels     ipsw[IPPROTO_RDP].ipsw_hlen = sizeof(struct ip) + RDPHDRSZ;
799*25202Skarels }
800*25202Skarels 
rdp_ctlinput(prc_code,arg)801*25202Skarels rdp_ctlinput (prc_code, arg)
802*25202Skarels caddr_t arg;
803*25202Skarels {
804*25202Skarels     int error;
805*25202Skarels 
806*25202Skarels     error = inetctlerrmap[prc_code];
807*25202Skarels 
808*25202Skarels     switch (prc_code)
809*25202Skarels     {
810*25202Skarels 	case PRC_UNREACH_PROTOCOL:	/* icmp message */
811*25202Skarels 	case PRC_UNREACH_PORT:
812*25202Skarels 	case PRC_MSGSIZE:
813*25202Skarels 	    {
814*25202Skarels 	    RDPHDR *pkt;
815*25202Skarels 	    RDPCB *rdpcb;
816*25202Skarels 	    struct ip *ip;
817*25202Skarels 
818*25202Skarels 	    ip = (struct ip *) (&((struct icmp *) arg)->ic_iphdr);
819*25202Skarels 	    pkt = (RDPHDR *) (ip+1);
820*25202Skarels 	    rdpcb = (RDPCB *) rdp_conn_used((struct inpcb *) NULL,
821*25202Skarels 		pkt->rh_sport, ip->ip_src.s_addr,
822*25202Skarels 		pkt->rh_dport, ip->ip_dst.s_addr);
823*25202Skarels 
824*25202Skarels 	    if (rdpcb)
825*25202Skarels 	    {
826*25202Skarels 		rdpcb->r_inpcb->inp_socket->so_error = error;
827*25202Skarels 		rdp_close(rdpcb);
828*25202Skarels 	    }
829*25202Skarels 	    }
830*25202Skarels 	    break;
831*25202Skarels 
832*25202Skarels 	case PRC_UNREACH_NET:
833*25202Skarels 	case PRC_UNREACH_HOST:
834*25202Skarels 	    {
835*25202Skarels 	    RDPHDR *pkt;
836*25202Skarels 	    RDPCB *rdpcb;
837*25202Skarels 	    struct ip *ip;
838*25202Skarels 
839*25202Skarels 	    ip = (struct ip *) (&((struct icmp *) arg)->ic_iphdr);
840*25202Skarels 	    pkt = (RDPHDR *) (ip+1);
841*25202Skarels 	    rdpcb = (RDPCB *) rdp_conn_used((struct inpcb *) NULL,
842*25202Skarels 		pkt->rh_sport, ip->ip_src.s_addr,
843*25202Skarels 		pkt->rh_dport, ip->ip_dst.s_addr);
844*25202Skarels 
845*25202Skarels 	    if (rdpcb)
846*25202Skarels 	    {
847*25202Skarels 		struct socket *so;
848*25202Skarels 
849*25202Skarels 		so = rdpcb->r_inpcb->inp_socket;
850*25202Skarels 		if ((so->so_state & SS_NOFDREF) == 0)
851*25202Skarels 		    advise_user(so, error);
852*25202Skarels 		else
853*25202Skarels 		{
854*25202Skarels 		    so->so_error = error;
855*25202Skarels 		    rdp_close(rdpcb);
856*25202Skarels 		}
857*25202Skarels 	    }
858*25202Skarels 	    }
859*25202Skarels 	    break;
860*25202Skarels 
861*25202Skarels 	case PRC_GWDOWN:
862*25202Skarels 	    in_gdown (&rdp, (u_long) arg);
863*25202Skarels 	    break;
864*25202Skarels 
865*25202Skarels 	case PRC_REDIRECT_NET:	/* icmp message */
866*25202Skarels 	case PRC_REDIRECT_HOST:
867*25202Skarels 	    {
868*25202Skarels 	    RDPHDR *pkt;
869*25202Skarels 	    RDPCB *rdpcb;
870*25202Skarels 	    struct ip *ip;
871*25202Skarels 
872*25202Skarels 	    ip = (struct ip *) (&((struct icmp *) arg)->ic_iphdr);
873*25202Skarels 	    pkt = (RDPHDR *) (ip+1);
874*25202Skarels 	    rdpcb = (RDPCB *) rdp_conn_used((struct inpcb *) NULL,
875*25202Skarels 		pkt->rh_sport, ip->ip_src.s_addr,
876*25202Skarels 		pkt->rh_dport, ip->ip_dst.s_addr);
877*25202Skarels 
878*25202Skarels 	    if (rdpcb)
879*25202Skarels 		icmp_redirect_inp(rdpcb->r_inpcb, (struct icmp *) arg,
880*25202Skarels 		     prc_code == PRC_REDIRECT_NET ? rtnet : rthost);
881*25202Skarels 	    }
882*25202Skarels 	    break;
883*25202Skarels 
884*25202Skarels 	case PRC_TIMXCEED_INTRANS:	/* icmp message */
885*25202Skarels 	case PRC_TIMXCEED_REASS:
886*25202Skarels 	case PRC_PARAMPROB:
887*25202Skarels 	    break;
888*25202Skarels 
889*25202Skarels 	case PRC_QUENCH:	/* icmp message */
890*25202Skarels 	    /*
891*25202Skarels 	     * Reduce the traffic on this connection, so the gateway is happy.
892*25202Skarels 	     * Since can't change message size, must change frequency.  If continue
893*25202Skarels 	     * to send it straight out in response to write(2), can only tweak
894*25202Skarels 	     * retransmission period.
895*25202Skarels 	     *
896*25202Skarels 	     * This will allow the gateway to relax until things flow again and we
897*25202Skarels 	     * calculate another round trip time.
898*25202Skarels 	     */
899*25202Skarels 	    {
900*25202Skarels 	    RDPHDR *pkt;
901*25202Skarels 	    RDPCB *rdpcb;
902*25202Skarels 	    struct ip *ip;
903*25202Skarels 
904*25202Skarels 	    ip = (struct ip *) (&((struct icmp *) arg)->ic_iphdr);
905*25202Skarels 	    pkt = (RDPHDR *) (ip+1);
906*25202Skarels 	    rdpcb = (RDPCB *) rdp_conn_used((struct inpcb *) NULL,
907*25202Skarels 		pkt->rh_sport, ip->ip_src.s_addr,
908*25202Skarels 		pkt->rh_dport, ip->ip_dst.s_addr);
909*25202Skarels 	    if (rdpcb)
910*25202Skarels 		rdpcb->r_rxmitime = MIN(rdpcb->r_rxmitime +1, RDP_tvRXMAX);
911*25202Skarels 	    }
912*25202Skarels 	    break;
913*25202Skarels 
914*25202Skarels 	case PRC_IFDOWN:
915*25202Skarels 	    {
916*25202Skarels 	    u_long addr;
917*25202Skarels 
918*25202Skarels 	    addr = ((struct sockaddr_in *)(arg))->sin_addr.s_addr;
919*25202Skarels 	    inpcb_notify(&rdp, addr, (u_long) 0, error);
920*25202Skarels 	    inpcb_notify(&rdp, (u_long) 0, addr, error);
921*25202Skarels 	    }
922*25202Skarels 	    break;
923*25202Skarels 
924*25202Skarels 	case PRC_HOSTDEAD:	/* from imp interface */
925*25202Skarels 	case PRC_HOSTUNREACH:
926*25202Skarels 	    /*
927*25202Skarels 	     * get same message for destination hosts and gateways.
928*25202Skarels 	     */
929*25202Skarels 	    {
930*25202Skarels 	    u_long addr;
931*25202Skarels 
932*25202Skarels 	    addr = ((struct sockaddr_in *)arg)->sin_addr.s_addr;
933*25202Skarels 	    in_gdown (&rdp, addr);
934*25202Skarels 	    inpcb_notify(&rdp, (u_long) 0, addr, error);
935*25202Skarels 	    }
936*25202Skarels 	    break;
937*25202Skarels 
938*25202Skarels 	default:
939*25202Skarels 	    panic("rdp_ctlinput");
940*25202Skarels     }
941*25202Skarels }
942*25202Skarels #endif
943