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