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