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