xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 4592)
1 /* tcp_usrreq.c 1.10 81/10/23 */
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../bbnnet/net.h"
6 #include "../bbnnet/mbuf.h"
7 #include "../bbnnet/tcp.h"
8 #include "../bbnnet/ip.h"
9 #include "../bbnnet/imp.h"
10 #include "../bbnnet/ucb.h"
11 #define TCPFSTAB
12 #ifdef TCPDEBUG
13 #define TCPSTATES
14 #endif
15 #include "../bbnnet/fsm.h"
16 
17 tcp_timeo()
18 {
19 	register struct tcb *tp;
20 	int s = splnet();
21 COUNT(TCP_TIMEO);
22 
23 	/*
24 	 * Search through tcb's and update active timers.
25 	 */
26 	for (tp = netcb.n_tcb_head; tp != NULL; tp = tp->t_tcb_next) {
27 		if (tp->t_init != 0 && --tp->t_init == 0)
28 			tcp_usrreq(ISTIMER, TINIT, tp, 0);
29 		if (tp->t_rexmt != 0 && --tp->t_rexmt == 0)
30 			tcp_usrreq(ISTIMER, TREXMT, tp, 0);
31 		if (tp->t_rexmttl != 0 && --tp->t_rexmttl == 0)
32 			tcp_usrreq(ISTIMER, TREXMTTL, tp, 0);
33 		if (tp->t_persist != 0 && --tp->t_persist == 0)
34 			tcp_usrreq(ISTIMER, TPERSIST, tp, 0);
35 		if (tp->t_finack != 0 && --tp->t_finack == 0)
36 			tcp_usrreq(ISTIMER, TFINACK, tp, 0);
37 		tp->t_xmt++;
38 	}
39 	netcb.n_iss += ISSINCR;		/* increment iss */
40 	timeout(tcp_timeo, 0, hz);      /* reschedule every second */
41 	splx(s);
42 }
43 
44 tcp_usrreq(input, timertype, tp, mp)
45 	int input, timertype;
46 	register struct tcb *tp;
47 	struct mbuf *mp;
48 {
49 	int s = splnet();
50 	register int nstate;
51 #ifdef TCPDEBUG
52 	struct tcp_debug tdb;
53 #endif
54 COUNT(TCP_USRREQ);
55 
56 	nstate = tp->t_state;
57 	tp->tc_flags &= ~TC_NET_KEEP;
58 	acounts[nstate][input]++;
59 #ifdef TCPDEBUG
60 	if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
61 		tdb.td_tod = time;
62 		tdb.td_tcb = tp;
63 		tdb.td_old = nstate;
64 		tdb.td_inp = input;
65 		tdb.td_tim = timertype;
66 	} else
67 		tdb.td_tod = 0;
68 #endif
69 	switch (tcp_fstab[nstate][input]) {
70 
71 	default:
72 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
73 		    tp, tp->t_state, input);
74 		nstate = EFAILEC;
75 		break;
76 
77 	case LIS_CLS:				/* 1 */
78 		t_open(tp, PASSIVE);
79 		nstate = LISTEN;
80 		break;
81 
82 	case SYS_CLS:				/* 2 */
83 		t_open(tp, ACTIVE);
84 		send_ctl(tp);
85 		nstate = SYN_SENT;
86 		break;
87 
88 	case CLS_OPN:				/* 10 */
89 		t_close(tp, UCLOSED);
90 		nstate = CLOSED;
91 		break;
92 
93 	case CL2_CLW:				/* 10 */
94 		tp->tc_flags |= TC_SND_FIN;
95 		send_ctl(tp);
96 		tp->tc_flags |= TC_USR_CLOSED;
97 		nstate = CLOSING2;
98 		break;
99 
100 	case TIMERS:				/* 14,17,34,35,36,37,38 */
101 		nstate = tcp_timers(tp, timertype);
102 		break;
103 
104 	case CLS_RWT:				/* 20 */
105 		present_data(tp);
106 		if (rcv_empty(tp)) {
107 			t_close(tp, UCLOSED);
108 			nstate = CLOSED;
109 		} else
110 			nstate = RCV_WAIT;
111 		break;
112 
113 	case FW1_SYR:				/* 24,25 */
114 		tp->tc_flags |= TC_SND_FIN;
115 		send_ctl(tp);
116 		tp->tc_flags |= TC_USR_CLOSED;
117 		nstate = FIN_W1;
118 		break;
119 
120 	case SSS_SND:				/* 40,41 */
121 		nstate = sss_snd(tp, mp);
122 		break;
123 
124 	case SSS_RCV:				/* 42 */
125 		send_ctl(tp);		/* send new window */
126 		present_data(tp);
127 		break;
128 
129 	case CLS_NSY:				/* 44 */
130 		t_close(tp, UABORT);
131 		nstate = CLOSED;
132 		break;
133 
134 	case CLS_SYN:				/* 45 */
135 		tp->tc_flags |= TC_SND_RST;
136 		send_null(tp);
137 		t_close(tp, UABORT);
138 		nstate = CLOSED;
139 		break;
140 
141 	case CLS_ACT:				/* 47 */
142 		t_close(tp, UNETDWN);
143 		nstate = CLOSED;
144 		break;
145 
146 	case NOP:
147 		break;
148 
149 	case CLS_ERR:
150 		to_user(tp->t_ucb, UCLSERR);
151 		break;
152 	}
153 #ifdef TCPDEBUG
154 	if (tdb.td_tod) {
155 		tdb.td_new = nstate;
156 		tcp_debug[tdbx++ % TDBSIZE] = tdb;
157 		if (tcpconsdebug)
158 			tcp_prt(&tdb);
159 	}
160 #endif
161 	/* YECH */
162 	switch (nstate) {
163 
164 	case CLOSED:
165 	case SAME:
166 		break;
167 
168 	case EFAILEC:
169 		if (mp)
170 			m_freem(dtom(mp));
171 		break;
172 
173 	default:
174 		tp->t_state = nstate;
175 		break;
176 	}
177 	splx(s);
178 }
179 
180 t_open(tp, mode)                /* set up a tcb for a connection */
181 	register struct tcb *tp;
182 	int mode;
183 {
184 	register struct ucb *up;
185 COUNT(T_OPEN);
186 
187 	/* enqueue the tcb */
188 
189 	if (netcb.n_tcb_head == NULL) {
190 		netcb.n_tcb_head = tp;
191 		netcb.n_tcb_tail = tp;
192 	} else {
193 		tp->t_tcb_next = netcb.n_tcb_head;
194 		netcb.n_tcb_head->t_tcb_prev = tp;
195 		netcb.n_tcb_head = tp;
196 	}
197 
198 	/* initialize non-zero tcb fields */
199 
200 	tp->t_rcv_next = (struct th *)tp;
201 	tp->t_rcv_prev = (struct th *)tp;
202 	tp->t_xmtime = T_REXMT;
203 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi =
204 	              tp->snd_una = tp->iss = netcb.n_iss;
205 	tp->snd_off = tp->iss + 1;
206 	netcb.n_iss += (ISSINCR >> 1) + 1;
207 
208 	/* set timeout for open */
209 
210 	up = tp->t_ucb;
211 	tp->t_init = (up->uc_timeo != 0 ? up->uc_timeo :
212 					(mode == ACTIVE ? T_INIT : 0));
213 	up->uc_timeo = 0;       /* overlays uc_ssize */
214 }
215 
216 t_close(tp, state)
217 	register struct tcb *tp;
218 	short state;
219 {
220 	register struct ucb *up;
221 	register struct th *t;
222 	register struct mbuf *m;
223 COUNT(T_CLOSE);
224 
225 	up = tp->t_ucb;
226 
227 	tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist =
228 	    tp->t_finack = 0;
229 
230 	/* delete tcb */
231 
232 	if (tp->t_tcb_prev == NULL)
233 		netcb.n_tcb_head = tp->t_tcb_next;
234 	else
235 		tp->t_tcb_prev->t_tcb_next = tp->t_tcb_next;
236 	if (tp->t_tcb_next == NULL)
237 		netcb.n_tcb_tail = tp->t_tcb_prev;
238 	else
239 		tp->t_tcb_next->t_tcb_prev = tp->t_tcb_prev;
240 
241 	/* free all data on receive and send buffers */
242 
243 	for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next)
244 		m_freem(dtom(t));
245 
246 	if (up->uc_rbuf != NULL) {
247 		m_freem(up->uc_rbuf);
248 		up->uc_rbuf = NULL;
249 	}
250 	up->uc_rsize = 0;
251 	if (up->uc_sbuf != NULL) {
252 		m_freem(up->uc_sbuf);
253 		up->uc_sbuf = NULL;
254 	}
255 	up->uc_ssize = 0;
256 	for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) {
257 		m_freem(m);
258 		tp->t_rcv_unack = NULL;
259 	}
260 	m = dtom(tp);
261 	m->m_off = 0;
262 	m_free(m);
263 	up->uc_tcb = NULL;
264 
265 	/* lower buffer allocation and decrement host entry */
266 
267 	netcb.n_lowat -= up->uc_snd + up->uc_rcv + 2;
268 	netcb.n_hiwat = 2 * netcb.n_lowat;
269 	if (up->uc_host != NULL) {
270 		h_free(up->uc_host);
271 		up->uc_host = NULL;
272 	}
273 
274 	/* if user has initiated close (via close call), delete ucb
275 	   entry, otherwise just wakeup so user can issue close call */
276 
277 	if (tp->tc_flags&TC_USR_ABORT)
278         	up->uc_proc = NULL;
279 	else
280         	to_user(up, state);
281 }
282 
283 sss_snd(tp, m0)
284 	register struct tcb *tp;
285 	struct mbuf *m0;
286 {
287 	register struct mbuf *m, *n;
288 	register struct ucb *up = tp->t_ucb;
289 	register off;
290 	seq_t last;
291 
292 	last = tp->snd_off;
293 	for (m = n = m0; m != NULL; m = m->m_next) {
294 		up->uc_ssize++;
295 		if (m->m_off > MMAXOFF)
296 			up->uc_ssize += NMBPG;
297 		last += m->m_len;
298 	}
299 	if ((m = up->uc_sbuf) == NULL)
300 		up->uc_sbuf = n;
301 	else {
302 		while (m->m_next != NULL) {
303 			m = m->m_next;
304 			last += m->m_len;
305 		}
306 		if (m->m_off <= MMAXOFF) {
307 			last += m->m_len;
308 			off = m->m_off + m->m_len;
309 			while (n && n->m_off <= MMAXOFF &&
310 			    (MMAXOFF - off) >= n->m_len) {
311 				bcopy((caddr_t)((int)n + n->m_off),
312 				      (caddr_t)((int)m + off), n->m_len);
313 				m->m_len += n->m_len;
314 				off += n->m_len;
315 				up->uc_ssize--;
316 				n = m_free(n);
317 			}
318 		}
319 		m->m_next = n;
320 	}
321 	if (up->uc_flags & UEOL)
322 		tp->snd_end = last;
323 	if (up->uc_flags & UURG) {
324 		tp->snd_urp = last+1;
325 		tp->tc_flags |= TC_SND_URG;
326 	}
327 	send(tp);
328 	return (SAME);
329 }
330 
331 tcp_timers(tp, timertype)
332 	register struct tcb *tp;
333 	int timertype;
334 {
335 
336 COUNT(TCP_TIMERS);
337 	switch (timertype) {
338 
339 	case TINIT:		/* initialization timer */
340 		if ((tp->tc_flags&TC_SYN_ACKED) == 0) {		/* 35 */
341 			t_close(tp, UINTIMO);
342 			return (CLOSED);
343 		}
344 		return (SAME);
345 
346 	case TFINACK:		/* fin-ack timer */
347 		switch (tp->t_state) {
348 
349 		case TIME_WAIT:
350 			/*
351 			 * We can be sure our ACK of foreign FIN was rcvd,
352 			 * and can close if no data left for user.
353 			 */
354 			if (rcv_empty(tp)) {
355 				t_close(tp, UCLOSED);		/* 14 */
356 				return (CLOSED);
357 			}
358 			return (RCV_WAIT);			/* 17 */
359 
360 		case CLOSING1:
361 			tp->tc_flags |= TC_WAITED_2_ML;
362 			return (SAME);
363 
364 		default:
365 			return (SAME);
366 		}
367 
368 	case TREXMT:		/* retransmission timer */
369 		if (tp->t_rexmt_val > tp->snd_una) {	 	/* 34 */
370 			/*
371 			 * Set up for a retransmission, increase rexmt time
372 			 * in case of multiple retransmissions.
373 			 */
374 			tp->snd_nxt = tp->snd_una;
375 			tp->tc_flags |= TC_REXMT;
376 			tp->t_xmtime = tp->t_xmtime << 1;
377 			if (tp->t_xmtime > T_REMAX)
378 				tp->t_xmtime = T_REMAX;
379 			send(tp);
380 		}
381 		return (SAME);
382 
383 	case TREXMTTL:		/* retransmit too long */
384 		if (tp->t_rtl_val > tp->snd_una)		/* 36 */
385 			to_user(tp->t_ucb, URXTIMO);
386 		/*
387 		 * If user has already closed, abort the connection.
388 		 */
389 		if (tp->tc_flags & TC_USR_CLOSED) {
390 			t_close(tp, URXTIMO);
391 			return (CLOSED);
392 		}
393 		return (SAME);
394 
395 	case TPERSIST:		/* persist timer */
396 		/*
397 		 * Force a byte send through closed window.
398 		 */
399 		tp->tc_flags |= TC_FORCE_ONE;
400 		send(tp);
401 		return (SAME);
402 	}
403 	panic("tcp_timers");
404 }
405 
406 /* THIS ROUTINE IS A CROCK */
407 to_user(up, state)
408 	register struct ucb *up;
409 	register short state;
410 {
411 COUNT(TO_USER);
412 
413 	up->uc_state |= state;
414 	netwakeup(up);
415   	if (state == UURGENT)
416 		psignal(up->uc_proc, SIGURG);
417 }
418 
419 #ifdef TCPDEBUG
420 tcp_prt(tdp)
421 	register struct tcp_debug *tdp;
422 {
423 COUNT(TCP_PRT);
424 
425 	printf("TCP(%X) %s X %s",
426 	    tdp->td_tcb, tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]);
427 	if (tdp->td_inp == ISTIMER)
428 		printf("(%s)", tcptimers[tdp->td_tim]);
429 	printf(" --> %s",
430 	    tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]);
431 	/* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */
432 	if (tdp->td_new < 0)
433 		printf(" (FAILED)");
434 	printf("\n");
435 }
436 #endif
437