125202Skarels /*
225202Skarels  $Log:	rdp_states.c,v $
325202Skarels  * Revision 2.14  85/06/18  14:38:50  walsh
425202Skarels  * eliminated inpcb flags.
525202Skarels  *
625202Skarels  * Revision 2.13  85/05/31  14:39:06  walsh
725202Skarels  * copy sequential delivery desires when fork off a new socket.
825202Skarels  *
925202Skarels  * Revision 2.12  84/12/03  09:42:20  walsh
1025202Skarels  * Keep no route messages from flooding console.
1125202Skarels  *
1225202Skarels  * Revision 2.11  84/11/29  13:06:17  walsh
1325202Skarels  * Have the NULL message retransmission back off so that don't load
1425202Skarels  * a jammed network and so that don't wake user up so often when
1525202Skarels  * some intermediary hop has gone down on a (normally) fast connection.
1625202Skarels  *
1725202Skarels  * Revision 2.10  84/11/15  09:56:14  walsh
1825202Skarels  * redid how we deal with compiler padding in the RDP header structure.
1925202Skarels  *
2025202Skarels  * Revision 2.9  84/11/08  16:12:06  walsh
2125202Skarels  * Added code to gather statistics on RDP traffic.  This makes the RDPCB
2225202Skarels  * too big unles you make mbufs 512 bytes large.  RDP_CS should be turned off
2325202Skarels  * unless you do.
2425202Skarels  *
2525202Skarels  * Revision 2.8  84/11/06  15:24:54  walsh
2625202Skarels  * *** empty log message ***
2725202Skarels  *
2825202Skarels  * Revision 2.7  84/11/05  15:54:34  walsh
2925202Skarels  * update_nulltimer() macro began to look inappropriate with recent
3025202Skarels  * changes, so its been stripped out and put in-line.
3125202Skarels  *
3225202Skarels  * Revision 2.6  84/11/05  12:42:34  walsh
3325202Skarels  * Set things up so can debug RDP connections just like can debug TCP
3425202Skarels  * connections.
3525202Skarels  *
3625202Skarels  * Revision 2.5  84/11/05  11:34:36  walsh
3725202Skarels  * Don't let round trip time estimate drift upward on lossy networks.
3825202Skarels  * Check for retransmissions of packets used to measure round trip time.
3925202Skarels  *
4025202Skarels  * Revision 2.4  84/11/05  10:47:38  walsh
4125202Skarels  * More changes to go with NULL messages getting their own sequence
4225202Skarels  * number.
4325202Skarels  *
4425202Skarels  * Revision 2.3  84/11/02  18:24:20  walsh
4525202Skarels  * Protocol specifiers want NULL message to have own sequence number in
4625202Skarels  * case of slow (t>NULL msg timeout) packets.  I don't see this as a problem,
4725202Skarels  * and even if happened (dubious) would only delay discovery, but I
4825202Skarels  * didn't win this one.  Initially not designed for this, but fixes are
4925202Skarels  * in almost neatly.
5025202Skarels  *
5125202Skarels  * Revision 2.2  84/11/02  15:29:32  walsh
5225202Skarels  * Allow for RDP header fields not on natural boundries.  (Protocol
5325202Skarels  * specifiers say will be part of next version in 6-12 months).
5425202Skarels  * Until then, there goes the speed...  Yucho modifications.
5525202Skarels  *
5625202Skarels  * Revision 2.1  84/11/02  10:14:11  walsh
5725202Skarels  * Fixed to include RCS comments in checked out source.
5825202Skarels  *
5925202Skarels  *
6025202Skarels  * description:
6125202Skarels  * The state transition functions for the Reliable Datagram Protocol.
6225202Skarels  *
6325202Skarels  * revision 1.17
6425202Skarels  * date: 84/07/24 16:58:17;  author: walsh;  state: Exp;  lines added/del: 2/2
6525202Skarels  * When had gone to making retransmit took too long advisory,
6625202Skarels  * had forgotten to change RDP_sCLOSED to RDP_sSAME.
6725202Skarels  *
6825202Skarels  * revision 1.16
6925202Skarels  * date: 84/07/23 12:58:31;  author: walsh;  state: Exp;  lines added/del: 27/6
7025202Skarels  * Clear all timers when enter close state.  Updates to protocol had not
7125202Skarels  * been complete in this respect.
7225202Skarels  *
7325202Skarels  * Retransmission and acceptance in CLOSEWAIT do not seem to be in the cards
7425202Skarels  * in dealing with protocol specifiers, so removed ### markers and commented.
7525202Skarels  *
7625202Skarels  * revision 1.15
7725202Skarels  * date: 84/07/22 19:45:31;  author: walsh;  state: Exp;  lines added/del: 19/0
7825202Skarels  * Added a state transition function rdp_closew_rcv() to compensate for
7925202Skarels  * socket code's dropping of system priority level for a brief period of time.
8025202Skarels  *
8125202Skarels  * revision 1.14
8225202Skarels  * date: 84/07/19 10:21:42;  author: walsh;  state: Exp;  lines added/del: 14/85
8325202Skarels  * Organized macros and classified their definitions in rdp_macros.h.
8425202Skarels  *
8525202Skarels  * revision 1.13
8625202Skarels  * date: 84/07/19 08:54:01;  author: walsh;  state: Exp;  lines added/del: 4/0
8725202Skarels  * NULL message processing should start before receive a packet in ESTAB,
8825202Skarels  * so start up NULL timer when enter ESTAB.
8925202Skarels  *
9025202Skarels  * revision 1.12
9125202Skarels  * date: 84/07/18 18:50:55;  author: walsh;  state: Exp;  lines added/del: 36/5
9225202Skarels  * Added provision for sending of NULL messages.  These are sent on an idle
9325202Skarels  * connection to determine that the other side still exists.
9425202Skarels  *
9525202Skarels  * revision 1.11
9625202Skarels  * date: 84/07/18 13:35:36;  author: walsh;  state: Exp;  lines added/del: 6/6
9725202Skarels  * made provisions for user-adjustable RTTL time period.
9825202Skarels  *
9925202Skarels  * revision 1.10
10025202Skarels  * date: 84/07/13 09:50:33;  author: walsh;  state: Exp;  lines added/del: 22/19
10125202Skarels  * When first send datagram, we determine its length.
10225202Skarels  * Might as wellsave that length in m_act for retransmission.
10325202Skarels  *
10425202Skarels  * revision 1.9
10525202Skarels  * date: 84/07/12 13:48:22;  author: walsh;  state: Exp;  lines added/del: 1/0
10625202Skarels  * Rather than in-line stuffing of IP/RDP headers, at least half of which are
10725202Skarels  * constant, copy headers in from a template of what the headers are like.  The
10825202Skarels  * bcopy() call is turned into a movc3 instruction on the VAX by a sed script
10925202Skarels  * run over the assembler output of the C compiler.  Marginal speed-up.
11025202Skarels  *
11125202Skarels  * revision 1.8
11225202Skarels  * date: 84/07/12 09:55:02;  author: walsh;  state: Exp;  lines added/del: 5/13
11325202Skarels  * some small optimizations.
11425202Skarels  *
11525202Skarels  * revision 1.7
11625202Skarels  * date: 84/07/10 14:48:13;  author: walsh;  state: Exp;  lines added/del: 1/1
11725202Skarels  * Reduced amount of unnecessary wakeup action.
11825202Skarels  *
11925202Skarels  * revision 1.6
12025202Skarels  * date: 84/07/10 10:28:33;  author: walsh;  state: Exp;  lines added/del: 35/35
12125202Skarels  * Added register declarations.
12225202Skarels  *
12325202Skarels  * revision 1.5
12425202Skarels  * date: 84/07/09 14:31:33;  author: walsh;  state: Exp;  lines added/del: 11/2
12525202Skarels  * Added an ACK-delay algorithm to reduce cpu and network loading.
12625202Skarels  *
12725202Skarels  * revision 1.4
12825202Skarels  * date: 84/07/08 21:36:47;  author: walsh;  state: Exp;  lines added/del: 3/3
12925202Skarels  * changed some references to r_sendq.rq_baseseq to r_snduna for clarity.
13025202Skarels  *
13125202Skarels  * revision 1.3
13225202Skarels  * date: 84/07/06 15:13:50;  author: wjacobso;  state: Exp;  lines added/del: 17/17
13325202Skarels  * add register var definitions; use sndnxt-baseseq instead of maxqlen
13425202Skarels  * to determine number of passes
13525202Skarels  *
13625202Skarels  * revision 1.2
13725202Skarels  * date: 84/07/06 09:49:52;  author: root;  state: Exp;  lines added/del: 93/35
13825202Skarels  * This version seems to run bug-free.
13925202Skarels  *
14025202Skarels  * revision 1.1
14125202Skarels  * date: 84/06/26 14:18:09;  author: walsh;  state: Exp;
14225202Skarels  * Initial revision
14325202Skarels  */
14425202Skarels 
14525202Skarels 
14625202Skarels #ifdef RDP
14725202Skarels #include "../h/param.h"
14825202Skarels #include "../h/dir.h"
14925202Skarels #include "../h/user.h"
15025202Skarels #include "../h/kernel.h"
15125202Skarels #include "../h/inode.h"
15225202Skarels #include "../h/mbuf.h"
15325202Skarels #include "../h/socket.h"
15425202Skarels #include "../h/socketvar.h"
15525202Skarels #include "../h/errno.h"
15625202Skarels #include "../h/syslog.h"
15725202Skarels 
15825202Skarels #include "../net/if.h"
15925202Skarels #include "../net/route.h"
16025202Skarels 
16125202Skarels #include "../bbnnet/in.h"
16225202Skarels #include "../bbnnet/net.h"
16325202Skarels #include "../bbnnet/in_pcb.h"
16425202Skarels #include "../bbnnet/in_var.h"
16525202Skarels #include "../bbnnet/ip.h"
16625202Skarels #include "../bbnnet/rdp.h"
16725202Skarels #include "../bbnnet/seq.h"
16825202Skarels #include "../bbnnet/rdp_macros.h"
16925202Skarels 
17025202Skarels extern struct rtentry *ip_route();
17125202Skarels 
17225202Skarels /*
17325202Skarels  * Since a message just got through, re-associating rttl (retransmit
17425202Skarels  * took too long) with some other current outstanding datagram (cf. wait
17525202Skarels  * until some new dgram) is a little paranoid, but let's be careful
17625202Skarels  * in case that new dgram doesn't come along for a while.  This also
17725202Skarels  * allows us to decide that the check-for-retransmit and
17825202Skarels  * retransmit-took-too-long timers can be cancelled.
17925202Skarels  */
clear_rxtimer(rdpcb,N)18025202Skarels clear_rxtimer(rdpcb, N)
18125202Skarels register RDPCB	*rdpcb;
18225202Skarels {
18325202Skarels     int Xi;
18425202Skarels     int pass;
18525202Skarels 
18625202Skarels     rdpcb->r_rxtimers[N] = 0;
18725202Skarels     if (rdpcb->r_rttlindex == N)
18825202Skarels     {
18925202Skarels 	/*
19025202Skarels 	 * look for new dgram of which to check rttl
19125202Skarels 	 */
19225202Skarels 	Xi = rdpcb->r_sendq.rq_front;
19325202Skarels 	pass = rdpcb->r_sndnxt - rdpcb->r_snduna;
19425202Skarels 	while (--pass >= 0)
19525202Skarels 	{
19625202Skarels 	    if (rdpcb->r_rxtimers[Xi])
19725202Skarels 	    {
19825202Skarels 		rdpcb->r_rttlindex = Xi;
19925202Skarels 		rdpcb->r_timers[RDP_tRTTL] = rdpcb->r_rttl;
20025202Skarels 		return;
20125202Skarels 	    }
20225202Skarels 	    Xi = (Xi + 1) % rdpcb->r_sendq.rq_maxqlen;
20325202Skarels 	}
20425202Skarels 	/*
20525202Skarels 	 * No outstanding dgrams left.
20625202Skarels 	 */
20725202Skarels 	rdpcb->r_rttlindex = (-1);
20825202Skarels 	rdpcb->r_timers[RDP_tRTTL] = 0;
20925202Skarels 	rdpcb->r_timers[RDP_tRXMIT] = 0;
21025202Skarels     }
21125202Skarels }
21225202Skarels 
21325202Skarels /*
21425202Skarels  * set up things to discover the rtt (round trip time) for this
21525202Skarels  * DATA-containing packet.
21625202Skarels  */
21725202Skarels #define time_rtt(rdpcb, seqnum) \
21825202Skarels 	if (! (rdpcb)->r_rttiming){            \
21925202Skarels 		(rdpcb)->r_rttiming = TRUE;    \
22025202Skarels 		(rdpcb)->r_rtt = 0;            \
22125202Skarels 		(rdpcb)->r_rttimed = (seqnum); \
22225202Skarels 	}
22325202Skarels 
22425202Skarels 
22525202Skarels /*
22625202Skarels  * Since we play with sb_cc for the socket send buffer to prevent the
22725202Skarels  * user process from sending packets we can't buffer, must ensure it
22825202Skarels  * is restored to a reasonable value before call upon socket code to clean
22925202Skarels  * up or we'll get a "panic: sbdrop".  Socket code is called by
23025202Skarels  * in_pcbdetach().
23125202Skarels  */
trash_pcbs(rdpcb)23225202Skarels trash_pcbs(rdpcb)
23325202Skarels RDPCB *rdpcb;
23425202Skarels {
23525202Skarels     register struct sockbuf *sosnd;
23625202Skarels 
23725202Skarels     sosnd = &rdpcb->r_inpcb->inp_socket->so_snd;
23825202Skarels     if ((sosnd->sb_cc == sosnd->sb_hiwat) && (sosnd->sb_mb == NULL))
23925202Skarels 	sosnd->sb_cc = 0;
24025202Skarels     in_pcbdetach (rdpcb->r_inpcb, rdp_pcbdisconnect);
24125202Skarels }
24225202Skarels 
cancel_timers(rdpcb)24325202Skarels cancel_timers(rdpcb)
24425202Skarels register RDPCB *rdpcb;
24525202Skarels {
24625202Skarels     register int i;
24725202Skarels 
24825202Skarels     for (i=0; i<RDP_NTIMERS; i++)
24925202Skarels 	rdpcb->r_timers[i] = 0;
25025202Skarels }
25125202Skarels 
25225202Skarels /************************************************************************/
25325202Skarels 
25425202Skarels /*
25525202Skarels  *	state: RDP_sUNOPENED
25625202Skarels  *	input: RDP_iCONNECT
25725202Skarels  */
25825202Skarels /*ARGSUSED*/
rdp_unop_connect(rdpcb,nil)25925202Skarels rdp_unop_connect (rdpcb, nil)
26025202Skarels register RDPCB	*rdpcb;
26125202Skarels {
26225202Skarels     /*
26325202Skarels      * Send a SYN
26425202Skarels      * and set re-transmission timer to ensure SYN eventually gets there
26525202Skarels      */
26625202Skarels     (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_iss);
26725202Skarels     set_rxtimer (rdpcb, 0);
26825202Skarels     return (RDP_sSYNSENT);
26925202Skarels }
27025202Skarels 
27125202Skarels /*
27225202Skarels  *	state: RDP_sUNOPENED
27325202Skarels  *	input: RDP_iLISTEN
27425202Skarels  */
27525202Skarels /*ARGSUSED*/
rdp_unop_listen(rdpcb,nil)27625202Skarels rdp_unop_listen (rdpcb, nil)
27725202Skarels RDPCB	*rdpcb;
27825202Skarels {
27925202Skarels     return (RDP_sLISTEN);
28025202Skarels }
28125202Skarels 
28225202Skarels /*
28325202Skarels  *	state: RDP_sUNOPENED
28425202Skarels  *	input: RDP_iNETR
28525202Skarels  */
28625202Skarels /*ARGSUSED*/
rdp_unop_netr(rdpcb,pkt)28725202Skarels rdp_unop_netr (rdpcb, pkt)
28825202Skarels RDPCB	*rdpcb;
28925202Skarels register RDPHDR	*pkt;
29025202Skarels {
29125202Skarels     if (pkt->rh_flags & (RDP_fACK|RDP_fEACK|RDP_fNULL))
29225202Skarels 	/*
29325202Skarels 	 * We haven't sent anything to (e)ack.  Nor have we
29425202Skarels 	 * established a connection and received something
29525202Skarels 	 * that we should ack (null).  The sender is very mixed
29625202Skarels 	 * up, so we'll send him a reset.
29725202Skarels 	 */
29825202Skarels 	rdp_uncon_rst (pkt);
29925202Skarels     else
30025202Skarels 	/*
30125202Skarels 	 * ignore packet in hope user connect(2)s or listen(2)s before
30225202Skarels 	 * it's re-transmission comes in.
30325202Skarels 	 */
30425202Skarels 	m_freem(dtom(pkt));
30525202Skarels 
30625202Skarels     return (RDP_sSAME);
30725202Skarels }
30825202Skarels 
30925202Skarels /*
31025202Skarels  *	state: RDP_sUNOPENED
31125202Skarels  *	input: RDP_iUCLOSE
31225202Skarels  */
31325202Skarels /*ARGSUSED*/
rdp_unop_close(rdpcb,nil)31425202Skarels rdp_unop_close (rdpcb, nil)
31525202Skarels RDPCB	*rdpcb;
31625202Skarels {
31725202Skarels     trash_pcbs(rdpcb);
31825202Skarels     return (RDP_sCLOSED);
31925202Skarels }
32025202Skarels 
32125202Skarels /************************************************************************/
32225202Skarels 
32325202Skarels /*
32425202Skarels  *	state: RDP_sLISTEN
32525202Skarels  *	input: RDP_iLISTEN
32625202Skarels  */
32725202Skarels /*ARGSUSED*/
rdp_lis_listen(rdpcb,nil)32825202Skarels rdp_lis_listen (rdpcb, nil)
32925202Skarels RDPCB	*rdpcb;
33025202Skarels {
33125202Skarels     return (RDP_sSAME);
33225202Skarels }
33325202Skarels 
33425202Skarels /*
33525202Skarels  *	state: RDP_sLISTEN
33625202Skarels  *	input: RDP_iNETR
33725202Skarels  */
rdp_lis_netr(rdpcb,pkt)33825202Skarels rdp_lis_netr (rdpcb, pkt)
33925202Skarels RDPCB	*rdpcb;
34025202Skarels register RDPHDR		*pkt;
34125202Skarels {
34225202Skarels     INPCB	*inp;
34325202Skarels     struct socket	*so;
34425202Skarels     struct rtentry	*rt;
34525202Skarels     register RDPCB		*newrdpcb;
34625202Skarels     register INPCB		*newinp;
34725202Skarels     struct socket	*newso;
34825202Skarels     register struct ip	*ip;
34925202Skarels     register SYNOPTIONS	*synopt;
35025202Skarels 
35125202Skarels     if (pkt->rh_flags & (RDP_fRST|RDP_fACK|RDP_fEACK|RDP_fNULL))
35225202Skarels     {
35325202Skarels 	if (pkt->rh_flags & RDP_fRST)
35425202Skarels 	    /*
35525202Skarels 	     * Ignore resets since we haven't sent anything to
35625202Skarels 	     * reset.  The packet may be a slow arrival meant to
35725202Skarels 	     * close a child socket of ours that has already
35825202Skarels 	     * finished close protocol with this sender.  We
35925202Skarels 	     * ignore it and the other end closes/closed on its own.
36025202Skarels 	     */
36125202Skarels 	    m_freem(dtom(pkt));
36225202Skarels 	else
36325202Skarels 	    /*
36425202Skarels 	     * We haven't sent anything to (e)ack.  Nor have we
36525202Skarels 	     * established a connection and received something
36625202Skarels 	     * that we should ack (null).  The sender is very mixed
36725202Skarels 	     * up, so we'll send him a reset.
36825202Skarels 	     */
36925202Skarels 	    rdp_uncon_rst (pkt);
37025202Skarels 
37125202Skarels 	return (RDP_sSAME);
37225202Skarels     }
37325202Skarels 
37425202Skarels     if (pkt->rh_flags & RDP_fSYN)
37525202Skarels     {
37625202Skarels 	/* normal case, someone is trying to connect to us. */
37725202Skarels 
37825202Skarels 	ip = (struct ip *) (((char *) pkt) - sizeof(struct ip));
37925202Skarels 
38025202Skarels 	/*
38125202Skarels 	 * O.k., let's get a route back to him
38225202Skarels 	 */
38325202Skarels 	if (!(rt = ip_route(&ip->ip_dst, &ip->ip_src)))
38425202Skarels 	{
38525202Skarels 	    /*
38625202Skarels 	     * Can't talk to him.  Leave socket in receive state
38725202Skarels 	     * so we can connect to someone else, since we haven't
38825202Skarels 	     * been committed to anything yet anyway.
38925202Skarels 	     * Drop his info on the floor.
39025202Skarels 	     * Let the other machine figure out on it's own
39125202Skarels 	     * that it can't reach us that way.
39225202Skarels 	     */
39325202Skarels 	    no_route ("rdp", ip->ip_dst, ip->ip_src);
39425202Skarels 	    m_freem(dtom(pkt));
39525202Skarels 	    return(RDP_sSAME);
39625202Skarels 	}
39725202Skarels 
39825202Skarels 	inp = rdpcb->r_inpcb;
39925202Skarels 	so = inp->inp_socket;
40025202Skarels 
40125202Skarels 	/*
40225202Skarels 	 * This socket is in the listen state, so the socket should have
40325202Skarels 	 * so_options & SO_ACCEPTCONN set (solisten()).
40425202Skarels 	 *
40525202Skarels 	 * The order of sonewconn() and soisconnected() is
40625202Skarels 	 * important, in order for the process to be woken up
40725202Skarels 	 * at a time when the sleep condition is fulfilled.
40825202Skarels 	 * sonewconn() is done here on the original socket, and
40925202Skarels 	 * soisconnected() is done later in rdp_lsynrcvd_netr() on
41025202Skarels 	 * the new socket.
41125202Skarels 	 */
41225202Skarels 	if (newso = sonewconn(so))
41325202Skarels 	{
41425202Skarels 	    newinp = (INPCB *) newso->so_pcb;
41525202Skarels 	    newrdpcb = (RDPCB *) newinp->inp_ppcb;
41625202Skarels 	    /*
41725202Skarels 	     * Remember our peer for this connection.
41825202Skarels 	     */
41925202Skarels 	    newinp->inp_faddr = ip->ip_src;
42025202Skarels 	    newinp->inp_fport = pkt->rh_sport;
42125202Skarels 	    newinp->inp_laddr = ip->ip_dst;
42225202Skarels 	    /*
42325202Skarels 	     * and copy fields into the new inpcb
42425202Skarels 	     */
42525202Skarels 	    newinp->inp_lport = inp->inp_lport;
42625202Skarels 	    newinp->inp_route.ro_rt = rt;
42725202Skarels 	    /*
42825202Skarels 	     * and copy fields into the new rdpcb.  In particular,
42925202Skarels 	     * the user's desired buffering allocations should be
43025202Skarels 	     * propogated.
43125202Skarels 	     */
43225202Skarels 	    newrdpcb->r_ournbuf = rdpcb->r_ournbuf;
43325202Skarels 	    sbreserve (&newrdpcb->r_inpcb->inp_socket->so_rcv,
43425202Skarels 		rdpcb->r_inpcb->inp_socket->so_rcv.sb_hiwat);
43525202Skarels 	    pick_ourmaxlen(newrdpcb);
43625202Skarels 	    /*
43725202Skarels 	     * Sequential delivery is a combination of both side's
43825202Skarels 	     * desires, and must be copied from server socket since
43925202Skarels 	     * user does not have a handle on the child socket in
44025202Skarels 	     * it's early states.
44125202Skarels 	     */
44225202Skarels 	    newrdpcb->r_sequential = rdpcb->r_sequential;
44325202Skarels 
44425202Skarels 	    /*
44525202Skarels 	     * and stuff new information
44625202Skarels 	     */
44725202Skarels 	    got_syn(newrdpcb, RDP_SEQNO(pkt));
44825202Skarels 	    synopt = RDP_OPT(pkt, SYNOPTIONS *);
44925202Skarels 	    process_synopt(newrdpcb, synopt);
45025202Skarels 
45125202Skarels 	    /*
45225202Skarels 	     * So can debug connection problems without having to
45325202Skarels 	     * change every program or apply debugging flag to each
45425202Skarels 	     * program every time run it.
45525202Skarels 	     */
45625202Skarels 	    dowedebug(newinp, newso, &rdp_dfilter);
45725202Skarels 
45825202Skarels 	    /*
45925202Skarels 	     * send other guy our SYN and ACK his syn.
46025202Skarels 	     * set re-transmission timer to ensure eventually gets
46125202Skarels 	     * to him.
46225202Skarels 	     */
46325202Skarels 	    rdp_template(newrdpcb);
46425202Skarels 	    (void) rdp_sendpkt (newrdpcb, (MBUF *) NULL, 0,
46525202Skarels 		newrdpcb->r_iss);
46625202Skarels 	    set_rxtimer (newrdpcb, 0);
46725202Skarels 
46825202Skarels 	    newrdpcb->r_state = RDP_sLSYNRCVD;
46925202Skarels 	}
47025202Skarels 	else
47125202Skarels 	rtfree(rt);
47225202Skarels     }
47325202Skarels     m_freem(dtom(pkt));
47425202Skarels     return (RDP_sSAME);
47525202Skarels }
47625202Skarels 
47725202Skarels /*
47825202Skarels  *	state: RDP_sLISTEN
47925202Skarels  *	input: RDP_iUCLOSE
48025202Skarels  */
48125202Skarels /*ARGSUSED*/
rdp_lis_close(rdpcb,nil)48225202Skarels rdp_lis_close (rdpcb, nil)
48325202Skarels RDPCB	*rdpcb;
48425202Skarels {
48525202Skarels     trash_pcbs(rdpcb);
48625202Skarels     return (RDP_sCLOSED);
48725202Skarels }
48825202Skarels 
48925202Skarels /************************************************************************/
49025202Skarels 
49125202Skarels /*
49225202Skarels  *	state: RDP_sSYNSENT
49325202Skarels  *	input: RDP_iNETR
49425202Skarels  */
rdp_synsent_netr(rdpcb,pkt)49525202Skarels rdp_synsent_netr (rdpcb, pkt)
49625202Skarels register RDPCB	*rdpcb;
49725202Skarels register RDPHDR	*pkt;
49825202Skarels {
49925202Skarels     register rdpstate newstate;
50025202Skarels 
50125202Skarels     if (pkt->rh_flags & RDP_fACK)
50225202Skarels     {
50325202Skarels 	if (RDP_ACKNO(pkt) != rdpcb->r_iss)
50425202Skarels 	{
50525202Skarels 	    /*
50625202Skarels 	     * We haven't sent any data yet, only SYNs.
50725202Skarels 	     * He's confused.
50825202Skarels 	     */
50925202Skarels 	    rdp_uncon_rst (pkt);
51025202Skarels 	    return (RDP_sSAME);
51125202Skarels 	}
51225202Skarels     }
51325202Skarels 
51425202Skarels     if (pkt->rh_flags & RDP_fRST)
51525202Skarels     {
51625202Skarels 	/*
51725202Skarels 	 * Require (rst, ack, ackno) to know rst meant for this, not
51825202Skarels 	 * a previous, incarnation of the socket.  Is an "in window"
51925202Skarels 	 * check.  Avoids problems with "slow" packets.
52025202Skarels 	 */
52125202Skarels 	if (pkt->rh_flags & RDP_fACK)
52225202Skarels 	{
52325202Skarels 	    set_error (rdpcb, ECONNREFUSED);
52425202Skarels 	    trash_pcbs(rdpcb);
52525202Skarels 	    newstate = RDP_sCLOSED;
52625202Skarels 	}
52725202Skarels 	else
52825202Skarels 	    newstate = RDP_sSAME;
52925202Skarels 	m_freem(dtom(pkt));
53025202Skarels 	return (newstate);
53125202Skarels     }
53225202Skarels 
53325202Skarels     newstate = RDP_sSAME;
53425202Skarels     if (pkt->rh_flags & RDP_fSYN)
53525202Skarels     {
53625202Skarels 	register SYNOPTIONS	*synopt;
53725202Skarels 	rdpsequence seqnum;
53825202Skarels 
53925202Skarels 	got_syn(rdpcb, RDP_SEQNO(pkt));
54025202Skarels 	synopt = RDP_OPT(pkt, SYNOPTIONS *);
54125202Skarels 	process_synopt(rdpcb, synopt);
54225202Skarels 
54325202Skarels 	if (pkt->rh_flags & RDP_fACK)
54425202Skarels 	{
54525202Skarels 	    rdpcb->r_synacked = TRUE;
54625202Skarels 	    rdpisconnected(rdpcb);
54725202Skarels 	    newstate = RDP_sESTAB;
54825202Skarels 	    seqnum = rdpcb->r_iss +1;
54925202Skarels 	    /* clear re-xmit syn timer set in rdp_unop_connect() */
55025202Skarels 	    clear_rxtimer (rdpcb, 0);
55125202Skarels 	    /* start up connection loss detection */
55225202Skarels 	    rdpcb->r_timers[RDP_tNULL] = rdpcb->r_tvnull;
55325202Skarels 	}
55425202Skarels 	else
55525202Skarels 	{
55625202Skarels 	    newstate = RDP_sSYNRCVD;
55725202Skarels 	    seqnum = rdpcb->r_iss;
55825202Skarels 	    /* keep sending syn until he acks it */
55925202Skarels 	    set_rxtimer (rdpcb, 0);
56025202Skarels 	}
56125202Skarels 	/* and ack his syn, retransmit ours if necessary */
56225202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, seqnum);
56325202Skarels     }
56425202Skarels 
56525202Skarels     m_freem(dtom(pkt));
56625202Skarels     return (newstate);
56725202Skarels }
56825202Skarels 
56925202Skarels /*
57025202Skarels  *	state: RDP_sSYNSENT
57125202Skarels  *	input: RDP_iUCLOSE
57225202Skarels  */
57325202Skarels /*ARGSUSED*/
rdp_synsent_close(rdpcb,nil)57425202Skarels rdp_synsent_close (rdpcb, nil)
57525202Skarels register RDPCB *rdpcb;
57625202Skarels {
57725202Skarels     /* send RST */
57825202Skarels     rdpcb->r_sendrst = TRUE;
57925202Skarels     (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
58025202Skarels     trash_pcbs(rdpcb);
58125202Skarels     return (RDP_sCLOSED);
58225202Skarels }
58325202Skarels 
58425202Skarels 
58525202Skarels /*
58625202Skarels  *	state: RDP_sSYNSENT
58725202Skarels  *	input: RDP_iTIMER
58825202Skarels  */
rdp_synsent_timer(rdpcb,timer)58925202Skarels rdp_synsent_timer (rdpcb, timer)
59025202Skarels register RDPCB *rdpcb;
59125202Skarels {
59225202Skarels     switch (timer)
59325202Skarels     {
59425202Skarels       case RDP_tRTTL:
59525202Skarels 	/* retransmission took too long */
59625202Skarels 	rttl(rdpcb);
59725202Skarels 	return (RDP_sSAME);
59825202Skarels 
59925202Skarels       case RDP_tRXMIT:
60025202Skarels 	/*
60125202Skarels 	 * re-transmit our SYN.  Not every 0.5 second, though,
60225202Skarels 	 * but every RDP_tvRXMIN units.
60325202Skarels 	 */
60425202Skarels 	rdpcb->r_rxtimers[0] --;
60525202Skarels 	if (rdpcb->r_rxtimers[0] == 0)
60625202Skarels 	{
60725202Skarels 	    (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0,
60825202Skarels 		rdpcb->r_iss);
60925202Skarels 	    set_rxtimer (rdpcb, 0);
61025202Skarels #ifdef RDP_CS
61125202Skarels 	    rdpcb->r_sent.r_retrans ++;
61225202Skarels #endif
61325202Skarels 	}
61425202Skarels 	else
61525202Skarels 	    /*
61625202Skarels 	     * ensure keep checking even if no packet goes
61725202Skarels 	     * out this time.  ACK will stop this.
61825202Skarels 	     */
61925202Skarels 	    rdpcb->r_timers[RDP_tRXMIT] = RDP_tvRXCHECK;
62025202Skarels 	break;
62125202Skarels 
62225202Skarels       default:
623*25208Skarels 	log(LOG_INFO, "rdp_synsent_timer:  timer %d\n", timer);
62425202Skarels     }
62525202Skarels 
62625202Skarels     return(RDP_sSAME);
62725202Skarels }
62825202Skarels 
62925202Skarels /************************************************************************/
63025202Skarels 
63125202Skarels /*
63225202Skarels  *	state: RDP_sLSYNRCVD
63325202Skarels  *	input: RDP_iNETR
63425202Skarels  */
rdp_lsynrcvd_netr(rdpcb,pkt)63525202Skarels rdp_lsynrcvd_netr (rdpcb, pkt)
63625202Skarels register RDPCB		*rdpcb;
63725202Skarels register RDPHDR		*pkt;
63825202Skarels {
63925202Skarels     /*
64025202Skarels      * If it's a duplicate syn (seqno == irs), re-send ack since he must
64125202Skarels      * have missed our ack.  If it's out of the window, well, let's give
64225202Skarels      * him the benefit of the doubt and assume it's junk from an old
64325202Skarels      * connection/window that took a while to get to us.
64425202Skarels      */
64525202Skarels     if (SEQ_LEQ(RDP_SEQNO(pkt), rdpcb->r_irs) ||
64625202Skarels 	SEQ_GEQ(RDP_SEQNO(pkt), rdpcb->r_rcvq.rq_baseseq + rdpcb->r_rcvq.rq_maxqlen))
64725202Skarels     {
64825202Skarels 
64925202Skarels #ifdef RDP_CS
65025202Skarels 	rdpcb->r_rcvd.r_retrans ++;
65125202Skarels #endif
65225202Skarels 	/* try to synchronize again */
65325202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_iss);
65425202Skarels 	m_freem(dtom(pkt));
65525202Skarels 	return(RDP_sSAME);
65625202Skarels     }
65725202Skarels 
65825202Skarels     if (pkt->rh_flags & (RDP_fRST|RDP_fEACK|RDP_fSYN))
65925202Skarels     {
66025202Skarels 	if (pkt->rh_flags & RDP_fRST)
66125202Skarels 	{
66225202Skarels 	    /*
66325202Skarels 	     * User closed while his socket was in synsent state.
66425202Skarels 	     */
66525202Skarels 	    set_error (rdpcb, ECONNREFUSED);
66625202Skarels 	    trash_pcbs(rdpcb);
66725202Skarels 	    m_freem(dtom(pkt));
66825202Skarels 	    return (RDP_sCLOSED);
66925202Skarels 	}
67025202Skarels 	if (pkt->rh_flags & RDP_fEACK)
67125202Skarels 	{
67225202Skarels 	    /*
67325202Skarels 	     * shouldn't be EACK, since we haven't sent anything yet
67425202Skarels 	     */
67525202Skarels 	    rdp_uncon_rst (pkt);	/* frees mbufs for pkt */
67625202Skarels 	    return(RDP_sSAME);
67725202Skarels 	}
67825202Skarels 	if (pkt->rh_flags & RDP_fSYN)
67925202Skarels 	{
68025202Skarels 	    /*
68125202Skarels 	     * Boy, is the other end confused!  His syn has changed
68225202Skarels 	     * sequence numbers.
68325202Skarels 	     */
68425202Skarels 	    rdp_uncon_rst (pkt);
68525202Skarels 	    set_error (rdpcb, ECONNRESET);
68625202Skarels 	    trash_pcbs(rdpcb);
68725202Skarels 	    return (RDP_sCLOSED);
68825202Skarels 	}
68925202Skarels     }
69025202Skarels 
69125202Skarels     if (pkt->rh_flags & RDP_fACK)
69225202Skarels     {
69325202Skarels 	if (RDP_ACKNO(pkt) != rdpcb->r_iss)
69425202Skarels 	{
69525202Skarels 	    rdp_uncon_rst (pkt);	/* frees mbufs for pkt */
69625202Skarels 	    return(RDP_sSAME);
69725202Skarels 	}
69825202Skarels     }
69925202Skarels     else
70025202Skarels     {
70125202Skarels 	m_freem(dtom(pkt));
70225202Skarels 	return(RDP_sSAME);
70325202Skarels     }
70425202Skarels 
70525202Skarels     /*
70625202Skarels      * clear timer for re-transmission of syn that we set in
70725202Skarels      * rdp_lis_netr().
70825202Skarels      */
70925202Skarels     clear_rxtimer (rdpcb, 0);
71025202Skarels     rdpcb->r_synacked = TRUE;
71125202Skarels 
71225202Skarels 
71325202Skarels     if (pkt->rh_dlen > rdpcb->r_ourmaxlen)
71425202Skarels     {
715*25208Skarels 	log(LOG_INFO, "RDP too large packet %d > %d\n",
71625202Skarels 	    pkt->rh_dlen, rdpcb->r_ourmaxlen);
71725202Skarels theygoofed :
71825202Skarels 	rdp_uncon_rst(pkt);
71925202Skarels 	rdpcb->r_timers[RDP_tCLOSEWAIT] = rdpcb->r_closewait;
72025202Skarels 	set_error(rdpcb, ECONNRESET);
72125202Skarels 	return (RDP_sCLOSEWAIT);
72225202Skarels     }
72325202Skarels     /*
72425202Skarels      * zero length packets can be NULL messages or (E)ACKs,
72525202Skarels      * but all NULL messages must be zero length
72625202Skarels      */
72725202Skarels     if (pkt->rh_flags & RDP_fNULL)
72825202Skarels     {
72925202Skarels 	if (pkt->rh_dlen != 0)
73025202Skarels 	{
731*25208Skarels 	    log(LOG_INFO, "RDP %d length NULL packet\n", pkt->rh_dlen);
73225202Skarels 	    goto theygoofed;
73325202Skarels 	}
73425202Skarels 	if (RDP_SEQNO(pkt) != rdpcb->r_rcvq.rq_baseseq)
73525202Skarels 	{
736*25208Skarels 	    log(LOG_INFO, "RDP NULL 0x%x rcvq baseseq 0x%x\n",
73725202Skarels 		RDP_SEQNO(pkt), rdpcb->r_rcvq.rq_baseseq);
73825202Skarels 	    goto theygoofed;
73925202Skarels 	}
74025202Skarels 	rdpcb->r_rcvq.rq_msgs[rdpcb->r_rcvq.rq_front] = NULL;
74125202Skarels 	rdpcb->r_rcvq.rq_front =
74225202Skarels 	    (rdpcb->r_rcvq.rq_front +1) % rdpcb->r_rcvq.rq_maxqlen;
74325202Skarels 	rdpcb->r_rcvq.rq_baseseq ++;
74425202Skarels 
74525202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
74625202Skarels 	m_freem(dtom(pkt));
74725202Skarels     }
74825202Skarels     else if (pkt->rh_dlen)
74925202Skarels     {
75025202Skarels #ifdef RDP_CS
75125202Skarels 	if (rdp_qinsert (&rdpcb->r_rcvq, dtom(pkt), RDP_SEQNO(pkt)) == -1)
75225202Skarels 	    rdpcb->r_rcvd.r_retrans ++;
75325202Skarels #else
75425202Skarels 	(void) rdp_qinsert (&rdpcb->r_rcvq, dtom(pkt), RDP_SEQNO(pkt));
75525202Skarels #endif
75625202Skarels 	/* No (e)ack now.  Wait til gets to user */
75725202Skarels     }
75825202Skarels     else
75925202Skarels 	/* Was an ACK-only packet */
76025202Skarels 	m_freem(dtom(pkt));
76125202Skarels 
76225202Skarels 
76325202Skarels     rdpisconnected(rdpcb);
76425202Skarels     /* start up connection loss detection */
76525202Skarels     rdpcb->r_timers[RDP_tNULL] = rdpcb->r_tvnull;
76625202Skarels     return (RDP_sESTAB);
76725202Skarels }
76825202Skarels 
76925202Skarels /*
77025202Skarels  *	state: RDP_sLSYNRCVD
77125202Skarels  *	input: RDP_iUCLOSE
77225202Skarels  */
77325202Skarels /*ARGSUSED*/
rdp_lsynrcvd_close(rdpcb,nil)77425202Skarels rdp_lsynrcvd_close (rdpcb, nil)
77525202Skarels register RDPCB *rdpcb;
77625202Skarels {
77725202Skarels     /* send RST */
77825202Skarels     rdpcb->r_sendrst = TRUE;
77925202Skarels     (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
78025202Skarels     trash_pcbs(rdpcb);
78125202Skarels     return (RDP_sCLOSED);
78225202Skarels }
78325202Skarels 
78425202Skarels /*
78525202Skarels  *	state: RDP_sLSYNRCVD
78625202Skarels  *	input: RDP_iTIMER
78725202Skarels  */
rdp_lsynrcvd_timer(rdpcb,timer)78825202Skarels rdp_lsynrcvd_timer (rdpcb, timer)
78925202Skarels RDPCB	*rdpcb;
79025202Skarels {
79125202Skarels     /* whether connecting via connect(2) (SYNSENT) or child of
79225202Skarels      * or via child of a listen(2)ing socket (LSYNRCVD), need to
79325202Skarels      * retransmit out syn until it gets acked.
79425202Skarels      */
79525202Skarels 
79625202Skarels 
79725202Skarels     return (rdp_synsent_timer (rdpcb, timer));
79825202Skarels }
79925202Skarels 
80025202Skarels /************************************************************************/
80125202Skarels 
80225202Skarels /*
80325202Skarels  *	state: RDP_sSYNRCVD
80425202Skarels  *	input: RDP_iNETR
80525202Skarels  */
rdp_synrcvd_netr(rdpcb,pkt)80625202Skarels rdp_synrcvd_netr (rdpcb, pkt)
80725202Skarels RDPCB	*rdpcb;
80825202Skarels RDPHDR	*pkt;
80925202Skarels {
81025202Skarels     return (rdp_lsynrcvd_netr(rdpcb, pkt));
81125202Skarels }
81225202Skarels 
81325202Skarels /*
81425202Skarels  *	state: RDP_sSYNRCVD
81525202Skarels  *	input: RDP_iUCLOSE
81625202Skarels  */
rdp_synrcvd_close(rdpcb,nil)81725202Skarels rdp_synrcvd_close (rdpcb, nil)
81825202Skarels RDPCB	*rdpcb;
81925202Skarels {
82025202Skarels     return (rdp_lsynrcvd_close(rdpcb, nil));
82125202Skarels }
82225202Skarels 
82325202Skarels /*
82425202Skarels  *	state: RDP_sSYNRCVD
82525202Skarels  *	input: RDP_iTIMER
82625202Skarels  */
rdp_synrcvd_timer(rdpcb,timer)82725202Skarels rdp_synrcvd_timer (rdpcb, timer)
82825202Skarels RDPCB	*rdpcb;
82925202Skarels {
83025202Skarels     return (rdp_lsynrcvd_timer (rdpcb, timer));
83125202Skarels }
83225202Skarels 
83325202Skarels /************************************************************************/
83425202Skarels 
83525202Skarels /*
83625202Skarels  *	state: RDP_sESTAB
83725202Skarels  *	input: RDP_iNETR
83825202Skarels  */
rdp_estab_netr(rdpcb,pkt)83925202Skarels rdp_estab_netr (rdpcb, pkt)
84025202Skarels register RDPCB		*rdpcb;
84125202Skarels register RDPHDR		*pkt;
84225202Skarels {
84325202Skarels     /*
84425202Skarels      * ensure packet is in window.  If not, ack him to straighten things
84525202Skarels      * out.
84625202Skarels      */
84725202Skarels     if (SEQ_LT(RDP_SEQNO(pkt), rdpcb->r_rcvq.rq_baseseq) ||
84825202Skarels 	SEQ_GEQ(RDP_SEQNO(pkt), rdpcb->r_rcvq.rq_baseseq + rdpcb->r_rcvq.rq_maxqlen))
84925202Skarels     {
85025202Skarels #ifdef RDP_CS
85125202Skarels 	rdpcb->r_rcvd.r_retrans ++;
85225202Skarels #endif
85325202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
85425202Skarels 	m_freem(dtom(pkt));
85525202Skarels 	return (RDP_sSAME);
85625202Skarels     }
85725202Skarels 
85825202Skarels     /*
85925202Skarels      * Whenever we receive a packet and we're not already waiting for
86025202Skarels      * an ack of a NULL we sent, reset NULL timer.  Connection is alive.
86125202Skarels      *
86225202Skarels      * Don't reset for any packet if have an outstanding NULL since want
86325202Skarels      * to keep timer at zero and not generate a new NULL segment until
86425202Skarels      * current one is acknowledged.  (This might be a new message, not
86525202Skarels      * the NULL's ack.  Send and receive paths may differ?)
86625202Skarels      *
86725202Skarels      * Don't reset NULL timer on datagram transmissions since those imply
86825202Skarels      * receiving ACKs.  Besides, we want to know if he is up, not if we're
86925202Skarels      * up.
87025202Skarels      */
87125202Skarels     if (rdpcb->r_nullsent == 0)
87225202Skarels 	rdpcb->r_timers[RDP_tNULL] = rdpcb->r_tvnull;
87325202Skarels 
87425202Skarels     if (pkt->rh_flags &  (RDP_fSYN|RDP_fRST))
87525202Skarels     {
87625202Skarels 	m_freem(dtom(pkt));
87725202Skarels 	set_error(rdpcb, ECONNRESET);
87825202Skarels 
87925202Skarels 	if (pkt->rh_flags & RDP_fSYN)
88025202Skarels 	{
88125202Skarels 	    /*
88225202Skarels 	     * We've gotten past the syn stage.  He's confused.
88325202Skarels 	     * His syn has also changed sequence numbers.
88425202Skarels 	     */
88525202Skarels 	    rdpcb->r_sendrst = TRUE;
88625202Skarels 	    (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
88725202Skarels 	    trash_pcbs(rdpcb);
88825202Skarels 	    return (RDP_sCLOSED);
88925202Skarels 	}
89025202Skarels 
89125202Skarels 	/*
89225202Skarels 	 * Since we've been reset, the user cannot send anymore
89325202Skarels 	 * datagrams.  user_cantsendmore() also wakes writers up
89425202Skarels 	 * in case he is doing synchronous i/o and is waiting for
89525202Skarels 	 * buffering space at the (socket) level.
89625202Skarels 	 */
89725202Skarels 	user_cantsendmore(rdpcb);
89825202Skarels 	/*
89925202Skarels 	 * User can't read anymore either, per specification.
90025202Skarels 	 * Reliable delivery and acceptance must be determined
90125202Skarels 	 * by the application before closing.
90225202Skarels 	 */
90325202Skarels 	user_cantreadmore(rdpcb);
90425202Skarels 	cancel_timers(rdpcb);
90525202Skarels 	rdpcb->r_timers[RDP_tCLOSEWAIT] = rdpcb->r_closewait;
90625202Skarels 	return (RDP_sCLOSEWAIT);
90725202Skarels     }
90825202Skarels 
90925202Skarels     if (pkt->rh_flags & RDP_fACK)
91025202Skarels 	he_acked (rdpcb, RDP_ACKNO(pkt));
91125202Skarels 
91225202Skarels     if (pkt->rh_flags & RDP_fEACK)
91325202Skarels     {
91425202Skarels 	register int		 neacks;
91525202Skarels 	register EACKOPTIONS	*eackopt;
91625202Skarels 
91725202Skarels 	neacks = (hdrlen(pkt) - RDPHDRSZ) / sizeof(EACKOPTIONS);
91825202Skarels 	eackopt = RDP_OPT(pkt, EACKOPTIONS *);
91925202Skarels 	while (--neacks >= 0)
92025202Skarels 	{
92125202Skarels 	    he_eacked (rdpcb, ntohl(eackopt->rh_eackno));
92225202Skarels 	    eackopt ++;
92325202Skarels 	}
92425202Skarels     }
92525202Skarels 
92625202Skarels     if (pkt->rh_dlen > rdpcb->r_ourmaxlen)
92725202Skarels     {
928*25208Skarels 	log(LOG_INFO, "RDP pkt too large %d > %d\n",
92925202Skarels 	    pkt->rh_dlen, rdpcb->r_ourmaxlen);
93025202Skarels theygoofed :
93125202Skarels 	rdp_uncon_rst(pkt);
93225202Skarels 	set_error(rdpcb, ECONNRESET);
93325202Skarels 	user_cantsendmore(rdpcb);
93425202Skarels 	user_cantreadmore(rdpcb);
93525202Skarels 	cancel_timers(rdpcb);
93625202Skarels 	rdpcb->r_timers[RDP_tCLOSEWAIT] = rdpcb->r_closewait;
93725202Skarels 	return (RDP_sCLOSEWAIT);
93825202Skarels     }
93925202Skarels 
94025202Skarels     if (pkt->rh_flags & RDP_fNULL)
94125202Skarels     {
94225202Skarels 	if (pkt->rh_dlen != 0)
94325202Skarels 	{
944*25208Skarels 	    log(LOG_INFO, "RDP %d length NULL pkt\n", pkt->rh_dlen);
94525202Skarels 	    goto theygoofed;
94625202Skarels 	}
94725202Skarels 	if (RDP_SEQNO(pkt) != rdpcb->r_rcvq.rq_baseseq)
94825202Skarels 	{
949*25208Skarels 	    log(LOG_INFO, "RDP NULL 0x%x rcvq baseseq 0x%x\n",
95025202Skarels 		RDP_SEQNO(pkt), rdpcb->r_rcvq.rq_baseseq);
95125202Skarels 	    goto theygoofed;
95225202Skarels 	}
95325202Skarels 	rdpcb->r_rcvq.rq_msgs[rdpcb->r_rcvq.rq_front] = NULL;
95425202Skarels 	rdpcb->r_rcvq.rq_front =
95525202Skarels 	    (rdpcb->r_rcvq.rq_front +1) % rdpcb->r_rcvq.rq_maxqlen;
95625202Skarels 	rdpcb->r_rcvq.rq_baseseq ++;
95725202Skarels 
95825202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
95925202Skarels 	m_freem(dtom(pkt));
96025202Skarels     }
96125202Skarels     else if (pkt->rh_dlen)
96225202Skarels     {
96325202Skarels #ifdef RDP_CS
96425202Skarels 	if (rdp_qinsert (&rdpcb->r_rcvq, dtom(pkt), RDP_SEQNO(pkt)) == -1)
96525202Skarels 	    rdpcb->r_rcvd.r_retrans ++;
96625202Skarels #else
96725202Skarels 	(void) rdp_qinsert (&rdpcb->r_rcvq, dtom(pkt), RDP_SEQNO(pkt));
96825202Skarels #endif
96925202Skarels     }
97025202Skarels     else
97125202Skarels 	/* Was an ACK-only packet */
97225202Skarels 	m_freem(dtom(pkt));
97325202Skarels 
97425202Skarels 
97525202Skarels     if (usr_rbuf_is_empty(rdpcb))
97625202Skarels     {
97725202Skarels 	register MBUF *m;
97825202Skarels 
97925202Skarels 	if (m = rdp_qremove(&rdpcb->r_rcvq, !rdpcb->r_sequential))
98025202Skarels 	{
98125202Skarels 	    /*
98225202Skarels 	     * IP and RDP headers should be in the first mbuf.
98325202Skarels 	     * User does not see them.
98425202Skarels 	     */
98525202Skarels 	    pkt = (RDPHDR *) (mtod(m, char *) + sizeof(struct ip));
98625202Skarels #ifdef RDP_CS
98725202Skarels 	    rdpcb->r_rcvd.r_nbytes += pkt->rh_dlen;
98825202Skarels #endif
98925202Skarels 	    m->m_off += sizeof(struct ip) + hdrlen(pkt);
99025202Skarels 	    m->m_len -= sizeof(struct ip) + hdrlen(pkt);
99125202Skarels 
99225202Skarels 	    usr_rbuf_append(rdpcb, m);
99325202Skarels 	    wakeup_reader(rdpcb);
99425202Skarels 	}
99525202Skarels     }
99625202Skarels 
99725202Skarels     /*
99825202Skarels      * datagrams go straight out in response to the send(2) PRU_SEND,
99925202Skarels      * so getting (e)acks doesn't cause an outgoing datagram.
100025202Skarels      * Hold off on (e)ack of incoming packet until user receives it
100125202Skarels      * and we know that by PRU_RCV.
100225202Skarels      */
100325202Skarels     return (RDP_sSAME);
100425202Skarels }
100525202Skarels 
100625202Skarels /*
100725202Skarels  *	state: RDP_sESTAB
100825202Skarels  *	input: RDP_iUCLOSE
100925202Skarels  */
101025202Skarels /*ARGSUSED*/
rdp_estab_close(rdpcb,nil)101125202Skarels rdp_estab_close (rdpcb, nil)
101225202Skarels register RDPCB *rdpcb;
101325202Skarels {
101425202Skarels     /* send RST */
101525202Skarels     rdpcb->r_sendrst = TRUE;
101625202Skarels     (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
101725202Skarels 
101825202Skarels     /*
101925202Skarels      * Don't retransmit unacked datagrams, since user can't pick them
102025202Skarels      * up anymore once he's been reset (according to specification).
102125202Skarels      * Reliable delivery and acceptance must be determined by the
102225202Skarels      * application before closing.
102325202Skarels      */
102425202Skarels     cancel_timers(rdpcb);
102525202Skarels     rdpcb->r_timers[RDP_tCLOSEWAIT] = rdpcb->r_closewait;
102625202Skarels     return (RDP_sCLOSEWAIT);
102725202Skarels }
102825202Skarels 
102925202Skarels /*
103025202Skarels  *	state: RDP_sESTAB
103125202Skarels  *	input: RDP_iTIMER
103225202Skarels  */
rdp_estab_timer(rdpcb,timer)103325202Skarels rdp_estab_timer (rdpcb, timer)
103425202Skarels register RDPCB	*rdpcb;
103525202Skarels {
103625202Skarels     register MBUF	*rxmit_data;
103725202Skarels     register int	index, passes;
103825202Skarels     rdpsequence	seqno;
103925202Skarels 
104025202Skarels     switch (timer)
104125202Skarels     {
104225202Skarels       case RDP_tRTTL:
104325202Skarels 	/* retransmission took too long */
104425202Skarels 	rttl(rdpcb);
104525202Skarels 	return (RDP_sSAME);
104625202Skarels 
104725202Skarels       case RDP_tRXMIT:
104825202Skarels 	/*
104925202Skarels 	 * ensure keep checking even if no packet goes
105025202Skarels 	 * out this time.  ACK will stop this.
105125202Skarels 	 */
105225202Skarels 	rdpcb->r_timers[RDP_tRXMIT] = RDP_tvRXCHECK;
105325202Skarels 
105425202Skarels 	index	= rdpcb->r_sendq.rq_front;
105525202Skarels 	passes	= rdpcb->r_sndnxt - rdpcb->r_snduna;
105625202Skarels 	seqno	= rdpcb->r_sendq.rq_baseseq; /* == r_snduna */
105725202Skarels 
105825202Skarels 	while (--passes >= 0)
105925202Skarels 	{
106025202Skarels 	    if (rdpcb->r_rxtimers[index])
106125202Skarels 	    {
106225202Skarels 		rdpcb->r_rxtimers[index] --;
106325202Skarels 		if (rdpcb->r_rxtimers[index] == 0)
106425202Skarels 		{
106525202Skarels 		    MBUF *m;
106625202Skarels 
106725202Skarels 		    /*
106825202Skarels 		     * Over lossy networks, do not let
106925202Skarels 		     * the round trip time estimate
107025202Skarels 		     * drift unecessarily high.  If we're
107125202Skarels 		     * considering the round-trip-time-
107225202Skarels 		     * measuring packet lost, and are
107325202Skarels 		     * retransmitting it, then we should
107425202Skarels 		     * reset the round trip time measurment
107525202Skarels 		     */
107625202Skarels 		    if (rdpcb->r_rttiming)
107725202Skarels 			if (seqno == rdpcb->r_rttimed)
107825202Skarels 			    rdpcb->r_rttiming = FALSE;
107925202Skarels 
108025202Skarels 		    m = rdpcb->r_sendq.rq_msgs[index];
108125202Skarels 		    if (m == RDP_NULLMSG)
108225202Skarels 		    {
108325202Skarels 			rdpcb->r_sendnull = TRUE;
108425202Skarels 			if (rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, seqno) == 0)
108525202Skarels 			    time_rtt(rdpcb, seqno);
108625202Skarels 
108725202Skarels 			/*
108825202Skarels 			 * Back off on retransmissions,
108925202Skarels 			 * because the host might be
109025202Skarels 			 * down or the network could be
109125202Skarels 			 * jammed.  rxmitime will drop
109225202Skarels 			 * to normal when we get the ACK
109325202Skarels 			 */
109425202Skarels 			rdpcb->r_rxmitime = MIN (RDP_tvRXMAX,
109525202Skarels 						 rdpcb->r_rxmitime << 1);
109625202Skarels 
109725202Skarels 			if (++rdpcb->r_nullsent > RDP_MAXNULL)
109825202Skarels 			{
109925202Skarels 			    /* advisory only */
110025202Skarels 			    set_error(rdpcb, ETIMEDOUT);
110125202Skarels 			    wakeup_reader(rdpcb);
110225202Skarels 			    /* writer timeout via rttl */
110325202Skarels 
110425202Skarels 			    /* avoid rollover to zero
110525202Skarels 			     *
110625202Skarels 			     * NOTE: user will get
110725202Skarels 			     * ETIMEDOUT on every
110825202Skarels 			     * rxmit, another reason
110925202Skarels 			     * to back off above.
111025202Skarels 			     */
111125202Skarels 			    rdpcb->r_nullsent --;
111225202Skarels 			}
111325202Skarels 		    }
111425202Skarels 		    else
111525202Skarels 		    {
111625202Skarels 			if (rxmit_data =m_copy(m, 0, M_COPYALL))
111725202Skarels 			    /*
111825202Skarels 			     * When we 1st sent it, we
111925202Skarels 			     * remembered the len in m_act
112025202Skarels 			     */
112125202Skarels 			    if (rdp_sendpkt(rdpcb,rxmit_data,(int)m->m_act,seqno)==0)
112225202Skarels 			        time_rtt(rdpcb, seqno);
112325202Skarels 
112425202Skarels 			/*
112525202Skarels 			 * We aren't backing off here,
112625202Skarels 			 * since the single number is
112725202Skarels 			 * used for all datagrams,
112825202Skarels 			 * each of which may be at a
112925202Skarels 			 * different nth rxmission
113025202Skarels 			 */
113125202Skarels 		    }
113225202Skarels 
113325202Skarels #ifdef RDP_CS
113425202Skarels 		    rdpcb->r_sent.r_retrans ++;
113525202Skarels #endif
113625202Skarels 		    set_rxtimer (rdpcb, index);
113725202Skarels 		}
113825202Skarels 	    }
113925202Skarels 	    index = (index + 1) % rdpcb->r_sendq.rq_maxqlen;
114025202Skarels 	    seqno ++;
114125202Skarels 	}
114225202Skarels 	break;
114325202Skarels 
114425202Skarels       case RDP_tACKDELAY:
114525202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
114625202Skarels 	break;
114725202Skarels 
114825202Skarels       case RDP_tNULL:
114925202Skarels 	/*
115025202Skarels 	 * If we're retransmitting, then we don't need to
115125202Skarels 	 * send NULL messages.  The NULL timer drops to zero
115225202Skarels 	 * and gets restarted when we get some packet from
115325202Skarels 	 * them (rdp_estab_netr).  User will get ETIMEDOUT
115425202Skarels 	 * from retransmit took too long if we don't get a
115525202Skarels 	 * packet.
115625202Skarels 	 */
115725202Skarels 	if (rdpcb->r_rttlindex < 0)
115825202Skarels 	{
115925202Skarels 	    /* are not retransmitting */
116025202Skarels 
116125202Skarels 	    /*
116225202Skarels 	     * Idea:  The connection has been idle for too
116325202Skarels 	     * long. send a NULL packet which has its own
116425202Skarels 	     * sequence number (so can distinguish slow to
116525202Skarels 	     * arrive ack from ack of this NULL) and
116625202Skarels 	     * retransmit it via normal packet
116725202Skarels 	     * retransmission algorithm.
116825202Skarels 	     */
116925202Skarels 
117025202Skarels 	    if (rdp_qinsert(&rdpcb->r_sendq, RDP_NULLMSG, rdpcb->r_sndnxt) != 1)
117125202Skarels 		panic("rdp RDP_tNULL");
117225202Skarels 
117325202Skarels 	    rdpcb->r_sendnull = TRUE;
117425202Skarels 	    (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
117525202Skarels 	    index = rdpcb->r_sendq.rq_front + (rdpcb->r_sndnxt - rdpcb->r_snduna);
117625202Skarels 	    index %= rdpcb->r_sendq.rq_maxqlen;
117725202Skarels 	    set_rxtimer (rdpcb, index);
117825202Skarels 	    rdpcb->r_sndnxt ++;
117925202Skarels 	    rdpcb->r_nullsent = 1;
118025202Skarels 	}
118125202Skarels 	break;
118225202Skarels 
118325202Skarels       default:
1184*25208Skarels 	log(LOG_INFO, "rdp_estab_timer:  timer %d\n", timer);
118525202Skarels     }
118625202Skarels 
118725202Skarels     return(RDP_sSAME);
118825202Skarels }
118925202Skarels 
119025202Skarels /*
119125202Skarels  *	state: RDP_sESTAB
119225202Skarels  *	input: RDP_iRCV
119325202Skarels  */
119425202Skarels /*ARGSUSED*/
rdp_estab_rcv(rdpcb,nil)119525202Skarels rdp_estab_rcv (rdpcb, nil)
119625202Skarels register RDPCB	*rdpcb;
119725202Skarels {
119825202Skarels     MBUF	*m;
119925202Skarels 
120025202Skarels     /*
120125202Skarels      * Now that user has received the packet, bump the front so that
120225202Skarels      * we can ACK it and move the window along.
120325202Skarels      */
120425202Skarels     rdp_received (&rdpcb->r_rcvq);
120525202Skarels 
120625202Skarels     /*
120725202Skarels      * user picked up the packet we left on the socket for him.
120825202Skarels      * Let's put another one there.
120925202Skarels      */
121025202Skarels     if (m = rdp_qremove(&rdpcb->r_rcvq, !rdpcb->r_sequential))
121125202Skarels     {
121225202Skarels 	RDPHDR *pkt;
121325202Skarels 
121425202Skarels 	/*
121525202Skarels 	 * IP and RDP headers should be in the first mbuf.
121625202Skarels 	 * User does not see them.
121725202Skarels 	 */
121825202Skarels 	pkt = (RDPHDR *) (mtod(m, char *) + sizeof(struct ip));
121925202Skarels #ifdef RDP_CS
122025202Skarels 	rdpcb->r_rcvd.r_nbytes += pkt->rh_dlen;
122125202Skarels #endif
122225202Skarels 	m->m_off += sizeof(struct ip) + hdrlen(pkt);
122325202Skarels 	m->m_len -= sizeof(struct ip) + hdrlen(pkt);
122425202Skarels 
122525202Skarels 	usr_rbuf_append(rdpcb, m);
122625202Skarels 	/* wakeup_reader(rdpcb); is awake, performing read(2) */
122725202Skarels     }
122825202Skarels 
122925202Skarels     /*
123025202Skarels      * Send an ACK, but apply an ACK-delay algorithm in order to
123125202Skarels      * reduce CPU loading on both hosts involved.  Reduces network
123225202Skarels      * load, too.  Skip at most one ACK.
123325202Skarels      */
123425202Skarels     if (rdpcb->r_timers[RDP_tACKDELAY])
123525202Skarels 	(void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
123625202Skarels     else
123725202Skarels 	rdpcb->r_timers[RDP_tACKDELAY] = 1;
123825202Skarels 
123925202Skarels     return (RDP_sSAME);
124025202Skarels }
124125202Skarels 
124225202Skarels /*
124325202Skarels  *	state: RDP_sESTAB
124425202Skarels  *	input: RDP_iSEND
124525202Skarels  */
rdp_estab_send(rdpcb,m)124625202Skarels rdp_estab_send (rdpcb, m)
124725202Skarels register RDPCB	*rdpcb;
124825202Skarels register MBUF	*m;
124925202Skarels {
125025202Skarels     register MBUF	*copym;
125125202Skarels     register int	 len;
125225202Skarels     register int	 index;
125325202Skarels 
125425202Skarels     /*
125525202Skarels      * q message on send q.
125625202Skarels      */
125725202Skarels     if (rdp_qinsert(&rdpcb->r_sendq, m, rdpcb->r_sndnxt) != 1)
125825202Skarels 	panic("rdp_estab_send");
125925202Skarels 
126025202Skarels     /*
126125202Skarels      * Remember the length of the datagram for sending now,
126225202Skarels      * and for retransmissions later.
126325202Skarels      */
126425202Skarels     len = 0;
126525202Skarels     for (copym = m; copym; copym = copym->m_next)
126625202Skarels 	len += copym->m_len;
126725202Skarels     m->m_act = ((MBUF *) len);
126825202Skarels 
126925202Skarels     /*
127025202Skarels      * if reached end of window, block socket code from allowing
127125202Skarels      * sends until get an ACK
127225202Skarels      */
127325202Skarels     if (SEQ_GEQ(rdpcb->r_sndnxt, rdpcb->r_snduna + rdpcb->r_hisnbuf -1))
127425202Skarels 	sendbufisfull(rdpcb);
127525202Skarels 
127625202Skarels     /*
127725202Skarels      * send a copy of the datagram
127825202Skarels      */
127925202Skarels     if (copym = m_copy(m, 0, M_COPYALL))
128025202Skarels 	if (rdp_sendpkt(rdpcb, copym, len, rdpcb->r_sndnxt) == 0)
128125202Skarels 	    time_rtt (rdpcb, rdpcb->r_sndnxt);
128225202Skarels 
128325202Skarels     index = rdpcb->r_sendq.rq_front + (rdpcb->r_sndnxt - rdpcb->r_snduna);
128425202Skarels     index %= rdpcb->r_sendq.rq_maxqlen;
128525202Skarels     set_rxtimer(rdpcb, index);
128625202Skarels 
128725202Skarels     rdpcb->r_sndnxt ++;
128825202Skarels 
128925202Skarels     return (RDP_sSAME);
129025202Skarels }
129125202Skarels 
129225202Skarels /************************************************************************/
129325202Skarels 
129425202Skarels /*
129525202Skarels  *	state: RDP_sCLOSEWAIT
129625202Skarels  *	input: RDP_iNETR
129725202Skarels  */
rdp_closew_netr(rdpcb,pkt)129825202Skarels rdp_closew_netr (rdpcb, pkt)
129925202Skarels RDPCB	*rdpcb;
130025202Skarels RDPHDR	*pkt;
130125202Skarels {
130225202Skarels     rdpstate newstate;
130325202Skarels 
130425202Skarels     if (pkt->rh_flags & RDP_fRST)
130525202Skarels     {
130625202Skarels 	/*
130725202Skarels 	 * We've both agreed to shut down the connection
130825202Skarels 	 */
130925202Skarels 	trash_pcbs(rdpcb);
131025202Skarels 	newstate = RDP_sCLOSED;
131125202Skarels     }
131225202Skarels     else
131325202Skarels 	newstate = RDP_sSAME;
131425202Skarels 
131525202Skarels     m_freem(dtom(pkt));
131625202Skarels     return(newstate);
131725202Skarels }
131825202Skarels 
131925202Skarels /*
132025202Skarels  *	state: RDP_sCLOSEWAIT
132125202Skarels  *	input: RDP_iUCLOSE
132225202Skarels  */
132325202Skarels /*ARGSUSED*/
rdp_closew_close(rdpcb,nil)132425202Skarels rdp_closew_close (rdpcb, nil)
132525202Skarels register RDPCB *rdpcb;
132625202Skarels {
132725202Skarels     /*
132825202Skarels      * rdp_usrreq() only allows one close call to the finite state machine.
132925202Skarels      * Therefore, we entered CLOSEWAIT in response to a RST, not a close.
133025202Skarels      * So, now both sides agree to close co-operatively.
133125202Skarels      */
133225202Skarels     rdpcb->r_sendrst = TRUE;
133325202Skarels     (void) rdp_sendpkt (rdpcb, (MBUF *) NULL, 0, rdpcb->r_sndnxt);
133425202Skarels 
133525202Skarels     trash_pcbs(rdpcb);
133625202Skarels     return(RDP_sCLOSED);
133725202Skarels }
133825202Skarels 
133925202Skarels /*
134025202Skarels  *	state: RDP_sCLOSEWAIT
134125202Skarels  *	input: RDP_iTIMER
134225202Skarels  */
rdp_closew_timer(rdpcb,timer)134325202Skarels rdp_closew_timer (rdpcb, timer)
134425202Skarels RDPCB	*rdpcb;
134525202Skarels {
134625202Skarels     if (timer != RDP_tCLOSEWAIT)
134725202Skarels     {
1348*25208Skarels 	log(LOG_INFO, "rdp_closew_timer:  timer %d\n", timer);
134925202Skarels 	return(RDP_sSAME);
135025202Skarels     }
135125202Skarels 
135225202Skarels     trash_pcbs(rdpcb);
135325202Skarels     return(RDP_sCLOSED);
135425202Skarels }
135525202Skarels 
135625202Skarels /*
135725202Skarels  *	state: RDP_sCLOSEWAIT
135825202Skarels  *	input: RDP_iRCV
135925202Skarels  */
136025202Skarels /*ARGSUSED*/
rdp_closew_rcv(rdpcb,nil)136125202Skarels rdp_closew_rcv(rdpcb, nil)
136225202Skarels {
136325202Skarels     /*
136425202Skarels      * Technically, an illegal transition.  However, socket code drops
136525202Skarels      * system priority level, allowing processing of a network packet
136625202Skarels      * containing RDP reset to cause ESTAB -> CLOSEWAIT in the middle of
136725202Skarels      * passing the user a packet.
136825202Skarels      *
136925202Skarels      * ESTAB ... user receives packet, priority dropped for uiomove()
137025202Skarels      *      --- network packet processed ---
137125202Skarels      * CLOSEWAIT ... socket code continues, causing this action.
137225202Skarels      *
137325202Skarels      * ### This can be a serious problem in general.
137425202Skarels      */
137525202Skarels }
137625202Skarels #endif
1377