xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 4911)
1 /* tcp_usrreq.c 1.29 81/11/16 */
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 inaddr *)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_DISCONNECT:
171 		if ((tp->tc_flags & TC_FIN_RCVD) == 0)
172 			goto abort;
173 		if (nstate < ESTAB)
174 			tcp_disconnect(tp);
175 		else {
176 			tp->tc_flags |= TC_SND_FIN;
177 			(void) tcp_sndctl(tp);
178 			tp->tc_flags |= TC_USR_CLOSED;
179 			soisdisconnecting(so);
180 		}
181 		break;
182 
183 	case PRU_FLUSH:
184 		error = EOPNOTSUPP;
185 		break;
186 
187 	case PRU_SHUTDOWN:
188 		switch (nstate) {
189 
190 		case LISTEN:
191 		case SYN_SENT:
192 			nstate = CLOSED;
193 			break;
194 
195 		case SYN_RCVD:
196 		case L_SYN_RCVD:
197 		case ESTAB:
198 		case CLOSE_WAIT:
199 			tp->tc_flags |= TC_SND_FIN;
200 			(void) tcp_sndctl(tp);
201 			tp->tc_flags |= TC_USR_CLOSED;
202 			nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK;
203 			break;
204 
205 		case FIN_W1:
206 		case FIN_W2:
207 		case TIME_WAIT:
208 		case CLOSING:
209 		case LAST_ACK:
210 		case RCV_WAIT:
211 			break;
212 
213 		default:
214 			goto bad;
215 		}
216 		break;
217 
218 	case PRU_RCVD:
219 		if (nstate < ESTAB || nstate == CLOSED)
220 			goto bad;
221 		tcp_sndwin(tp);
222 		if ((tp->tc_flags&TC_FIN_RCVD) &&
223 		    (tp->tc_flags&TC_USR_CLOSED) == 0 &&
224 		    rcv_empty(tp))
225 			error = ESHUTDOWN;
226 		if (nstate == RCV_WAIT && rcv_empty(tp))
227 			nstate = CLOSED;
228 		break;
229 
230 	case PRU_SEND:
231 		switch (nstate) {
232 
233 		case ESTAB:
234 		case CLOSE_WAIT:
235 			tcp_usrsend(tp, m);
236 			break;
237 
238 		default:
239 			if (nstate < ESTAB)
240 				goto bad;
241 			m_freem(m);
242 			error = ENOTCONN;
243 			break;
244 		}
245 		break;
246 
247 abort:
248 	case PRU_ABORT:
249 		tcp_abort(tp);
250 		nstate = CLOSED;
251 		break;
252 
253 	case PRU_CONTROL:
254 		error = EOPNOTSUPP;
255 		break;
256 
257 	case PRU_SLOWTIMO:
258 		switch (nstate) {
259 
260 		case 0:
261 		case CLOSED:
262 		case LISTEN:
263 			goto bad;
264 
265 		default:
266 			nstate = tcp_timers(tp, (int)addr);
267 		}
268 		break;
269 
270 	default:
271 		panic("tcp_usrreq");
272 	bad:
273 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
274 		    tp, tp->t_state, req);
275 		nstate = EFAILEC;
276 		break;
277 	}
278 #ifdef TCPDEBUG
279 	if (tdb.td_tod)
280 		tdb_stuff(&tdb, nstate);
281 #endif
282 	switch (nstate) {
283 
284 	case CLOSED:
285 	case SAME:
286 		break;
287 
288 	case EFAILEC:
289 		if (m)
290 			m_freem(dtom(m));
291 		break;
292 
293 	default:
294 		tp->t_state = nstate;
295 		break;
296 	}
297 	splx(s);
298 	return (error);
299 }
300 
301 tcp_attach(so)
302 	struct socket *so;
303 {
304 	register struct tcpcb *tp = sototcpcb(so);
305 COUNT(TCP_ATTACH);
306 
307 	/*
308 	 * Make empty reassembly queue.
309 	 */
310 	tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
311 
312 	/*
313 	 * Initialize sequence numbers and round trip retransmit timer.
314 	 */
315 	tp->t_xmtime = T_REXMT;
316 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una =
317 	    tp->iss = tcp_iss;
318 	tp->snd_off = tp->iss + 1;
319 	tcp_iss += (ISSINCR >> 1) + 1;
320 }
321 
322 tcp_detach(tp)
323 	struct tcpcb *tp;
324 {
325 COUNT(TCP_DETACH);
326 
327 	in_pcbfree(tp->t_inpcb);
328 	(void) m_free(dtom(tp));
329 }
330 
331 tcp_disconnect(tp)
332 	register struct tcpcb *tp;
333 {
334 	register struct tcpiphdr *t;
335 
336 	tcp_tcancel(tp);
337 	t = tp->seg_next;
338 	for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next)
339 		m_freem(dtom(t));
340 	tcp_drainunack(tp);
341 	if (tp->t_template) {
342 		(void) m_free(dtom(tp->t_template));
343 		tp->t_template = 0;
344 	}
345 	in_pcbfree(tp->t_inpcb);
346 }
347 
348 tcp_abort(tp)
349 	register struct tcpcb *tp;
350 {
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 	soisdisconnected(tp->t_inpcb->inp_socket);
363 }
364 
365 /*
366 /*###366 [cc] warning: struct/union or struct/union pointer required %%%*/
367 /*###366 [cc] member of structure or union required %%%*/
368 /*###366 [cc] tp_inpcb undefined %%%*/
369  * Send data queue headed by m0 into the protocol.
370  */
371 tcp_usrsend(tp, m0)
372 	register struct tcpcb *tp;
373 	struct mbuf *m0;
374 {
375 	register struct socket *so = tp->t_inpcb->inp_socket;
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 	(void) 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 			(void) 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(tp, 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 		(void) tcp_send(tp);
454 		return (SAME);
455 	}
456 	panic("tcp_timers");
457 	/*NOTREACHED*/
458 }
459 
460 /*ARGSUSED*/
461 tcp_sense(m)
462 	struct mbuf *m;
463 {
464 
465 	return (EOPNOTSUPP);
466 }
467 
468 tcp_error(tp, errno)
469 	struct tcpcb *tp;
470 	int errno;
471 {
472 	struct socket *so = tp->t_inpcb->inp_socket;
473 COUNT(TCP_ERROR);
474 
475 	so->so_error = errno;
476 	sorwakeup(so);
477 	sowwakeup(so);
478 }
479 
480 #ifdef TCPDEBUG
481 /*
482  * TCP debugging utility subroutines.
483  * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID.
484  */
485 tdb_setup(tp, n, input, tdp)
486 	struct tcpcb *tp;
487 	register struct tcpiphdr *n;
488 	int input;
489 	register struct tcp_debug *tdp;
490 {
491 
492 COUNT(TDB_SETUP);
493 	tdp->td_tod = time;
494 	tdp->td_tcb = tp;
495 	tdp->td_old = tp->t_state;
496 	tdp->td_inp = input;
497 	tdp->td_tim = 0;
498 	tdp->td_new = -1;
499 	if (n) {
500 		tdp->td_sno = n->ti_seq;
501 		tdp->td_ano = n->ti_ackno;
502 		tdp->td_wno = n->t_win;
503 		tdp->td_lno = n->ti_len;
504 		tdp->td_flg = n->ti_flags;
505 	} else
506 		tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno =
507 		    tdp->td_flg = 0;
508 }
509 
510 tdb_stuff(tdp, nstate)
511 	struct tcp_debug *tdp;
512 	int nstate;
513 {
514 COUNT(TDB_STUFF);
515 
516 	tdp->td_new = nstate;
517 	tcp_debug[tdbx++ % TDBSIZE] = *tdp;
518 	if (tcpconsdebug & 2)
519 		tcp_prt(tdp);
520 }
521 
522 tcp_prt(tdp)
523 	register struct tcp_debug *tdp;
524 {
525 COUNT(TCP_PRT);
526 
527 	printf("%x ", ((int)tdp->td_tcb)&0xffffff);
528 	if (tdp->td_inp == INSEND) {
529 		printf("SEND #%x", tdp->td_sno);
530 		tdp->td_lno = ntohs(tdp->td_lno);
531 		tdp->td_wno = ntohs(tdp->td_wno);
532 	} else {
533 		if (tdp->td_inp == INRECV)
534 			printf("RCV #%x ", tdp->td_sno);
535 		printf("%s.%s",
536 		    tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]);
537 		if (tdp->td_inp == ISTIMER)
538 			printf("(%s)", tcptimers[tdp->td_tim]);
539 		printf(" -> %s",
540 		    tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]);
541 		if (tdp->td_new == -1)
542 			printf(" (FAILED)");
543 	}
544 	/* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */
545 	if (tdp->td_lno)
546 		printf(" len=%d", tdp->td_lno);
547 	if (tdp->td_wno)
548 		printf(" win=%d", tdp->td_wno);
549 	if (tdp->td_flg & TH_FIN) printf(" FIN");
550 	if (tdp->td_flg & TH_SYN) printf(" SYN");
551 	if (tdp->td_flg & TH_RST) printf(" RST");
552 	if (tdp->td_flg & TH_EOL) printf(" EOL");
553 	if (tdp->td_flg & TH_ACK)  printf(" ACK %x", tdp->td_ano);
554 	if (tdp->td_flg & TH_URG) printf(" URG");
555 	printf("\n");
556 }
557 #endif
558