xref: /original-bsd/sys/netinet/tcp_usrreq.c (revision 2d15e5d1)
1 /* tcp_usrreq.c 1.30 81/11/18 */
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/mbuf.h"
6 #include "../h/socket.h"
7 #include "../h/socketvar.h"
8 #include "../h/protosw.h"
9 #include "../net/inet.h"
10 #include "../net/inet_host.h"
11 #include "../net/inet_pcb.h"
12 #include "../net/inet_systm.h"
13 #include "../net/imp.h"
14 #include "../net/ip.h"
15 #include "../net/ip_var.h"
16 #include "../net/tcp.h"
17 #define TCPFSTAB
18 #ifdef TCPDEBUG
19 #define TCPSTATES
20 #endif
21 #include "../net/tcp_fsm.h"
22 #include "../net/tcp_var.h"
23 #include "/usr/include/errno.h"
24 
25 /*
26  * Tcp initialization
27  */
28 tcp_init()
29 {
30 
31 	tcp_iss = 1;		/* wrong */
32 	tcb.inp_next = tcb.inp_prev = &tcb;
33 }
34 
35 /*
36  * Tcp finite state machine entries for timer and user generated
37  * requests.  These routines raise the ipl to that of the network
38  * to prevent reentry.  In particluar, this requires that the software
39  * clock interrupt have lower priority than the network so that
40  * we can enter the network from timeout routines without improperly
41  * nesting the interrupt stack.
42  */
43 
44 /*
45  * Tcp protocol timeout routine called every 500 ms.
46  * Updates the timers in all active tcb's and
47  * causes finite state machine actions if timers expire.
48  */
49 tcp_slowtimo()
50 {
51 	register struct inpcb *ip;
52 	register struct tcpcb *tp;
53 	int s = splnet();
54 	register short *tmp;
55 	register int i;
56 COUNT(TCP_TIMEO);
57 
58 	/*
59 	 * Search through tcb's and update active timers.
60 	 */
61 	for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) {
62 		tp = intotcpcb(ip);
63 		tmp = &tp->t_init;
64 		for (i = 0; i < TNTIMERS; i++) {
65 			if (*tmp && --*tmp == 0)
66 				(void) tcp_usrreq(tp->t_inpcb->inp_socket,
67 				    PRU_SLOWTIMO, (struct mbuf *)0,
68 				    (caddr_t)i);
69 			tmp++;
70 		}
71 		tp->t_xmt++;
72 	}
73 	tcp_iss += ISSINCR/2;		/* increment iss */
74 	splx(s);
75 }
76 
77 /*
78  * Cancel all timers for tcp tp.
79  */
80 tcp_tcancel(tp)
81 	struct tcpcb *tp;
82 {
83 	register short *tmp = &tp->t_init;
84 	register int i;
85 
86 	for (i = 0; i < TNTIMERS; i++)
87 		*tmp++ = 0;
88 }
89 
90 /*
91  * Process a TCP user request for tcp tb.  If this is a send request
92  * then m is the mbuf chain of send data.  If this is a timer expiration
93  * (called from the software clock routine), then timertype tells which timer.
94  */
95 tcp_usrreq(so, req, m, addr)
96 	struct socket *so;
97 	int req;
98 	struct mbuf *m;
99 	caddr_t addr;
100 {
101 	register struct inpcb *inp = sotoinpcb(so);
102 	register struct tcpcb *tp;
103 	int s = splnet();
104 	register int nstate;
105 #ifdef TCPDEBUG
106 	struct tcp_debug tdb;
107 #endif
108 	int error = 0;
109 COUNT(TCP_USRREQ);
110 
111 	/*
112 	 * Make sure attached.  If not,
113 	 * only PRU_ATTACH is valid.
114 	 */
115 #ifdef TCPDEBUG
116 	tdb.td_tod = 0;
117 #endif
118 	if (inp == 0) {
119 		if (req != PRU_ATTACH) {
120 			splx(s);
121 			return (EINVAL);
122 		}
123 	} else {
124 		tp = intotcpcb(inp);
125 		nstate = tp->t_state;
126 #ifdef KPROF
127 		tcp_acounts[nstate][req]++;
128 #endif
129 #ifdef TCPDEBUG
130 		if (((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug)) {
131 			tdb_setup(tp, (struct tcpiphdr *)0, req, &tdb);
132 			tdb.td_tim = timertype;
133 		}
134 #endif
135 		tp->tc_flags &= ~TC_NET_KEEP;
136 	}
137 
138 	switch (req) {
139 
140 	case PRU_ATTACH:
141 		if (tp) {
142 			error = EISCONN;
143 			break;
144 		}
145 		tcp_attach(so);
146 		tp = sototcpcb(so);
147 		if (so->so_options & SO_ACCEPTCONN) {
148 			inp->inp_lhost = in_hostalloc(&n_lhost);	/*XXX*/
149 			inp->inp_lport = in_pcbgenport(&tcb);
150 			nstate = LISTEN;
151 		} else
152 			nstate = CLOSED;
153 		break;
154 
155 	case PRU_DETACH:
156 		tcp_detach(tp);
157 		break;
158 
159 	case PRU_CONNECT:
160 		if (tp->t_state != 0 && tp->t_state != CLOSED)
161 			goto bad;
162 		inp->inp_fhost = in_hosteval((struct sockaddr *)addr, &error);
163 		if (inp->inp_fhost == 0)
164 			break;
165 		(void) tcp_sndctl(tp);
166 		nstate = SYN_SENT;
167 		soisconnecting(so);
168 		break;
169 
170 	case PRU_ACCEPT:
171 		return (EOPNOTSUPP);		/* XXX */
172 
173 	case PRU_DISCONNECT:
174 		if ((tp->tc_flags & TC_FIN_RCVD) == 0)
175 			goto abort;
176 		if (nstate < ESTAB)
177 			tcp_disconnect(tp);
178 		else {
179 			tp->tc_flags |= TC_SND_FIN;
180 			(void) tcp_sndctl(tp);
181 			tp->tc_flags |= TC_USR_CLOSED;
182 			soisdisconnecting(so);
183 		}
184 		break;
185 
186 	case PRU_SHUTDOWN:
187 		switch (nstate) {
188 
189 		case LISTEN:
190 		case SYN_SENT:
191 			nstate = CLOSED;
192 			break;
193 
194 		case SYN_RCVD:
195 		case L_SYN_RCVD:
196 		case ESTAB:
197 		case CLOSE_WAIT:
198 			tp->tc_flags |= TC_SND_FIN;
199 			(void) tcp_sndctl(tp);
200 			tp->tc_flags |= TC_USR_CLOSED;
201 			nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK;
202 			break;
203 
204 		case FIN_W1:
205 		case FIN_W2:
206 		case TIME_WAIT:
207 		case CLOSING:
208 		case LAST_ACK:
209 		case RCV_WAIT:
210 			break;
211 
212 		default:
213 			goto bad;
214 		}
215 		break;
216 
217 	case PRU_RCVD:
218 		if (nstate < ESTAB || nstate == CLOSED)
219 			goto bad;
220 		tcp_sndwin(tp);
221 		if ((tp->tc_flags&TC_FIN_RCVD) &&
222 		    (tp->tc_flags&TC_USR_CLOSED) == 0 &&
223 		    rcv_empty(tp))
224 			error = ESHUTDOWN;
225 		if (nstate == RCV_WAIT && rcv_empty(tp))
226 			nstate = CLOSED;
227 		break;
228 
229 	case PRU_SEND:
230 		switch (nstate) {
231 
232 		case ESTAB:
233 		case CLOSE_WAIT:
234 			tcp_usrsend(tp, m);
235 			break;
236 
237 		default:
238 			if (nstate < ESTAB)
239 				goto bad;
240 			m_freem(m);
241 			error = ENOTCONN;
242 			break;
243 		}
244 		break;
245 
246 abort:
247 	case PRU_ABORT:
248 		tcp_abort(tp);
249 		nstate = CLOSED;
250 		break;
251 
252 	case PRU_CONTROL:
253 		error = EOPNOTSUPP;
254 		break;
255 
256 	case PRU_SLOWTIMO:
257 		switch (nstate) {
258 
259 		case 0:
260 		case CLOSED:
261 		case LISTEN:
262 			goto bad;
263 
264 		default:
265 			nstate = tcp_timers(tp, (int)addr);
266 		}
267 		break;
268 
269 	default:
270 		panic("tcp_usrreq");
271 	bad:
272 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
273 		    tp, tp->t_state, req);
274 		nstate = EFAILEC;
275 		break;
276 	}
277 #ifdef TCPDEBUG
278 	if (tdb.td_tod)
279 		tdb_stuff(&tdb, nstate);
280 #endif
281 	switch (nstate) {
282 
283 	case CLOSED:
284 	case SAME:
285 		break;
286 
287 	case EFAILEC:
288 		if (m)
289 			m_freem(dtom(m));
290 		break;
291 
292 	default:
293 		tp->t_state = nstate;
294 		break;
295 	}
296 	splx(s);
297 	return (error);
298 }
299 
300 tcp_attach(so)
301 	struct socket *so;
302 {
303 	register struct tcpcb *tp = sototcpcb(so);
304 COUNT(TCP_ATTACH);
305 
306 	/*
307 	 * Make empty reassembly queue.
308 	 */
309 	tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
310 
311 	/*
312 	 * Initialize sequence numbers and round trip retransmit timer.
313 	 */
314 	tp->t_xmtime = T_REXMT;
315 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una =
316 	    tp->iss = tcp_iss;
317 	tp->snd_off = tp->iss + 1;
318 	tcp_iss += (ISSINCR >> 1) + 1;
319 }
320 
321 tcp_detach(tp)
322 	struct tcpcb *tp;
323 {
324 COUNT(TCP_DETACH);
325 
326 	in_pcbfree(tp->t_inpcb);
327 	(void) m_free(dtom(tp));
328 }
329 
330 tcp_disconnect(tp)
331 	register struct tcpcb *tp;
332 {
333 	register struct tcpiphdr *t;
334 
335 	tcp_tcancel(tp);
336 	t = tp->seg_next;
337 	for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next)
338 		m_freem(dtom(t));
339 	tcp_drainunack(tp);
340 	if (tp->t_template) {
341 		(void) m_free(dtom(tp->t_template));
342 		tp->t_template = 0;
343 	}
344 	in_pcbfree(tp->t_inpcb);
345 }
346 
347 tcp_abort(tp)
348 	register struct tcpcb *tp;
349 {
350 
351 	switch (tp->t_state) {
352 
353 	case SYN_RCVD:
354 	case ESTAB:
355 	case FIN_W1:
356 	case FIN_W2:
357 	case CLOSE_WAIT:
358 		tp->tc_flags |= TC_SND_RST;
359 		tcp_sndnull(tp);
360 	}
361 	soisdisconnected(tp->t_inpcb->inp_socket);
362 }
363 
364 /*
365  * Send data queue headed by m0 into the protocol.
366  */
367 tcp_usrsend(tp, m0)
368 	register struct tcpcb *tp;
369 	struct mbuf *m0;
370 {
371 	register struct socket *so = tp->t_inpcb->inp_socket;
372 COUNT(TCP_USRSEND);
373 
374 	sbappend(&so->so_snd, m0);
375 	if (tp->t_options & TO_EOL)
376 		tp->snd_end = tp->snd_off + so->so_snd.sb_cc;
377 	if (tp->t_options & TO_URG) {
378 		tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1;
379 		tp->tc_flags |= TC_SND_URG;
380 	}
381 	(void) tcp_send(tp);
382 }
383 
384 /*
385  * TCP timer went off processing.
386  */
387 tcp_timers(tp, timertype)
388 	register struct tcpcb *tp;
389 	int timertype;
390 {
391 
392 COUNT(TCP_TIMERS);
393 	switch (timertype) {
394 
395 	case TFINACK:		/* fin-ack timer */
396 		switch (tp->t_state) {
397 
398 		case TIME_WAIT:
399 			/*
400 			 * We can be sure our ACK of foreign FIN was rcvd,
401 			 * and can close if no data left for user.
402 			 */
403 			if (rcv_empty(tp)) {
404 				tcp_disconnect(tp);
405 				return (CLOSED);
406 			}
407 			return (RCV_WAIT);			/* 17 */
408 
409 		case CLOSING:
410 			tp->tc_flags |= TC_WAITED_2_ML;
411 			return (SAME);
412 
413 		default:
414 			return (SAME);
415 		}
416 
417 	case TREXMT:		/* retransmission timer */
418 		if (tp->t_rexmt_val > tp->snd_una) {	 	/* 34 */
419 			/*
420 			 * Set so for a retransmission, increase rexmt time
421 			 * in case of multiple retransmissions.
422 			 */
423 			tp->snd_nxt = tp->snd_una;
424 			tp->tc_flags |= TC_REXMT;
425 			tp->t_xmtime = tp->t_xmtime << 1;
426 			if (tp->t_xmtime > T_REMAX)
427 				tp->t_xmtime = T_REMAX;
428 			(void) tcp_send(tp);
429 		}
430 		return (SAME);
431 
432 	case TREXMTTL:		/* retransmit too long */
433 		if (tp->t_rtl_val > tp->snd_una)		/* 36 */
434 			tcp_error(tp, EIO);		/* URXTIMO !?! */
435 		/*
436 		 * If user has already closed, abort the connection.
437 		 */
438 		if (tp->tc_flags & TC_USR_CLOSED) {
439 			tcp_abort(tp);
440 			return (CLOSED);
441 		}
442 		return (SAME);
443 
444 	case TPERSIST:		/* persist timer */
445 		/*
446 		 * Force a byte send through closed window.
447 		 */
448 		tp->tc_flags |= TC_FORCE_ONE;
449 		(void) tcp_send(tp);
450 		return (SAME);
451 	}
452 	panic("tcp_timers");
453 	/*NOTREACHED*/
454 }
455 
456 /*ARGSUSED*/
457 tcp_sense(m)
458 	struct mbuf *m;
459 {
460 
461 	return (EOPNOTSUPP);
462 }
463 
464 tcp_error(tp, errno)
465 	struct tcpcb *tp;
466 	int errno;
467 {
468 	struct socket *so = tp->t_inpcb->inp_socket;
469 COUNT(TCP_ERROR);
470 
471 	so->so_error = errno;
472 	sorwakeup(so);
473 	sowwakeup(so);
474 }
475 
476 #ifdef TCPDEBUG
477 /*
478  * TCP debugging utility subroutines.
479  * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID.
480  */
481 tdb_setup(tp, n, input, tdp)
482 	struct tcpcb *tp;
483 	register struct tcpiphdr *n;
484 	int input;
485 	register struct tcp_debug *tdp;
486 {
487 
488 COUNT(TDB_SETUP);
489 	tdp->td_tod = time;
490 	tdp->td_tcb = tp;
491 	tdp->td_old = tp->t_state;
492 	tdp->td_inp = input;
493 	tdp->td_tim = 0;
494 	tdp->td_new = -1;
495 	if (n) {
496 		tdp->td_sno = n->ti_seq;
497 		tdp->td_ano = n->ti_ackno;
498 		tdp->td_wno = n->t_win;
499 		tdp->td_lno = n->ti_len;
500 		tdp->td_flg = n->ti_flags;
501 	} else
502 		tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno =
503 		    tdp->td_flg = 0;
504 }
505 
506 tdb_stuff(tdp, nstate)
507 	struct tcp_debug *tdp;
508 	int nstate;
509 {
510 COUNT(TDB_STUFF);
511 
512 	tdp->td_new = nstate;
513 	tcp_debug[tdbx++ % TDBSIZE] = *tdp;
514 	if (tcpconsdebug & 2)
515 		tcp_prt(tdp);
516 }
517 
518 tcp_prt(tdp)
519 	register struct tcp_debug *tdp;
520 {
521 COUNT(TCP_PRT);
522 
523 	printf("%x ", ((int)tdp->td_tcb)&0xffffff);
524 	if (tdp->td_inp == INSEND) {
525 		printf("SEND #%x", tdp->td_sno);
526 		tdp->td_lno = ntohs(tdp->td_lno);
527 		tdp->td_wno = ntohs(tdp->td_wno);
528 	} else {
529 		if (tdp->td_inp == INRECV)
530 			printf("RCV #%x ", tdp->td_sno);
531 		printf("%s.%s",
532 		    tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]);
533 		if (tdp->td_inp == ISTIMER)
534 			printf("(%s)", tcptimers[tdp->td_tim]);
535 		printf(" -> %s",
536 		    tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]);
537 		if (tdp->td_new == -1)
538 			printf(" (FAILED)");
539 	}
540 	/* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */
541 	if (tdp->td_lno)
542 		printf(" len=%d", tdp->td_lno);
543 	if (tdp->td_wno)
544 		printf(" win=%d", tdp->td_wno);
545 	if (tdp->td_flg & TH_FIN) printf(" FIN");
546 	if (tdp->td_flg & TH_SYN) printf(" SYN");
547 	if (tdp->td_flg & TH_RST) printf(" RST");
548 	if (tdp->td_flg & TH_EOL) printf(" EOL");
549 	if (tdp->td_flg & TH_ACK)  printf(" ACK %x", tdp->td_ano);
550 	if (tdp->td_flg & TH_URG) printf(" URG");
551 	printf("\n");
552 }
553 #endif
554