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