|
|
1.1 ! root 1: /* tcp_input.c 6.1 83/07/29 */ ! 2: #include "tcp.h" ! 3: #if NTCP > 0 ! 4: ! 5: #include "../h/param.h" ! 6: #include "../h/systm.h" ! 7: #include "../h/stream.h" ! 8: ! 9: #include "../h/inet/mbuf.h" ! 10: #include "../h/inet/in.h" ! 11: #include "../h/inet/ip.h" ! 12: #include "../h/inet/ip_var.h" ! 13: #include "../h/inet/tcp.h" ! 14: #include "../h/inet/tcp_fsm.h" ! 15: #include "../h/inet/tcp_seq.h" ! 16: #include "../h/inet/tcp_timer.h" ! 17: #include "../h/inet/tcp_var.h" ! 18: #include "../h/inet/tcpip.h" ! 19: #include "../h/inet/socket.h" ! 20: ! 21: int tcpprintfs = 0; ! 22: int tcpcksum = 1; ! 23: int tcp_dropcode = 0; ! 24: extern tcpnodelack; ! 25: ! 26: /* ! 27: * TCP input routine, follows pages 65-76 of the ! 28: * protocol specification dated September, 1981 very closely. ! 29: */ ! 30: tcp_input(m0) ! 31: struct mbuf *m0; ! 32: { ! 33: register struct tcpiphdr *ti; ! 34: register struct mbuf *m; ! 35: struct mbuf *om = 0; ! 36: int len, tlen, off; ! 37: register struct tcpcb *tp = 0; ! 38: register struct socket *so; ! 39: register int tiflags; ! 40: int todrop, acked; ! 41: in_addr laddr; ! 42: int dropsocket = 0; ! 43: ! 44: /* ! 45: * Get IP and TCP header together in first mbuf. ! 46: * Note: IP leaves IP header in first mbuf. ! 47: */ ! 48: m = m0; ! 49: ti = mtod(m, struct tcpiphdr *); ! 50: if (((struct ip *)ti)->ip_hl > (sizeof (struct ip) >> 2)) ! 51: ip_stripoptions((struct ip *)ti, (struct mbuf *)0); ! 52: if (BLEN(m) < sizeof (struct tcpiphdr)) { ! 53: if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) { ! 54: tcpstat.tcps_hdrops++; ! 55: return; ! 56: } ! 57: ti = mtod(m, struct tcpiphdr *); ! 58: } ! 59: ! 60: /* ! 61: * Checksum extended TCP header and data. ! 62: */ ! 63: tlen = ((struct ip *)ti)->ip_len; ! 64: len = sizeof (struct ip) + tlen; ! 65: ti->ti_src = htonl(ti->ti_src); ! 66: ti->ti_dst = htonl(ti->ti_dst); ! 67: if (tcpcksum) { ! 68: ti->ti_next = ti->ti_prev = 0; ! 69: ti->ti_x1 = 0; ! 70: ti->ti_len = htons((u_short)tlen); ! 71: if (ti->ti_sum = in_cksum(m, len)) { ! 72: if (tcpprintfs) ! 73: printf("tcp sum: src %x, len %d\n", ti->ti_src, len); ! 74: tcpstat.tcps_badsum++; ! 75: goto drop; ! 76: } ! 77: } ! 78: ! 79: /* ! 80: * Check that TCP offset makes sense, ! 81: * pull out TCP options and adjust length. ! 82: */ ! 83: off = ti->ti_off << 2; ! 84: if (off < sizeof (struct tcphdr) || off > tlen) { ! 85: if (tcpprintfs) ! 86: printf("tcp off: src %x off %d\n", ti->ti_src, off); ! 87: tcpstat.tcps_badoff++; ! 88: goto drop; ! 89: } ! 90: tlen -= off; ! 91: ! 92: /* make sure debug length is in network order */ ! 93: ti->ti_len = htons((u_short)tlen); ! 94: tcp_debug(ti, 0); ! 95: ti->ti_len = ntohs(ti->ti_len); ! 96: if (off > sizeof (struct tcphdr)) { ! 97: if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) { ! 98: tcpstat.tcps_hdrops++; ! 99: return; ! 100: } ! 101: ti = mtod(m, struct tcpiphdr *); ! 102: om = m_get(M_DONTWAIT, MT_DATA); ! 103: if (om == 0) ! 104: goto drop; ! 105: om->next = 0; ! 106: om->wptr += off - sizeof (struct tcphdr); ! 107: { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr); ! 108: bcopy(op, mtod(om, caddr_t), (unsigned)BLEN(om)); ! 109: m->wptr -= BLEN(om); ! 110: bcopy(op+BLEN(om), op, ! 111: (unsigned)(BLEN(m)-sizeof (struct tcpiphdr))); ! 112: } ! 113: } ! 114: tiflags = ti->ti_flags; ! 115: ! 116: /* ! 117: * Drop TCP and IP headers. ! 118: */ ! 119: off += sizeof (struct ip); ! 120: m->rptr += off; ! 121: ! 122: /* ! 123: * Convert TCP protocol specific fields to host format. ! 124: */ ! 125: ti->ti_seq = ntohl(ti->ti_seq); ! 126: ti->ti_ack = ntohl(ti->ti_ack); ! 127: ti->ti_win = ntohs(ti->ti_win); ! 128: ti->ti_urp = ntohs(ti->ti_urp); ! 129: ti->ti_src = ntohl(ti->ti_src); ! 130: ti->ti_dst = ntohl(ti->ti_dst); ! 131: ti->ti_sport = ntohs(ti->ti_sport); ! 132: ti->ti_dport = ntohs(ti->ti_dport); ! 133: ! 134: /* ! 135: * Locate pcb for segment. ! 136: * If the state is CLOSED (i.e., TCB does not exist) then ! 137: * all data in the incoming segment is discarded. ! 138: */ ! 139: so = so_lookup(ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport); ! 140: if (so == 0) { ! 141: tcp_dropcode = 1; ! 142: goto dropwithreset; ! 143: } ! 144: tp = so->so_tcpcb; ! 145: if(tp == 0) { ! 146: tcp_dropcode = 2; ! 147: goto dropwithreset; ! 148: } ! 149: if (so->so_options & SO_ACCEPTCONN) { ! 150: so = sonewconn(so); ! 151: if (so == 0) ! 152: goto drop; ! 153: /* ! 154: * This is ugly, but .... ! 155: * ! 156: * Mark socket as temporary until we're ! 157: * committed to keeping it. The code at ! 158: * ``drop'' and ``dropwithreset'' check the ! 159: * flag dropsocket to see if the temporary ! 160: * socket created here should be discarded. ! 161: * We mark the socket as discardable until ! 162: * we're committed to it below in TCPS_LISTEN. ! 163: */ ! 164: dropsocket++; ! 165: so->so_laddr = ti->ti_dst; ! 166: so->so_lport = ti->ti_dport; ! 167: so->so_faddr = ti->ti_src; ! 168: so->so_fport = ti->ti_sport; ! 169: tp = sototcpcb(so); ! 170: tp->t_state = TCPS_LISTEN; ! 171: } ! 172: ! 173: /* ! 174: * Segment received on connection. ! 175: * Reset idle time and keep-alive timer. ! 176: */ ! 177: tp->t_idle = 0; ! 178: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; ! 179: ! 180: /* ! 181: * Process options. ! 182: */ ! 183: if (om) { ! 184: tcp_dooptions(tp, om); ! 185: om = 0; ! 186: } ! 187: ! 188: /* ! 189: * Calculate amount of space in receive window, ! 190: * and then do TCP input processing. ! 191: */ ! 192: tp->rcv_wnd = sbrcvspace(so); ! 193: if (tp->rcv_wnd < 0) ! 194: tp->rcv_wnd = 0; ! 195: ! 196: switch (tp->t_state) { ! 197: ! 198: /* ! 199: * If the state is LISTEN then ignore segment if it contains an RST. ! 200: * If the segment contains an ACK then it is bad and send a RST. ! 201: * If it does not contain a SYN then it is not interesting; drop it. ! 202: * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial ! 203: * tp->iss, and send a segment: ! 204: * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> ! 205: * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. ! 206: * Fill in remote peer address fields if not previously specified. ! 207: * Enter SYN_RECEIVED state, and process any other fields of this ! 208: * segment in this state. ! 209: */ ! 210: case TCPS_LISTEN: { ! 211: if (tiflags & TH_RST) ! 212: goto drop; ! 213: if (tiflags & TH_ACK) { ! 214: tcp_dropcode = 3; ! 215: goto dropwithreset; ! 216: } ! 217: if ((tiflags & TH_SYN) == 0) ! 218: goto drop; ! 219: laddr = so->so_laddr; ! 220: if (so->so_laddr == INADDR_ANY) ! 221: so->so_laddr = ti->ti_dst; ! 222: tp->t_template = tcp_template(tp); ! 223: if (tp->t_template == 0) { ! 224: so->so_laddr = laddr; ! 225: tp = 0; ! 226: goto drop; ! 227: } ! 228: tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; ! 229: tp->irs = ti->ti_seq; ! 230: tcp_sendseqinit(tp); ! 231: tcp_rcvseqinit(tp); ! 232: tp->t_state = TCPS_SYN_RECEIVED; ! 233: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; ! 234: dropsocket = 0; /* committed to socket */ ! 235: goto trimthenstep6; ! 236: } ! 237: ! 238: /* ! 239: * If the state is SYN_SENT: ! 240: * if seg contains an ACK, but not for our SYN, drop the input. ! 241: * if seg contains a RST, then drop the connection. ! 242: * if seg does not contain SYN, then drop it. ! 243: * Otherwise this is an acceptable SYN segment ! 244: * initialize tp->rcv_nxt and tp->irs ! 245: * if seg contains ack then advance tp->snd_una ! 246: * if SYN has been acked change to ESTABLISHED else SYN_RCVD state ! 247: * arrange for segment to be acked (eventually) ! 248: * continue processing rest of data/controls, beginning with URG ! 249: */ ! 250: case TCPS_SYN_SENT: ! 251: if ((tiflags & TH_ACK) && ! 252: /* this should be SEQ_LT; is SEQ_LEQ for BBN vax TCP only */ ! 253: (SEQ_LT(ti->ti_ack, tp->iss) || ! 254: SEQ_GT(ti->ti_ack, tp->snd_max))) { ! 255: tcp_dropcode = 4; ! 256: goto dropwithreset; ! 257: } ! 258: if (tiflags & TH_RST) { ! 259: if (tiflags & TH_ACK) ! 260: tp = tcp_drop(tp); ! 261: goto drop; ! 262: } ! 263: if ((tiflags & TH_SYN) == 0) ! 264: goto drop; ! 265: tp->snd_una = ti->ti_ack; ! 266: if (SEQ_LT(tp->snd_nxt, tp->snd_una)) ! 267: tp->snd_nxt = tp->snd_una; ! 268: tp->t_timer[TCPT_REXMT] = 0; ! 269: tp->irs = ti->ti_seq; ! 270: tcp_rcvseqinit(tp); ! 271: tp->t_flags |= TF_ACKNOW; ! 272: if (SEQ_GT(tp->snd_una, tp->iss)) { ! 273: soisconnected(so); ! 274: tp->t_state = TCPS_ESTABLISHED; ! 275: (void) tcp_reass(tp, (struct tcpiphdr *)0); ! 276: } else ! 277: tp->t_state = TCPS_SYN_RECEIVED; ! 278: goto trimthenstep6; ! 279: ! 280: trimthenstep6: ! 281: /* ! 282: * Advance ti->ti_seq to correspond to first data byte. ! 283: * If data, trim to stay within window, ! 284: * dropping FIN if necessary. ! 285: */ ! 286: ti->ti_seq++; ! 287: if (ti->ti_len > tp->rcv_wnd) { ! 288: todrop = ti->ti_len - tp->rcv_wnd; ! 289: m_adj(m, -todrop); ! 290: ti->ti_len = tp->rcv_wnd; ! 291: ti->ti_flags &= ~TH_FIN; ! 292: } ! 293: tp->snd_wl1 = ti->ti_seq - 1; ! 294: goto step6; ! 295: } ! 296: ! 297: /* ! 298: * States other than LISTEN or SYN_SENT. ! 299: * First check that at least some bytes of segment are within ! 300: * receive window. ! 301: */ ! 302: if (tp->rcv_wnd == 0) { ! 303: /* ! 304: * If window is closed can only take segments at ! 305: * window edge, and have to drop data and PUSH from ! 306: * incoming segments. ! 307: */ ! 308: if (tp->rcv_nxt != ti->ti_seq) ! 309: goto dropafterack; ! 310: if (ti->ti_len > 0) { ! 311: m_adj(m, ti->ti_len); ! 312: ti->ti_len = 0; ! 313: ti->ti_flags &= ~(TH_PUSH|TH_FIN); ! 314: } ! 315: } else { ! 316: /* ! 317: * smb proofing; this disables most of the funtionality ! 318: * of the reassembly queue. Doesn't seem to hurt performance ! 319: * under normal circs. ! 320: */ ! 321: if(ti->ti_seq > tp->rcv_nxt) ! 322: goto drop; ! 323: /* ! 324: * If segment begins before rcv_nxt, drop leading ! 325: * data (and SYN); if nothing left, just ack. ! 326: */ ! 327: todrop = tp->rcv_nxt - ti->ti_seq; ! 328: if (todrop > 0) { ! 329: if (tiflags & TH_SYN) { ! 330: tiflags &= ~TH_SYN; ! 331: ti->ti_flags &= ~TH_SYN; ! 332: ti->ti_seq++; ! 333: if (ti->ti_urp > 1) ! 334: ti->ti_urp--; ! 335: else ! 336: tiflags &= ~TH_URG; ! 337: todrop--; ! 338: } ! 339: if (todrop > ti->ti_len || ! 340: todrop == ti->ti_len && (tiflags&TH_FIN) == 0) ! 341: goto dropafterack; ! 342: m_adj(m, todrop); ! 343: ti->ti_seq += todrop; ! 344: ti->ti_len -= todrop; ! 345: if (ti->ti_urp > todrop) ! 346: ti->ti_urp -= todrop; ! 347: else { ! 348: tiflags &= ~TH_URG; ! 349: ti->ti_flags &= ~TH_URG; ! 350: ti->ti_urp = 0; ! 351: } ! 352: } ! 353: /* ! 354: * If segment ends after window, drop trailing data ! 355: * (and PUSH and FIN); if nothing left, just ACK. ! 356: */ ! 357: todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); ! 358: if (todrop > 0) { ! 359: if (todrop >= ti->ti_len) ! 360: goto dropafterack; ! 361: m_adj(m, -todrop); ! 362: ti->ti_len -= todrop; ! 363: ti->ti_flags &= ~(TH_PUSH|TH_FIN); ! 364: } ! 365: } ! 366: ! 367: /* ! 368: * If data is received on a connection after the ! 369: * user processes are gone, then RST the other end. ! 370: */ ! 371: if ((so->so_state & SS_OPEN)==0 && tp->t_state > TCPS_CLOSE_WAIT && ! 372: ti->ti_len) { ! 373: tp = tcp_close(tp); ! 374: tcp_dropcode = 5; ! 375: goto dropwithreset; ! 376: } ! 377: ! 378: /* ! 379: * If the RST bit is set examine the state: ! 380: * SYN_RECEIVED STATE: ! 381: * If passive open, return to LISTEN state. ! 382: * If active open, inform user that connection was refused. ! 383: * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: ! 384: * Inform user that connection was reset, and close tcb. ! 385: * CLOSING, LAST_ACK, TIME_WAIT STATES ! 386: * Close the tcb. ! 387: */ ! 388: if (tiflags&TH_RST) switch (tp->t_state) { ! 389: ! 390: case TCPS_SYN_RECEIVED: ! 391: tp = tcp_drop(tp); ! 392: goto drop; ! 393: ! 394: case TCPS_ESTABLISHED: ! 395: case TCPS_FIN_WAIT_1: ! 396: case TCPS_FIN_WAIT_2: ! 397: case TCPS_CLOSE_WAIT: ! 398: tp = tcp_drop(tp); ! 399: goto drop; ! 400: ! 401: case TCPS_CLOSING: ! 402: case TCPS_LAST_ACK: ! 403: case TCPS_TIME_WAIT: ! 404: tp = tcp_close(tp); ! 405: goto drop; ! 406: } ! 407: ! 408: /* ! 409: * If a SYN is in the window, then this is an ! 410: * error and we send an RST and drop the connection. ! 411: */ ! 412: if (tiflags & TH_SYN) { ! 413: tp = tcp_drop(tp); ! 414: tcp_dropcode = 6; ! 415: goto dropwithreset; ! 416: } ! 417: ! 418: /* ! 419: * If the ACK bit is off we drop the segment and return. ! 420: */ ! 421: if ((tiflags & TH_ACK) == 0) ! 422: goto drop; ! 423: ! 424: /* ! 425: * Ack processing. ! 426: */ ! 427: switch (tp->t_state) { ! 428: ! 429: /* ! 430: * In SYN_RECEIVED state if the ack ACKs our SYN then enter ! 431: * ESTABLISHED state and continue processing, othewise ! 432: * send an RST. ! 433: */ ! 434: case TCPS_SYN_RECEIVED: ! 435: if (SEQ_GT(tp->snd_una, ti->ti_ack) || ! 436: SEQ_GT(ti->ti_ack, tp->snd_max)) { ! 437: tcp_dropcode = 7; ! 438: goto dropwithreset; ! 439: } ! 440: tp->snd_una++; /* SYN acked */ ! 441: if (SEQ_LT(tp->snd_nxt, tp->snd_una)) ! 442: tp->snd_nxt = tp->snd_una; ! 443: tp->t_timer[TCPT_REXMT] = 0; ! 444: soisconnected(so); ! 445: tp->t_state = TCPS_ESTABLISHED; ! 446: (void) tcp_reass(tp, (struct tcpiphdr *)0); ! 447: tp->snd_wl1 = ti->ti_seq - 1; ! 448: /* fall into ... */ ! 449: ! 450: /* ! 451: * In ESTABLISHED state: drop duplicate ACKs; ACK out of range ! 452: * ACKs. If the ack is in the range ! 453: * tp->snd_una < ti->ti_ack <= tp->snd_max ! 454: * then advance tp->snd_una to ti->ti_ack and drop ! 455: * data from the retransmission queue. If this ACK reflects ! 456: * more up to date window information we update our window information. ! 457: */ ! 458: case TCPS_ESTABLISHED: ! 459: case TCPS_FIN_WAIT_1: ! 460: case TCPS_FIN_WAIT_2: ! 461: case TCPS_CLOSE_WAIT: ! 462: case TCPS_CLOSING: ! 463: case TCPS_LAST_ACK: ! 464: case TCPS_TIME_WAIT: ! 465: #define ourfinisacked (acked > 0) ! 466: ! 467: if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) ! 468: break; ! 469: if (SEQ_GT(ti->ti_ack, tp->snd_max)) ! 470: goto dropafterack; ! 471: acked = ti->ti_ack - tp->snd_una; ! 472: ! 473: /* ! 474: * If transmit timer is running and timed sequence ! 475: * number was acked, update smoothed round trip time. ! 476: */ ! 477: if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) { ! 478: if (tp->t_srtt == 0) ! 479: tp->t_srtt = tp->t_rtt; ! 480: else ! 481: tp->t_srtt = ! 482: tcp_alpha * tp->t_srtt + ! 483: (1 - tcp_alpha) * tp->t_rtt; ! 484: tp->t_rtt = 0; ! 485: } ! 486: ! 487: if (ti->ti_ack == tp->snd_max) ! 488: tp->t_timer[TCPT_REXMT] = 0; ! 489: else { ! 490: TCPT_RANGESET(tp->t_timer[TCPT_REXMT], ! 491: tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); ! 492: tp->t_rtt = 1; ! 493: tp->t_rxtshift = 0; ! 494: } ! 495: if (acked > sosndcc(so)) { ! 496: tp->snd_wnd -= sosndcc(so); ! 497: sbsnddrop(so, sosndcc(so)); ! 498: } else { ! 499: sbsnddrop(so, acked); ! 500: tp->snd_wnd -= acked; ! 501: acked = 0; ! 502: } ! 503: tp->snd_una = ti->ti_ack; ! 504: if (SEQ_LT(tp->snd_nxt, tp->snd_una)) ! 505: tp->snd_nxt = tp->snd_una; ! 506: ! 507: switch (tp->t_state) { ! 508: ! 509: /* ! 510: * In FIN_WAIT_1 STATE in addition to the processing ! 511: * for the ESTABLISHED state if our FIN is now acknowledged ! 512: * then enter FIN_WAIT_2. ! 513: */ ! 514: case TCPS_FIN_WAIT_1: ! 515: if (ourfinisacked) { ! 516: /* ! 517: * If we can't receive any more ! 518: * data, then closing user can proceed. ! 519: */ ! 520: tp->t_state = TCPS_FIN_WAIT_2; ! 521: } ! 522: break; ! 523: ! 524: /* ! 525: * In CLOSING STATE in addition to the processing for ! 526: * the ESTABLISHED state if the ACK acknowledges our FIN ! 527: * then enter the TIME-WAIT state, otherwise ignore ! 528: * the segment. ! 529: */ ! 530: case TCPS_CLOSING: ! 531: if (ourfinisacked) { ! 532: tp->t_state = TCPS_TIME_WAIT; ! 533: tcp_canceltimers(tp); ! 534: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; ! 535: soisdisconnected(so); ! 536: } ! 537: break; ! 538: ! 539: /* ! 540: * The only thing that can arrive in LAST_ACK state ! 541: * is an acknowledgment of our FIN. If our FIN is now ! 542: * acknowledged, delete the TCB, enter the closed state ! 543: * and return. ! 544: */ ! 545: case TCPS_LAST_ACK: ! 546: if (ourfinisacked) ! 547: tp = tcp_close(tp); ! 548: goto drop; ! 549: ! 550: /* ! 551: * In TIME_WAIT state the only thing that should arrive ! 552: * is a retransmission of the remote FIN. Acknowledge ! 553: * it and restart the finack timer. ! 554: */ ! 555: case TCPS_TIME_WAIT: ! 556: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; ! 557: goto dropafterack; ! 558: } ! 559: #undef ourfinisacked ! 560: } ! 561: ! 562: step6: ! 563: /* ! 564: * Update window information. ! 565: */ ! 566: if (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq && ! 567: (SEQ_LT(tp->snd_wl2, ti->ti_ack) || ! 568: tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd)) { ! 569: tp->snd_wnd = ti->ti_win; ! 570: tp->snd_wl1 = ti->ti_seq; ! 571: tp->snd_wl2 = ti->ti_ack; ! 572: if (tp->snd_wnd != 0) ! 573: tp->t_timer[TCPT_PERSIST] = 0; ! 574: } ! 575: ! 576: /* ! 577: * Process segments with URG. ! 578: */ ! 579: if ((tiflags & TH_URG) && ti->ti_urp && ! 580: TCPS_HAVERCVDFIN(tp->t_state) == 0) { ! 581: /* ! 582: * This is a kludge, but if we receive accept ! 583: * random urgent pointers, we'll crash in ! 584: * soreceive. It's hard to imagine someone ! 585: * actually wanting to send this much urgent data. ! 586: */ ! 587: if (ti->ti_urp > tp->t_maxseg) { /* XXX */ ! 588: ti->ti_urp = 0; /* XXX */ ! 589: tiflags &= ~TH_URG; /* XXX */ ! 590: ti->ti_flags &= ~TH_URG; /* XXX */ ! 591: goto badurp; /* XXX */ ! 592: } ! 593: /* ! 594: * If this segment advances the known urgent pointer, ! 595: * then mark the data stream. This should not happen ! 596: * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since ! 597: * a FIN has been received from the remote side. ! 598: * In these states we ignore the URG. ! 599: */ ! 600: if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { ! 601: /* M_CTL, maybe? looks like it's put in the data stream */ ! 602: tp->rcv_up = ti->ti_seq + ti->ti_urp; ! 603: so->so_oobmark = 0 + ! 604: (tp->rcv_up - tp->rcv_nxt) - 1; ! 605: if (so->so_oobmark == 0) ! 606: so->so_state |= SS_RCVATMARK; ! 607: sohasoutofband(so); ! 608: tp->t_oobflags &= ~TCPOOB_HAVEDATA; ! 609: } ! 610: /* ! 611: * Remove out of band data so doesn't get presented to user. ! 612: * This can happen independent of advancing the URG pointer, ! 613: * but if two URG's are pending at once, some out-of-band ! 614: * data may creep in... ick. ! 615: */ ! 616: if (ti->ti_urp <= ti->ti_len) ! 617: tcp_pulloutofband(so, ti); ! 618: } ! 619: badurp: /* XXX */ ! 620: ! 621: /* ! 622: * Process the segment text, merging it into the TCP sequencing queue, ! 623: * and arranging for acknowledgment of receipt if necessary. ! 624: * This process logically involves adjusting tp->rcv_wnd as data ! 625: * is presented to the user (this happens in tcp_usrreq.c, ! 626: * case PRU_RCVD). If a FIN has already been received on this ! 627: * connection then we just ignore the text. ! 628: */ ! 629: if ((ti->ti_len || (tiflags&TH_FIN)) && ! 630: TCPS_HAVERCVDFIN(tp->t_state) == 0) { ! 631: tiflags = tcp_reass(tp, ti); ! 632: if (tcpnodelack == 0) ! 633: tp->t_flags |= TF_DELACK; ! 634: else ! 635: tp->t_flags |= TF_ACKNOW; ! 636: } else { ! 637: m_freem(m); ! 638: tiflags &= ~TH_FIN; ! 639: } ! 640: ! 641: /* ! 642: * If FIN is received ACK the FIN and let the user know ! 643: * that the connection is closing. ! 644: */ ! 645: if (tiflags & TH_FIN) { ! 646: if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { ! 647: socantrcvmore(so); ! 648: tp->t_flags |= TF_ACKNOW; ! 649: tp->rcv_nxt++; ! 650: } ! 651: switch (tp->t_state) { ! 652: ! 653: /* ! 654: * In SYN_RECEIVED and ESTABLISHED STATES ! 655: * enter the CLOSE_WAIT state. ! 656: */ ! 657: case TCPS_SYN_RECEIVED: ! 658: tp->t_state = TCPS_CLOSE_WAIT; ! 659: soisdisconnected(so); ! 660: break; ! 661: case TCPS_ESTABLISHED: ! 662: tp->t_state = TCPS_CLOSE_WAIT; ! 663: break; ! 664: ! 665: /* ! 666: * If still in FIN_WAIT_1 STATE FIN has not been acked so ! 667: * enter the CLOSING state. ! 668: */ ! 669: case TCPS_FIN_WAIT_1: ! 670: tp->t_state = TCPS_CLOSING; ! 671: break; ! 672: ! 673: /* ! 674: * In FIN_WAIT_2 state enter the TIME_WAIT state, ! 675: * starting the time-wait timer, turning off the other ! 676: * standard timers. ! 677: */ ! 678: case TCPS_FIN_WAIT_2: ! 679: tp->t_state = TCPS_TIME_WAIT; ! 680: tcp_canceltimers(tp); ! 681: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; ! 682: soisdisconnected(so); ! 683: break; ! 684: ! 685: /* ! 686: * In TIME_WAIT state restart the 2 MSL time_wait timer. ! 687: */ ! 688: case TCPS_TIME_WAIT: ! 689: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; ! 690: break; ! 691: } ! 692: } ! 693: ! 694: /* ! 695: * Return any desired output. ! 696: */ ! 697: (void) tcp_output(tp); ! 698: return; ! 699: ! 700: dropafterack: ! 701: /* ! 702: * Generate an ACK dropping incoming segment if it occupies ! 703: * sequence space, where the ACK reflects our state. ! 704: */ ! 705: if ((tiflags&TH_RST) || ! 706: tlen == 0 && (tiflags&(TH_SYN|TH_FIN)) == 0) ! 707: goto drop; ! 708: tcp_respond(tp, ti, tp->rcv_nxt, tp->snd_nxt, TH_ACK); ! 709: return; ! 710: ! 711: dropwithreset: ! 712: if (om) { ! 713: (void) m_free(om); ! 714: om = 0; ! 715: } ! 716: /* ! 717: * Generate a RST, dropping incoming segment. ! 718: * Make ACK acceptable to originator of segment. ! 719: */ ! 720: if (tiflags & TH_RST) ! 721: goto drop; ! 722: if (tiflags & TH_ACK) ! 723: tcp_respond(tp, ti, (tcp_seq)0, ti->ti_ack, TH_RST); ! 724: else { ! 725: if (tiflags & TH_SYN) ! 726: ti->ti_len++; ! 727: tcp_respond(tp, ti, ti->ti_seq+ti->ti_len, (tcp_seq)0, ! 728: TH_RST|TH_ACK); ! 729: } ! 730: /* destroy temporarily created socket */ ! 731: if (dropsocket) ! 732: (void) soabort(so); ! 733: return; ! 734: ! 735: drop: ! 736: if (om) ! 737: (void) m_free(om); ! 738: /* ! 739: * Drop space held by incoming segment and return. ! 740: */ ! 741: m_freem(m); ! 742: /* destroy temporarily created socket */ ! 743: if (dropsocket) ! 744: (void) soabort(so); ! 745: return; ! 746: } ! 747: ! 748: tcp_dooptions(tp, om) ! 749: struct tcpcb *tp; ! 750: struct mbuf *om; ! 751: { ! 752: register u_char *cp; ! 753: int opt, optlen, cnt; ! 754: ! 755: cp = mtod(om, u_char *); ! 756: cnt = BLEN(om); ! 757: for (; cnt > 0; cnt -= optlen, cp += optlen) { ! 758: opt = cp[0]; ! 759: if (opt == TCPOPT_EOL) ! 760: break; ! 761: if (opt == TCPOPT_NOP) ! 762: optlen = 1; ! 763: else { ! 764: optlen = cp[1]; ! 765: if (optlen <= 0) ! 766: break; ! 767: } ! 768: switch (opt) { ! 769: ! 770: default: ! 771: break; ! 772: ! 773: case TCPOPT_MAXSEG: ! 774: if (optlen != 4) ! 775: continue; ! 776: tp->t_maxseg = *(u_short *)(cp + 2); ! 777: tp->t_maxseg = ntohs((u_short)tp->t_maxseg); ! 778: break; ! 779: } ! 780: } ! 781: (void) m_free(om); ! 782: } ! 783: ! 784: /* ! 785: * Pull out of band byte out of a segment so ! 786: * it doesn't appear in the user's data queue. ! 787: * It is still reflected in the segment length for ! 788: * sequencing purposes. ! 789: */ ! 790: tcp_pulloutofband(so, ti) ! 791: struct socket *so; ! 792: struct tcpiphdr *ti; ! 793: { ! 794: register struct mbuf *m; ! 795: int cnt = ti->ti_urp - 1; ! 796: ! 797: m = dtom(ti); ! 798: while (cnt >= 0) { ! 799: if (BLEN(m) > cnt) { ! 800: char *cp = mtod(m, caddr_t) + cnt; ! 801: struct tcpcb *tp = sototcpcb(so); ! 802: ! 803: tp->t_iobc = *cp; ! 804: tp->t_oobflags |= TCPOOB_HAVEDATA; ! 805: bcopy(cp+1, cp, (unsigned)(BLEN(m) - cnt - 1)); ! 806: m->wptr--; ! 807: return; ! 808: } ! 809: cnt -= BLEN(m); ! 810: m = m->m_next; ! 811: if (m == 0) ! 812: break; ! 813: } ! 814: panic("tcp_pulloutofband"); ! 815: } ! 816: ! 817: /* ! 818: * Insert segment ti into reassembly queue of tcp with ! 819: * control block tp. Return TH_FIN if reassembly now includes ! 820: * a segment with FIN. ! 821: */ ! 822: tcp_reass(tp, ti) ! 823: register struct tcpcb *tp; ! 824: register struct tcpiphdr *ti; ! 825: { ! 826: register struct tcpiphdr *q; ! 827: struct socket *so = tp->t_socket; ! 828: struct mbuf *m; ! 829: int flags; ! 830: ! 831: /* ! 832: * Call with ti==0 after become established to ! 833: * force pre-ESTABLISHED data up to user socket. ! 834: */ ! 835: if (ti == 0) ! 836: goto present; ! 837: ! 838: /* ! 839: * Find a segment which begins after this one does. ! 840: */ ! 841: for (q = tp->seg_next; q != (struct tcpiphdr *)tp; ! 842: q = (struct tcpiphdr *)q->ti_next) ! 843: if (SEQ_GT(q->ti_seq, ti->ti_seq)) ! 844: break; ! 845: ! 846: /* ! 847: * If there is a preceding segment, it may provide some of ! 848: * our data already. If so, drop the data from the incoming ! 849: * segment. If it provides all of our data, drop us. ! 850: */ ! 851: if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { ! 852: register int i; ! 853: q = (struct tcpiphdr *)q->ti_prev; ! 854: /* conversion to int (in i) handles seq wraparound */ ! 855: i = q->ti_seq + q->ti_len - ti->ti_seq; ! 856: if (i > 0) { ! 857: tcpstat.tcps_duplicates++; ! 858: if (i >= ti->ti_len) ! 859: goto drop; ! 860: m_adj(dtom(ti), i); ! 861: ti->ti_len -= i; ! 862: ti->ti_seq += i; ! 863: } ! 864: q = (struct tcpiphdr *)(q->ti_next); ! 865: } ! 866: ! 867: /* ! 868: * While we overlap succeeding segments trim them or, ! 869: * if they are completely covered, dequeue them. ! 870: */ ! 871: while (q != (struct tcpiphdr *)tp) { ! 872: register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; ! 873: if (i <= 0) ! 874: break; ! 875: tcpstat.tcps_delayed++; ! 876: if (i < q->ti_len) { ! 877: q->ti_seq += i; ! 878: q->ti_len -= i; ! 879: m_adj(dtom(q), i); ! 880: break; ! 881: } ! 882: q = (struct tcpiphdr *)q->ti_next; ! 883: m = dtom(q->ti_prev); ! 884: remque(q->ti_prev); ! 885: m_freem(m); ! 886: } ! 887: ! 888: /* ! 889: * Stick new segment in its place. ! 890: */ ! 891: insque(ti, q->ti_prev); ! 892: ! 893: present: ! 894: /* ! 895: * Present data to user, advancing rcv_nxt through ! 896: * completed sequence space. ! 897: */ ! 898: if (TCPS_HAVERCVDSYN(tp->t_state) == 0) ! 899: return (0); ! 900: ti = tp->seg_next; ! 901: if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) ! 902: return (0); ! 903: if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) ! 904: return (0); ! 905: do { ! 906: tp->rcv_nxt += ti->ti_len; ! 907: flags = ti->ti_flags & TH_FIN; ! 908: remque(ti); ! 909: m = dtom(ti); ! 910: ti = (struct tcpiphdr *)ti->ti_next; ! 911: if (so->so_state & SS_OPEN) ! 912: tcpdrint(m, so); ! 913: else ! 914: m_freem(m); ! 915: } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); ! 916: return (flags); ! 917: drop: ! 918: m_freem(dtom(ti)); ! 919: return (0); ! 920: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.