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