1 /*
2  $Log:	rdp_subr.c,v $
3  * Revision 2.7  84/11/21  12:06:30  walsh
4  * *** empty log message ***
5  *
6  * Revision 2.6  84/11/08  16:12:53  walsh
7  * Added code to gather statistics on RDP traffic.  This makes the RDPCB
8  * too big unles you make mbufs 512 bytes large.  RDP_CS should be turned off
9  * unless you do.
10  *
11  * Revision 2.5  84/11/06  13:54:21  walsh
12  * *** empty log message ***
13  *
14  * Revision 2.4  84/11/05  16:25:18  walsh
15  * tied rdp to icmp source quenches.  See icmp_quench and rdp_quench.
16  *
17  * Revision 2.3  84/11/05  15:55:13  walsh
18  * update_nulltimer() macro began to look inappropriate with recent
19  * changes, so its been stripped out and put in-line.
20  *
21  * Revision 2.2  84/11/02  18:25:47  walsh
22  * Protocol specifiers want NULL message to have own sequence number in
23  * case of slow (t>NULL msg timeout) packets.  I don't see this as a problem,
24  * and even if happened (dubious) would only delay discovery, but I
25  * didn't win this one.  Initially not designed for this, but fixes are
26  * in almost neatly.
27  *
28  * Revision 2.1  84/11/02  10:15:35  walsh
29  * Fixed to include RCS comments in checked out source.
30  *
31  *
32  * description:
33  * Some subroutines for manipulating the datagram q's for RDP.
34  *
35  * revision 1.11
36  * date: 84/07/20 10:30:42;  author: walsh;  state: Exp;  lines added/del: 21/1
37  * Tied RDP acknowledgements to ping reduction, just like TCP.
38  *
39  * revision 1.10
40  * date: 84/07/19 10:22:33;  author: walsh;  state: Exp;  lines added/del: 1/17
41  * Organized macros and classified their definitions in rdp_macros.h.
42  *
43  * revision 1.9
44  * date: 84/07/17 22:35:26;  author: walsh;  state: Exp;  lines added/del: 3/0
45  * Ensure cannot bind port number greater than RDP_pMAX.
46  *
47  * revision 1.8
48  * date: 84/07/12 10:12:48;  author: walsh;  state: Exp;  lines added/del: 14/18
49  * some small optimizations.
50  *
51  * revision 1.7
52  * date: 84/07/12 09:39:06;  author: walsh;  state: Exp;  lines added/del: 2/4
53  * small optimizations.  ( a = (a+1)%b quicker than a++; a %= b)
54  *
55  * revision 1.6
56  * date: 84/07/10 14:58:24;  author: walsh;  state: Exp;  lines added/del: 10/3
57  * Now no unecessary wakeups of the user process are done.
58  *
59  * revision 1.5
60  * date: 84/07/10 10:38:24;  author: walsh;  state: Exp;  lines added/del: 13/13
61  * added register declarations.
62  *
63  * revision 1.4
64  * date: 84/07/06 14:28:53;  author: wjacobso;  state: Exp;  lines added/del: 6/6
65  * *** empty log message ***
66  *
67  * revision 1.3
68  * date: 84/07/06 14:17:02;  author: wjacobso;  state: Exp;  lines added/del: 8/8
69  * added register var definitions
70  *
71  * revision 1.2
72  * date: 84/07/06 09:51:12;  author: root;  state: Exp;  lines added/del: 2/1
73  * This version seems to run bug-free.
74  *
75  * revision 1.1
76  * date: 84/06/26 14:18:30;  author: walsh;  state: Exp;
77  * Initial revision
78  */
79 
80 
81 #ifdef RDP
82 #include "../h/param.h"
83 #include "../h/dir.h"
84 #include "../h/user.h"
85 #include "../h/kernel.h"
86 #include "../h/inode.h"
87 #include "../h/mbuf.h"
88 #include "../h/socket.h"
89 #include "../h/socketvar.h"
90 #include "../h/syslog.h"
91 
92 #include "../net/if.h"
93 #include "../net/route.h"
94 
95 #include "../bbnnet/in.h"
96 #include "../bbnnet/net.h"
97 #include "../bbnnet/in_pcb.h"
98 #include "../bbnnet/in_var.h"
99 #include "../bbnnet/ip.h"
100 #include "../bbnnet/icmp.h"
101 #include "../bbnnet/rdp.h"
102 #include "../bbnnet/seq.h"
103 #include "../bbnnet/rdp_macros.h"
104 
105 /*
106  * Called on ACK of a message we sent.
107  */
108 he_acked(rdpcb, msgnum)
109 register RDPCB		*rdpcb;
110 rdpsequence msgnum;
111 {
112     register int		 index;
113     register int		 i;
114     register MBUF		*m;
115 
116     index = msgnum - rdpcb->r_sendq.rq_baseseq;
117     if (index < 0 || index >= rdpcb->r_sendq.rq_maxqlen)
118 	return;
119 
120     /*
121      * an ACK is cumulative and may be for more than one message
122      */
123     for (i=0; i<=index; i++)
124     {
125 	register int j;
126 
127 	j = (rdpcb->r_sendq.rq_front + i) % rdpcb->r_sendq.rq_maxqlen;
128 	m = rdpcb->r_sendq.rq_msgs[j];
129 	/*
130 	 * ignore redundant ACKs.  May have been EACKed (RDP_DELIVERED).
131 	 */
132 	if (m)
133 	{
134 	    if (m == RDP_NULLMSG)
135 	    {
136 		/* and restart connection loss detection */
137 		rdpcb->r_nullsent = 0;
138 		rdpcb->r_timers[RDP_tNULL] = rdpcb->r_tvnull;
139 	    }
140 	    else if (m != RDP_DELIVERED)
141 	    {
142 #ifdef RDP_CS
143 		/* count when acked, not queued */
144 		rdpcb->r_sent.r_nbytes += (int) m->m_act;
145 #endif
146 		m_freem(m);
147 	    }
148 	    rdpcb->r_sendq.rq_msgs[j] = NULL;
149 	}
150 	clear_rxtimer (rdpcb, j);
151     }
152 
153     /*
154      * Ensure front is always NULL or an undelivered (unacked) message.
155      */
156     rdpcb->r_sendq.rq_front   += (index +1);
157     rdpcb->r_sendq.rq_front   %= rdpcb->r_sendq.rq_maxqlen;
158     rdpcb->r_sendq.rq_baseseq += (index +1);	/* bumps r_snduna */
159 
160     /*
161      * and, did this ack allow us to measure current round trip time?
162      */
163     if (rdpcb->r_rttiming)
164     {
165 	if (SEQ_GT(rdpcb->r_sendq.rq_baseseq, rdpcb->r_rttimed))
166 	{
167 	    update_rttestimate(rdpcb);
168 	    update_rxmitime(rdpcb);
169 	    rdpcb->r_rttiming = FALSE;
170 	}
171     }
172 
173 #ifdef BBNPING
174     /*
175      * We've sent him NEW data, perhaps by a gateway, that he
176      * has successfully received.  If that's the case, then
177      * we know the route works and we don't have to ping that
178      * gateway.
179      *
180      * see check_ping()
181      */
182     {
183 	register struct rtentry *rt;
184 
185 	if (rt = rdpcb->r_inpcb->inp_route.ro_rt)
186 	    if (rt->rt_flags & RTF_GATEWAY)
187 		rt->irt_pings = (-1);
188     }
189 #endif
190 
191     /*
192      * and let sender send more pkts now that we have space.
193      */
194     sendbufhasspace(rdpcb);
195 }
196 
197 /*
198  * Called on EACK of a message we sent.
199  */
200 he_eacked(rdpcb, msgnum)
201 register RDPCB		*rdpcb;
202 rdpsequence msgnum;
203 {
204     register int		 index;
205     register MBUF		*m;
206 
207     index = msgnum - rdpcb->r_sendq.rq_baseseq;
208     if (index < 0 || index >= rdpcb->r_sendq.rq_maxqlen)
209 	return;
210 
211     index = (index + rdpcb->r_sendq.rq_front) % rdpcb->r_sendq.rq_maxqlen;
212     m = rdpcb->r_sendq.rq_msgs[index];
213     /*
214      * ignore redundant EACKs
215      */
216     if (m && (m != RDP_DELIVERED))
217     {
218 	if (m == RDP_NULLMSG)
219 	{
220 	    /* and restart connection loss detection */
221 	    rdpcb->r_nullsent = 0;
222 	    rdpcb->r_timers[RDP_tNULL] = rdpcb->r_tvnull;
223 	    log(LOG_INFO, "Incorrect ACK strategy on rdpcb 0x%x\n", rdpcb);
224 	}
225 	else
226 	{
227 #ifdef RDP_CS
228 	    rdpcb->r_sent.r_nbytes += (int) m->m_act;
229 #endif
230 	    m_freem(m);
231 	}
232 	rdpcb->r_sendq.rq_msgs[index] = RDP_DELIVERED;
233 	clear_rxtimer(rdpcb, index);
234 
235 	/*
236 	 * did this eack allow us to measure current round trip time?
237 	 */
238 	if (rdpcb->r_rttiming)
239 	{
240 	    if (msgnum == rdpcb->r_rttimed)
241 	    {
242 		update_rttestimate(rdpcb);
243 		update_rxmitime(rdpcb);
244 		rdpcb->r_rttiming = FALSE;
245 	    }
246 	}
247     }
248 }
249 
250 
251 /*
252  * Grab a message for passing to the user.  msgq is our rcvq.
253  * Called on net reception if user recv q is empty.
254  * Called on PRU_RECV after user picks up current packet on socket.
255  * Only one packet is attached to the socket at a time.
256  */
257 MBUF *rdp_qremove(msgq, async)
258 register RDP_MSGQ	*msgq;
259 {
260     MBUF	*m;
261     int	index;
262     int	pass;
263 
264     index = msgq->rq_front;
265     pass = msgq->rq_maxqlen;
266     do
267     {
268 	m = msgq->rq_msgs[index];
269 	if (m && m != RDP_DELIVERED)
270 	{
271 	    msgq->rq_msgs[index] = RDP_DELIVERED;
272 	    return (m);
273 	}
274 	index = (index +1) % msgq->rq_maxqlen;
275     }
276     while (async && (--pass > 0));
277 
278     return (NULL);
279 }
280 
281 /*
282  * rdp_qremove() grabbed a message to pass to the user.  When he picks it up,
283  * PRU_RCVD occurs.  At that point, we bump front and we send an ACK.
284  */
285 rdp_received(msgq)
286 register RDP_MSGQ	*msgq;
287 {
288     register MBUF		*m;
289     register int		 index;
290 
291     do
292     {
293 	index	= msgq->rq_front;
294 	m	= msgq->rq_msgs[index];
295 	if (m == RDP_DELIVERED)
296 	{
297 	    msgq->rq_front = (msgq->rq_front +1) % msgq->rq_maxqlen;
298 	    msgq->rq_baseseq ++;
299 	    msgq->rq_msgs[index] = NULL;
300 	}
301     }
302     while (m == RDP_DELIVERED);
303 }
304 
305 /*
306  * Put a message on our send or rcv q.
307  *
308  *	0	internal error somewhere
309  *	1	new message
310  *	-1	duplicate message
311  */
312 rdp_qinsert(msgq, m, msgnum)
313 register RDP_MSGQ	*msgq;
314 MBUF	*m;
315 rdpsequence msgnum;
316 {
317     register int		 index;
318     int isdup;
319 
320     index = msgnum - msgq->rq_baseseq;
321     if ((index < 0) || (index >= msgq->rq_maxqlen))
322     {
323 	m_freem(m);
324 	return(0);
325     }
326 
327     index = (index + msgq->rq_front) % msgq->rq_maxqlen;
328     if (msgq->rq_msgs[index] == RDP_DELIVERED)
329     {
330 	/* rcvd duplicate of a message the user already has on socket */
331 	m_freem(m);
332 	isdup = -1;
333     }
334     else
335     {
336 	if (msgq->rq_msgs[index])
337 	{
338 	    m_freem(msgq->rq_msgs[index]);
339 	    isdup = -1;
340 	}
341 	else
342 	    isdup = 1;
343 	msgq->rq_msgs[index] = m;
344     }
345     return(isdup);
346 }
347 #endif
348