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