xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 4497)
1*4497Swnj /* tcp_usrreq.c 1.1 81/10/14 */
2*4497Swnj #include "../h/param.h"
3*4497Swnj #include "../bbnnet/net.h"
4*4497Swnj #include "../bbnnet/tcp.h"
5*4497Swnj #include "../bbnnet/ip.h"
6*4497Swnj #include "../bbnnet/imp.h"
7*4497Swnj #include "../bbnnet/ucb.h"
8*4497Swnj #include "../bbnnet/fsm.h"
9*4497Swnj #include "../bbnnet/tcp_pred.h"
10*4497Swnj 
11*4497Swnj lis_cls(wp)             /* passive open (1) */
12*4497Swnj struct work *wp;
13*4497Swnj {
14*4497Swnj 
15*4497Swnj COUNT(LIS_CLS);
16*4497Swnj 	t_open(wp->w_tcb, PASSIVE);
17*4497Swnj 
18*4497Swnj 	return(LISTEN);
19*4497Swnj }
20*4497Swnj 
21*4497Swnj sys_cls(wp)             /* active open (6) */
22*4497Swnj register struct work *wp;
23*4497Swnj {
24*4497Swnj 
25*4497Swnj COUNT(SYS_CLS);
26*4497Swnj 	t_open(wp->w_tcb, ACTIVE);
27*4497Swnj 	send_ctl(wp->w_tcb);            /* send SYN */
28*4497Swnj 
29*4497Swnj 	return(SYN_SENT);
30*4497Swnj }
31*4497Swnj 
32*4497Swnj cls_opn(wp)             /* close request before receiving foreign SYN (10) */
33*4497Swnj struct work *wp;
34*4497Swnj {
35*4497Swnj 
36*4497Swnj COUNT(CLS_OPN);
37*4497Swnj 	t_close(wp->w_tcb, UCLOSED);
38*4497Swnj 
39*4497Swnj 	return(CLOSED);
40*4497Swnj }
41*4497Swnj 
42*4497Swnj cl2_clw(wp)             /* close request after receiving foreign FIN (13) */
43*4497Swnj struct work *wp;
44*4497Swnj {
45*4497Swnj 	register struct tcb *tp;
46*4497Swnj 
47*4497Swnj COUNT(CL2_CLW);
48*4497Swnj 	tp = wp->w_tcb;
49*4497Swnj 
50*4497Swnj 	tp->snd_fin = TRUE;             /* send our own FIN */
51*4497Swnj 	send_ctl(tp);
52*4497Swnj 	tp->usr_closed = TRUE;
53*4497Swnj 
54*4497Swnj 	return(CLOSING2);
55*4497Swnj }
56*4497Swnj 
57*4497Swnj cls_rwt(wp)             /* rcv request after foreign close (20) */
58*4497Swnj struct work *wp;
59*4497Swnj {
60*4497Swnj 	register struct tcb *tp;
61*4497Swnj 
62*4497Swnj COUNT(CLS_RWT);
63*4497Swnj 	tp = wp->w_tcb;
64*4497Swnj 
65*4497Swnj 	present_data(tp);       /* present any remaining data */
66*4497Swnj 
67*4497Swnj 	if (rcv_empty(tp)) {
68*4497Swnj         	t_close(tp, UCLOSED);
69*4497Swnj          	return(CLOSED);
70*4497Swnj 	} else
71*4497Swnj 		return(RCV_WAIT);
72*4497Swnj 
73*4497Swnj }
74*4497Swnj 
75*4497Swnj fw1_syr(wp)             /* close request on synced connection (24,25) */
76*4497Swnj struct work *wp;
77*4497Swnj {
78*4497Swnj 	register struct tcb *tp;
79*4497Swnj 
80*4497Swnj COUNT(FW1_SYR);
81*4497Swnj 	tp = wp->w_tcb;
82*4497Swnj 
83*4497Swnj 	tp->snd_fin = TRUE;                     /* send FIN */
84*4497Swnj 	send_ctl(tp);
85*4497Swnj 	tp->usr_closed = TRUE;
86*4497Swnj 
87*4497Swnj 	return(FIN_W1);
88*4497Swnj }
89*4497Swnj 
90*4497Swnj sss_syn(wp)             /* incoming seq on open connection (39) */
91*4497Swnj struct work *wp;
92*4497Swnj {
93*4497Swnj 	register struct tcb *tp;
94*4497Swnj 
95*4497Swnj COUNT(SSS_SYN);
96*4497Swnj 	tp = wp->w_tcb;
97*4497Swnj 
98*4497Swnj 	rcv_data(tp, wp->w_dat);
99*4497Swnj 	present_data(tp);
100*4497Swnj 
101*4497Swnj 	return(SAME);
102*4497Swnj }
103*4497Swnj 
104*4497Swnj sss_snd(wp)             /* send request on open connection (40,41) */
105*4497Swnj struct work *wp;
106*4497Swnj {
107*4497Swnj 	register struct tcb *tp;
108*4497Swnj 	register struct mbuf *m, *n;
109*4497Swnj 	register struct ucb *up;
110*4497Swnj 	register off;
111*4497Swnj 	sequence last;
112*4497Swnj 
113*4497Swnj COUNT(SSS_SND);
114*4497Swnj 	tp = wp->w_tcb;
115*4497Swnj 	up = tp->t_ucb;
116*4497Swnj 
117*4497Swnj 	last = tp->snd_off;
118*4497Swnj 
119*4497Swnj 	/* count number of mbufs in send data */
120*4497Swnj 
121*4497Swnj 	for (m = n = (struct mbuf *)wp->w_dat; m != NULL; m = m->m_next) {
122*4497Swnj 		up->uc_ssize++;
123*4497Swnj 		last += m->m_len;
124*4497Swnj 	}
125*4497Swnj 
126*4497Swnj 	/* find end of send buffer and append data */
127*4497Swnj 
128*4497Swnj 	if ((m = up->uc_sbuf) != NULL) {        /* something in send buffer */
129*4497Swnj 		while (m->m_next != NULL) {             /* find the end */
130*4497Swnj 			m = m->m_next;
131*4497Swnj 			last += m->m_len;
132*4497Swnj 		}
133*4497Swnj 		last += m->m_len;
134*4497Swnj 
135*4497Swnj 		/* if there's room in old buffer for new data, consolidate */
136*4497Swnj 
137*4497Swnj 		off = m->m_off + m->m_len;
138*4497Swnj 		while (n != NULL && (MSIZE - off) >= n->m_len) {
139*4497Swnj 			bcopy((caddr_t)((int)n + n->m_off),
140*4497Swnj 			      (caddr_t)((int)m + off), n->m_len);
141*4497Swnj 			m->m_len += n->m_len;
142*4497Swnj 			off += n->m_len;
143*4497Swnj 			up->uc_ssize--;
144*4497Swnj 			n = m_free(n);
145*4497Swnj 		}
146*4497Swnj 		m->m_next = n;
147*4497Swnj 
148*4497Swnj 	} else                                  /* nothing in send buffer */
149*4497Swnj 		up->uc_sbuf = n;
150*4497Swnj 
151*4497Swnj 	if (up->uc_flags & UEOL) {               /* set EOL */
152*4497Swnj 		tp->snd_end = last;
153*4497Swnj 	}
154*4497Swnj 
155*4497Swnj 	if (up->uc_flags & UURG) {              /* urgent data */
156*4497Swnj 		tp->snd_urp = last+1;
157*4497Swnj 		tp->snd_urg = TRUE;
158*4497Swnj 	}
159*4497Swnj 
160*4497Swnj 	send(tp);
161*4497Swnj 
162*4497Swnj 	return(SAME);
163*4497Swnj }
164*4497Swnj 
165*4497Swnj sss_rcv(wp)             /* rcv request on open connection (42) */
166*4497Swnj struct work *wp;
167*4497Swnj {
168*4497Swnj 	register struct tcb *tp;
169*4497Swnj 
170*4497Swnj COUNT(SSS_RCV);
171*4497Swnj 	tp = wp->w_tcb;
172*4497Swnj 
173*4497Swnj 	send_ctl(tp);                   /* send new window */
174*4497Swnj 	present_data(tp);
175*4497Swnj 
176*4497Swnj 	return(SAME);
177*4497Swnj }
178*4497Swnj 
179*4497Swnj cls_nsy(wp)                  /* abort request on unsynced connection (44) */
180*4497Swnj struct work *wp;
181*4497Swnj {
182*4497Swnj 
183*4497Swnj COUNT(CLS_NSY);
184*4497Swnj 	t_close(wp->w_tcb, UABORT);
185*4497Swnj 
186*4497Swnj 	return(CLOSED);
187*4497Swnj }
188*4497Swnj 
189*4497Swnj cls_syn(wp)             /* abort request on synced connection (45) */
190*4497Swnj struct work *wp;
191*4497Swnj {
192*4497Swnj 	register struct tcb *tp;
193*4497Swnj 
194*4497Swnj COUNT(CLS_SYN);
195*4497Swnj 	tp = wp->w_tcb;
196*4497Swnj 
197*4497Swnj 	tp->snd_rst = TRUE;            /* send reset */
198*4497Swnj 	send_null(tp);
199*4497Swnj 	t_close(tp, UABORT);
200*4497Swnj 
201*4497Swnj 	return(CLOSED);
202*4497Swnj }
203*4497Swnj 
204*4497Swnj cls_act(wp)             /* net closing open connection (47) */
205*4497Swnj struct work *wp;
206*4497Swnj {
207*4497Swnj 
208*4497Swnj COUNT(CLS_ACT);
209*4497Swnj 	t_close(wp->w_tcb, UNETDWN);
210*4497Swnj 
211*4497Swnj 	return(CLOSED);
212*4497Swnj }
213*4497Swnj 
214*4497Swnj cls_err(wp)             /* invalid user request in closing states */
215*4497Swnj struct work *wp;
216*4497Swnj {
217*4497Swnj COUNT(CLS_ERR);
218*4497Swnj 	to_user(wp->w_tcb->t_ucb, UCLSERR);
219*4497Swnj 
220*4497Swnj 	return(SAME);
221*4497Swnj }
222*4497Swnj 
223*4497Swnj lis_netr(wp)             /* incoming seg in LISTEN (3,4) */
224*4497Swnj struct work *wp;
225*4497Swnj {
226*4497Swnj 	register struct tcb *tp;
227*4497Swnj 	register struct th *n;
228*4497Swnj 
229*4497Swnj COUNT(LIS_NETR);
230*4497Swnj 	tp = wp->w_tcb;
231*4497Swnj 	n = (struct th *)wp->w_dat;
232*4497Swnj 
233*4497Swnj 	if (!syn_ok(tp, n))             /* must have good SYN */
234*4497Swnj 		return(EFAILEC);
235*4497Swnj 
236*4497Swnj 	/* fill in unspecified foreign host address.  get/create entry
237*4497Swnj 	   in foreign host table.  if none available, ignore.  probably
238*4497Swnj 	   should send reset here. */
239*4497Swnj 
240*4497Swnj 	if ((tp->t_ucb->uc_host = h_make(&n->t_s)) == NULL)
241*4497Swnj 		return(EFAILEC);
242*4497Swnj 
243*4497Swnj 	tp->t_fport = n->t_src;
244*4497Swnj 
245*4497Swnj 	rcv_data(tp, n);
246*4497Swnj 
247*4497Swnj 	if (!tp->fin_rcvd) {            /* no FIN (4) */
248*4497Swnj 
249*4497Swnj 		/* start init timer now that we have foreign host */
250*4497Swnj 
251*4497Swnj 		tp->t_init = T_INIT/2;
252*4497Swnj 		return(L_SYN_RCVD);
253*4497Swnj 
254*4497Swnj 	} else {                        /* got a FIN, start timer (3) */
255*4497Swnj         	tp->t_finack = T_2ML;
256*4497Swnj         	tp->waited_2_ml = FALSE;
257*4497Swnj 		return(CLOSE_WAIT);
258*4497Swnj 	}
259*4497Swnj }
260*4497Swnj 
261*4497Swnj sys_netr(wp)            /* incoming segment after SYN sent (8,9,11,32) */
262*4497Swnj struct work *wp;
263*4497Swnj {
264*4497Swnj 	register struct tcb *tp;
265*4497Swnj 	register struct th *n;
266*4497Swnj 
267*4497Swnj COUNT(SYS_NETR);
268*4497Swnj 	tp = wp->w_tcb;
269*4497Swnj 	n = (struct th *)wp->w_dat;
270*4497Swnj 
271*4497Swnj 	if (!syn_ok(tp, n))             /* must have good SYN */
272*4497Swnj 		return(EFAILEC);
273*4497Swnj 
274*4497Swnj 	rcv_data(tp, n);
275*4497Swnj 
276*4497Swnj 	if (tp->fin_rcvd) {             /* got a FIN */
277*4497Swnj 
278*4497Swnj 		/* if good ACK, present any data */
279*4497Swnj 
280*4497Swnj 		if (n->t_ack) {
281*4497Swnj 
282*4497Swnj 			if (n->t_ackno > tp->iss)       /* 32 */
283*4497Swnj 				present_data(tp);
284*4497Swnj 
285*4497Swnj 		} else {                                /* 9 */
286*4497Swnj                 	tp->t_finack = T_2ML;
287*4497Swnj                 	tp->waited_2_ml = FALSE;
288*4497Swnj 		}
289*4497Swnj 		return (CLOSE_WAIT);
290*4497Swnj 
291*4497Swnj 	} else                          /* no FIN */
292*4497Swnj 
293*4497Swnj 		/* if good ACK, open connection, otherwise wait for one */
294*4497Swnj 
295*4497Swnj 		if (n->t_ack) {                         /* 11 */
296*4497Swnj 			present_data(tp);
297*4497Swnj 			return(ESTAB);
298*4497Swnj 		} else
299*4497Swnj 			return(SYN_RCVD);               /* 8 */
300*4497Swnj }
301*4497Swnj 
302*4497Swnj cl1_netr(wp)            /* incoming seg after we closed (15,18,22,23,30,39) */
303*4497Swnj struct work *wp;
304*4497Swnj {
305*4497Swnj 	register struct tcb *tp;
306*4497Swnj 	register struct th *n;
307*4497Swnj 
308*4497Swnj COUNT(CL1_NETR);
309*4497Swnj 	tp = wp->w_tcb;
310*4497Swnj 	n = (struct th *)wp->w_dat;
311*4497Swnj 
312*4497Swnj 	if (ack_fin(tp, n))                     /* got ACK of our FIN */
313*4497Swnj 
314*4497Swnj         	if (n->t_fin) {                 /* got for FIN (23) */
315*4497Swnj 
316*4497Swnj         		rcv_ctl(tp, n);
317*4497Swnj                 	tp->t_finack = T_2ML;
318*4497Swnj                 	tp->waited_2_ml = FALSE;
319*4497Swnj                         return(TIME_WAIT);
320*4497Swnj         	} else {
321*4497Swnj 
322*4497Swnj 			/* if wait done, see if any data left for user */
323*4497Swnj 
324*4497Swnj         		if (tp->waited_2_ml)
325*4497Swnj 
326*4497Swnj         			if (rcv_empty(tp)) {    /* 15 */
327*4497Swnj 
328*4497Swnj         				t_close(tp, UCLOSED);
329*4497Swnj         				return(CLOSED);
330*4497Swnj         			} else
331*4497Swnj         				return(RCV_WAIT);       /* 18 */
332*4497Swnj 
333*4497Swnj         		else
334*4497Swnj         			return(TIME_WAIT);      /* 22 */
335*4497Swnj 		}
336*4497Swnj 
337*4497Swnj 	else                            /* our FIN not ACKed yet */
338*4497Swnj 
339*4497Swnj 		if (n->t_fin) {                 /* rcvd for FIN (30) */
340*4497Swnj 
341*4497Swnj 			rcv_ctl(tp, n);
342*4497Swnj                 	tp->t_finack = T_2ML;
343*4497Swnj                 	tp->waited_2_ml = FALSE;
344*4497Swnj 
345*4497Swnj 		} else {                        /* no FIN, just proc new data (39) */
346*4497Swnj 
347*4497Swnj         		rcv_data(tp, n);
348*4497Swnj         		present_data(tp);
349*4497Swnj 		}
350*4497Swnj 
351*4497Swnj 	return(SAME);
352*4497Swnj }
353*4497Swnj 
354*4497Swnj cl2_netr(wp)            /* incoming seg after foreign close (16,19,31,39) */
355*4497Swnj struct work *wp;
356*4497Swnj {
357*4497Swnj 	register struct tcb *tp;
358*4497Swnj 	register struct th *n;
359*4497Swnj 
360*4497Swnj COUNT(CL2_NETR);
361*4497Swnj 	tp = wp->w_tcb;
362*4497Swnj 	n = (struct th *)wp->w_dat;
363*4497Swnj 
364*4497Swnj 	if (ack_fin(tp, n)) {                   /* this is ACK of our fin */
365*4497Swnj 
366*4497Swnj 		/* if no data left for user, close; otherwise wait */
367*4497Swnj 
368*4497Swnj 		if (rcv_empty(tp)) {                            /* 16 */
369*4497Swnj 
370*4497Swnj 			t_close(tp, UCLOSED);
371*4497Swnj 			return(CLOSED);
372*4497Swnj 		} else                                          /* 19 */
373*4497Swnj 			return(RCV_WAIT);
374*4497Swnj 
375*4497Swnj 	} else                                  /* no ACK of our FIN */
376*4497Swnj 
377*4497Swnj 		/* duplicate FIN or data */
378*4497Swnj 
379*4497Swnj 		if (n->t_fin)                                   /* 31 */
380*4497Swnj 			send_ctl(tp);           /* ACK duplicate FIN */
381*4497Swnj 
382*4497Swnj 		else {                                          /* 39 */
383*4497Swnj 			rcv_data(tp, n);
384*4497Swnj 			present_data(tp);
385*4497Swnj 		}
386*4497Swnj 
387*4497Swnj 	return(SAME);
388*4497Swnj }
389*4497Swnj 
390*4497Swnj fw1_netr(wp)            /* incoming seg after user close (26,27,28,39) */
391*4497Swnj struct work *wp;
392*4497Swnj {
393*4497Swnj 	register struct tcb *tp;
394*4497Swnj 	register struct th *n;
395*4497Swnj 
396*4497Swnj COUNT(FW1_NETR);
397*4497Swnj 	tp = wp->w_tcb;
398*4497Swnj 	n = (struct th *)wp->w_dat;
399*4497Swnj 
400*4497Swnj 	/* process any incoming data, since we closed but they didn't */
401*4497Swnj 
402*4497Swnj 	rcv_data(tp, n);
403*4497Swnj 	present_data(tp);
404*4497Swnj 
405*4497Swnj 	if (ack_fin(tp, n))                     /* our FIN got ACKed */
406*4497Swnj 
407*4497Swnj 		if (tp->fin_rcvd) {                     /* got for FIN (28) */
408*4497Swnj                 	tp->t_finack = T_2ML;
409*4497Swnj                 	tp->waited_2_ml = FALSE;
410*4497Swnj 			return(TIME_WAIT);
411*4497Swnj 		} else                                  /* no FIN, wait (27) */
412*4497Swnj 			return(FIN_W2);
413*4497Swnj 
414*4497Swnj 	else                                    /* no ACK of FIN */
415*4497Swnj 
416*4497Swnj 		if (tp->fin_rcvd) {                     /* got for FIN (26) */
417*4497Swnj                 	tp->t_finack = T_2ML;
418*4497Swnj                 	tp->waited_2_ml = FALSE;
419*4497Swnj 			return(CLOSING1);
420*4497Swnj                 }
421*4497Swnj 
422*4497Swnj 	return(SAME);                                   /* 39 */
423*4497Swnj }
424*4497Swnj 
425*4497Swnj syr_netr(wp)             /* incoming seg after SYN rcvd (5,33) */
426*4497Swnj struct work *wp;
427*4497Swnj {
428*4497Swnj 	register struct tcb *tp;
429*4497Swnj 	register struct th *n;
430*4497Swnj 
431*4497Swnj COUNT(SYR_NETR);
432*4497Swnj 	tp = wp->w_tcb;
433*4497Swnj 	n = (struct th *)wp->w_dat;
434*4497Swnj 
435*4497Swnj 	if (!n->t_ack || (n->t_ack && n->t_ackno <= tp->iss))  /* must have ACK of our SYN */
436*4497Swnj 		return(EFAILEC);
437*4497Swnj 
438*4497Swnj 	rcv_data(tp, n);
439*4497Swnj 	present_data(tp);
440*4497Swnj 
441*4497Swnj 	/* if no FIN, open connection, otherwise wait for user close */
442*4497Swnj 
443*4497Swnj 	if (tp->fin_rcvd)                               /* 33 */
444*4497Swnj 		return(CLOSE_WAIT);
445*4497Swnj 	else                                            /* 5 */
446*4497Swnj 		return(ESTAB);
447*4497Swnj 
448*4497Swnj }
449*4497Swnj 
450*4497Swnj est_netr(wp)            /* incoming seg on open connection (12,39) */
451*4497Swnj struct work *wp;
452*4497Swnj {
453*4497Swnj 	register struct tcb *tp;
454*4497Swnj 	register struct th *n;
455*4497Swnj 
456*4497Swnj COUNT(EST_NETR);
457*4497Swnj 	tp = wp->w_tcb;
458*4497Swnj 	n = (struct th *)wp->w_dat;
459*4497Swnj 
460*4497Swnj 	rcv_data(tp, n);
461*4497Swnj 	present_data(tp);
462*4497Swnj 
463*4497Swnj 	/* if no FIN, remain open, otherwise wait for user close */
464*4497Swnj 
465*4497Swnj 	if (tp->fin_rcvd)                       /* 12 */
466*4497Swnj 		return(CLOSE_WAIT);
467*4497Swnj 	else                                    /* 39 */
468*4497Swnj         	return(SAME);
469*4497Swnj }
470*4497Swnj 
471*4497Swnj fw2_netr(wp)            /* incoming seg while waiting for for FIN (12,39) */
472*4497Swnj struct work *wp;
473*4497Swnj {
474*4497Swnj 	register struct tcb *tp;
475*4497Swnj 	register struct th *n;
476*4497Swnj 
477*4497Swnj COUNT(FW2_NETR);
478*4497Swnj 	tp = wp->w_tcb;
479*4497Swnj 	n = (struct th *)wp->w_dat;
480*4497Swnj 
481*4497Swnj 	/* process data since we closed, but they may not have */
482*4497Swnj 
483*4497Swnj 	rcv_data(tp, n);
484*4497Swnj 	present_data(tp);
485*4497Swnj 
486*4497Swnj 	/* if we get the FIN, start the finack timer, else keep waiting */
487*4497Swnj 
488*4497Swnj 	if (tp->fin_rcvd) {                     /* got for FIN (29) */
489*4497Swnj 		tp->t_finack = T_2ML;
490*4497Swnj 		tp->waited_2_ml = FALSE;
491*4497Swnj 		return(TIME_WAIT);
492*4497Swnj 	} else                                  /* 39 */
493*4497Swnj         	return(SAME);
494*4497Swnj }
495*4497Swnj 
496*4497Swnj cwt_netr(wp)            /* incoming seg after exchange of FINs (30,31,39) */
497*4497Swnj struct work *wp;
498*4497Swnj {
499*4497Swnj 	register struct tcb *tp;
500*4497Swnj 	register struct th *n;
501*4497Swnj 
502*4497Swnj COUNT(CWT_NETR);
503*4497Swnj 	tp = wp->w_tcb;
504*4497Swnj 	n = (struct th *)wp->w_dat;
505*4497Swnj 
506*4497Swnj 	/* either duplicate FIN or data */
507*4497Swnj 
508*4497Swnj 	if (n->t_fin) {
509*4497Swnj 
510*4497Swnj 		if (n->t_ack && n->t_ackno <= tp->seq_fin) {    /* dup ACK (30) */
511*4497Swnj 
512*4497Swnj                 	rcv_ctl(tp, n);
513*4497Swnj                 	tp->t_finack = T_2ML;
514*4497Swnj                 	tp->waited_2_ml = FALSE;
515*4497Swnj 		} else                                          /* 31 */
516*4497Swnj 			send_ctl(tp);
517*4497Swnj 
518*4497Swnj 	} else {                /* duplicate data (39) */
519*4497Swnj 
520*4497Swnj 		rcv_data(tp, n);
521*4497Swnj 		present_data(tp);
522*4497Swnj 	}
523*4497Swnj 
524*4497Swnj 	return(SAME);
525*4497Swnj }
526*4497Swnj 
527*4497Swnj rwt_netr(wp)            /* incoming seg while waiting for user rcv (30,21) */
528*4497Swnj struct work *wp;
529*4497Swnj {
530*4497Swnj 	register struct tcb *tp;
531*4497Swnj 	register struct th *n;
532*4497Swnj 
533*4497Swnj COUNT(RWT_NETR);
534*4497Swnj 	tp = wp->w_tcb;
535*4497Swnj 	n = (struct th *)wp->w_dat;
536*4497Swnj 
537*4497Swnj 	/* handle duplicate ACK of our FIN */
538*4497Swnj 
539*4497Swnj 	if (n->t_fin && n->t_ack && n->t_ackno <= tp->seq_fin) {    /* 30 */
540*4497Swnj 
541*4497Swnj         	rcv_ctl(tp, n);
542*4497Swnj         	tp->t_finack = T_2ML;
543*4497Swnj         	tp->waited_2_ml = FALSE;
544*4497Swnj 	}
545*4497Swnj 
546*4497Swnj 	return(SAME);
547*4497Swnj }
548*4497Swnj 
549*4497Swnj timers(wp)              /* timer processor (14,17,34,35,36,37,38) */
550*4497Swnj struct work *wp;
551*4497Swnj {
552*4497Swnj 	register struct tcb *tp;
553*4497Swnj 	register type;
554*4497Swnj 
555*4497Swnj COUNT(TIMERS);
556*4497Swnj 	tp = wp->w_tcb;
557*4497Swnj 	type = wp->w_stype;
558*4497Swnj 
559*4497Swnj 	switch (type) {
560*4497Swnj 
561*4497Swnj 	case TINIT:             /* initialization timer */
562*4497Swnj 
563*4497Swnj 		if (!tp->syn_acked) {           /* haven't got ACK of our SYN (35) */
564*4497Swnj 
565*4497Swnj 			t_close(tp, UINTIMO);
566*4497Swnj 			return(CLOSED);
567*4497Swnj 		}
568*4497Swnj 		break;
569*4497Swnj 
570*4497Swnj 	case TFINACK:           /* fin-ack timer */
571*4497Swnj 
572*4497Swnj 		if (tp->t_state == TIME_WAIT) {
573*4497Swnj 
574*4497Swnj 			/* can be sure our ACK of for FIN was rcvd,
575*4497Swnj 			   can close if no data left for user */
576*4497Swnj 
577*4497Swnj 			if (rcv_empty(tp)) {            /* 14 */
578*4497Swnj 				t_close(tp, UCLOSED);
579*4497Swnj 				return(CLOSED);
580*4497Swnj 			} else                          /* 17 */
581*4497Swnj 				return(RCV_WAIT);
582*4497Swnj 
583*4497Swnj 		} else if (tp->t_state == CLOSING1)     /* 37 */
584*4497Swnj 
585*4497Swnj 			/* safe to close */
586*4497Swnj 
587*4497Swnj 			tp->waited_2_ml = TRUE;
588*4497Swnj 
589*4497Swnj 	        break;
590*4497Swnj 
591*4497Swnj 	case TREXMT:            /* retransmission timer */
592*4497Swnj 
593*4497Swnj 		/* set up for a retransmission, increase rexmt time
594*4497Swnj 		   in case of multiple retransmissions. */
595*4497Swnj 
596*4497Swnj 	        if (tp->t_rexmt_val > tp->snd_una) {   /* 34 */
597*4497Swnj 	        	tp->snd_nxt = tp->snd_una;
598*4497Swnj 	        	tp->rexmt = TRUE;
599*4497Swnj 			tp->t_xmtime = tp->t_xmtime << 1;
600*4497Swnj         		if (tp->t_xmtime > T_REMAX)
601*4497Swnj         			tp->t_xmtime = T_REMAX;
602*4497Swnj 	        	send(tp);
603*4497Swnj 	        }
604*4497Swnj 		break;
605*4497Swnj 
606*4497Swnj 	case TREXMTTL:          /* retransmit too long */
607*4497Swnj 
608*4497Swnj 		/* tell user */
609*4497Swnj 
610*4497Swnj         	if (tp->t_rtl_val > tp->snd_una)        /* 36 */
611*4497Swnj         		to_user(tp->t_ucb, URXTIMO);
612*4497Swnj 
613*4497Swnj 		/* if user has already closed, abort the connection */
614*4497Swnj 
615*4497Swnj 		if (tp->usr_closed) {
616*4497Swnj 			t_close(tp, URXTIMO);
617*4497Swnj 			return(CLOSED);
618*4497Swnj 		}
619*4497Swnj 		break;
620*4497Swnj 
621*4497Swnj 	case TPERSIST:          /* persist timer */
622*4497Swnj 
623*4497Swnj 		/* force a byte send through closed window */
624*4497Swnj 
625*4497Swnj         	tp->force_one = TRUE;                   /* 38 */
626*4497Swnj         	send(tp);
627*4497Swnj 		break;
628*4497Swnj 	}
629*4497Swnj 
630*4497Swnj 	return(SAME);
631*4497Swnj }
632*4497Swnj 
633*4497Swnj netprepr(tp, n)         /* network preproc (66,67,68,69,70,71,72,73,74,75,76) */
634*4497Swnj register struct tcb *tp;
635*4497Swnj register struct th *n;
636*4497Swnj {
637*4497Swnj 
638*4497Swnj COUNT(NETPREPR);
639*4497Swnj 	switch (tp->t_state) {
640*4497Swnj 
641*4497Swnj 	case LISTEN:
642*4497Swnj 
643*4497Swnj 		if (n->t_ack || !syn_ok(tp, n))
644*4497Swnj 			send_rst(tp, n);
645*4497Swnj 		else if (!n->t_rst)
646*4497Swnj 			return(0);
647*4497Swnj 		break;
648*4497Swnj 
649*4497Swnj 	case SYN_SENT:
650*4497Swnj 
651*4497Swnj 		if (!ack_ok(tp, n) || !syn_ok(tp, n))
652*4497Swnj 
653*4497Swnj 			send_rst(tp, n);        /* 71,72,75 */
654*4497Swnj 
655*4497Swnj 		else if (n->t_rst) {
656*4497Swnj 
657*4497Swnj 			t_close(tp, URESET);            /* 70 */
658*4497Swnj 			return(CLOSED);
659*4497Swnj 		} else
660*4497Swnj 			return(0);
661*4497Swnj 		break;
662*4497Swnj 
663*4497Swnj 	default:
664*4497Swnj 
665*4497Swnj         	if (n->t_rst) {         /* any resets? */
666*4497Swnj 
667*4497Swnj         		if (n->t_seq >= tp->rcv_nxt) {  /* good reset */
668*4497Swnj 
669*4497Swnj         			if (tp->t_state == L_SYN_RCVD) {
670*4497Swnj 
671*4497Swnj         				if (ack_ok(tp, n)) {    /* 67 */
672*4497Swnj 						t_cancel(tp, TREXMT);
673*4497Swnj 						t_cancel(tp, TREXMTTL);
674*4497Swnj 						t_cancel(tp, TPERSIST);
675*4497Swnj 						h_free(tp->t_ucb->uc_host);
676*4497Swnj         					return(LISTEN);
677*4497Swnj 					}
678*4497Swnj         			} else {                        /* 66 */
679*4497Swnj                         		t_close(tp, URESET);
680*4497Swnj                 			return(CLOSED);
681*4497Swnj         			}
682*4497Swnj         		}                               /* else 69 */
683*4497Swnj         		break;
684*4497Swnj         	}
685*4497Swnj 
686*4497Swnj 	case SYN_RCVD:
687*4497Swnj 
688*4497Swnj 		if (ack_ok(tp, n))              /* acceptable ack */
689*4497Swnj 
690*4497Swnj 			if (syn_ok(tp, n) && n->t_seq != tp->irs)
691*4497Swnj 
692*4497Swnj 				/* bad syn (73,75,76) */
693*4497Swnj 
694*4497Swnj 				send_null(tp);
695*4497Swnj 			else
696*4497Swnj 				return(0);      /* acceptable segment */
697*4497Swnj 		else
698*4497Swnj 			send_rst(tp, n);        /* bad ack (74) */
699*4497Swnj 
700*4497Swnj 	}
701*4497Swnj 
702*4497Swnj 	return(-1);     /* tell caller to eat segment (unacceptable) */
703*4497Swnj }
704