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