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