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