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