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