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