fixes for range locking
[unix-history] / usr / src / sys / deprecated / bbnnet / tcp_states.c
CommitLineData
17efd7fe
MK
1#ifdef RCSIDENT
2static char rcsident[] = "$Header: tcp_states.c,v 1.21 85/07/31 09:42:53 walsh Exp $";
3#endif
4
5
6#include "../h/param.h"
7#include "../h/mbuf.h"
8#include "../h/socket.h"
9#include "../h/socketvar.h"
10#include "../h/errno.h"
11#include "../h/systm.h"
12
13#include "../net/if.h"
14#include "../net/route.h"
15
16#include "../bbnnet/in.h"
17#include "../bbnnet/in_pcb.h"
18#include "../bbnnet/in_var.h"
19#include "../bbnnet/net.h"
20#include "../bbnnet/fsm.h"
21#include "../bbnnet/tcp.h"
22#include "../bbnnet/seq.h"
23#include "../bbnnet/ip.h"
24#include "../bbnnet/macros.h"
25#include "../bbnnet/sws.h"
26#ifdef HMPTRAPS
27#include "../bbnnet/hmp_traps.h"
28#endif
29
30extern struct rtentry *ip_route();
31
32/*
33 * These are the action routines of the TCP finite state machine. They are
34 * called from the TCP fsm dispatcher action(). These routines call
35 * on the routines in tcp_procs.c to do the actual segment processing.
36 */
37
38/*
39 * UNOPENED x IUOPENA == passive open == listen()
40 */
41lis_cls(wp)
42struct work *wp;
43{
44 register struct tcpcb *tp = wp->w_tcb;
45
46 /* listen() system call */
47
48 /*
49 * Don't know who we're talking to yet, so we don't have a route
50 * or mtu yet.
51 */
52 tp->t_maxseg = TCPMAXSND;
53 tp->t_timers[TINIT] = tp->t_itimeo;
54
55 return(LISTEN);
56}
57
58/*
59 * UNOPENED x IUOPENR == active open == connect()
60 */
61sys_cls(wp)
62register struct work *wp;
63{
64 register struct tcpcb *tp;
65 register struct inpcb *inp;
66
67 /* connect() system call */
68
69 tp = wp->w_tcb;
70 inp = tp->t_in_pcb;
71 /*
72 * Know foreign host and have a route to there.
73 */
74#ifdef NOTCPOPTS
75 tp->t_maxseg = inp->inp_route.ro_rt->rt_ifp->if_mtu - TCPIPMAX;
76#else
77 /*
78 * Best can do until other guy tells us otherwise.
79 */
80 tp->t_maxseg =
81 MIN(inp->inp_route.ro_rt->rt_ifp->if_mtu - TCPIPMAX, TCPMAXSND);
82#endif
83 tp->t_maxseg -= inp->inp_optlen;
84
85 tp->t_timers[TINIT] = (tp->t_itimeo ? tp->t_itimeo : TCP_tvINIT);
86
87 send_tcp(tp, TCP_CTL); /* send SYN */
88 return(SYN_SENT);
89}
90
91/*
92 * UNOPENED x IUCLOSE
93 * LISTEN x IUCLOSE
94 * SYN_SENT x IUCLOSE
95 *
96 * User close request before receiving foreign SYN
97 */
98cls_opn(wp)
99struct work *wp;
100{
101 t_close(wp->w_tcb, ECONNABORTED);
102 return(CLOSED);
103}
104
105/*
106 * SYN_RCVD x IUCLOSE
107 * L_SYN_RCVD x IUCLOSE
108 * ESTAB x IUCLOSE
109 *
110 * close request on synched connection
111 */
112fw1_syr(wp)
113struct work *wp;
114{
115 register struct tcpcb *tp = wp->w_tcb;
116
117 tp->snd_fin = TRUE; /* send FIN */
118 send_tcp(tp, TCP_CTL);
119 tp->usr_closed = TRUE;
120 tp->t_noact = TCP_tvNOACT;
121 tp->t_timers[TNOACT] = TCP_tvNOACT;
122 return(FIN_W1);
123}
124
125/*
126 * CLOSE_WAIT x IUCLOSE
127 *
128 * close request after received foreign FIN
129 */
130cl2_clw(wp)
131struct work *wp;
132{
133 register struct tcpcb *tp = wp->w_tcb;
134
135 tp->snd_fin = TRUE; /* send our own FIN */
136 send_tcp(tp, TCP_CTL);
137 tp->usr_closed = TRUE;
138 tp->t_noact = TCP_tvNOACT;
139 tp->t_timers[TNOACT] = TCP_tvNOACT;
140 return(CLOSING2);
141}
142
143/*
144 * UNOPENED x IUABORT
145 * LISTEN x IUABORT
146 * SYN_SENT x IUABORT
147 * SYN_RCVD x IUABORT
148 * L_SYN_RCVD x IUABORT
149 *
150 * User abort request on unsynched connection
151 */
152cls_nsy(wp)
153struct work *wp;
154{
155 t_close(wp->w_tcb, ECONNABORTED);
156 return(CLOSED);
157}
158
159/*
160 * ESTAB x IUABORT
161 * FIN_WAIT_1 x IUABORT
162 * FIN_WAIT_2 x IUABORT
163 * TIME_WAIT x IUABORT
164 * CLOSE_WAIT x IUABORT
165 * CLOSING_1 x IUABORT
166 * CLOSING_2 x IUABORT
167 * RCV_WAIT x IUABORT
168 *
169 * User abort request on synched connection
170 */
171cls_syn(wp)
172struct work *wp;
173{
174 register struct tcpcb *tp = wp->w_tcb;
175
176 tp->snd_rst = TRUE; /* send reset */
177 (void) send_pkt(tp, 0, 0);
178 /* tp->ack_due = FALSE; don't since about to throw tcpcb away */
179 t_close(tp, ECONNABORTED);
180 return(CLOSED);
181}
182
183/*
184 * LISTEN x INRECV
185 *
186 * From tcp_input/netprepr, we know the packet is a well formed SYN
187 */
188lis_netr(wp)
189struct work *wp;
190{
191 register struct tcpcb *tp;
192 register struct th *n;
193 register struct inpcb *inp;
194 register struct socket *so, *newso;
195 struct rtentry *rt;
196 struct tcpcb *newtp;
197 struct inpcb *newinp;
198
199 struct in_addr firsthop;
200 extern int ip_nhops;
201 extern struct in_addr ip_hops[];
202
203 n = (struct th *)wp->w_dat;
204
205 /*
206 * Need to route on basis of IP destination -- see ip_send()
207 * ### What if loose routing and 1st hop not on local net and reroute?
208 */
209 if (ip_nhops == 0)
210 firsthop = n->t_s;
211 else
212 /* source routed SYN packet */
213 firsthop = ip_hops[ip_nhops];
214
215 /*
216 * O.k., let's get a route back to him
217 */
218 if (!(rt = ip_route(&n->t_d, &firsthop)))
219 {
220 /*
221 * Can't talk to him. Leave socket in receive state
222 * so we can connect to someone else, since we haven't
223 * been committed to anything yet anyway.
224 * ### Drop his info on the floor.
225 * Let the other machine just figure out on it's own that
226 * it can't reach us that way.
227 */
228 no_route ("tcp", n->t_d, firsthop);
229 return(LISTEN);
230 }
231
232 tp = wp->w_tcb;
233 inp = tp->t_in_pcb;
234 so = inp->inp_socket;
235
236 /*
237 * This socket is in the listen state, so the socket should have
238 * so_options & SO_ACCEPTCONN set (solisten()).
239 *
240 * The order of sonewconn() and soisconnected() is
241 * important, in order for the process to be woken up
242 * at a time when the sleep condition is fulfilled.
243 * sonewconn() is done here on the original socket, and
244 * soisconnected() is done later in syr_netr() on the new
245 * socket.
246 */
247 if (newso = sonewconn(so))
248 {
249 newinp = (struct inpcb *) newso->so_pcb;
250 newtp = (struct tcpcb *) newinp->inp_ppcb;
251 /*
252 * Remember our peer for this connection.
253 */
254 newinp->inp_faddr = n->t_s;
255 newinp->inp_fport = n->t_src;
256 newinp->inp_laddr = n->t_d;
257 if (ip_nhops > 0)
258 {
259 /*
260 * optlen includes the source route to be copied
261 * to the outgoing IP header, not the firsthop
262 * which replaces ip_dst.
263 */
264 bcopy((caddr_t)ip_hops,newinp->inp_options, (unsigned)(ip_nhops+1)*4);
265 newinp->inp_optlen = ip_nhops * 4;
266 }
267 /*
268 * and copy fields into the new inpcb
269 */
270 newinp->inp_lport = inp->inp_lport;
271 newinp->inp_route.ro_rt = rt;
272
273 /*
274 * and copy fields to the new tcpcb
275 */
276 newtp->t_maxfrag = tp->t_maxfrag; /* set in tcp_input() */
277 newtp->t_itimeo = tp->t_itimeo;
278 newtp->t_noact = tp->t_noact;
279 newtp->t_push = tp->t_push;
280 newtp->t_noactsig = tp->t_noactsig;
281 newtp->t_noactprobe = tp->t_noactprobe;
282
283 /*
284 * and initialize others with new info
285 * Upward negotiation of t_maxseg in tcp_opt() done
286 * on socket in LISTEN.
287 */
288 newtp->t_maxseg = MIN(rt->rt_ifp->if_mtu - TCPIPMAX, tp->t_maxseg);
289 newtp->t_maxseg -= newinp->inp_optlen;
290 /*
291 * In case next client doesn't negotiate maxseg.
292 */
293 tp->t_maxseg = TCPMAXSND;
294
295
296 if (!(newtp->t_template = tcp_template(newtp)))
297 {
298 soabort (newso);
299 return (LISTEN);
300 }
301
302 newtp->sws_qff = SWS_QFF_DEF;
303
304 /*
305 * So can debug connection problems without having to change
306 * every program or apply debugging flag to each program every
307 * time run it.
308 */
309 dowedebug(newinp, newso, &tcp_dfilter);
310
311 /*
312 * rcv_tcp may set fin_rcvd. If so, We went up and down or
313 * we got a garbage/misrouted packet. If it's set, it's
314 * meant for some other socket or some other instantiation
315 * of it. In any case, ignore it and listen for other
316 * talkers.
317 */
318 rcv_tcp(newtp, n, TCP_DATA);
319
320 if (newtp->fin_rcvd)
321 soabort (newso);
322 else
323 {
324 /*
325 * no FIN (4)
326 * start init timer now that we have foreign host.
327 * Parent socket might have init timer as zero to
328 * avoid getting ETIMEDOUT, but we do want this
329 * child socket to time out on synchronization
330 * just in case other host just went down.
331 */
332 newtp->t_timers[TINIT] = (newtp->t_itimeo != 0
333 ? newtp->t_itimeo
334 : TCP_tvINIT/2);
335 newtp->t_state = L_SYN_RCVD;
336 }
337 }
338 else
339 rtfree(rt);
340
341 return(LISTEN); /* original file descriptor stays in LISTEN state */
342}
343
344/*
345 * SYN_SENT x INRECV
346 *
347 * from tcp_input/netprepr, we know its a SYN, with perhaps a well formed ACK
348 */
349sys_netr(wp)
350struct work *wp;
351{
352 register struct tcpcb *tp = wp->w_tcb;
353 register struct th *n = (struct th *)wp->w_dat;
354
355 rcv_tcp(tp, n, TCP_DATA);
356 if (tp->fin_rcvd)
357 { /* got a FIN */
358
359 /* if good ACK, present any data */
360
361 if (n->t_flags&T_ACK)
362 {
363 if (SEQ_GT(n->t_ackno, tp->iss)) /* 32 */
364 present_data(tp);
365 }
366 else
367 { /* 9 */
368 tp->t_timers[TFINACK] = TCP_tv2ML;
369 tp->waited_2_ml = FALSE;
370 }
371 tp->t_timers[TNOACT] = tp->t_noact;
372 return (CLOSE_WAIT);
373 }
374 else /* no FIN */
375 /* if good ACK, open connection, otherwise wait for one */
376 if (n->t_flags&T_ACK)
377 { /* 11 */
378 present_data(tp);
379 tp->t_timers[TNOACT] = tp->t_noact;
380 soisconnected (tp->t_in_pcb->inp_socket);
381 return(ESTAB);
382 }
383
384 return(SYN_RCVD); /* 8 */
385}
386
387/*
388 * SYN_RCVD x INRECV
389 * L_SYN_RCVD x INRECV
390 *
391 * from tcp_input/netprepr, we know its an ACK of our SYN
392 */
393syr_netr(wp)
394struct work *wp;
395{
396 register struct tcpcb *tp = wp->w_tcb;
397 register struct th *n = (struct th *)wp->w_dat;
398
399 rcv_tcp(tp, n, TCP_DATA);
400 present_data(tp);
401
402 /* if no FIN, open connection, otherwise wait for user close */
403
404 tp->t_timers[TNOACT] = tp->t_noact;
405 if (tp->fin_rcvd) /* 33 */
406 return(CLOSE_WAIT);
407 else
408 {
409 /* 5 */
410 soisconnected (tp->t_in_pcb->inp_socket);
411 return(ESTAB);
412 }
413}
414
415/*
416 * ESTAB x INRECV
417 */
418est_netr(wp)
419struct work *wp;
420{
421 register struct tcpcb *tp = wp->w_tcb;
422
423 rcv_tcp(tp, (struct th *)wp->w_dat, TCP_DATA);
424 PRESENT_DATA(tp);
425
426 /* if no FIN, remain open, otherwise wait for user close */
427
428 if (tp->fin_rcvd) /* 12 */
429 return(CLOSE_WAIT);
430 else /* 39 */
431 return(SAME);
432}
433
434/*
435 * FIN_WAIT_1 x INRECV
436 *
437 * incoming segment after user has closed
438 */
439fw1_netr(wp)
440struct work *wp;
441{
442 register struct tcpcb *tp = wp->w_tcb;
443 register struct th *n = (struct th *)wp->w_dat;
444
445 /* process any incoming data, since we closed but they didn't */
446
447 rcv_tcp(tp, n, TCP_DATA);
448 present_data(tp);
449
450 /* send any data remaining on send buffer */
451
452 send_tcp(tp, TCP_DATA);
453 if (ack_fin(tp, n))
454 { /* our FIN got ACKed */
455 if (tp->fin_rcvd)
456 { /* got for FIN (28) */
457 tp->t_timers[TFINACK] = TCP_tv2ML;
458 tp->waited_2_ml = FALSE;
459 return(TIME_WAIT);
460 }
461 else /* no FIN, wait (27) */
462 return(FIN_W2);
463 }
464 else
465 { /* no ACK of FIN */
466 if (tp->fin_rcvd)
467 { /* got for FIN (26) */
468 tp->t_timers[TFINACK] = TCP_tv2ML;
469 tp->waited_2_ml = FALSE;
470 return(CLOSING1);
471 }
472 }
473 return(SAME); /* 39 */
474}
475
476/*
477 * FIN_WAIT_2 x INRECV
478 *
479 * incoming segment while waiting for foreign FIN
480 */
481fw2_netr(wp)
482struct work *wp;
483{
484 register struct tcpcb *tp = wp->w_tcb;
485 register struct th *n = (struct th *)wp->w_dat;
486
487 /* process data since we closed, but they may not have */
488
489 rcv_tcp(tp, n, TCP_DATA);
490 present_data(tp);
491
492 /* if we get the FIN, start the finack timer, else keep waiting */
493
494 if (tp->fin_rcvd)
495 { /* got for FIN (29) */
496 tp->t_timers[TFINACK] = TCP_tv2ML;
497 tp->waited_2_ml = FALSE;
498 return(TIME_WAIT);
499 }
500 else /* 39 */
501 return(SAME);
502}
503
504/*
505 * TIME_WAIT x INRECV
506 *
507 * The close protocol (exchange of FINs) has progressed as far as it can.
508 * We do not enter CLOSED immediately, but use TIME_WAIT so that if our ack
509 * of other guys FIN didn't reach him, he can retransmit and we'll ack his
510 * fin rather than respond with an rst.
511 *
512 * Since we received a packet, apparently our ack of his fin didn't get
513 * there and we'll have to try again. Restart finack timer in case this
514 * one fails too.
515 */
516sss_syn(wp)
517struct work *wp;
518{
519 register struct tcpcb *tp = wp->w_tcb;
520
521 rcv_tcp(tp, (struct th *) wp->w_dat, TCP_DATA);
522 present_data(tp);
523 tp->t_timers[TFINACK] = TCP_tv2ML;
524 return(SAME);
525}
526
527/*
528 * CLOSE_WAIT x INRECV
529 *
530 * incoming segment after receipt of foreign FIN (local end still open)
531 */
532cwt_netr(wp)
533struct work *wp;
534{
535 register struct tcpcb *tp = wp->w_tcb;
536 register struct th *n = (struct th *)wp->w_dat;
537
538 /* either duplicate FIN or data */
539
540 if (n->t_flags&T_FIN)
541 {
542 if (n->t_flags&T_ACK && SEQ_LEQ(n->t_ackno, tp->seq_fin))
543 {
544 rcv_tcp(tp, n, TCP_CTL);
545 tp->t_timers[TFINACK] = TCP_tv2ML;
546 tp->waited_2_ml = FALSE;
547 }
548 else /* 31 */
549 send_tcp(tp, TCP_CTL);
550 }
551 else
552 { /* duplicate data (39) */
553 rcv_tcp(tp, n, TCP_DATA);
554 present_data(tp);
555 }
556 return(SAME);
557}
558
559/*
560 * CLOSING_1 x INRECV
561 *
562 * incoming segment after we closed
563 */
564cl1_netr(wp)
565struct work *wp;
566{
567 register struct tcpcb *tp = wp->w_tcb;
568 register struct th *n = (struct th *)wp->w_dat;
569
570 if (ack_fin(tp, n))
571 { /* got ACK of our FIN */
572 if (n->t_flags&T_FIN)
573 { /* got for FIN (23) */
574 rcv_tcp(tp, n, TCP_CTL);
575 tp->t_timers[TFINACK] = TCP_tv2ML;
576 tp->waited_2_ml = FALSE;
577 return(TIME_WAIT);
578 }
579 else
580 {
581
582 /* if wait done, see if any data left for user */
583
584 if (tp->waited_2_ml)
585 if (rcv_empty(tp))
586 { /* 15 */
587 t_close(tp, ECONNABORTED);
588 return(CLOSED);
589 }
590 else
591 return(RCV_WAIT); /* 18 */
592 else
593 return(TIME_WAIT); /* 22 */
594 }
595 }
596 else
597 { /* our FIN not ACKed yet */
598 if (n->t_flags&T_FIN)
599 { /* rcvd for FIN (30) */
600 rcv_tcp(tp, n, TCP_CTL);
601 tp->t_timers[TFINACK] = TCP_tv2ML;
602 tp->waited_2_ml = FALSE;
603 }
604 else
605 { /* no FIN, just proc new data (39) */
606 rcv_tcp(tp, n, TCP_DATA);
607 present_data(tp);
608 }
609 }
610 return(SAME);
611}
612
613/*
614 * CLOSING_2 x INRECV
615 *
616 * incoming segment after both of us have started closing
617 */
618cl2_netr(wp)
619struct work *wp;
620{
621 register struct tcpcb *tp = wp->w_tcb;
622 register struct th *n = (struct th *)wp->w_dat;
623
624 if (ack_fin(tp, n))
625 { /* this is ACK of our fin */
626
627 /* if no data left for user, close; otherwise wait */
628
629 if (rcv_empty(tp))
630 { /* 16 */
631 t_close(tp, ECONNABORTED);
632 return(CLOSED);
633 }
634 else /* 19 */
635 return(RCV_WAIT);
636 }
637 else
638 { /* no ACK of our FIN */
639 /* duplicate FIN or data */
640
641 if (n->t_flags&T_FIN) /* 31 */
642 send_tcp(tp, TCP_CTL); /* ACK duplicate FIN */
643 else
644 {
645 /* 39 */
646 rcv_tcp(tp, n, TCP_DATA);
647 present_data(tp);
648 }
649 }
650 return(SAME);
651}
652
653/*
654 * RCV_WAIT x INRECV
655 */
656rwt_netr(wp) /* incoming seg while waiting for user rcv (30,21) */
657struct work *wp;
658{
659 register struct tcpcb *tp = wp->w_tcb;
660 register struct th *n = (struct th *)wp->w_dat;
661
662 /* handle duplicate ACK of our FIN */
663
664 if (n->t_flags&T_FIN && n->t_flags&T_ACK && SEQ_LEQ(n->t_ackno, tp->seq_fin))
665 { /* 30 */
666 rcv_tcp(tp, n, TCP_CTL);
667 tp->t_timers[TFINACK] = TCP_tv2ML;
668 tp->waited_2_ml = FALSE;
669 }
670 return(SAME);
671}
672
673/*
674 * ESTAB x IURECV
675 * CLOSE_WAIT x IURECV
676 *
677 * and allowing for shutdown()
678 *
679 * FIN_WAIT_1 x IURECV
680 * FIN_WAIT_2 x IURECV
681 * TIME_WAIT x IURECV
682 * CLOSING_1 x IURECV
683 * CLOSING_2 x IURECV
684 */
685sss_rcv(wp) /* rcv request on open connection (42) */
686struct work *wp;
687{
688 register struct tcpcb *tp = wp->w_tcb;
689
690 PRESENT_DATA(tp);
691
692 /* if last window sent was zero, send an ACK to update window */
693
694 if (tp->sent_zero)
695 {
696 tp->force_ack = TRUE; /* don't delay ACK here */
697 send_tcp(tp, TCP_CTL);
698 }
699 return(SAME);
700}
701
702/*
703 * RCV_WAIT x IURECV
704 */
705cls_rwt(wp) /* rcv request after foreign close (20) */
706struct work *wp;
707{
708 register struct tcpcb *tp = wp->w_tcb;
709
710 present_data(tp); /* present any remaining data */
711 if (rcv_empty(tp))
712 {
713 t_close(tp, ECONNABORTED);
714 return(CLOSED);
715 }
716 else
717 return(RCV_WAIT);
718}
719
720/*
721 * SYN_SENT x IUSEND
722 * SYN_RCVD x IUSEND
723 * ESTAB x IUSEND
724 * CLOSE_WAIT x IUSEND
725 *
726 * For SYN_SENT and SYN_RCVD, just want to buffer data until connected.
727 */
728sss_snd(wp) /* send request on open connection (40,41) */
729struct work *wp;
730{
731 register struct tcpcb *tcp = wp->w_tcb;
732 register struct inpcb *inp = tcp->t_in_pcb;
733 sequence last;
734
735 sbappend(&inp->inp_socket->so_snd, (struct mbuf *) wp->w_dat);
736 last = tcp->snd_una + inp->inp_socket->so_snd.sb_cc;
737
738 if (tcp->t_push)
739 tcp->snd_end = last;
740 if (tcp->t_urg)
741 {
742 tcp->snd_urp = last; /* this byte is not urgent */
743 tcp->snd_urg = TRUE;
744 }
745 send_tcp(tcp, TCP_DATA);
746 return(SAME);
747}
748
749cls_act(wp) /* net closing open connection (47) */
750struct work *wp;
751{
752 t_close(wp->w_tcb, ECONNABORTED);
753 return(CLOSED);
754}
755
756cls_err(wp) /* invalid user request in closing states */
757struct work *wp;
758{
759 advise_user(tcpcbtoso(wp->w_tcb), ECONNABORTED);
760 return(SAME);
761}
762
763
764
765timers(wp) /* timer processor (14,17,34,35,36,37,38) */
766struct work *wp;
767{
768 register struct tcpcb *tp = wp->w_tcb;
769 register type = wp->w_stype;
770
771 switch (type)
772 {
773
774 case TINIT: /* initialization timer */
775 /*
776 * Haven't got an ACK of our SYN yet
777 */
778 if (tp->t_in_pcb->inp_socket->so_state & SS_NOFDREF)
779 {
780 /*
781 * was a child socket of a listen(2)er trying to
782 * establish connection with other end.
783 * (state L_SYN_RCVD)
784 */
785 t_close(tp, ETIMEDOUT);
786 return(CLOSED);
787 }
788 /* socket in connect(2) */
789 advise_user(tcpcbtoso(tp), ETIMEDOUT);
790 tp->t_timers[TINIT] = tp->t_itimeo;
791 break;
792
793 case TFINACK: /* fin-ack timer */
794
795 if (tp->t_state == TIME_WAIT)
796 {
797
798 /* can be sure our ACK of for FIN was rcvd,
799 can close if no data left for user */
800
801 if (rcv_empty(tp))
802 { /* 14 */
803 t_close(tp, ECONNABORTED);
804 return(CLOSED);
805 }
806 else /* 17 */
807 return(RCV_WAIT);
808
809 }
810 else if (tp->t_state == CLOSING1) /* 37 */
811
812 /* safe to close */
813
814 tp->waited_2_ml = TRUE;
815
816 break;
817
818 case TREXMT: /* retransmission timer */
819
820 if (is_unacked(tp))
821 {
822 /* statistics */
823 tp->t_rxtct++;
824 tcpstat.t_retransmit ++;
825
826 /*
827 * If we're retransmitting, then the network
828 * may be dropping packets because it is overloaded.
829 * Therefore, increase the retransmission time for
830 * successive retransmissions. When we get an ACK,
831 * the srtt and rxmitime will be recalculated.
832 */
833 tp->t_rxmitime = tp->t_rxmitime << 1;
834 if (tp->t_rxmitime > TCP_tvRXMAX)
835 tp->t_rxmitime = TCP_tvRXMAX;
836
837 tp->snd_nxt = tp->snd_una;
838 tp->rexmt = TRUE;
839 send_tcp(tp, TCP_DATA);
840 tp->rexmt = FALSE;
841 }
842 break;
843
844 case TREXMTTL: /* retransmit too long */
845
846#ifdef HMPTRAPS
847 /* hmp_trap(T_TCP_REXMTTL, (caddr_t)0, 0); */
848#endif
849 if (tp->usr_abort)
850 {
851 /* user has already closed for r/w so abort connection
852 * usr_closed == closed for w (close or shutdown).
853 */
854 t_close(tp, ETIMEDOUT);
855 return(CLOSED);
856 }
857 advise_user(tcpcbtoso(tp), ETIMEDOUT);
858 tp->t_timers[TREXMTTL] = tp->t_rttltimeo;
859 break;
860
861 case TPERSIST: /* persist timer */
862
863 /* force a byte send through closed window */
864
865 tp->force_one = TRUE; /* 38 */
866 send_tcp(tp, TCP_DATA); /* restarts timer */
867 tp->force_one = FALSE;
868 break;
869
870 case TDELACK: /* ack-delay timer */
871
872 /* make sure an ack gets sent now */
873
874 tp->force_ack = TRUE;
875 send_tcp(tp, TCP_CTL);
876 break;
877
878 case TNOACT: /* no activity timer */
879 /*
880 * This timer is used for 2 reasons:
881 * 1) by the user to determine if the connection is idle or if the
882 * other side has aborted/rebooted... This is open states entry.
883 * See tcp_newtcpcb()
884 * 2) by the system to timeout on receipt of ACK of our FIN.
885 * This is separate from use of FINACK timer for other guy
886 * to get our ACK of his FIN. If closing has started, finish it.
887 */
888
889 /*
890 * if its a shutdown(),
891 * usr_closed == TRUE, usr_abort == FALSE
892 * the user will find out about any problems getting an ACK of our
893 * FIN through the retransmit took too long timer
894 * the connection could be idle because it takes the remote end a
895 * while to compute and produce a reply
896 * user only gets to crank up protocol close once, but he can
897 * shutdown and then close, thereby adjusting usr_abort so
898 * that things get cleaned up if the remote host died.
899 *
900 * if its a close(),
901 * usr_closed == TRUE, usr_abort == TRUE
902 * user could be lingering (and SS_NOFDREF will still be false)
903 * connection could be idle because the other host failed, and it
904 * could be down for days. We don't want to wait for it to
905 * come back up and give us a reset. Release resources now.
906 */
907 if (tp->usr_abort)
908 {
909 t_close(tp, ETIMEDOUT);
910 return(CLOSED);
911 }
912
913 if (tp->t_noactprobe)
914 send_tcp(tp, TCP_CTL);
915
916 if (tp->t_noactsig)
917 advise_user(tcpcbtoso(tp), ETIMEDOUT);
918
919 tp->t_timers[TNOACT] = tp->t_noact;
920 break;
921
922 }
923 return(SAME);
924}