125202Skarels /*
225202Skarels  $Log:	rdp_subr.c,v $
325202Skarels  * Revision 2.7  84/11/21  12:06:30  walsh
425202Skarels  * *** empty log message ***
525202Skarels  *
625202Skarels  * Revision 2.6  84/11/08  16:12:53  walsh
725202Skarels  * Added code to gather statistics on RDP traffic.  This makes the RDPCB
825202Skarels  * too big unles you make mbufs 512 bytes large.  RDP_CS should be turned off
925202Skarels  * unless you do.
1025202Skarels  *
1125202Skarels  * Revision 2.5  84/11/06  13:54:21  walsh
1225202Skarels  * *** empty log message ***
1325202Skarels  *
1425202Skarels  * Revision 2.4  84/11/05  16:25:18  walsh
1525202Skarels  * tied rdp to icmp source quenches.  See icmp_quench and rdp_quench.
1625202Skarels  *
1725202Skarels  * Revision 2.3  84/11/05  15:55:13  walsh
1825202Skarels  * update_nulltimer() macro began to look inappropriate with recent
1925202Skarels  * changes, so its been stripped out and put in-line.
2025202Skarels  *
2125202Skarels  * Revision 2.2  84/11/02  18:25:47  walsh
2225202Skarels  * Protocol specifiers want NULL message to have own sequence number in
2325202Skarels  * case of slow (t>NULL msg timeout) packets.  I don't see this as a problem,
2425202Skarels  * and even if happened (dubious) would only delay discovery, but I
2525202Skarels  * didn't win this one.  Initially not designed for this, but fixes are
2625202Skarels  * in almost neatly.
2725202Skarels  *
2825202Skarels  * Revision 2.1  84/11/02  10:15:35  walsh
2925202Skarels  * Fixed to include RCS comments in checked out source.
3025202Skarels  *
3125202Skarels  *
3225202Skarels  * description:
3325202Skarels  * Some subroutines for manipulating the datagram q's for RDP.
3425202Skarels  *
3525202Skarels  * revision 1.11
3625202Skarels  * date: 84/07/20 10:30:42;  author: walsh;  state: Exp;  lines added/del: 21/1
3725202Skarels  * Tied RDP acknowledgements to ping reduction, just like TCP.
3825202Skarels  *
3925202Skarels  * revision 1.10
4025202Skarels  * date: 84/07/19 10:22:33;  author: walsh;  state: Exp;  lines added/del: 1/17
4125202Skarels  * Organized macros and classified their definitions in rdp_macros.h.
4225202Skarels  *
4325202Skarels  * revision 1.9
4425202Skarels  * date: 84/07/17 22:35:26;  author: walsh;  state: Exp;  lines added/del: 3/0
4525202Skarels  * Ensure cannot bind port number greater than RDP_pMAX.
4625202Skarels  *
4725202Skarels  * revision 1.8
4825202Skarels  * date: 84/07/12 10:12:48;  author: walsh;  state: Exp;  lines added/del: 14/18
4925202Skarels  * some small optimizations.
5025202Skarels  *
5125202Skarels  * revision 1.7
5225202Skarels  * date: 84/07/12 09:39:06;  author: walsh;  state: Exp;  lines added/del: 2/4
5325202Skarels  * small optimizations.  ( a = (a+1)%b quicker than a++; a %= b)
5425202Skarels  *
5525202Skarels  * revision 1.6
5625202Skarels  * date: 84/07/10 14:58:24;  author: walsh;  state: Exp;  lines added/del: 10/3
5725202Skarels  * Now no unecessary wakeups of the user process are done.
5825202Skarels  *
5925202Skarels  * revision 1.5
6025202Skarels  * date: 84/07/10 10:38:24;  author: walsh;  state: Exp;  lines added/del: 13/13
6125202Skarels  * added register declarations.
6225202Skarels  *
6325202Skarels  * revision 1.4
6425202Skarels  * date: 84/07/06 14:28:53;  author: wjacobso;  state: Exp;  lines added/del: 6/6
6525202Skarels  * *** empty log message ***
6625202Skarels  *
6725202Skarels  * revision 1.3
6825202Skarels  * date: 84/07/06 14:17:02;  author: wjacobso;  state: Exp;  lines added/del: 8/8
6925202Skarels  * added register var definitions
7025202Skarels  *
7125202Skarels  * revision 1.2
7225202Skarels  * date: 84/07/06 09:51:12;  author: root;  state: Exp;  lines added/del: 2/1
7325202Skarels  * This version seems to run bug-free.
7425202Skarels  *
7525202Skarels  * revision 1.1
7625202Skarels  * date: 84/06/26 14:18:30;  author: walsh;  state: Exp;
7725202Skarels  * Initial revision
7825202Skarels  */
7925202Skarels 
8025202Skarels 
8125202Skarels #ifdef RDP
8225202Skarels #include "../h/param.h"
8325202Skarels #include "../h/dir.h"
8425202Skarels #include "../h/user.h"
8525202Skarels #include "../h/kernel.h"
8625202Skarels #include "../h/inode.h"
8725202Skarels #include "../h/mbuf.h"
8825202Skarels #include "../h/socket.h"
8925202Skarels #include "../h/socketvar.h"
9025202Skarels #include "../h/syslog.h"
9125202Skarels 
9225202Skarels #include "../net/if.h"
9325202Skarels #include "../net/route.h"
9425202Skarels 
9525202Skarels #include "../bbnnet/in.h"
9625202Skarels #include "../bbnnet/net.h"
9725202Skarels #include "../bbnnet/in_pcb.h"
9825202Skarels #include "../bbnnet/in_var.h"
9925202Skarels #include "../bbnnet/ip.h"
10025202Skarels #include "../bbnnet/icmp.h"
10125202Skarels #include "../bbnnet/rdp.h"
10225202Skarels #include "../bbnnet/seq.h"
10325202Skarels #include "../bbnnet/rdp_macros.h"
10425202Skarels 
10525202Skarels /*
10625202Skarels  * Called on ACK of a message we sent.
10725202Skarels  */
he_acked(rdpcb,msgnum)10825202Skarels he_acked(rdpcb, msgnum)
10925202Skarels register RDPCB		*rdpcb;
11025202Skarels rdpsequence msgnum;
11125202Skarels {
11225202Skarels     register int		 index;
11325202Skarels     register int		 i;
11425202Skarels     register MBUF		*m;
11525202Skarels 
11625202Skarels     index = msgnum - rdpcb->r_sendq.rq_baseseq;
11725202Skarels     if (index < 0 || index >= rdpcb->r_sendq.rq_maxqlen)
11825202Skarels 	return;
11925202Skarels 
12025202Skarels     /*
12125202Skarels      * an ACK is cumulative and may be for more than one message
12225202Skarels      */
12325202Skarels     for (i=0; i<=index; i++)
12425202Skarels     {
12525202Skarels 	register int j;
12625202Skarels 
12725202Skarels 	j = (rdpcb->r_sendq.rq_front + i) % rdpcb->r_sendq.rq_maxqlen;
12825202Skarels 	m = rdpcb->r_sendq.rq_msgs[j];
12925202Skarels 	/*
13025202Skarels 	 * ignore redundant ACKs.  May have been EACKed (RDP_DELIVERED).
13125202Skarels 	 */
13225202Skarels 	if (m)
13325202Skarels 	{
13425202Skarels 	    if (m == RDP_NULLMSG)
13525202Skarels 	    {
13625202Skarels 		/* and restart connection loss detection */
13725202Skarels 		rdpcb->r_nullsent = 0;
13825202Skarels 		rdpcb->r_timers[RDP_tNULL] = rdpcb->r_tvnull;
13925202Skarels 	    }
14025202Skarels 	    else if (m != RDP_DELIVERED)
14125202Skarels 	    {
14225202Skarels #ifdef RDP_CS
14325202Skarels 		/* count when acked, not queued */
14425202Skarels 		rdpcb->r_sent.r_nbytes += (int) m->m_act;
14525202Skarels #endif
14625202Skarels 		m_freem(m);
14725202Skarels 	    }
14825202Skarels 	    rdpcb->r_sendq.rq_msgs[j] = NULL;
14925202Skarels 	}
15025202Skarels 	clear_rxtimer (rdpcb, j);
15125202Skarels     }
15225202Skarels 
15325202Skarels     /*
15425202Skarels      * Ensure front is always NULL or an undelivered (unacked) message.
15525202Skarels      */
15625202Skarels     rdpcb->r_sendq.rq_front   += (index +1);
15725202Skarels     rdpcb->r_sendq.rq_front   %= rdpcb->r_sendq.rq_maxqlen;
15825202Skarels     rdpcb->r_sendq.rq_baseseq += (index +1);	/* bumps r_snduna */
15925202Skarels 
16025202Skarels     /*
16125202Skarels      * and, did this ack allow us to measure current round trip time?
16225202Skarels      */
16325202Skarels     if (rdpcb->r_rttiming)
16425202Skarels     {
16525202Skarels 	if (SEQ_GT(rdpcb->r_sendq.rq_baseseq, rdpcb->r_rttimed))
16625202Skarels 	{
16725202Skarels 	    update_rttestimate(rdpcb);
16825202Skarels 	    update_rxmitime(rdpcb);
16925202Skarels 	    rdpcb->r_rttiming = FALSE;
17025202Skarels 	}
17125202Skarels     }
17225202Skarels 
17325202Skarels #ifdef BBNPING
17425202Skarels     /*
17525202Skarels      * We've sent him NEW data, perhaps by a gateway, that he
17625202Skarels      * has successfully received.  If that's the case, then
17725202Skarels      * we know the route works and we don't have to ping that
17825202Skarels      * gateway.
17925202Skarels      *
18025202Skarels      * see check_ping()
18125202Skarels      */
18225202Skarels     {
18325202Skarels 	register struct rtentry *rt;
18425202Skarels 
18525202Skarels 	if (rt = rdpcb->r_inpcb->inp_route.ro_rt)
18625202Skarels 	    if (rt->rt_flags & RTF_GATEWAY)
18725202Skarels 		rt->irt_pings = (-1);
18825202Skarels     }
18925202Skarels #endif
19025202Skarels 
19125202Skarels     /*
19225202Skarels      * and let sender send more pkts now that we have space.
19325202Skarels      */
19425202Skarels     sendbufhasspace(rdpcb);
19525202Skarels }
19625202Skarels 
19725202Skarels /*
19825202Skarels  * Called on EACK of a message we sent.
19925202Skarels  */
he_eacked(rdpcb,msgnum)20025202Skarels he_eacked(rdpcb, msgnum)
20125202Skarels register RDPCB		*rdpcb;
20225202Skarels rdpsequence msgnum;
20325202Skarels {
20425202Skarels     register int		 index;
20525202Skarels     register MBUF		*m;
20625202Skarels 
20725202Skarels     index = msgnum - rdpcb->r_sendq.rq_baseseq;
20825202Skarels     if (index < 0 || index >= rdpcb->r_sendq.rq_maxqlen)
20925202Skarels 	return;
21025202Skarels 
21125202Skarels     index = (index + rdpcb->r_sendq.rq_front) % rdpcb->r_sendq.rq_maxqlen;
21225202Skarels     m = rdpcb->r_sendq.rq_msgs[index];
21325202Skarels     /*
21425202Skarels      * ignore redundant EACKs
21525202Skarels      */
21625202Skarels     if (m && (m != RDP_DELIVERED))
21725202Skarels     {
21825202Skarels 	if (m == RDP_NULLMSG)
21925202Skarels 	{
22025202Skarels 	    /* and restart connection loss detection */
22125202Skarels 	    rdpcb->r_nullsent = 0;
22225202Skarels 	    rdpcb->r_timers[RDP_tNULL] = rdpcb->r_tvnull;
223*25209Skarels 	    log(LOG_INFO, "Incorrect ACK strategy on rdpcb 0x%x\n", rdpcb);
22425202Skarels 	}
22525202Skarels 	else
22625202Skarels 	{
22725202Skarels #ifdef RDP_CS
22825202Skarels 	    rdpcb->r_sent.r_nbytes += (int) m->m_act;
22925202Skarels #endif
23025202Skarels 	    m_freem(m);
23125202Skarels 	}
23225202Skarels 	rdpcb->r_sendq.rq_msgs[index] = RDP_DELIVERED;
23325202Skarels 	clear_rxtimer(rdpcb, index);
23425202Skarels 
23525202Skarels 	/*
23625202Skarels 	 * did this eack allow us to measure current round trip time?
23725202Skarels 	 */
23825202Skarels 	if (rdpcb->r_rttiming)
23925202Skarels 	{
24025202Skarels 	    if (msgnum == rdpcb->r_rttimed)
24125202Skarels 	    {
24225202Skarels 		update_rttestimate(rdpcb);
24325202Skarels 		update_rxmitime(rdpcb);
24425202Skarels 		rdpcb->r_rttiming = FALSE;
24525202Skarels 	    }
24625202Skarels 	}
24725202Skarels     }
24825202Skarels }
24925202Skarels 
25025202Skarels 
25125202Skarels /*
25225202Skarels  * Grab a message for passing to the user.  msgq is our rcvq.
25325202Skarels  * Called on net reception if user recv q is empty.
25425202Skarels  * Called on PRU_RECV after user picks up current packet on socket.
25525202Skarels  * Only one packet is attached to the socket at a time.
25625202Skarels  */
rdp_qremove(msgq,async)25725202Skarels MBUF *rdp_qremove(msgq, async)
25825202Skarels register RDP_MSGQ	*msgq;
25925202Skarels {
26025202Skarels     MBUF	*m;
26125202Skarels     int	index;
26225202Skarels     int	pass;
26325202Skarels 
26425202Skarels     index = msgq->rq_front;
26525202Skarels     pass = msgq->rq_maxqlen;
26625202Skarels     do
26725202Skarels     {
26825202Skarels 	m = msgq->rq_msgs[index];
26925202Skarels 	if (m && m != RDP_DELIVERED)
27025202Skarels 	{
27125202Skarels 	    msgq->rq_msgs[index] = RDP_DELIVERED;
27225202Skarels 	    return (m);
27325202Skarels 	}
27425202Skarels 	index = (index +1) % msgq->rq_maxqlen;
27525202Skarels     }
27625202Skarels     while (async && (--pass > 0));
27725202Skarels 
27825202Skarels     return (NULL);
27925202Skarels }
28025202Skarels 
28125202Skarels /*
28225202Skarels  * rdp_qremove() grabbed a message to pass to the user.  When he picks it up,
28325202Skarels  * PRU_RCVD occurs.  At that point, we bump front and we send an ACK.
28425202Skarels  */
rdp_received(msgq)28525202Skarels rdp_received(msgq)
28625202Skarels register RDP_MSGQ	*msgq;
28725202Skarels {
28825202Skarels     register MBUF		*m;
28925202Skarels     register int		 index;
29025202Skarels 
29125202Skarels     do
29225202Skarels     {
29325202Skarels 	index	= msgq->rq_front;
29425202Skarels 	m	= msgq->rq_msgs[index];
29525202Skarels 	if (m == RDP_DELIVERED)
29625202Skarels 	{
29725202Skarels 	    msgq->rq_front = (msgq->rq_front +1) % msgq->rq_maxqlen;
29825202Skarels 	    msgq->rq_baseseq ++;
29925202Skarels 	    msgq->rq_msgs[index] = NULL;
30025202Skarels 	}
30125202Skarels     }
30225202Skarels     while (m == RDP_DELIVERED);
30325202Skarels }
30425202Skarels 
30525202Skarels /*
30625202Skarels  * Put a message on our send or rcv q.
30725202Skarels  *
30825202Skarels  *	0	internal error somewhere
30925202Skarels  *	1	new message
31025202Skarels  *	-1	duplicate message
31125202Skarels  */
rdp_qinsert(msgq,m,msgnum)31225202Skarels rdp_qinsert(msgq, m, msgnum)
31325202Skarels register RDP_MSGQ	*msgq;
31425202Skarels MBUF	*m;
31525202Skarels rdpsequence msgnum;
31625202Skarels {
31725202Skarels     register int		 index;
31825202Skarels     int isdup;
31925202Skarels 
32025202Skarels     index = msgnum - msgq->rq_baseseq;
32125202Skarels     if ((index < 0) || (index >= msgq->rq_maxqlen))
32225202Skarels     {
32325202Skarels 	m_freem(m);
32425202Skarels 	return(0);
32525202Skarels     }
32625202Skarels 
32725202Skarels     index = (index + msgq->rq_front) % msgq->rq_maxqlen;
32825202Skarels     if (msgq->rq_msgs[index] == RDP_DELIVERED)
32925202Skarels     {
33025202Skarels 	/* rcvd duplicate of a message the user already has on socket */
33125202Skarels 	m_freem(m);
33225202Skarels 	isdup = -1;
33325202Skarels     }
33425202Skarels     else
33525202Skarels     {
33625202Skarels 	if (msgq->rq_msgs[index])
33725202Skarels 	{
33825202Skarels 	    m_freem(msgq->rq_msgs[index]);
33925202Skarels 	    isdup = -1;
34025202Skarels 	}
34125202Skarels 	else
34225202Skarels 	    isdup = 1;
34325202Skarels 	msgq->rq_msgs[index] = m;
34425202Skarels     }
34525202Skarels     return(isdup);
34625202Skarels }
34725202Skarels #endif
348