1 /* tcp_usrreq.c 1.31 81/11/20 */ 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 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) 160 nstate = LISTEN; 161 else 162 nstate = CLOSED; 163 break; 164 165 case PRU_DETACH: 166 tcp_detach(tp); 167 break; 168 169 case PRU_CONNECT: 170 if (tp->t_state != 0 && tp->t_state != CLOSED) 171 goto bad; 172 error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); 173 if (error) 174 break; 175 (void) tcp_sndctl(tp); 176 nstate = SYN_SENT; 177 soisconnecting(so); 178 break; 179 180 case PRU_ACCEPT: 181 soisconnected(so); 182 break; 183 184 case PRU_DISCONNECT: 185 if ((tp->tc_flags & TC_FIN_RCVD) == 0) 186 goto abort; 187 if (nstate < ESTAB) 188 tcp_disconnect(tp); 189 else { 190 tp->tc_flags |= TC_SND_FIN; 191 (void) tcp_sndctl(tp); 192 tp->tc_flags |= TC_USR_CLOSED; 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 tp->tc_flags |= TC_USR_CLOSED; 212 nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; 213 break; 214 215 case FIN_W1: 216 case FIN_W2: 217 case TIME_WAIT: 218 case CLOSING: 219 case LAST_ACK: 220 case RCV_WAIT: 221 break; 222 223 default: 224 goto bad; 225 } 226 break; 227 228 case PRU_RCVD: 229 if (nstate < ESTAB || nstate == CLOSED) 230 goto bad; 231 tcp_sndwin(tp); 232 if ((tp->tc_flags&TC_FIN_RCVD) && 233 (tp->tc_flags&TC_USR_CLOSED) == 0 && 234 rcv_empty(tp)) 235 error = ESHUTDOWN; 236 if (nstate == RCV_WAIT && rcv_empty(tp)) 237 nstate = CLOSED; 238 break; 239 240 case PRU_SEND: 241 switch (nstate) { 242 243 case ESTAB: 244 case CLOSE_WAIT: 245 tcp_usrsend(tp, m); 246 break; 247 248 default: 249 if (nstate < ESTAB) 250 goto bad; 251 m_freem(m); 252 error = ENOTCONN; 253 break; 254 } 255 break; 256 257 abort: 258 case PRU_ABORT: 259 tcp_abort(tp); 260 nstate = CLOSED; 261 break; 262 263 case PRU_CONTROL: 264 error = EOPNOTSUPP; 265 break; 266 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 280 default: 281 panic("tcp_usrreq"); 282 bad: 283 printf("tcp: bad state: tcb=%x state=%d input=%d\n", 284 tp, tp->t_state, req); 285 nstate = EFAILEC; 286 break; 287 } 288 #ifdef TCPDEBUG 289 if (tdb.td_tod) 290 tdb_stuff(&tdb, nstate); 291 #endif 292 switch (nstate) { 293 294 case CLOSED: 295 case SAME: 296 break; 297 298 case EFAILEC: 299 if (m) 300 m_freem(dtom(m)); 301 break; 302 303 default: 304 tp->t_state = nstate; 305 break; 306 } 307 splx(s); 308 return (error); 309 } 310 311 struct tcpcb * 312 tcp_newtcpcb() 313 { 314 struct mbuf *m = m_getclr(0); 315 register struct tcpcb *tp; 316 COUNT(TCP_NEWTCPCB); 317 318 if (m == 0) 319 return (0); 320 tp = mtod(m, struct tcpcb *); 321 322 /* 323 * Make empty reassembly queue. 324 */ 325 tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 326 327 /* 328 * Initialize sequence numbers and round trip retransmit timer. 329 */ 330 tp->t_xmtime = T_REXMT; 331 tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = 332 tp->iss = tcp_iss; 333 tp->snd_off = tp->iss + 1; 334 tcp_iss += (ISSINCR >> 1) + 1; 335 return (tp); 336 } 337 338 tcp_detach(tp) 339 struct tcpcb *tp; 340 { 341 COUNT(TCP_DETACH); 342 343 in_pcbfree(tp->t_inpcb); 344 (void) m_free(dtom(tp)); 345 } 346 347 tcp_disconnect(tp) 348 register struct tcpcb *tp; 349 { 350 register struct tcpiphdr *t; 351 352 COUNT(TCP_DISCONNECT); 353 tcp_tcancel(tp); 354 t = tp->seg_next; 355 for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next) 356 m_freem(dtom(t)); 357 tcp_drainunack(tp); 358 if (tp->t_template) { 359 (void) m_free(dtom(tp->t_template)); 360 tp->t_template = 0; 361 } 362 in_pcbfree(tp->t_inpcb); 363 } 364 365 tcp_abort(tp) 366 register struct tcpcb *tp; 367 { 368 369 COUNT(TCP_ABORT); 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 } 380 soisdisconnected(tp->t_inpcb->inp_socket); 381 } 382 383 /* 384 * Send data queue headed by m0 into the protocol. 385 */ 386 tcp_usrsend(tp, m0) 387 register struct tcpcb *tp; 388 struct mbuf *m0; 389 { 390 register struct socket *so = tp->t_inpcb->inp_socket; 391 COUNT(TCP_USRSEND); 392 393 sbappend(&so->so_snd, m0); 394 if (tp->t_options & TO_EOL) 395 tp->snd_end = tp->snd_off + so->so_snd.sb_cc; 396 if (tp->t_options & TO_URG) { 397 tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1; 398 tp->tc_flags |= TC_SND_URG; 399 } 400 (void) tcp_send(tp); 401 } 402 403 /* 404 * TCP timer went off processing. 405 */ 406 tcp_timers(tp, timertype) 407 register struct tcpcb *tp; 408 int timertype; 409 { 410 411 COUNT(TCP_TIMERS); 412 switch (timertype) { 413 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)) { 423 tcp_disconnect(tp); 424 return (CLOSED); 425 } 426 return (RCV_WAIT); /* 17 */ 427 428 case CLOSING: 429 tp->tc_flags |= TC_WAITED_2_ML; 430 return (SAME); 431 432 default: 433 return (SAME); 434 } 435 436 case TREXMT: /* retransmission timer */ 437 if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 438 /* 439 * Set so for a retransmission, increase rexmt time 440 * in case of multiple retransmissions. 441 */ 442 tp->snd_nxt = tp->snd_una; 443 tp->tc_flags |= TC_REXMT; 444 tp->t_xmtime = tp->t_xmtime << 1; 445 if (tp->t_xmtime > T_REMAX) 446 tp->t_xmtime = T_REMAX; 447 (void) tcp_send(tp); 448 } 449 return (SAME); 450 451 case TREXMTTL: /* retransmit too long */ 452 if (tp->t_rtl_val > tp->snd_una) /* 36 */ 453 tcp_error(tp, EIO); /* URXTIMO !?! */ 454 /* 455 * If user has already closed, abort the connection. 456 */ 457 if (tp->tc_flags & TC_USR_CLOSED) { 458 tcp_abort(tp); 459 return (CLOSED); 460 } 461 return (SAME); 462 463 case TPERSIST: /* persist timer */ 464 /* 465 * Force a byte send through closed window. 466 */ 467 tp->tc_flags |= TC_FORCE_ONE; 468 (void) tcp_send(tp); 469 return (SAME); 470 } 471 panic("tcp_timers"); 472 /*NOTREACHED*/ 473 } 474 475 /*ARGSUSED*/ 476 tcp_sense(m) 477 struct mbuf *m; 478 { 479 480 COUNT(TCP_SENSE); 481 return (EOPNOTSUPP); 482 } 483 484 tcp_error(tp, errno) 485 struct tcpcb *tp; 486 int errno; 487 { 488 struct socket *so = tp->t_inpcb->inp_socket; 489 490 COUNT(TCP_ERROR); 491 so->so_error = errno; 492 sorwakeup(so); 493 sowwakeup(so); 494 } 495 496 #ifdef TCPDEBUG 497 /* 498 * TCP debugging utility subroutines. 499 * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID. 500 */ 501 tdb_setup(tp, n, input, tdp) 502 struct tcpcb *tp; 503 register struct tcpiphdr *n; 504 int input; 505 register struct tcp_debug *tdp; 506 { 507 508 COUNT(TDB_SETUP); 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) { 516 tdp->td_sno = n->ti_seq; 517 tdp->td_ano = n->ti_ackno; 518 tdp->td_wno = n->t_win; 519 tdp->td_lno = n->ti_len; 520 tdp->td_flg = n->ti_flags; 521 } else 522 tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = 523 tdp->td_flg = 0; 524 } 525 526 tdb_stuff(tdp, nstate) 527 struct tcp_debug *tdp; 528 int nstate; 529 { 530 COUNT(TDB_STUFF); 531 532 tdp->td_new = nstate; 533 tcp_debug[tdbx++ % TDBSIZE] = *tdp; 534 if (tcpconsdebug & 2) 535 tcp_prt(tdp); 536 } 537 538 tcp_prt(tdp) 539 register struct tcp_debug *tdp; 540 { 541 COUNT(TCP_PRT); 542 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)"); 559 } 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"); 571 printf("\n"); 572 } 573 #endif 574