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