so_addr
[unix-history] / usr / src / sys / netinet / tcp_usrreq.c
CommitLineData
4ad99bae 1/* tcp_usrreq.c 1.31 81/11/20 */
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"
eee3ab16
BJ
7#include "../h/socketvar.h"
8#include "../h/protosw.h"
9#include "../net/inet.h"
53a5409e 10#include "../net/inet_pcb.h"
eee3ab16 11#include "../net/inet_systm.h"
4ad99bae 12#include "../net/if.h"
eee3ab16
BJ
13#include "../net/imp.h"
14#include "../net/ip.h"
eb44bfb2 15#include "../net/ip_var.h"
eee3ab16 16#include "../net/tcp.h"
72f24d7d 17#define TCPFSTAB
186b5a8a
BJ
18#ifdef TCPDEBUG
19#define TCPSTATES
20#endif
eee3ab16
BJ
21#include "../net/tcp_fsm.h"
22#include "../net/tcp_var.h"
23#include "/usr/include/errno.h"
24
eee3ab16
BJ
25/*
26 * Tcp initialization
27 */
28tcp_init()
29{
30
31 tcp_iss = 1; /* wrong */
53a5409e 32 tcb.inp_next = tcb.inp_prev = &tcb;
eee3ab16 33}
4eb5d593 34
e1506033
BJ
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/*
eee3ab16 45 * Tcp protocol timeout routine called every 500 ms.
e1506033
BJ
46 * Updates the timers in all active tcb's and
47 * causes finite state machine actions if timers expire.
48 */
eee3ab16 49tcp_slowtimo()
4eb5d593 50{
53a5409e
BJ
51 register struct inpcb *ip;
52 register struct tcpcb *tp;
72f24d7d 53 int s = splnet();
eee3ab16 54 register short *tmp;
9c5022e3 55 register int i;
72f24d7d
BJ
56COUNT(TCP_TIMEO);
57
58 /*
59 * Search through tcb's and update active timers.
60 */
53a5409e
BJ
61 for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) {
62 tp = intotcpcb(ip);
9c5022e3 63 tmp = &tp->t_init;
2e80fb4c 64 for (i = 0; i < TNTIMERS; i++) {
9c5022e3 65 if (*tmp && --*tmp == 0)
cdad2eb1
BJ
66 (void) tcp_usrreq(tp->t_inpcb->inp_socket,
67 PRU_SLOWTIMO, (struct mbuf *)0,
68 (caddr_t)i);
2e80fb4c
BJ
69 tmp++;
70 }
72f24d7d
BJ
71 tp->t_xmt++;
72 }
eee3ab16 73 tcp_iss += ISSINCR/2; /* increment iss */
72f24d7d 74 splx(s);
4eb5d593
BJ
75}
76
e1506033
BJ
77/*
78 * Cancel all timers for tcp tp.
79 */
80tcp_tcancel(tp)
53a5409e 81 struct tcpcb *tp;
e1506033 82{
eee3ab16 83 register short *tmp = &tp->t_init;
e1506033
BJ
84 register int i;
85
86 for (i = 0; i < TNTIMERS; i++)
87 *tmp++ = 0;
88}
89
4ad99bae 90struct tcpcb *tcp_newtcpcb();
9c5022e3
BJ
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 */
eee3ab16
BJ
96tcp_usrreq(so, req, m, addr)
97 struct socket *so;
98 int req;
9c5022e3 99 struct mbuf *m;
eee3ab16 100 caddr_t addr;
4eb5d593 101{
53a5409e 102 register struct inpcb *inp = sotoinpcb(so);
cdad2eb1 103 register struct tcpcb *tp;
72f24d7d
BJ
104 int s = splnet();
105 register int nstate;
186b5a8a
BJ
106#ifdef TCPDEBUG
107 struct tcp_debug tdb;
108#endif
eee3ab16 109 int error = 0;
72f24d7d
BJ
110COUNT(TCP_USRREQ);
111
53a5409e
BJ
112 /*
113 * Make sure attached. If not,
114 * only PRU_ATTACH is valid.
115 */
cdad2eb1
BJ
116#ifdef TCPDEBUG
117 tdb.td_tod = 0;
118#endif
119 if (inp == 0) {
53a5409e
BJ
120 if (req != PRU_ATTACH) {
121 splx(s);
122 return (EINVAL);
123 }
cdad2eb1
BJ
124 } else {
125 tp = intotcpcb(inp);
126 nstate = tp->t_state;
9c5022e3 127#ifdef KPROF
cdad2eb1 128 tcp_acounts[nstate][req]++;
9c5022e3 129#endif
186b5a8a 130#ifdef TCPDEBUG
cdad2eb1
BJ
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 }
186b5a8a 135#endif
cdad2eb1
BJ
136 tp->tc_flags &= ~TC_NET_KEEP;
137 }
138
eee3ab16 139 switch (req) {
4eb5d593 140
eee3ab16 141 case PRU_ATTACH:
4ad99bae 142 if (inp) {
eee3ab16 143 error = EISCONN;
cdad2eb1 144 break;
53a5409e 145 }
4ad99bae
BJ
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)
53a5409e 160 nstate = LISTEN;
4ad99bae 161 else
53a5409e 162 nstate = CLOSED;
72f24d7d 163 break;
4eb5d593 164
eee3ab16 165 case PRU_DETACH:
cdad2eb1 166 tcp_detach(tp);
eee3ab16
BJ
167 break;
168
eee3ab16 169 case PRU_CONNECT:
53a5409e 170 if (tp->t_state != 0 && tp->t_state != CLOSED)
9c5022e3 171 goto bad;
4ad99bae
BJ
172 error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
173 if (error)
53a5409e 174 break;
cdad2eb1 175 (void) tcp_sndctl(tp);
72f24d7d 176 nstate = SYN_SENT;
53a5409e 177 soisconnecting(so);
72f24d7d 178 break;
4eb5d593 179
2b4b57cd 180 case PRU_ACCEPT:
4ad99bae
BJ
181 soisconnected(so);
182 break;
2b4b57cd 183
eee3ab16 184 case PRU_DISCONNECT:
53a5409e
BJ
185 if ((tp->tc_flags & TC_FIN_RCVD) == 0)
186 goto abort;
187 if (nstate < ESTAB)
cdad2eb1 188 tcp_disconnect(tp);
53a5409e
BJ
189 else {
190 tp->tc_flags |= TC_SND_FIN;
cdad2eb1 191 (void) tcp_sndctl(tp);
53a5409e
BJ
192 tp->tc_flags |= TC_USR_CLOSED;
193 soisdisconnecting(so);
194 }
eee3ab16
BJ
195 break;
196
eee3ab16 197 case PRU_SHUTDOWN:
9c5022e3 198 switch (nstate) {
4eb5d593 199
9c5022e3 200 case LISTEN:
e1506033 201 case SYN_SENT:
72f24d7d 202 nstate = CLOSED;
9c5022e3 203 break;
4eb5d593 204
e1506033 205 case SYN_RCVD:
9c5022e3
BJ
206 case L_SYN_RCVD:
207 case ESTAB:
e1506033 208 case CLOSE_WAIT:
9c5022e3 209 tp->tc_flags |= TC_SND_FIN;
cdad2eb1 210 (void) tcp_sndctl(tp);
9c5022e3
BJ
211 tp->tc_flags |= TC_USR_CLOSED;
212 nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK;
213 break;
214
9c5022e3
BJ
215 case FIN_W1:
216 case FIN_W2:
217 case TIME_WAIT:
218 case CLOSING:
219 case LAST_ACK:
220 case RCV_WAIT:
9c5022e3
BJ
221 break;
222
223 default:
224 goto bad;
225 }
72f24d7d
BJ
226 break;
227
eee3ab16 228 case PRU_RCVD:
9c5022e3
BJ
229 if (nstate < ESTAB || nstate == CLOSED)
230 goto bad;
e1506033 231 tcp_sndwin(tp);
2a4921ab
BJ
232 if ((tp->tc_flags&TC_FIN_RCVD) &&
233 (tp->tc_flags&TC_USR_CLOSED) == 0 &&
234 rcv_empty(tp))
53a5409e 235 error = ESHUTDOWN;
eee3ab16 236 if (nstate == RCV_WAIT && rcv_empty(tp))
9c5022e3 237 nstate = CLOSED;
72f24d7d
BJ
238 break;
239
eee3ab16 240 case PRU_SEND:
9c5022e3
BJ
241 switch (nstate) {
242
243 case ESTAB:
244 case CLOSE_WAIT:
53a5409e 245 tcp_usrsend(tp, m);
9c5022e3
BJ
246 break;
247
248 default:
249 if (nstate < ESTAB)
250 goto bad;
eee3ab16 251 m_freem(m);
53a5409e 252 error = ENOTCONN;
9c5022e3
BJ
253 break;
254 }
72f24d7d
BJ
255 break;
256
53a5409e 257abort:
eee3ab16 258 case PRU_ABORT:
53a5409e 259 tcp_abort(tp);
72f24d7d
BJ
260 nstate = CLOSED;
261 break;
262
eee3ab16 263 case PRU_CONTROL:
53a5409e 264 error = EOPNOTSUPP;
eee3ab16
BJ
265 break;
266
eee3ab16
BJ
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
9c5022e3
BJ
280 default:
281 panic("tcp_usrreq");
282 bad:
283 printf("tcp: bad state: tcb=%x state=%d input=%d\n",
eee3ab16 284 tp, tp->t_state, req);
9c5022e3 285 nstate = EFAILEC;
72f24d7d
BJ
286 break;
287 }
72f24d7d 288#ifdef TCPDEBUG
8f5a3361
BJ
289 if (tdb.td_tod)
290 tdb_stuff(&tdb, nstate);
72f24d7d 291#endif
72f24d7d
BJ
292 switch (nstate) {
293
186b5a8a 294 case CLOSED:
72f24d7d
BJ
295 case SAME:
296 break;
4eb5d593 297
72f24d7d 298 case EFAILEC:
9c5022e3
BJ
299 if (m)
300 m_freem(dtom(m));
72f24d7d 301 break;
4eb5d593 302
72f24d7d
BJ
303 default:
304 tp->t_state = nstate;
305 break;
306 }
307 splx(s);
53a5409e 308 return (error);
4eb5d593
BJ
309}
310
4ad99bae
BJ
311struct tcpcb *
312tcp_newtcpcb()
72f24d7d 313{
4ad99bae
BJ
314 struct mbuf *m = m_getclr(0);
315 register struct tcpcb *tp;
316COUNT(TCP_NEWTCPCB);
317
318 if (m == 0)
319 return (0);
320 tp = mtod(m, struct tcpcb *);
72f24d7d 321
a1904ebf 322 /*
53a5409e 323 * Make empty reassembly queue.
a1904ebf 324 */
53a5409e 325 tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
4eb5d593 326
a1904ebf 327 /*
53a5409e 328 * Initialize sequence numbers and round trip retransmit timer.
a1904ebf 329 */
72f24d7d 330 tp->t_xmtime = T_REXMT;
a1904ebf
BJ
331 tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una =
332 tp->iss = tcp_iss;
72f24d7d 333 tp->snd_off = tp->iss + 1;
dad64fdf 334 tcp_iss += (ISSINCR >> 1) + 1;
4ad99bae 335 return (tp);
4eb5d593
BJ
336}
337
cdad2eb1
BJ
338tcp_detach(tp)
339 struct tcpcb *tp;
72f24d7d 340{
eee3ab16 341COUNT(TCP_DETACH);
72f24d7d 342
cdad2eb1
BJ
343 in_pcbfree(tp->t_inpcb);
344 (void) m_free(dtom(tp));
53a5409e 345}
eee3ab16 346
53a5409e
BJ
347tcp_disconnect(tp)
348 register struct tcpcb *tp;
349{
350 register struct tcpiphdr *t;
a1904ebf 351
4ad99bae 352COUNT(TCP_DISCONNECT);
53a5409e
BJ
353 tcp_tcancel(tp);
354 t = tp->seg_next;
eb44bfb2 355 for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next)
53a5409e
BJ
356 m_freem(dtom(t));
357 tcp_drainunack(tp);
e1506033 358 if (tp->t_template) {
cdad2eb1 359 (void) m_free(dtom(tp->t_template));
e1506033 360 tp->t_template = 0;
dad64fdf 361 }
53a5409e
BJ
362 in_pcbfree(tp->t_inpcb);
363}
364
cdad2eb1
BJ
365tcp_abort(tp)
366 register struct tcpcb *tp;
53a5409e 367{
53a5409e 368
4ad99bae 369COUNT(TCP_ABORT);
53a5409e
BJ
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 }
cdad2eb1 380 soisdisconnected(tp->t_inpcb->inp_socket);
4eb5d593
BJ
381}
382
a1904ebf 383/*
e1506033 384 * Send data queue headed by m0 into the protocol.
a1904ebf 385 */
ea727f86 386tcp_usrsend(tp, m0)
53a5409e 387 register struct tcpcb *tp;
186b5a8a
BJ
388 struct mbuf *m0;
389{
53a5409e 390 register struct socket *so = tp->t_inpcb->inp_socket;
a1904ebf 391COUNT(TCP_USRSEND);
4eb5d593 392
53a5409e 393 sbappend(&so->so_snd, m0);
eee3ab16 394 if (tp->t_options & TO_EOL)
53a5409e 395 tp->snd_end = tp->snd_off + so->so_snd.sb_cc;
eee3ab16 396 if (tp->t_options & TO_URG) {
53a5409e 397 tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1;
a3d78bbd 398 tp->tc_flags |= TC_SND_URG;
72f24d7d 399 }
cdad2eb1 400 (void) tcp_send(tp);
4eb5d593
BJ
401}
402
a1904ebf
BJ
403/*
404 * TCP timer went off processing.
405 */
186b5a8a 406tcp_timers(tp, timertype)
53a5409e 407 register struct tcpcb *tp;
186b5a8a 408 int timertype;
4eb5d593 409{
4eb5d593 410
72f24d7d 411COUNT(TCP_TIMERS);
186b5a8a 412 switch (timertype) {
4eb5d593 413
72f24d7d
BJ
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)) {
53a5409e 423 tcp_disconnect(tp);
72f24d7d
BJ
424 return (CLOSED);
425 }
426 return (RCV_WAIT); /* 17 */
427
9c5022e3 428 case CLOSING:
a3d78bbd 429 tp->tc_flags |= TC_WAITED_2_ML;
72f24d7d
BJ
430 return (SAME);
431
432 default:
433 return (SAME);
434 }
4eb5d593 435
72f24d7d
BJ
436 case TREXMT: /* retransmission timer */
437 if (tp->t_rexmt_val > tp->snd_una) { /* 34 */
438 /*
eee3ab16 439 * Set so for a retransmission, increase rexmt time
72f24d7d
BJ
440 * in case of multiple retransmissions.
441 */
442 tp->snd_nxt = tp->snd_una;
a3d78bbd 443 tp->tc_flags |= TC_REXMT;
72f24d7d
BJ
444 tp->t_xmtime = tp->t_xmtime << 1;
445 if (tp->t_xmtime > T_REMAX)
446 tp->t_xmtime = T_REMAX;
cdad2eb1 447 (void) tcp_send(tp);
72f24d7d
BJ
448 }
449 return (SAME);
450
451 case TREXMTTL: /* retransmit too long */
452 if (tp->t_rtl_val > tp->snd_una) /* 36 */
cdad2eb1 453 tcp_error(tp, EIO); /* URXTIMO !?! */
72f24d7d
BJ
454 /*
455 * If user has already closed, abort the connection.
456 */
a3d78bbd 457 if (tp->tc_flags & TC_USR_CLOSED) {
53a5409e 458 tcp_abort(tp);
72f24d7d
BJ
459 return (CLOSED);
460 }
461 return (SAME);
462
463 case TPERSIST: /* persist timer */
464 /*
465 * Force a byte send through closed window.
466 */
a3d78bbd 467 tp->tc_flags |= TC_FORCE_ONE;
cdad2eb1 468 (void) tcp_send(tp);
72f24d7d
BJ
469 return (SAME);
470 }
471 panic("tcp_timers");
cdad2eb1 472 /*NOTREACHED*/
4eb5d593
BJ
473}
474
cdad2eb1 475/*ARGSUSED*/
53a5409e
BJ
476tcp_sense(m)
477 struct mbuf *m;
478{
479
4ad99bae 480COUNT(TCP_SENSE);
53a5409e
BJ
481 return (EOPNOTSUPP);
482}
483
cdad2eb1
BJ
484tcp_error(tp, errno)
485 struct tcpcb *tp;
eee3ab16 486 int errno;
4eb5d593 487{
cdad2eb1 488 struct socket *so = tp->t_inpcb->inp_socket;
4eb5d593 489
4ad99bae 490COUNT(TCP_ERROR);
eee3ab16 491 so->so_error = errno;
53a5409e
BJ
492 sorwakeup(so);
493 sowwakeup(so);
4eb5d593 494}
186b5a8a
BJ
495
496#ifdef TCPDEBUG
a1904ebf
BJ
497/*
498 * TCP debugging utility subroutines.
499 * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID.
500 */
e006f425 501tdb_setup(tp, n, input, tdp)
53a5409e
BJ
502 struct tcpcb *tp;
503 register struct tcpiphdr *n;
e006f425
BJ
504 int input;
505 register struct tcp_debug *tdp;
506{
507
a1904ebf 508COUNT(TDB_SETUP);
e006f425
BJ
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) {
eb44bfb2
BJ
516 tdp->td_sno = n->ti_seq;
517 tdp->td_ano = n->ti_ackno;
e006f425 518 tdp->td_wno = n->t_win;
eb44bfb2
BJ
519 tdp->td_lno = n->ti_len;
520 tdp->td_flg = n->ti_flags;
e006f425
BJ
521 } else
522 tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno =
523 tdp->td_flg = 0;
524}
525
526tdb_stuff(tdp, nstate)
527 struct tcp_debug *tdp;
528 int nstate;
529{
a1904ebf 530COUNT(TDB_STUFF);
e006f425
BJ
531
532 tdp->td_new = nstate;
533 tcp_debug[tdbx++ % TDBSIZE] = *tdp;
534 if (tcpconsdebug & 2)
535 tcp_prt(tdp);
536}
a1904ebf 537
a1904ebf
BJ
538tcp_prt(tdp)
539 register struct tcp_debug *tdp;
540{
541COUNT(TCP_PRT);
542
ddfd844e
BJ
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)");
a1904ebf 559 }
ddfd844e
BJ
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");
a1904ebf
BJ
571 printf("\n");
572}
e006f425 573#endif