1*25202Skarels /*
2*25202Skarels  $Log:	rdp_states.c,v $
3*25202Skarels  * Revision 2.14  85/06/18  14:38:50  walsh
4*25202Skarels  * eliminated inpcb flags.
5*25202Skarels  *
6*25202Skarels  * Revision 2.13  85/05/31  14:39:06  walsh
7*25202Skarels  * copy sequential delivery desires when fork off a new socket.
8*25202Skarels  *
9*25202Skarels  * Revision 2.12  84/12/03  09:42:20  walsh
10*25202Skarels  * Keep no route messages from flooding console.
11*25202Skarels  *
12*25202Skarels  * Revision 2.11  84/11/29  13:06:17  walsh
13*25202Skarels  * Have the NULL message retransmission back off so that don't load
14*25202Skarels  * a jammed network and so that don't wake user up so often when
15*25202Skarels  * some intermediary hop has gone down on a (normally) fast connection.
16*25202Skarels  *
17*25202Skarels  * Revision 2.10  84/11/15  09:56:14  walsh
18*25202Skarels  * redid how we deal with compiler padding in the RDP header structure.
19*25202Skarels  *
20*25202Skarels  * Revision 2.9  84/11/08  16:12:06  walsh
21*25202Skarels  * Added code to gather statistics on RDP traffic.  This makes the RDPCB
22*25202Skarels  * too big unles you make mbufs 512 bytes large.  RDP_CS should be turned off
23*25202Skarels  * unless you do.
24*25202Skarels  *
25*25202Skarels  * Revision 2.8  84/11/06  15:24:54  walsh
26*25202Skarels  * *** empty log message ***
27*25202Skarels  *
28*25202Skarels  * Revision 2.7  84/11/05  15:54:34  walsh
29*25202Skarels  * update_nulltimer() macro began to look inappropriate with recent
30*25202Skarels  * changes, so its been stripped out and put in-line.
31*25202Skarels  *
32*25202Skarels  * Revision 2.6  84/11/05  12:42:34  walsh
33*25202Skarels  * Set things up so can debug RDP connections just like can debug TCP
34*25202Skarels  * connections.
35*25202Skarels  *
36*25202Skarels  * Revision 2.5  84/11/05  11:34:36  walsh
37*25202Skarels  * Don't let round trip time estimate drift upward on lossy networks.
38*25202Skarels  * Check for retransmissions of packets used to measure round trip time.
39*25202Skarels  *
40*25202Skarels  * Revision 2.4  84/11/05  10:47:38  walsh
41*25202Skarels  * More changes to go with NULL messages getting their own sequence
42*25202Skarels  * number.
43*25202Skarels  *
44*25202Skarels  * Revision 2.3  84/11/02  18:24:20  walsh
45*25202Skarels  * Protocol specifiers want NULL message to have own sequence number in
46*25202Skarels  * case of slow (t>NULL msg timeout) packets.  I don't see this as a problem,
47*25202Skarels  * and even if happened (dubious) would only delay discovery, but I
48*25202Skarels  * didn't win this one.  Initially not designed for this, but fixes are
49*25202Skarels  * in almost neatly.
50*25202Skarels  *
51*25202Skarels  * Revision 2.2  84/11/02  15:29:32  walsh
52*25202Skarels  * Allow for RDP header fields not on natural boundries.  (Protocol
53*25202Skarels  * specifiers say will be part of next version in 6-12 months).
54*25202Skarels  * Until then, there goes the speed...  Yucho modifications.
55*25202Skarels  *
56*25202Skarels  * Revision 2.1  84/11/02  10:14:11  walsh
57*25202Skarels  * Fixed to include RCS comments in checked out source.
58*25202Skarels  *
59*25202Skarels  *
60*25202Skarels  * description:
61*25202Skarels  * The state transition functions for the Reliable Datagram Protocol.
62*25202Skarels  *
63*25202Skarels  * revision 1.17
64*25202Skarels  * date: 84/07/24 16:58:17;  author: walsh;  state: Exp;  lines added/del: 2/2
65*25202Skarels  * When had gone to making retransmit took too long advisory,
66*25202Skarels  * had forgotten to change RDP_sCLOSED to RDP_sSAME.
67*25202Skarels  *
68*25202Skarels  * revision 1.16
69*25202Skarels  * date: 84/07/23 12:58:31;  author: walsh;  state: Exp;  lines added/del: 27/6
70*25202Skarels  * Clear all timers when enter close state.  Updates to protocol had not
71*25202Skarels  * been complete in this respect.
72*25202Skarels  *
73*25202Skarels  * Retransmission and acceptance in CLOSEWAIT do not seem to be in the cards
74*25202Skarels  * in dealing with protocol specifiers, so removed ### markers and commented.
75*25202Skarels  *
76*25202Skarels  * revision 1.15
77*25202Skarels  * date: 84/07/22 19:45:31;  author: walsh;  state: Exp;  lines added/del: 19/0
78*25202Skarels  * Added a state transition function rdp_closew_rcv() to compensate for
79*25202Skarels  * socket code's dropping of system priority level for a brief period of time.
80*25202Skarels  *
81*25202Skarels  * revision 1.14
82*25202Skarels  * date: 84/07/19 10:21:42;  author: walsh;  state: Exp;  lines added/del: 14/85
83*25202Skarels  * Organized macros and classified their definitions in rdp_macros.h.
84*25202Skarels  *
85*25202Skarels  * revision 1.13
86*25202Skarels  * date: 84/07/19 08:54:01;  author: walsh;  state: Exp;  lines added/del: 4/0
87*25202Skarels  * NULL message processing should start before receive a packet in ESTAB,
88*25202Skarels  * so start up NULL timer when enter ESTAB.
89*25202Skarels  *
90*25202Skarels  * revision 1.12
91*25202Skarels  * date: 84/07/18 18:50:55;  author: walsh;  state: Exp;  lines added/del: 36/5
92*25202Skarels  * Added provision for sending of NULL messages.  These are sent on an idle
93*25202Skarels  * connection to determine that the other side still exists.
94*25202Skarels  *
95*25202Skarels  * revision 1.11
96*25202Skarels  * date: 84/07/18 13:35:36;  author: walsh;  state: Exp;  lines added/del: 6/6
97*25202Skarels  * made provisions for user-adjustable RTTL time period.
98*25202Skarels  *
99*25202Skarels  * revision 1.10
100*25202Skarels  * date: 84/07/13 09:50:33;  author: walsh;  state: Exp;  lines added/del: 22/19
101*25202Skarels  * When first send datagram, we determine its length.
102*25202Skarels  * Might as wellsave that length in m_act for retransmission.
103*25202Skarels  *
104*25202Skarels  * revision 1.9
105*25202Skarels  * date: 84/07/12 13:48:22;  author: walsh;  state: Exp;  lines added/del: 1/0
106*25202Skarels  * Rather than in-line stuffing of IP/RDP headers, at least half of which are
107*25202Skarels  * constant, copy headers in from a template of what the headers are like.  The
108*25202Skarels  * bcopy() call is turned into a movc3 instruction on the VAX by a sed script
109*25202Skarels  * run over the assembler output of the C compiler.  Marginal speed-up.
110*25202Skarels  *
111*25202Skarels  * revision 1.8
112*25202Skarels  * date: 84/07/12 09:55:02;  author: walsh;  state: Exp;  lines added/del: 5/13
113*25202Skarels  * some small optimizations.
114*25202Skarels  *
115*25202Skarels  * revision 1.7
116*25202Skarels  * date: 84/07/10 14:48:13;  author: walsh;  state: Exp;  lines added/del: 1/1
117*25202Skarels  * Reduced amount of unnecessary wakeup action.
118*25202Skarels  *
119*25202Skarels  * revision 1.6
120*25202Skarels  * date: 84/07/10 10:28:33;  author: walsh;  state: Exp;  lines added/del: 35/35
121*25202Skarels  * Added register declarations.
122*25202Skarels  *
123*25202Skarels  * revision 1.5
124*25202Skarels  * date: 84/07/09 14:31:33;  author: walsh;  state: Exp;  lines added/del: 11/2
125*25202Skarels  * Added an ACK-delay algorithm to reduce cpu and network loading.
126*25202Skarels  *
127*25202Skarels  * revision 1.4
128*25202Skarels  * date: 84/07/08 21:36:47;  author: walsh;  state: Exp;  lines added/del: 3/3
129*25202Skarels  * changed some references to r_sendq.rq_baseseq to r_snduna for clarity.
130*25202Skarels  *
131*25202Skarels  * revision 1.3
132*25202Skarels  * date: 84/07/06 15:13:50;  author: wjacobso;  state: Exp;  lines added/del: 17/17
133*25202Skarels  * add register var definitions; use sndnxt-baseseq instead of maxqlen
134*25202Skarels  * to determine number of passes
135*25202Skarels  *
136*25202Skarels  * revision 1.2
137*25202Skarels  * date: 84/07/06 09:49:52;  author: root;  state: Exp;  lines added/del: 93/35
138*25202Skarels  * This version seems to run bug-free.
139*25202Skarels  *
140*25202Skarels  * revision 1.1
141*25202Skarels  * date: 84/06/26 14:18:09;  author: walsh;  state: Exp;
142*25202Skarels  * Initial revision
143*25202Skarels  */
144*25202Skarels 
145*25202Skarels 
146*25202Skarels #ifdef RDP
147*25202Skarels #include "../h/param.h"
148*25202Skarels #include "../h/dir.h"
149*25202Skarels #include "../h/user.h"
150*25202Skarels #include "../h/kernel.h"
151*25202Skarels #include "../h/inode.h"
152*25202Skarels #include "../h/mbuf.h"
153*25202Skarels #include "../h/socket.h"
154*25202Skarels #include "../h/socketvar.h"
155*25202Skarels #include "../h/errno.h"
156*25202Skarels #include "../h/syslog.h"
157*25202Skarels 
158*25202Skarels #include "../net/if.h"
159*25202Skarels #include "../net/route.h"
160*25202Skarels 
161*25202Skarels #include "../bbnnet/in.h"
162*25202Skarels #include "../bbnnet/net.h"
163*25202Skarels #include "../bbnnet/in_pcb.h"
164*25202Skarels #include "../bbnnet/in_var.h"
165*25202Skarels #include "../bbnnet/ip.h"
166*25202Skarels #include "../bbnnet/rdp.h"
167*25202Skarels #include "../bbnnet/seq.h"
168*25202Skarels #include "../bbnnet/rdp_macros.h"
169*25202Skarels 
170*25202Skarels extern struct rtentry *ip_route();
171*25202Skarels 
172*25202Skarels /*
173*25202Skarels  * Since a message just got through, re-associating rttl (retransmit
174*25202Skarels  * took too long) with some other current outstanding datagram (cf. wait
175*25202Skarels  * until some new dgram) is a little paranoid, but let's be careful
176*25202Skarels  * in case that new dgram doesn't come along for a while.  This also
177*25202Skarels  * allows us to decide that the check-for-retransmit and
178*25202Skarels  * retransmit-took-too-long timers can be cancelled.
179*25202Skarels  */
180*25202Skarels clear_rxtimer(rdpcb, N)
181*25202Skarels register RDPCB	*rdpcb;
182*25202Skarels {
183*25202Skarels     int Xi;
184*25202Skarels     int pass;
185*25202Skarels 
186*25202Skarels     rdpcb->r_rxtimers[N] = 0;
187*25202Skarels     if (rdpcb->r_rttlindex == N)
188*25202Skarels     {
189*25202Skarels 	/*
190*25202Skarels 	 * look for new dgram of which to check rttl
191*25202Skarels 	 */
192*25202Skarels 	Xi = rdpcb->r_sendq.rq_front;
193*25202Skarels 	pass = rdpcb->r_sndnxt - rdpcb->r_snduna;
194*25202Skarels 	while (--pass >= 0)
195*25202Skarels 	{
196*25202Skarels 	    if (rdpcb->r_rxtimers[Xi])
197*25202Skarels 	    {
198*25202Skarels 		rdpcb->r_rttlindex = Xi;
199*25202Skarels 		rdpcb->r_timers[RDP_tRTTL] = rdpcb->r_rttl;
200*25202Skarels 		return;
201*25202Skarels 	    }
202*25202Skarels 	    Xi = (Xi + 1) % rdpcb->r_sendq.rq_maxqlen;
203*25202Skarels 	}
204*25202Skarels 	/*
205*25202Skarels 	 * No outstanding dgrams left.
206*25202Skarels 	 */
207*25202Skarels 	rdpcb->r_rttlindex = (-1);
208*25202Skarels 	rdpcb->r_timers[RDP_tRTTL] = 0;
209*25202Skarels 	rdpcb->r_timers[RDP_tRXMIT] = 0;
210*25202Skarels     }
211*25202Skarels }
212*25202Skarels 
213*25202Skarels /*
214*25202Skarels  * set up things to discover the rtt (round trip time) for this
215*25202Skarels  * DATA-containing packet.
216*25202Skarels  */
217*25202Skarels #define time_rtt(rdpcb, seqnum) \
218*25202Skarels 	if (! (rdpcb)->r_rttiming){            \
219*25202Skarels 		(rdpcb)->r_rttiming = TRUE;    \
220*25202Skarels 		(rdpcb)->r_rtt = 0;            \
221*25202Skarels 		(rdpcb)->r_rttimed = (seqnum); \
222*25202Skarels 	}
223*25202Skarels 
224*25202Skarels 
225*25202Skarels /*
226*25202Skarels  * Since we play with sb_cc for the socket send buffer to prevent the
227*25202Skarels  * user process from sending packets we can't buffer, must ensure it
228*25202Skarels  * is restored to a reasonable value before call upon socket code to clean
229*25202Skarels  * up or we'll get a "panic: sbdrop".  Socket code is called by
230*25202Skarels  * in_pcbdetach().
231*25202Skarels  */
232*25202Skarels trash_pcbs(rdpcb)
233*25202Skarels RDPCB *rdpcb;
234*25202Skarels {
235*25202Skarels     register struct sockbuf *sosnd;
236*25202Skarels 
237*25202Skarels     sosnd = &rdpcb->r_inpcb->inp_socket->so_snd;
238*25202Skarels     if ((sosnd->sb_cc == sosnd->sb_hiwat) && (sosnd->sb_mb == NULL))
239*25202Skarels 	sosnd->sb_cc = 0;
240*25202Skarels     in_pcbdetach (rdpcb->r_inpcb, rdp_pcbdisconnect);
241*25202Skarels }
242*25202Skarels 
243*25202Skarels cancel_timers(rdpcb)
244*25202Skarels register RDPCB *rdpcb;
245*25202Skarels {
246*25202Skarels     register int i;
247*25202Skarels 
248*25202Skarels     for (i=0; i<RDP_NTIMERS; i++)
249*25202Skarels 	rdpcb->r_timers[i] = 0;
250*25202Skarels }
251*25202Skarels 
252*25202Skarels /************************************************************************/
253*25202Skarels 
254*25202Skarels /*
255*25202Skarels  *	state: RDP_sUNOPENED
256*25202Skarels  *	input: RDP_iCONNECT
257*25202Skarels  */
258*25202Skarels /*ARGSUSED*/
259*25202Skarels rdp_unop_connect (rdpcb, nil)
260*25202Skarels register RDPCB	*rdpcb;
261*25202Skarels {
262*25202Skarels     /*
263*25202Skarels      * Send a SYN
264*25202Skarels      * and set re-transmission timer to ensure SYN eventually gets there
265*25202Skarels      */
266*25202Skarels     (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_iss);
267*25202Skarels     set_rxtimer (rdpcb, 0);
268*25202Skarels     return (RDP_sSYNSENT);
269*25202Skarels }
270*25202Skarels 
271*25202Skarels /*
272*25202Skarels  *	state: RDP_sUNOPENED
273*25202Skarels  *	input: RDP_iLISTEN
274*25202Skarels  */
275*25202Skarels /*ARGSUSED*/
276*25202Skarels rdp_unop_listen (rdpcb, nil)
277*25202Skarels RDPCB	*rdpcb;
278*25202Skarels {
279*25202Skarels     return (RDP_sLISTEN);
280*25202Skarels }
281*25202Skarels 
282*25202Skarels /*
283*25202Skarels  *	state: RDP_sUNOPENED
284*25202Skarels  *	input: RDP_iNETR
285*25202Skarels  */
286*25202Skarels /*ARGSUSED*/
287*25202Skarels rdp_unop_netr (rdpcb, pkt)
288*25202Skarels RDPCB	*rdpcb;
289*25202Skarels register RDPHDR	*pkt;
290*25202Skarels {
291*25202Skarels     if (pkt->rh_flags & (RDP_fACK|RDP_fEACK|RDP_fNULL))
292*25202Skarels 	/*
293*25202Skarels 	 * We haven't sent anything to (e)ack.  Nor have we
294*25202Skarels 	 * established a connection and received something
295*25202Skarels 	 * that we should ack (null).  The sender is very mixed
296*25202Skarels 	 * up, so we'll send him a reset.
297*25202Skarels 	 */
298*25202Skarels 	rdp_uncon_rst (pkt);
299*25202Skarels     else
300*25202Skarels 	/*
301*25202Skarels 	 * ignore packet in hope user connect(2)s or listen(2)s before
302*25202Skarels 	 * it's re-transmission comes in.
303*25202Skarels 	 */
304*25202Skarels 	m_freem(dtom(pkt));
305*25202Skarels 
306*25202Skarels     return (RDP_sSAME);
307*25202Skarels }
308*25202Skarels 
309*25202Skarels /*
310*25202Skarels  *	state: RDP_sUNOPENED
311*25202Skarels  *	input: RDP_iUCLOSE
312*25202Skarels  */
313*25202Skarels /*ARGSUSED*/
314*25202Skarels rdp_unop_close (rdpcb, nil)
315*25202Skarels RDPCB	*rdpcb;
316*25202Skarels {
317*25202Skarels     trash_pcbs(rdpcb);
318*25202Skarels     return (RDP_sCLOSED);
319*25202Skarels }
320*25202Skarels 
321*25202Skarels /************************************************************************/
322*25202Skarels 
323*25202Skarels /*
324*25202Skarels  *	state: RDP_sLISTEN
325*25202Skarels  *	input: RDP_iLISTEN
326*25202Skarels  */
327*25202Skarels /*ARGSUSED*/
328*25202Skarels rdp_lis_listen (rdpcb, nil)
329*25202Skarels RDPCB	*rdpcb;
330*25202Skarels {
331*25202Skarels     return (RDP_sSAME);
332*25202Skarels }
333*25202Skarels 
334*25202Skarels /*
335*25202Skarels  *	state: RDP_sLISTEN
336*25202Skarels  *	input: RDP_iNETR
337*25202Skarels  */
338*25202Skarels rdp_lis_netr (rdpcb, pkt)
339*25202Skarels RDPCB	*rdpcb;
340*25202Skarels register RDPHDR		*pkt;
341*25202Skarels {
342*25202Skarels     INPCB	*inp;
343*25202Skarels     struct socket	*so;
344*25202Skarels     struct rtentry	*rt;
345*25202Skarels     register RDPCB		*newrdpcb;
346*25202Skarels     register INPCB		*newinp;
347*25202Skarels     struct socket	*newso;
348*25202Skarels     register struct ip	*ip;
349*25202Skarels     register SYNOPTIONS	*synopt;
350*25202Skarels 
351*25202Skarels     if (pkt->rh_flags & (RDP_fRST|RDP_fACK|RDP_fEACK|RDP_fNULL))
352*25202Skarels     {
353*25202Skarels 	if (pkt->rh_flags & RDP_fRST)
354*25202Skarels 	    /*
355*25202Skarels 	     * Ignore resets since we haven't sent anything to
356*25202Skarels 	     * reset.  The packet may be a slow arrival meant to
357*25202Skarels 	     * close a child socket of ours that has already
358*25202Skarels 	     * finished close protocol with this sender.  We
359*25202Skarels 	     * ignore it and the other end closes/closed on its own.
360*25202Skarels 	     */
361*25202Skarels 	    m_freem(dtom(pkt));
362*25202Skarels 	else
363*25202Skarels 	    /*
364*25202Skarels 	     * We haven't sent anything to (e)ack.  Nor have we
365*25202Skarels 	     * established a connection and received something
366*25202Skarels 	     * that we should ack (null).  The sender is very mixed
367*25202Skarels 	     * up, so we'll send him a reset.
368*25202Skarels 	     */
369*25202Skarels 	    rdp_uncon_rst (pkt);
370*25202Skarels 
371*25202Skarels 	return (RDP_sSAME);
372*25202Skarels     }
373*25202Skarels 
374*25202Skarels     if (pkt->rh_flags & RDP_fSYN)
375*25202Skarels     {
376*25202Skarels 	/* normal case, someone is trying to connect to us. */
377*25202Skarels 
378*25202Skarels 	ip = (struct ip *) (((char *) pkt) - sizeof(struct ip));
379*25202Skarels 
380*25202Skarels 	/*
381*25202Skarels 	 * O.k., let's get a route back to him
382*25202Skarels 	 */
383*25202Skarels 	if (!(rt = ip_route(&ip->ip_dst, &ip->ip_src)))
384*25202Skarels 	{
385*25202Skarels 	    /*
386*25202Skarels 	     * Can't talk to him.  Leave socket in receive state
387*25202Skarels 	     * so we can connect to someone else, since we haven't
388*25202Skarels 	     * been committed to anything yet anyway.
389*25202Skarels 	     * Drop his info on the floor.
390*25202Skarels 	     * Let the other machine figure out on it's own
391*25202Skarels 	     * that it can't reach us that way.
392*25202Skarels 	     */
393*25202Skarels 	    no_route ("rdp", ip->ip_dst, ip->ip_src);
394*25202Skarels 	    m_freem(dtom(pkt));
395*25202Skarels 	    return(RDP_sSAME);
396*25202Skarels 	}
397*25202Skarels 
398*25202Skarels 	inp = rdpcb->r_inpcb;
399*25202Skarels 	so = inp->inp_socket;
400*25202Skarels 
401*25202Skarels 	/*
402*25202Skarels 	 * This socket is in the listen state, so the socket should have
403*25202Skarels 	 * so_options & SO_ACCEPTCONN set (solisten()).
404*25202Skarels 	 *
405*25202Skarels 	 * The order of sonewconn() and soisconnected() is
406*25202Skarels 	 * important, in order for the process to be woken up
407*25202Skarels 	 * at a time when the sleep condition is fulfilled.
408*25202Skarels 	 * sonewconn() is done here on the original socket, and
409*25202Skarels 	 * soisconnected() is done later in rdp_lsynrcvd_netr() on
410*25202Skarels 	 * the new socket.
411*25202Skarels 	 */
412*25202Skarels 	if (newso = sonewconn(so))
413*25202Skarels 	{
414*25202Skarels 	    newinp = (INPCB *) newso->so_pcb;
415*25202Skarels 	    newrdpcb = (RDPCB *) newinp->inp_ppcb;
416*25202Skarels 	    /*
417*25202Skarels 	     * Remember our peer for this connection.
418*25202Skarels 	     */
419*25202Skarels 	    newinp->inp_faddr = ip->ip_src;
420*25202Skarels 	    newinp->inp_fport = pkt->rh_sport;
421*25202Skarels 	    newinp->inp_laddr = ip->ip_dst;
422*25202Skarels 	    /*
423*25202Skarels 	     * and copy fields into the new inpcb
424*25202Skarels 	     */
425*25202Skarels 	    newinp->inp_lport = inp->inp_lport;
426*25202Skarels 	    newinp->inp_route.ro_rt = rt;
427*25202Skarels 	    /*
428*25202Skarels 	     * and copy fields into the new rdpcb.  In particular,
429*25202Skarels 	     * the user's desired buffering allocations should be
430*25202Skarels 	     * propogated.
431*25202Skarels 	     */
432*25202Skarels 	    newrdpcb->r_ournbuf = rdpcb->r_ournbuf;
433*25202Skarels 	    sbreserve (&newrdpcb->r_inpcb->inp_socket->so_rcv,
434*25202Skarels 		rdpcb->r_inpcb->inp_socket->so_rcv.sb_hiwat);
435*25202Skarels 	    pick_ourmaxlen(newrdpcb);
436*25202Skarels 	    /*
437*25202Skarels 	     * Sequential delivery is a combination of both side's
438*25202Skarels 	     * desires, and must be copied from server socket since
439*25202Skarels 	     * user does not have a handle on the child socket in
440*25202Skarels 	     * it's early states.
441*25202Skarels 	     */
442*25202Skarels 	    newrdpcb->r_sequential = rdpcb->r_sequential;
443*25202Skarels 
444*25202Skarels 	    /*
445*25202Skarels 	     * and stuff new information
446*25202Skarels 	     */
447*25202Skarels 	    got_syn(newrdpcb, RDP_SEQNO(pkt));
448*25202Skarels 	    synopt = RDP_OPT(pkt, SYNOPTIONS *);
449*25202Skarels 	    process_synopt(newrdpcb, synopt);
450*25202Skarels 
451*25202Skarels 	    /*
452*25202Skarels 	     * So can debug connection problems without having to
453*25202Skarels 	     * change every program or apply debugging flag to each
454*25202Skarels 	     * program every time run it.
455*25202Skarels 	     */
456*25202Skarels 	    dowedebug(newinp, newso, &rdp_dfilter);
457*25202Skarels 
458*25202Skarels 	    /*
459*25202Skarels 	     * send other guy our SYN and ACK his syn.
460*25202Skarels 	     * set re-transmission timer to ensure eventually gets
461*25202Skarels 	     * to him.
462*25202Skarels 	     */
463*25202Skarels 	    rdp_template(newrdpcb);
464*25202Skarels 	    (void) rdp_sendpkt (newrdpcb, (MBUF *) NULL, 0,
465*25202Skarels 		newrdpcb->r_iss);
466*25202Skarels 	    set_rxtimer (newrdpcb, 0);
467*25202Skarels 
468*25202Skarels 	    newrdpcb->r_state = RDP_sLSYNRCVD;
469*25202Skarels 	}
470*25202Skarels 	else
471*25202Skarels 	rtfree(rt);
472*25202Skarels     }
473*25202Skarels     m_freem(dtom(pkt));
474*25202Skarels     return (RDP_sSAME);
475*25202Skarels }
476*25202Skarels 
477*25202Skarels /*
478*25202Skarels  *	state: RDP_sLISTEN
479*25202Skarels  *	input: RDP_iUCLOSE
480*25202Skarels  */
481*25202Skarels /*ARGSUSED*/
482*25202Skarels rdp_lis_close (rdpcb, nil)
483*25202Skarels RDPCB	*rdpcb;
484*25202Skarels {
485*25202Skarels     trash_pcbs(rdpcb);
486*25202Skarels     return (RDP_sCLOSED);
487*25202Skarels }
488*25202Skarels 
489*25202Skarels /************************************************************************/
490*25202Skarels 
491*25202Skarels /*
492*25202Skarels  *	state: RDP_sSYNSENT
493*25202Skarels  *	input: RDP_iNETR
494*25202Skarels  */
495*25202Skarels rdp_synsent_netr (rdpcb, pkt)
496*25202Skarels register RDPCB	*rdpcb;
497*25202Skarels register RDPHDR	*pkt;
498*25202Skarels {
499*25202Skarels     register rdpstate newstate;
500*25202Skarels 
501*25202Skarels     if (pkt->rh_flags & RDP_fACK)
502*25202Skarels     {
503*25202Skarels 	if (RDP_ACKNO(pkt) != rdpcb->r_iss)
504*25202Skarels 	{
505*25202Skarels 	    /*
506*25202Skarels 	     * We haven't sent any data yet, only SYNs.
507*25202Skarels 	     * He's confused.
508*25202Skarels 	     */
509*25202Skarels 	    rdp_uncon_rst (pkt);
510*25202Skarels 	    return (RDP_sSAME);
511*25202Skarels 	}
512*25202Skarels     }
513*25202Skarels 
514*25202Skarels     if (pkt->rh_flags & RDP_fRST)
515*25202Skarels     {
516*25202Skarels 	/*
517*25202Skarels 	 * Require (rst, ack, ackno) to know rst meant for this, not
518*25202Skarels 	 * a previous, incarnation of the socket.  Is an "in window"
519*25202Skarels 	 * check.  Avoids problems with "slow" packets.
520*25202Skarels 	 */
521*25202Skarels 	if (pkt->rh_flags & RDP_fACK)
522*25202Skarels 	{
523*25202Skarels 	    set_error (rdpcb, ECONNREFUSED);
524*25202Skarels 	    trash_pcbs(rdpcb);
525*25202Skarels 	    newstate = RDP_sCLOSED;
526*25202Skarels 	}
527*25202Skarels 	else
528*25202Skarels 	    newstate = RDP_sSAME;
529*25202Skarels 	m_freem(dtom(pkt));
530*25202Skarels 	return (newstate);
531*25202Skarels     }
532*25202Skarels 
533*25202Skarels     newstate = RDP_sSAME;
534*25202Skarels     if (pkt->rh_flags & RDP_fSYN)
535*25202Skarels     {
536*25202Skarels 	register SYNOPTIONS	*synopt;
537*25202Skarels 	rdpsequence seqnum;
538*25202Skarels 
539*25202Skarels 	got_syn(rdpcb, RDP_SEQNO(pkt));
540*25202Skarels 	synopt = RDP_OPT(pkt, SYNOPTIONS *);
541*25202Skarels 	process_synopt(rdpcb, synopt);
542*25202Skarels 
543*25202Skarels 	if (pkt->rh_flags & RDP_fACK)
544*25202Skarels 	{
545*25202Skarels 	    rdpcb->r_synacked = TRUE;
546*25202Skarels 	    rdpisconnected(rdpcb);
547*25202Skarels 	    newstate = RDP_sESTAB;
548*25202Skarels 	    seqnum = rdpcb->r_iss +1;
549*25202Skarels 	    /* clear re-xmit syn timer set in rdp_unop_connect() */
550*25202Skarels 	    clear_rxtimer (rdpcb, 0);
551*25202Skarels 	    /* start up connection loss detection */
552*25202Skarels 	    rdpcb->r_timers[RDP_tNULL] = rdpcb->r_tvnull;
553*25202Skarels 	}
554*25202Skarels 	else
555*25202Skarels 	{
556*25202Skarels 	    newstate = RDP_sSYNRCVD;
557*25202Skarels 	    seqnum = rdpcb->r_iss;
558*25202Skarels 	    /* keep sending syn until he acks it */
559*25202Skarels 	    set_rxtimer (rdpcb, 0);
560*25202Skarels 	}
561*25202Skarels 	/* and ack his syn, retransmit ours if necessary */
562*25202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, seqnum);
563*25202Skarels     }
564*25202Skarels 
565*25202Skarels     m_freem(dtom(pkt));
566*25202Skarels     return (newstate);
567*25202Skarels }
568*25202Skarels 
569*25202Skarels /*
570*25202Skarels  *	state: RDP_sSYNSENT
571*25202Skarels  *	input: RDP_iUCLOSE
572*25202Skarels  */
573*25202Skarels /*ARGSUSED*/
574*25202Skarels rdp_synsent_close (rdpcb, nil)
575*25202Skarels register RDPCB *rdpcb;
576*25202Skarels {
577*25202Skarels     /* send RST */
578*25202Skarels     rdpcb->r_sendrst = TRUE;
579*25202Skarels     (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
580*25202Skarels     trash_pcbs(rdpcb);
581*25202Skarels     return (RDP_sCLOSED);
582*25202Skarels }
583*25202Skarels 
584*25202Skarels 
585*25202Skarels /*
586*25202Skarels  *	state: RDP_sSYNSENT
587*25202Skarels  *	input: RDP_iTIMER
588*25202Skarels  */
589*25202Skarels rdp_synsent_timer (rdpcb, timer)
590*25202Skarels register RDPCB *rdpcb;
591*25202Skarels {
592*25202Skarels     switch (timer)
593*25202Skarels     {
594*25202Skarels       case RDP_tRTTL:
595*25202Skarels 	/* retransmission took too long */
596*25202Skarels 	rttl(rdpcb);
597*25202Skarels 	return (RDP_sSAME);
598*25202Skarels 
599*25202Skarels       case RDP_tRXMIT:
600*25202Skarels 	/*
601*25202Skarels 	 * re-transmit our SYN.  Not every 0.5 second, though,
602*25202Skarels 	 * but every RDP_tvRXMIN units.
603*25202Skarels 	 */
604*25202Skarels 	rdpcb->r_rxtimers[0] --;
605*25202Skarels 	if (rdpcb->r_rxtimers[0] == 0)
606*25202Skarels 	{
607*25202Skarels 	    (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0,
608*25202Skarels 		rdpcb->r_iss);
609*25202Skarels 	    set_rxtimer (rdpcb, 0);
610*25202Skarels #ifdef RDP_CS
611*25202Skarels 	    rdpcb->r_sent.r_retrans ++;
612*25202Skarels #endif
613*25202Skarels 	}
614*25202Skarels 	else
615*25202Skarels 	    /*
616*25202Skarels 	     * ensure keep checking even if no packet goes
617*25202Skarels 	     * out this time.  ACK will stop this.
618*25202Skarels 	     */
619*25202Skarels 	    rdpcb->r_timers[RDP_tRXMIT] = RDP_tvRXCHECK;
620*25202Skarels 	break;
621*25202Skarels 
622*25202Skarels       default:
623*25202Skarels 	log(KERN_RECOV, "rdp_synsent_timer:  timer %d\n", timer);
624*25202Skarels     }
625*25202Skarels 
626*25202Skarels     return(RDP_sSAME);
627*25202Skarels }
628*25202Skarels 
629*25202Skarels /************************************************************************/
630*25202Skarels 
631*25202Skarels /*
632*25202Skarels  *	state: RDP_sLSYNRCVD
633*25202Skarels  *	input: RDP_iNETR
634*25202Skarels  */
635*25202Skarels rdp_lsynrcvd_netr (rdpcb, pkt)
636*25202Skarels register RDPCB		*rdpcb;
637*25202Skarels register RDPHDR		*pkt;
638*25202Skarels {
639*25202Skarels     /*
640*25202Skarels      * If it's a duplicate syn (seqno == irs), re-send ack since he must
641*25202Skarels      * have missed our ack.  If it's out of the window, well, let's give
642*25202Skarels      * him the benefit of the doubt and assume it's junk from an old
643*25202Skarels      * connection/window that took a while to get to us.
644*25202Skarels      */
645*25202Skarels     if (SEQ_LEQ(RDP_SEQNO(pkt), rdpcb->r_irs) ||
646*25202Skarels 	SEQ_GEQ(RDP_SEQNO(pkt), rdpcb->r_rcvq.rq_baseseq + rdpcb->r_rcvq.rq_maxqlen))
647*25202Skarels     {
648*25202Skarels 
649*25202Skarels #ifdef RDP_CS
650*25202Skarels 	rdpcb->r_rcvd.r_retrans ++;
651*25202Skarels #endif
652*25202Skarels 	/* try to synchronize again */
653*25202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_iss);
654*25202Skarels 	m_freem(dtom(pkt));
655*25202Skarels 	return(RDP_sSAME);
656*25202Skarels     }
657*25202Skarels 
658*25202Skarels     if (pkt->rh_flags & (RDP_fRST|RDP_fEACK|RDP_fSYN))
659*25202Skarels     {
660*25202Skarels 	if (pkt->rh_flags & RDP_fRST)
661*25202Skarels 	{
662*25202Skarels 	    /*
663*25202Skarels 	     * User closed while his socket was in synsent state.
664*25202Skarels 	     */
665*25202Skarels 	    set_error (rdpcb, ECONNREFUSED);
666*25202Skarels 	    trash_pcbs(rdpcb);
667*25202Skarels 	    m_freem(dtom(pkt));
668*25202Skarels 	    return (RDP_sCLOSED);
669*25202Skarels 	}
670*25202Skarels 	if (pkt->rh_flags & RDP_fEACK)
671*25202Skarels 	{
672*25202Skarels 	    /*
673*25202Skarels 	     * shouldn't be EACK, since we haven't sent anything yet
674*25202Skarels 	     */
675*25202Skarels 	    rdp_uncon_rst (pkt);	/* frees mbufs for pkt */
676*25202Skarels 	    return(RDP_sSAME);
677*25202Skarels 	}
678*25202Skarels 	if (pkt->rh_flags & RDP_fSYN)
679*25202Skarels 	{
680*25202Skarels 	    /*
681*25202Skarels 	     * Boy, is the other end confused!  His syn has changed
682*25202Skarels 	     * sequence numbers.
683*25202Skarels 	     */
684*25202Skarels 	    rdp_uncon_rst (pkt);
685*25202Skarels 	    set_error (rdpcb, ECONNRESET);
686*25202Skarels 	    trash_pcbs(rdpcb);
687*25202Skarels 	    return (RDP_sCLOSED);
688*25202Skarels 	}
689*25202Skarels     }
690*25202Skarels 
691*25202Skarels     if (pkt->rh_flags & RDP_fACK)
692*25202Skarels     {
693*25202Skarels 	if (RDP_ACKNO(pkt) != rdpcb->r_iss)
694*25202Skarels 	{
695*25202Skarels 	    rdp_uncon_rst (pkt);	/* frees mbufs for pkt */
696*25202Skarels 	    return(RDP_sSAME);
697*25202Skarels 	}
698*25202Skarels     }
699*25202Skarels     else
700*25202Skarels     {
701*25202Skarels 	m_freem(dtom(pkt));
702*25202Skarels 	return(RDP_sSAME);
703*25202Skarels     }
704*25202Skarels 
705*25202Skarels     /*
706*25202Skarels      * clear timer for re-transmission of syn that we set in
707*25202Skarels      * rdp_lis_netr().
708*25202Skarels      */
709*25202Skarels     clear_rxtimer (rdpcb, 0);
710*25202Skarels     rdpcb->r_synacked = TRUE;
711*25202Skarels 
712*25202Skarels 
713*25202Skarels     if (pkt->rh_dlen > rdpcb->r_ourmaxlen)
714*25202Skarels     {
715*25202Skarels 	log(KERN_RECOV, "RDP too large packet %d > %d\n",
716*25202Skarels 	    pkt->rh_dlen, rdpcb->r_ourmaxlen);
717*25202Skarels theygoofed :
718*25202Skarels 	rdp_uncon_rst(pkt);
719*25202Skarels 	rdpcb->r_timers[RDP_tCLOSEWAIT] = rdpcb->r_closewait;
720*25202Skarels 	set_error(rdpcb, ECONNRESET);
721*25202Skarels 	return (RDP_sCLOSEWAIT);
722*25202Skarels     }
723*25202Skarels     /*
724*25202Skarels      * zero length packets can be NULL messages or (E)ACKs,
725*25202Skarels      * but all NULL messages must be zero length
726*25202Skarels      */
727*25202Skarels     if (pkt->rh_flags & RDP_fNULL)
728*25202Skarels     {
729*25202Skarels 	if (pkt->rh_dlen != 0)
730*25202Skarels 	{
731*25202Skarels 	    log(KERN_RECOV, "RDP %d length NULL packet\n", pkt->rh_dlen);
732*25202Skarels 	    goto theygoofed;
733*25202Skarels 	}
734*25202Skarels 	if (RDP_SEQNO(pkt) != rdpcb->r_rcvq.rq_baseseq)
735*25202Skarels 	{
736*25202Skarels 	    log(KERN_RECOV, "RDP NULL 0x%x rcvq baseseq 0x%x\n",
737*25202Skarels 		RDP_SEQNO(pkt), rdpcb->r_rcvq.rq_baseseq);
738*25202Skarels 	    goto theygoofed;
739*25202Skarels 	}
740*25202Skarels 	rdpcb->r_rcvq.rq_msgs[rdpcb->r_rcvq.rq_front] = NULL;
741*25202Skarels 	rdpcb->r_rcvq.rq_front =
742*25202Skarels 	    (rdpcb->r_rcvq.rq_front +1) % rdpcb->r_rcvq.rq_maxqlen;
743*25202Skarels 	rdpcb->r_rcvq.rq_baseseq ++;
744*25202Skarels 
745*25202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
746*25202Skarels 	m_freem(dtom(pkt));
747*25202Skarels     }
748*25202Skarels     else if (pkt->rh_dlen)
749*25202Skarels     {
750*25202Skarels #ifdef RDP_CS
751*25202Skarels 	if (rdp_qinsert (&rdpcb->r_rcvq, dtom(pkt), RDP_SEQNO(pkt)) == -1)
752*25202Skarels 	    rdpcb->r_rcvd.r_retrans ++;
753*25202Skarels #else
754*25202Skarels 	(void) rdp_qinsert (&rdpcb->r_rcvq, dtom(pkt), RDP_SEQNO(pkt));
755*25202Skarels #endif
756*25202Skarels 	/* No (e)ack now.  Wait til gets to user */
757*25202Skarels     }
758*25202Skarels     else
759*25202Skarels 	/* Was an ACK-only packet */
760*25202Skarels 	m_freem(dtom(pkt));
761*25202Skarels 
762*25202Skarels 
763*25202Skarels     rdpisconnected(rdpcb);
764*25202Skarels     /* start up connection loss detection */
765*25202Skarels     rdpcb->r_timers[RDP_tNULL] = rdpcb->r_tvnull;
766*25202Skarels     return (RDP_sESTAB);
767*25202Skarels }
768*25202Skarels 
769*25202Skarels /*
770*25202Skarels  *	state: RDP_sLSYNRCVD
771*25202Skarels  *	input: RDP_iUCLOSE
772*25202Skarels  */
773*25202Skarels /*ARGSUSED*/
774*25202Skarels rdp_lsynrcvd_close (rdpcb, nil)
775*25202Skarels register RDPCB *rdpcb;
776*25202Skarels {
777*25202Skarels     /* send RST */
778*25202Skarels     rdpcb->r_sendrst = TRUE;
779*25202Skarels     (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
780*25202Skarels     trash_pcbs(rdpcb);
781*25202Skarels     return (RDP_sCLOSED);
782*25202Skarels }
783*25202Skarels 
784*25202Skarels /*
785*25202Skarels  *	state: RDP_sLSYNRCVD
786*25202Skarels  *	input: RDP_iTIMER
787*25202Skarels  */
788*25202Skarels rdp_lsynrcvd_timer (rdpcb, timer)
789*25202Skarels RDPCB	*rdpcb;
790*25202Skarels {
791*25202Skarels     /* whether connecting via connect(2) (SYNSENT) or child of
792*25202Skarels      * or via child of a listen(2)ing socket (LSYNRCVD), need to
793*25202Skarels      * retransmit out syn until it gets acked.
794*25202Skarels      */
795*25202Skarels 
796*25202Skarels 
797*25202Skarels     return (rdp_synsent_timer (rdpcb, timer));
798*25202Skarels }
799*25202Skarels 
800*25202Skarels /************************************************************************/
801*25202Skarels 
802*25202Skarels /*
803*25202Skarels  *	state: RDP_sSYNRCVD
804*25202Skarels  *	input: RDP_iNETR
805*25202Skarels  */
806*25202Skarels rdp_synrcvd_netr (rdpcb, pkt)
807*25202Skarels RDPCB	*rdpcb;
808*25202Skarels RDPHDR	*pkt;
809*25202Skarels {
810*25202Skarels     return (rdp_lsynrcvd_netr(rdpcb, pkt));
811*25202Skarels }
812*25202Skarels 
813*25202Skarels /*
814*25202Skarels  *	state: RDP_sSYNRCVD
815*25202Skarels  *	input: RDP_iUCLOSE
816*25202Skarels  */
817*25202Skarels rdp_synrcvd_close (rdpcb, nil)
818*25202Skarels RDPCB	*rdpcb;
819*25202Skarels {
820*25202Skarels     return (rdp_lsynrcvd_close(rdpcb, nil));
821*25202Skarels }
822*25202Skarels 
823*25202Skarels /*
824*25202Skarels  *	state: RDP_sSYNRCVD
825*25202Skarels  *	input: RDP_iTIMER
826*25202Skarels  */
827*25202Skarels rdp_synrcvd_timer (rdpcb, timer)
828*25202Skarels RDPCB	*rdpcb;
829*25202Skarels {
830*25202Skarels     return (rdp_lsynrcvd_timer (rdpcb, timer));
831*25202Skarels }
832*25202Skarels 
833*25202Skarels /************************************************************************/
834*25202Skarels 
835*25202Skarels /*
836*25202Skarels  *	state: RDP_sESTAB
837*25202Skarels  *	input: RDP_iNETR
838*25202Skarels  */
839*25202Skarels rdp_estab_netr (rdpcb, pkt)
840*25202Skarels register RDPCB		*rdpcb;
841*25202Skarels register RDPHDR		*pkt;
842*25202Skarels {
843*25202Skarels     /*
844*25202Skarels      * ensure packet is in window.  If not, ack him to straighten things
845*25202Skarels      * out.
846*25202Skarels      */
847*25202Skarels     if (SEQ_LT(RDP_SEQNO(pkt), rdpcb->r_rcvq.rq_baseseq) ||
848*25202Skarels 	SEQ_GEQ(RDP_SEQNO(pkt), rdpcb->r_rcvq.rq_baseseq + rdpcb->r_rcvq.rq_maxqlen))
849*25202Skarels     {
850*25202Skarels #ifdef RDP_CS
851*25202Skarels 	rdpcb->r_rcvd.r_retrans ++;
852*25202Skarels #endif
853*25202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
854*25202Skarels 	m_freem(dtom(pkt));
855*25202Skarels 	return (RDP_sSAME);
856*25202Skarels     }
857*25202Skarels 
858*25202Skarels     /*
859*25202Skarels      * Whenever we receive a packet and we're not already waiting for
860*25202Skarels      * an ack of a NULL we sent, reset NULL timer.  Connection is alive.
861*25202Skarels      *
862*25202Skarels      * Don't reset for any packet if have an outstanding NULL since want
863*25202Skarels      * to keep timer at zero and not generate a new NULL segment until
864*25202Skarels      * current one is acknowledged.  (This might be a new message, not
865*25202Skarels      * the NULL's ack.  Send and receive paths may differ?)
866*25202Skarels      *
867*25202Skarels      * Don't reset NULL timer on datagram transmissions since those imply
868*25202Skarels      * receiving ACKs.  Besides, we want to know if he is up, not if we're
869*25202Skarels      * up.
870*25202Skarels      */
871*25202Skarels     if (rdpcb->r_nullsent == 0)
872*25202Skarels 	rdpcb->r_timers[RDP_tNULL] = rdpcb->r_tvnull;
873*25202Skarels 
874*25202Skarels     if (pkt->rh_flags &  (RDP_fSYN|RDP_fRST))
875*25202Skarels     {
876*25202Skarels 	m_freem(dtom(pkt));
877*25202Skarels 	set_error(rdpcb, ECONNRESET);
878*25202Skarels 
879*25202Skarels 	if (pkt->rh_flags & RDP_fSYN)
880*25202Skarels 	{
881*25202Skarels 	    /*
882*25202Skarels 	     * We've gotten past the syn stage.  He's confused.
883*25202Skarels 	     * His syn has also changed sequence numbers.
884*25202Skarels 	     */
885*25202Skarels 	    rdpcb->r_sendrst = TRUE;
886*25202Skarels 	    (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
887*25202Skarels 	    trash_pcbs(rdpcb);
888*25202Skarels 	    return (RDP_sCLOSED);
889*25202Skarels 	}
890*25202Skarels 
891*25202Skarels 	/*
892*25202Skarels 	 * Since we've been reset, the user cannot send anymore
893*25202Skarels 	 * datagrams.  user_cantsendmore() also wakes writers up
894*25202Skarels 	 * in case he is doing synchronous i/o and is waiting for
895*25202Skarels 	 * buffering space at the (socket) level.
896*25202Skarels 	 */
897*25202Skarels 	user_cantsendmore(rdpcb);
898*25202Skarels 	/*
899*25202Skarels 	 * User can't read anymore either, per specification.
900*25202Skarels 	 * Reliable delivery and acceptance must be determined
901*25202Skarels 	 * by the application before closing.
902*25202Skarels 	 */
903*25202Skarels 	user_cantreadmore(rdpcb);
904*25202Skarels 	cancel_timers(rdpcb);
905*25202Skarels 	rdpcb->r_timers[RDP_tCLOSEWAIT] = rdpcb->r_closewait;
906*25202Skarels 	return (RDP_sCLOSEWAIT);
907*25202Skarels     }
908*25202Skarels 
909*25202Skarels     if (pkt->rh_flags & RDP_fACK)
910*25202Skarels 	he_acked (rdpcb, RDP_ACKNO(pkt));
911*25202Skarels 
912*25202Skarels     if (pkt->rh_flags & RDP_fEACK)
913*25202Skarels     {
914*25202Skarels 	register int		 neacks;
915*25202Skarels 	register EACKOPTIONS	*eackopt;
916*25202Skarels 
917*25202Skarels 	neacks = (hdrlen(pkt) - RDPHDRSZ) / sizeof(EACKOPTIONS);
918*25202Skarels 	eackopt = RDP_OPT(pkt, EACKOPTIONS *);
919*25202Skarels 	while (--neacks >= 0)
920*25202Skarels 	{
921*25202Skarels 	    he_eacked (rdpcb, ntohl(eackopt->rh_eackno));
922*25202Skarels 	    eackopt ++;
923*25202Skarels 	}
924*25202Skarels     }
925*25202Skarels 
926*25202Skarels     if (pkt->rh_dlen > rdpcb->r_ourmaxlen)
927*25202Skarels     {
928*25202Skarels 	log(KERN_RECOV, "RDP pkt too large %d > %d\n",
929*25202Skarels 	    pkt->rh_dlen, rdpcb->r_ourmaxlen);
930*25202Skarels theygoofed :
931*25202Skarels 	rdp_uncon_rst(pkt);
932*25202Skarels 	set_error(rdpcb, ECONNRESET);
933*25202Skarels 	user_cantsendmore(rdpcb);
934*25202Skarels 	user_cantreadmore(rdpcb);
935*25202Skarels 	cancel_timers(rdpcb);
936*25202Skarels 	rdpcb->r_timers[RDP_tCLOSEWAIT] = rdpcb->r_closewait;
937*25202Skarels 	return (RDP_sCLOSEWAIT);
938*25202Skarels     }
939*25202Skarels 
940*25202Skarels     if (pkt->rh_flags & RDP_fNULL)
941*25202Skarels     {
942*25202Skarels 	if (pkt->rh_dlen != 0)
943*25202Skarels 	{
944*25202Skarels 	    log(KERN_RECOV, "RDP %d length NULL pkt\n", pkt->rh_dlen);
945*25202Skarels 	    goto theygoofed;
946*25202Skarels 	}
947*25202Skarels 	if (RDP_SEQNO(pkt) != rdpcb->r_rcvq.rq_baseseq)
948*25202Skarels 	{
949*25202Skarels 	    log(KERN_RECOV, "RDP NULL 0x%x rcvq baseseq 0x%x\n",
950*25202Skarels 		RDP_SEQNO(pkt), rdpcb->r_rcvq.rq_baseseq);
951*25202Skarels 	    goto theygoofed;
952*25202Skarels 	}
953*25202Skarels 	rdpcb->r_rcvq.rq_msgs[rdpcb->r_rcvq.rq_front] = NULL;
954*25202Skarels 	rdpcb->r_rcvq.rq_front =
955*25202Skarels 	    (rdpcb->r_rcvq.rq_front +1) % rdpcb->r_rcvq.rq_maxqlen;
956*25202Skarels 	rdpcb->r_rcvq.rq_baseseq ++;
957*25202Skarels 
958*25202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
959*25202Skarels 	m_freem(dtom(pkt));
960*25202Skarels     }
961*25202Skarels     else if (pkt->rh_dlen)
962*25202Skarels     {
963*25202Skarels #ifdef RDP_CS
964*25202Skarels 	if (rdp_qinsert (&rdpcb->r_rcvq, dtom(pkt), RDP_SEQNO(pkt)) == -1)
965*25202Skarels 	    rdpcb->r_rcvd.r_retrans ++;
966*25202Skarels #else
967*25202Skarels 	(void) rdp_qinsert (&rdpcb->r_rcvq, dtom(pkt), RDP_SEQNO(pkt));
968*25202Skarels #endif
969*25202Skarels     }
970*25202Skarels     else
971*25202Skarels 	/* Was an ACK-only packet */
972*25202Skarels 	m_freem(dtom(pkt));
973*25202Skarels 
974*25202Skarels 
975*25202Skarels     if (usr_rbuf_is_empty(rdpcb))
976*25202Skarels     {
977*25202Skarels 	register MBUF *m;
978*25202Skarels 
979*25202Skarels 	if (m = rdp_qremove(&rdpcb->r_rcvq, !rdpcb->r_sequential))
980*25202Skarels 	{
981*25202Skarels 	    /*
982*25202Skarels 	     * IP and RDP headers should be in the first mbuf.
983*25202Skarels 	     * User does not see them.
984*25202Skarels 	     */
985*25202Skarels 	    pkt = (RDPHDR *) (mtod(m, char *) + sizeof(struct ip));
986*25202Skarels #ifdef RDP_CS
987*25202Skarels 	    rdpcb->r_rcvd.r_nbytes += pkt->rh_dlen;
988*25202Skarels #endif
989*25202Skarels 	    m->m_off += sizeof(struct ip) + hdrlen(pkt);
990*25202Skarels 	    m->m_len -= sizeof(struct ip) + hdrlen(pkt);
991*25202Skarels 
992*25202Skarels 	    usr_rbuf_append(rdpcb, m);
993*25202Skarels 	    wakeup_reader(rdpcb);
994*25202Skarels 	}
995*25202Skarels     }
996*25202Skarels 
997*25202Skarels     /*
998*25202Skarels      * datagrams go straight out in response to the send(2) PRU_SEND,
999*25202Skarels      * so getting (e)acks doesn't cause an outgoing datagram.
1000*25202Skarels      * Hold off on (e)ack of incoming packet until user receives it
1001*25202Skarels      * and we know that by PRU_RCV.
1002*25202Skarels      */
1003*25202Skarels     return (RDP_sSAME);
1004*25202Skarels }
1005*25202Skarels 
1006*25202Skarels /*
1007*25202Skarels  *	state: RDP_sESTAB
1008*25202Skarels  *	input: RDP_iUCLOSE
1009*25202Skarels  */
1010*25202Skarels /*ARGSUSED*/
1011*25202Skarels rdp_estab_close (rdpcb, nil)
1012*25202Skarels register RDPCB *rdpcb;
1013*25202Skarels {
1014*25202Skarels     /* send RST */
1015*25202Skarels     rdpcb->r_sendrst = TRUE;
1016*25202Skarels     (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
1017*25202Skarels 
1018*25202Skarels     /*
1019*25202Skarels      * Don't retransmit unacked datagrams, since user can't pick them
1020*25202Skarels      * up anymore once he's been reset (according to specification).
1021*25202Skarels      * Reliable delivery and acceptance must be determined by the
1022*25202Skarels      * application before closing.
1023*25202Skarels      */
1024*25202Skarels     cancel_timers(rdpcb);
1025*25202Skarels     rdpcb->r_timers[RDP_tCLOSEWAIT] = rdpcb->r_closewait;
1026*25202Skarels     return (RDP_sCLOSEWAIT);
1027*25202Skarels }
1028*25202Skarels 
1029*25202Skarels /*
1030*25202Skarels  *	state: RDP_sESTAB
1031*25202Skarels  *	input: RDP_iTIMER
1032*25202Skarels  */
1033*25202Skarels rdp_estab_timer (rdpcb, timer)
1034*25202Skarels register RDPCB	*rdpcb;
1035*25202Skarels {
1036*25202Skarels     register MBUF	*rxmit_data;
1037*25202Skarels     register int	index, passes;
1038*25202Skarels     rdpsequence	seqno;
1039*25202Skarels 
1040*25202Skarels     switch (timer)
1041*25202Skarels     {
1042*25202Skarels       case RDP_tRTTL:
1043*25202Skarels 	/* retransmission took too long */
1044*25202Skarels 	rttl(rdpcb);
1045*25202Skarels 	return (RDP_sSAME);
1046*25202Skarels 
1047*25202Skarels       case RDP_tRXMIT:
1048*25202Skarels 	/*
1049*25202Skarels 	 * ensure keep checking even if no packet goes
1050*25202Skarels 	 * out this time.  ACK will stop this.
1051*25202Skarels 	 */
1052*25202Skarels 	rdpcb->r_timers[RDP_tRXMIT] = RDP_tvRXCHECK;
1053*25202Skarels 
1054*25202Skarels 	index	= rdpcb->r_sendq.rq_front;
1055*25202Skarels 	passes	= rdpcb->r_sndnxt - rdpcb->r_snduna;
1056*25202Skarels 	seqno	= rdpcb->r_sendq.rq_baseseq; /* == r_snduna */
1057*25202Skarels 
1058*25202Skarels 	while (--passes >= 0)
1059*25202Skarels 	{
1060*25202Skarels 	    if (rdpcb->r_rxtimers[index])
1061*25202Skarels 	    {
1062*25202Skarels 		rdpcb->r_rxtimers[index] --;
1063*25202Skarels 		if (rdpcb->r_rxtimers[index] == 0)
1064*25202Skarels 		{
1065*25202Skarels 		    MBUF *m;
1066*25202Skarels 
1067*25202Skarels 		    /*
1068*25202Skarels 		     * Over lossy networks, do not let
1069*25202Skarels 		     * the round trip time estimate
1070*25202Skarels 		     * drift unecessarily high.  If we're
1071*25202Skarels 		     * considering the round-trip-time-
1072*25202Skarels 		     * measuring packet lost, and are
1073*25202Skarels 		     * retransmitting it, then we should
1074*25202Skarels 		     * reset the round trip time measurment
1075*25202Skarels 		     */
1076*25202Skarels 		    if (rdpcb->r_rttiming)
1077*25202Skarels 			if (seqno == rdpcb->r_rttimed)
1078*25202Skarels 			    rdpcb->r_rttiming = FALSE;
1079*25202Skarels 
1080*25202Skarels 		    m = rdpcb->r_sendq.rq_msgs[index];
1081*25202Skarels 		    if (m == RDP_NULLMSG)
1082*25202Skarels 		    {
1083*25202Skarels 			rdpcb->r_sendnull = TRUE;
1084*25202Skarels 			if (rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, seqno) == 0)
1085*25202Skarels 			    time_rtt(rdpcb, seqno);
1086*25202Skarels 
1087*25202Skarels 			/*
1088*25202Skarels 			 * Back off on retransmissions,
1089*25202Skarels 			 * because the host might be
1090*25202Skarels 			 * down or the network could be
1091*25202Skarels 			 * jammed.  rxmitime will drop
1092*25202Skarels 			 * to normal when we get the ACK
1093*25202Skarels 			 */
1094*25202Skarels 			rdpcb->r_rxmitime = MIN (RDP_tvRXMAX,
1095*25202Skarels 						 rdpcb->r_rxmitime << 1);
1096*25202Skarels 
1097*25202Skarels 			if (++rdpcb->r_nullsent > RDP_MAXNULL)
1098*25202Skarels 			{
1099*25202Skarels 			    /* advisory only */
1100*25202Skarels 			    set_error(rdpcb, ETIMEDOUT);
1101*25202Skarels 			    wakeup_reader(rdpcb);
1102*25202Skarels 			    /* writer timeout via rttl */
1103*25202Skarels 
1104*25202Skarels 			    /* avoid rollover to zero
1105*25202Skarels 			     *
1106*25202Skarels 			     * NOTE: user will get
1107*25202Skarels 			     * ETIMEDOUT on every
1108*25202Skarels 			     * rxmit, another reason
1109*25202Skarels 			     * to back off above.
1110*25202Skarels 			     */
1111*25202Skarels 			    rdpcb->r_nullsent --;
1112*25202Skarels 			}
1113*25202Skarels 		    }
1114*25202Skarels 		    else
1115*25202Skarels 		    {
1116*25202Skarels 			if (rxmit_data =m_copy(m, 0, M_COPYALL))
1117*25202Skarels 			    /*
1118*25202Skarels 			     * When we 1st sent it, we
1119*25202Skarels 			     * remembered the len in m_act
1120*25202Skarels 			     */
1121*25202Skarels 			    if (rdp_sendpkt(rdpcb,rxmit_data,(int)m->m_act,seqno)==0)
1122*25202Skarels 			        time_rtt(rdpcb, seqno);
1123*25202Skarels 
1124*25202Skarels 			/*
1125*25202Skarels 			 * We aren't backing off here,
1126*25202Skarels 			 * since the single number is
1127*25202Skarels 			 * used for all datagrams,
1128*25202Skarels 			 * each of which may be at a
1129*25202Skarels 			 * different nth rxmission
1130*25202Skarels 			 */
1131*25202Skarels 		    }
1132*25202Skarels 
1133*25202Skarels #ifdef RDP_CS
1134*25202Skarels 		    rdpcb->r_sent.r_retrans ++;
1135*25202Skarels #endif
1136*25202Skarels 		    set_rxtimer (rdpcb, index);
1137*25202Skarels 		}
1138*25202Skarels 	    }
1139*25202Skarels 	    index = (index + 1) % rdpcb->r_sendq.rq_maxqlen;
1140*25202Skarels 	    seqno ++;
1141*25202Skarels 	}
1142*25202Skarels 	break;
1143*25202Skarels 
1144*25202Skarels       case RDP_tACKDELAY:
1145*25202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
1146*25202Skarels 	break;
1147*25202Skarels 
1148*25202Skarels       case RDP_tNULL:
1149*25202Skarels 	/*
1150*25202Skarels 	 * If we're retransmitting, then we don't need to
1151*25202Skarels 	 * send NULL messages.  The NULL timer drops to zero
1152*25202Skarels 	 * and gets restarted when we get some packet from
1153*25202Skarels 	 * them (rdp_estab_netr).  User will get ETIMEDOUT
1154*25202Skarels 	 * from retransmit took too long if we don't get a
1155*25202Skarels 	 * packet.
1156*25202Skarels 	 */
1157*25202Skarels 	if (rdpcb->r_rttlindex < 0)
1158*25202Skarels 	{
1159*25202Skarels 	    /* are not retransmitting */
1160*25202Skarels 
1161*25202Skarels 	    /*
1162*25202Skarels 	     * Idea:  The connection has been idle for too
1163*25202Skarels 	     * long. send a NULL packet which has its own
1164*25202Skarels 	     * sequence number (so can distinguish slow to
1165*25202Skarels 	     * arrive ack from ack of this NULL) and
1166*25202Skarels 	     * retransmit it via normal packet
1167*25202Skarels 	     * retransmission algorithm.
1168*25202Skarels 	     */
1169*25202Skarels 
1170*25202Skarels 	    if (rdp_qinsert(&rdpcb->r_sendq, RDP_NULLMSG, rdpcb->r_sndnxt) != 1)
1171*25202Skarels 		panic("rdp RDP_tNULL");
1172*25202Skarels 
1173*25202Skarels 	    rdpcb->r_sendnull = TRUE;
1174*25202Skarels 	    (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
1175*25202Skarels 	    index = rdpcb->r_sendq.rq_front + (rdpcb->r_sndnxt - rdpcb->r_snduna);
1176*25202Skarels 	    index %= rdpcb->r_sendq.rq_maxqlen;
1177*25202Skarels 	    set_rxtimer (rdpcb, index);
1178*25202Skarels 	    rdpcb->r_sndnxt ++;
1179*25202Skarels 	    rdpcb->r_nullsent = 1;
1180*25202Skarels 	}
1181*25202Skarels 	break;
1182*25202Skarels 
1183*25202Skarels       default:
1184*25202Skarels 	log(KERN_RECOV, "rdp_estab_timer:  timer %d\n", timer);
1185*25202Skarels     }
1186*25202Skarels 
1187*25202Skarels     return(RDP_sSAME);
1188*25202Skarels }
1189*25202Skarels 
1190*25202Skarels /*
1191*25202Skarels  *	state: RDP_sESTAB
1192*25202Skarels  *	input: RDP_iRCV
1193*25202Skarels  */
1194*25202Skarels /*ARGSUSED*/
1195*25202Skarels rdp_estab_rcv (rdpcb, nil)
1196*25202Skarels register RDPCB	*rdpcb;
1197*25202Skarels {
1198*25202Skarels     MBUF	*m;
1199*25202Skarels 
1200*25202Skarels     /*
1201*25202Skarels      * Now that user has received the packet, bump the front so that
1202*25202Skarels      * we can ACK it and move the window along.
1203*25202Skarels      */
1204*25202Skarels     rdp_received (&rdpcb->r_rcvq);
1205*25202Skarels 
1206*25202Skarels     /*
1207*25202Skarels      * user picked up the packet we left on the socket for him.
1208*25202Skarels      * Let's put another one there.
1209*25202Skarels      */
1210*25202Skarels     if (m = rdp_qremove(&rdpcb->r_rcvq, !rdpcb->r_sequential))
1211*25202Skarels     {
1212*25202Skarels 	RDPHDR *pkt;
1213*25202Skarels 
1214*25202Skarels 	/*
1215*25202Skarels 	 * IP and RDP headers should be in the first mbuf.
1216*25202Skarels 	 * User does not see them.
1217*25202Skarels 	 */
1218*25202Skarels 	pkt = (RDPHDR *) (mtod(m, char *) + sizeof(struct ip));
1219*25202Skarels #ifdef RDP_CS
1220*25202Skarels 	rdpcb->r_rcvd.r_nbytes += pkt->rh_dlen;
1221*25202Skarels #endif
1222*25202Skarels 	m->m_off += sizeof(struct ip) + hdrlen(pkt);
1223*25202Skarels 	m->m_len -= sizeof(struct ip) + hdrlen(pkt);
1224*25202Skarels 
1225*25202Skarels 	usr_rbuf_append(rdpcb, m);
1226*25202Skarels 	/* wakeup_reader(rdpcb); is awake, performing read(2) */
1227*25202Skarels     }
1228*25202Skarels 
1229*25202Skarels     /*
1230*25202Skarels      * Send an ACK, but apply an ACK-delay algorithm in order to
1231*25202Skarels      * reduce CPU loading on both hosts involved.  Reduces network
1232*25202Skarels      * load, too.  Skip at most one ACK.
1233*25202Skarels      */
1234*25202Skarels     if (rdpcb->r_timers[RDP_tACKDELAY])
1235*25202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
1236*25202Skarels     else
1237*25202Skarels 	rdpcb->r_timers[RDP_tACKDELAY] = 1;
1238*25202Skarels 
1239*25202Skarels     return (RDP_sSAME);
1240*25202Skarels }
1241*25202Skarels 
1242*25202Skarels /*
1243*25202Skarels  *	state: RDP_sESTAB
1244*25202Skarels  *	input: RDP_iSEND
1245*25202Skarels  */
1246*25202Skarels rdp_estab_send (rdpcb, m)
1247*25202Skarels register RDPCB	*rdpcb;
1248*25202Skarels register MBUF	*m;
1249*25202Skarels {
1250*25202Skarels     register MBUF	*copym;
1251*25202Skarels     register int	 len;
1252*25202Skarels     register int	 index;
1253*25202Skarels 
1254*25202Skarels     /*
1255*25202Skarels      * q message on send q.
1256*25202Skarels      */
1257*25202Skarels     if (rdp_qinsert(&rdpcb->r_sendq, m, rdpcb->r_sndnxt) != 1)
1258*25202Skarels 	panic("rdp_estab_send");
1259*25202Skarels 
1260*25202Skarels     /*
1261*25202Skarels      * Remember the length of the datagram for sending now,
1262*25202Skarels      * and for retransmissions later.
1263*25202Skarels      */
1264*25202Skarels     len = 0;
1265*25202Skarels     for (copym = m; copym; copym = copym->m_next)
1266*25202Skarels 	len += copym->m_len;
1267*25202Skarels     m->m_act = ((MBUF *) len);
1268*25202Skarels 
1269*25202Skarels     /*
1270*25202Skarels      * if reached end of window, block socket code from allowing
1271*25202Skarels      * sends until get an ACK
1272*25202Skarels      */
1273*25202Skarels     if (SEQ_GEQ(rdpcb->r_sndnxt, rdpcb->r_snduna + rdpcb->r_hisnbuf -1))
1274*25202Skarels 	sendbufisfull(rdpcb);
1275*25202Skarels 
1276*25202Skarels     /*
1277*25202Skarels      * send a copy of the datagram
1278*25202Skarels      */
1279*25202Skarels     if (copym = m_copy(m, 0, M_COPYALL))
1280*25202Skarels 	if (rdp_sendpkt(rdpcb, copym, len, rdpcb->r_sndnxt) == 0)
1281*25202Skarels 	    time_rtt (rdpcb, rdpcb->r_sndnxt);
1282*25202Skarels 
1283*25202Skarels     index = rdpcb->r_sendq.rq_front + (rdpcb->r_sndnxt - rdpcb->r_snduna);
1284*25202Skarels     index %= rdpcb->r_sendq.rq_maxqlen;
1285*25202Skarels     set_rxtimer(rdpcb, index);
1286*25202Skarels 
1287*25202Skarels     rdpcb->r_sndnxt ++;
1288*25202Skarels 
1289*25202Skarels     return (RDP_sSAME);
1290*25202Skarels }
1291*25202Skarels 
1292*25202Skarels /************************************************************************/
1293*25202Skarels 
1294*25202Skarels /*
1295*25202Skarels  *	state: RDP_sCLOSEWAIT
1296*25202Skarels  *	input: RDP_iNETR
1297*25202Skarels  */
1298*25202Skarels rdp_closew_netr (rdpcb, pkt)
1299*25202Skarels RDPCB	*rdpcb;
1300*25202Skarels RDPHDR	*pkt;
1301*25202Skarels {
1302*25202Skarels     rdpstate newstate;
1303*25202Skarels 
1304*25202Skarels     if (pkt->rh_flags & RDP_fRST)
1305*25202Skarels     {
1306*25202Skarels 	/*
1307*25202Skarels 	 * We've both agreed to shut down the connection
1308*25202Skarels 	 */
1309*25202Skarels 	trash_pcbs(rdpcb);
1310*25202Skarels 	newstate = RDP_sCLOSED;
1311*25202Skarels     }
1312*25202Skarels     else
1313*25202Skarels 	newstate = RDP_sSAME;
1314*25202Skarels 
1315*25202Skarels     m_freem(dtom(pkt));
1316*25202Skarels     return(newstate);
1317*25202Skarels }
1318*25202Skarels 
1319*25202Skarels /*
1320*25202Skarels  *	state: RDP_sCLOSEWAIT
1321*25202Skarels  *	input: RDP_iUCLOSE
1322*25202Skarels  */
1323*25202Skarels /*ARGSUSED*/
1324*25202Skarels rdp_closew_close (rdpcb, nil)
1325*25202Skarels register RDPCB *rdpcb;
1326*25202Skarels {
1327*25202Skarels     /*
1328*25202Skarels      * rdp_usrreq() only allows one close call to the finite state machine.
1329*25202Skarels      * Therefore, we entered CLOSEWAIT in response to a RST, not a close.
1330*25202Skarels      * So, now both sides agree to close co-operatively.
1331*25202Skarels      */
1332*25202Skarels     rdpcb->r_sendrst = TRUE;
1333*25202Skarels     (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
1334*25202Skarels 
1335*25202Skarels     trash_pcbs(rdpcb);
1336*25202Skarels     return(RDP_sCLOSED);
1337*25202Skarels }
1338*25202Skarels 
1339*25202Skarels /*
1340*25202Skarels  *	state: RDP_sCLOSEWAIT
1341*25202Skarels  *	input: RDP_iTIMER
1342*25202Skarels  */
1343*25202Skarels rdp_closew_timer (rdpcb, timer)
1344*25202Skarels RDPCB	*rdpcb;
1345*25202Skarels {
1346*25202Skarels     if (timer != RDP_tCLOSEWAIT)
1347*25202Skarels     {
1348*25202Skarels 	log(KERN_RECOV, "rdp_closew_timer:  timer %d\n", timer);
1349*25202Skarels 	return(RDP_sSAME);
1350*25202Skarels     }
1351*25202Skarels 
1352*25202Skarels     trash_pcbs(rdpcb);
1353*25202Skarels     return(RDP_sCLOSED);
1354*25202Skarels }
1355*25202Skarels 
1356*25202Skarels /*
1357*25202Skarels  *	state: RDP_sCLOSEWAIT
1358*25202Skarels  *	input: RDP_iRCV
1359*25202Skarels  */
1360*25202Skarels /*ARGSUSED*/
1361*25202Skarels rdp_closew_rcv(rdpcb, nil)
1362*25202Skarels {
1363*25202Skarels     /*
1364*25202Skarels      * Technically, an illegal transition.  However, socket code drops
1365*25202Skarels      * system priority level, allowing processing of a network packet
1366*25202Skarels      * containing RDP reset to cause ESTAB -> CLOSEWAIT in the middle of
1367*25202Skarels      * passing the user a packet.
1368*25202Skarels      *
1369*25202Skarels      * ESTAB ... user receives packet, priority dropped for uiomove()
1370*25202Skarels      *      --- network packet processed ---
1371*25202Skarels      * CLOSEWAIT ... socket code continues, causing this action.
1372*25202Skarels      *
1373*25202Skarels      * ### This can be a serious problem in general.
1374*25202Skarels      */
1375*25202Skarels }
1376*25202Skarels #endif
1377