|
|
1.1 ! root 1: #include "u.h" ! 2: #include "../port/lib.h" ! 3: #include "mem.h" ! 4: #include "dat.h" ! 5: #include "fns.h" ! 6: #include "../port/error.h" ! 7: #include "arp.h" ! 8: #include "../port/ipdat.h" ! 9: ! 10: int tcpdbg = 0; ! 11: ushort tcp_mss = DEF_MSS; /* Maximum segment size to be sent with SYN */ ! 12: int tcp_irtt = DEF_RTT; /* Initial guess at round trip time */ ! 13: ! 14: #define DPRINT if(tcpdbg) print ! 15: #define LPRINT if(tcpdbg) print ! 16: ! 17: char *tcpstate[] = ! 18: { ! 19: "Closed", "Listen", "Syn_sent", "Syn_received", ! 20: "Established", "Finwait1", "Finwait2", "Close_wait", ! 21: "Closing", "Last_ack", "Time_wait" ! 22: }; ! 23: ! 24: void ! 25: sndrst(Ipaddr source, Ipaddr dest, ushort length, Tcp *seg) ! 26: { ! 27: Block *hbp; ! 28: Port tmp; ! 29: char rflags; ! 30: Tcphdr ph; ! 31: ! 32: if(seg->flags & RST) ! 33: return; ! 34: ! 35: hnputl(ph.tcpsrc, dest); ! 36: hnputl(ph.tcpdst, source); ! 37: ph.proto = IP_TCPPROTO; ! 38: hnputs(ph.tcplen, TCP_HDRSIZE); ! 39: ! 40: /* Swap port numbers */ ! 41: tmp = seg->dest; ! 42: seg->dest = seg->source; ! 43: seg->source = tmp; ! 44: ! 45: rflags = RST; ! 46: ! 47: /* convince the other end that this reset is in band */ ! 48: if(seg->flags & ACK) { ! 49: seg->seq = seg->ack; ! 50: seg->ack = 0; ! 51: } ! 52: else { ! 53: rflags |= ACK; ! 54: seg->ack = seg->seq; ! 55: seg->seq = 0; ! 56: if(seg->flags & SYN) ! 57: seg->ack++; ! 58: seg->ack += length; ! 59: if(seg->flags & FIN) ! 60: seg->ack++; ! 61: } ! 62: seg->flags = rflags; ! 63: seg->wnd = 0; ! 64: seg->up = 0; ! 65: seg->mss = 0; ! 66: if((hbp = htontcp(seg, 0, &ph)) == 0) ! 67: return; ! 68: ! 69: ipmuxoput(0, hbp); ! 70: } ! 71: ! 72: /* ! 73: * flush an incoming call; send a reset to the remote side and close the ! 74: * conversation ! 75: */ ! 76: void ! 77: tcpflushincoming(Ipconv *s) ! 78: { ! 79: Tcp seg; ! 80: Tcpctl *tcb; ! 81: uchar dst[4]; ! 82: ! 83: tcb = &s->tcpctl; ! 84: seg.source = s->pdst; ! 85: seg.dest = s->psrc; ! 86: seg.flags = ACK; ! 87: seg.seq = tcb->snd.ptr; ! 88: tcb->last_ack = tcb->rcv.nxt; ! 89: seg.ack = tcb->rcv.nxt; ! 90: ! 91: if(s->src == 0){ ! 92: hnputl(dst, s->dst); ! 93: s->src = ipgetsrc(dst); ! 94: } ! 95: sndrst(s->dst, s->src, 0, &seg); ! 96: localclose(s, 0); ! 97: } ! 98: ! 99: static void ! 100: tcpmove(struct Tctl *to, struct Tctl *from) ! 101: { ! 102: memmove(to, from, sizeof(struct Tctl)); ! 103: } ! 104: ! 105: Ipconv* ! 106: tcpincoming(Ipifc *ifc, Ipconv *s, Tcp *segp, Ipaddr source, Ipaddr dest) ! 107: { ! 108: Ipconv *new; ! 109: ! 110: qlock(s); ! 111: if(s->curlog >= s->backlog){ ! 112: qunlock(s); ! 113: return 0; ! 114: } ! 115: ! 116: new = ipincoming(ifc, s); ! 117: if(new == 0){ ! 118: qunlock(s); ! 119: return 0; ! 120: } ! 121: ! 122: s->curlog++; ! 123: qunlock(s); ! 124: new->psrc = segp->dest; ! 125: new->pdst = segp->source; ! 126: new->dst = source; ! 127: new->src = dest; ! 128: tcpmove(&new->tcpctl, &s->tcpctl); ! 129: new->tcpctl.flags &= ~CLONE; ! 130: new->tcpctl.timer.arg = new; ! 131: new->tcpctl.timer.state = TimerOFF; ! 132: new->tcpctl.acktimer.arg = new; ! 133: new->tcpctl.acktimer.state = TimerOFF; ! 134: new->newcon = s; ! 135: ! 136: wakeup(&s->listenr); ! 137: return new; ! 138: } ! 139: ! 140: void ! 141: tcpinput(Ipifc *ifc, Block *bp) ! 142: { ! 143: Tcp seg; ! 144: char tos; ! 145: Tcphdr *h; ! 146: int hdrlen; ! 147: Tcpctl *tcb; ! 148: ushort length; ! 149: Ipconv *spec, *gen; ! 150: Ipaddr source, dest; ! 151: Ipconv *s, **p, **etab; ! 152: ! 153: h = (Tcphdr *)(bp->rptr); ! 154: dest = nhgetl(h->tcpdst); ! 155: source = nhgetl(h->tcpsrc); ! 156: ! 157: tos = h->tos; ! 158: length = nhgets(h->length); ! 159: ! 160: h->Unused = 0; ! 161: hnputs(h->tcplen, length - (TCP_IPLEN+TCP_PHDRSIZE)); ! 162: if(ptcl_csum(bp, TCP_EHSIZE+TCP_IPLEN, length - TCP_IPLEN)) { ! 163: freeb(bp); ! 164: return; ! 165: } ! 166: ! 167: if((hdrlen = ntohtcp(&seg, &bp)) < 0) ! 168: return; ! 169: ! 170: /* trim the packet to the size claimed by the datagram */ ! 171: length -= (hdrlen+TCP_IPLEN+TCP_PHDRSIZE); ! 172: bp = btrim(bp, hdrlen+TCP_PKT, length); ! 173: if(bp == 0) ! 174: return; ! 175: ! 176: /* Look for a connection. failing that look for a listener. */ ! 177: s = ip_conn(ifc, seg.dest, seg.source, source); ! 178: if(s && s->tcpctl.state == Listen) ! 179: s = 0; /* can't talk directly to a listener */ ! 180: ! 181: if (s == 0) { ! 182: if(seg.flags & SYN){ ! 183: /* ! 184: * dump packets with bogus flags ! 185: */ ! 186: if(seg.flags & RST){ ! 187: freeb(bp); ! 188: return; ! 189: } ! 190: if(seg.flags & ACK) { ! 191: freeb(bp); ! 192: sndrst(source, dest, length, &seg); ! 193: return; ! 194: } ! 195: ! 196: /* ! 197: * find a listener specific to this port (spec) or, ! 198: * failing that, a general one (gen) ! 199: */ ! 200: spec = 0; ! 201: gen = 0; ! 202: etab = &ifc->conv[Nipconv]; ! 203: for(p = ifc->conv; p < etab && *p; p++) { ! 204: s = *p; ! 205: if(s->tcpctl.state == Listen) ! 206: if(s->pdst == 0) ! 207: if(s->dst == 0) { ! 208: if(s->psrc == seg.dest){ ! 209: spec = s; ! 210: break; ! 211: } ! 212: if(s->psrc == 0) ! 213: gen = s; ! 214: } ! 215: } ! 216: if(spec) ! 217: s = tcpincoming(ifc, spec, &seg, source, dest); ! 218: else if(gen) ! 219: s = tcpincoming(ifc, gen, &seg, source, dest); ! 220: else ! 221: s = 0; ! 222: } ! 223: if(s == 0){ ! 224: freeb(bp); ! 225: sndrst(source, dest, length, &seg); ! 226: return; ! 227: } ! 228: } ! 229: ! 230: /* The rest of the input state machine is run with the control block ! 231: * locked and implements the state machine directly out of the RFC ! 232: * Out-of-band data is ignored - it was always a bad idea. ! 233: */ ! 234: tcb = &s->tcpctl; ! 235: qlock(tcb); ! 236: ! 237: switch(tcb->state) { ! 238: case Closed: ! 239: freeb(bp); ! 240: sndrst(source, dest, length, &seg); ! 241: goto done; ! 242: case Listen: ! 243: if((seg.flags & (SYN|RST|ACK)) != SYN) { ! 244: /* ignore bogus packets */ ! 245: print("packet to channel in listen state %d <- %d\n", s->psrc, s->pdst); ! 246: freeb(bp); ! 247: goto done; ! 248: } ! 249: ! 250: proc_syn(s, tos, &seg); ! 251: tcpsndsyn(tcb); ! 252: tcpsetstate(s, Syn_received); ! 253: if(length != 0 || (seg.flags & FIN)) ! 254: break; ! 255: freeb(bp); ! 256: goto output; ! 257: case Syn_sent: ! 258: if(seg.flags & ACK) { ! 259: if(!seq_within(seg.ack, tcb->iss+1, tcb->snd.nxt)) { ! 260: freeb(bp); ! 261: sndrst(source, dest, length, &seg); ! 262: goto done; ! 263: } ! 264: } ! 265: if(seg.flags & RST) { ! 266: if(seg.flags & ACK) ! 267: localclose(s, Econrefused); ! 268: freeb(bp); ! 269: goto done; ! 270: } ! 271: ! 272: if(seg.flags & ACK) ! 273: if(PREC(tos) != PREC(tcb->tos)){ ! 274: freeb(bp); ! 275: sndrst(source, dest, length, &seg); ! 276: goto done; ! 277: } ! 278: ! 279: if(seg.flags & SYN) { ! 280: proc_syn(s, tos, &seg); ! 281: if(seg.flags & ACK){ ! 282: update(s, &seg); ! 283: tcpsetstate(s, Established); ! 284: } ! 285: else ! 286: tcpsetstate(s, Syn_received); ! 287: ! 288: if(length != 0 || (seg.flags & FIN)) ! 289: break; ! 290: ! 291: freeb(bp); ! 292: goto output; ! 293: } ! 294: else ! 295: freeb(bp); ! 296: goto done; ! 297: } ! 298: ! 299: /* Cut the data to fit the receive window */ ! 300: if(trim(tcb, &seg, &bp, &length) == -1) { ! 301: if(!(seg.flags & RST)) { ! 302: tcb->flags |= FORCE; ! 303: goto output; ! 304: } ! 305: goto done; ! 306: } ! 307: ! 308: /* Cannot accept so answer with a rst */ ! 309: if(length) ! 310: if(s->readq == 0) ! 311: if(tcb->state == Closed) { ! 312: freeb(bp); ! 313: sndrst(source, dest, length, &seg); ! 314: goto done; ! 315: } ! 316: ! 317: /* The segment is beyond the current receive pointer so ! 318: * queue the data in the resequence queue ! 319: */ ! 320: if(seg.seq != tcb->rcv.nxt) ! 321: if(length != 0 || (seg.flags & (SYN|FIN))) { ! 322: add_reseq(tcb, tos, &seg, bp, length); ! 323: tcb->flags |= FORCE; ! 324: goto output; ! 325: } ! 326: ! 327: /* ! 328: * keep looping till we've processed this packet plus any ! 329: * adjacent packets in the resequence queue ! 330: */ ! 331: for(;;) { ! 332: if(seg.flags & RST) { ! 333: localclose(s, Econrefused); ! 334: ! 335: freeb(bp); ! 336: goto done; ! 337: } ! 338: ! 339: /* This tos stuff should be removed */ ! 340: if(PREC(tos) != PREC(tcb->tos) || (seg.flags & SYN)){ ! 341: freeb(bp); ! 342: sndrst(source, dest, length, &seg); ! 343: goto done; ! 344: } ! 345: ! 346: if(!(seg.flags & ACK)) { ! 347: freeb(bp); ! 348: goto done; ! 349: } ! 350: ! 351: switch(tcb->state) { ! 352: case Syn_received: ! 353: if(!seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){ ! 354: freeb(bp); ! 355: sndrst(source, dest, length, &seg); ! 356: goto done; ! 357: } ! 358: update(s, &seg); ! 359: tcpsetstate(s, Established); ! 360: case Established: ! 361: case Close_wait: ! 362: update(s, &seg); ! 363: break; ! 364: case Finwait1: ! 365: update(s, &seg); ! 366: if(tcb->sndcnt == 0){ ! 367: tcb->kacounter = MAXBACKOFF; ! 368: tcpsetstate(s, Finwait2); ! 369: tcb->timer.start = MSL2 * (1000 / MSPTICK); ! 370: tcpgo(&tcb->timer); ! 371: } ! 372: break; ! 373: case Finwait2: ! 374: update(s, &seg); ! 375: break; ! 376: case Closing: ! 377: update(s, &seg); ! 378: if(tcb->sndcnt == 0) { ! 379: tcpsetstate(s, Time_wait); ! 380: tcb->timer.start = MSL2 * (1000 / MSPTICK); ! 381: tcpgo(&tcb->timer); ! 382: } ! 383: break; ! 384: case Last_ack: ! 385: update(s, &seg); ! 386: if(tcb->sndcnt == 0) { ! 387: freeb(bp); ! 388: localclose(s, 0); ! 389: goto done; ! 390: } ! 391: case Time_wait: ! 392: tcb->flags |= FORCE; ! 393: tcpgo(&tcb->timer); ! 394: } ! 395: ! 396: if((seg.flags&URG) && seg.up) { ! 397: if(seq_gt(seg.up + seg.seq, tcb->rcv.up)) { ! 398: tcb->rcv.up = seg.up + seg.seq; ! 399: pullb(&bp, seg.up); ! 400: } ! 401: } ! 402: else if(seq_gt(tcb->rcv.nxt, tcb->rcv.up)) ! 403: tcb->rcv.up = tcb->rcv.nxt; ! 404: ! 405: if(length == 0){ ! 406: if(bp) ! 407: freeb(bp); ! 408: } ! 409: else { ! 410: switch(tcb->state){ ! 411: default: ! 412: /* Ignore segment text */ ! 413: if(bp) ! 414: freeb(bp); ! 415: break; ! 416: ! 417: case Syn_received: ! 418: case Established: ! 419: case Finwait1: ! 420: /* If we still have some data place on receive queue */ ! 421: tcb->rcvcnt += blen(bp); ! 422: if(bp){ ! 423: if(s->readq) ! 424: PUTNEXT(s->readq, bp); ! 425: else ! 426: putb(&tcb->rcvq, bp); ! 427: bp = 0; ! 428: } ! 429: tcb->rcv.nxt += length; ! 430: ! 431: tcprcvwin(s); ! 432: ! 433: if(tcb->acktimer.state != TimerON) ! 434: tcpgo(&tcb->acktimer); ! 435: ! 436: if(tcb->rcv.nxt-tcb->last_ack > Streamhi/2) ! 437: tcb->flags |= FORCE; ! 438: ! 439: break; ! 440: case Finwait2: ! 441: /* no process to read the data, send a reset */ ! 442: if(bp) ! 443: freeb(bp); ! 444: sndrst(source, dest, length, &seg); ! 445: goto done; ! 446: } ! 447: } ! 448: ! 449: if(seg.flags & FIN) { ! 450: tcb->flags |= FORCE; ! 451: ! 452: switch(tcb->state) { ! 453: case Syn_received: ! 454: case Established: ! 455: tcb->rcv.nxt++; ! 456: tcpsetstate(s, Close_wait); ! 457: break; ! 458: case Finwait1: ! 459: tcb->rcv.nxt++; ! 460: if(tcb->sndcnt == 0) { ! 461: tcpsetstate(s, Time_wait); ! 462: tcb->timer.start = MSL2 * (1000/MSPTICK); ! 463: tcpgo(&tcb->timer); ! 464: } ! 465: else ! 466: tcpsetstate(s, Closing); ! 467: break; ! 468: case Finwait2: ! 469: tcb->rcv.nxt++; ! 470: tcpsetstate(s, Time_wait); ! 471: tcb->timer.start = MSL2 * (1000/MSPTICK); ! 472: tcpgo(&tcb->timer); ! 473: break; ! 474: case Close_wait: ! 475: case Closing: ! 476: case Last_ack: ! 477: break; ! 478: case Time_wait: ! 479: tcpgo(&tcb->timer); ! 480: break; ! 481: } ! 482: } ! 483: ! 484: /* ! 485: * get next adjacent segment from the requence queue. ! 486: * dump/trim any overlapping segments ! 487: */ ! 488: for(;;) { ! 489: if(tcb->reseq == 0) ! 490: goto output; ! 491: ! 492: if(seq_ge(tcb->rcv.nxt, tcb->reseq->seg.seq) == 0) ! 493: goto output; ! 494: ! 495: get_reseq(tcb, &tos, &seg, &bp, &length); ! 496: ! 497: if(trim(tcb, &seg, &bp, &length) == 0) ! 498: break; ! 499: } ! 500: } ! 501: output: ! 502: tcpoutput(s); ! 503: done: ! 504: qunlock(tcb); ! 505: } ! 506: ! 507: void ! 508: update(Ipconv *s, Tcp *seg) ! 509: { ! 510: int rtt; ! 511: ushort acked; ! 512: ushort expand; ! 513: Tcpctl *tcb = &s->tcpctl; ! 514: ! 515: tcb->kacounter = MAXBACKOFF; /* keep alive count down */ ! 516: ! 517: if(seq_gt(seg->ack, tcb->snd.nxt)) { ! 518: tcb->flags |= FORCE; ! 519: return; ! 520: } ! 521: ! 522: if(seq_ge(seg->ack,tcb->snd.wl2)) ! 523: if(seq_gt(seg->seq,tcb->snd.wl1) || (seg->seq == tcb->snd.wl1)) { ! 524: if(seg->wnd != 0) ! 525: if(tcb->snd.wnd == 0) ! 526: tcb->snd.ptr = tcb->snd.una; ! 527: ! 528: tcb->snd.wnd = seg->wnd; ! 529: tcb->snd.wl1 = seg->seq; ! 530: tcb->snd.wl2 = seg->ack; ! 531: } ! 532: ! 533: if(!seq_gt(seg->ack, tcb->snd.una)) ! 534: return; ! 535: ! 536: /* Compute the new send window size */ ! 537: acked = seg->ack - tcb->snd.una; ! 538: if(tcb->cwind < tcb->snd.wnd) { ! 539: if(tcb->cwind < tcb->ssthresh) ! 540: expand = MIN(acked,tcb->mss); ! 541: else ! 542: expand = ((long)tcb->mss * tcb->mss) / tcb->cwind; ! 543: ! 544: if(tcb->cwind + expand < tcb->cwind) ! 545: expand = 65535 - tcb->cwind; ! 546: if(tcb->cwind + expand > tcb->snd.wnd) ! 547: expand = tcb->snd.wnd - tcb->cwind; ! 548: if(expand != 0) ! 549: tcb->cwind += expand; ! 550: } ! 551: ! 552: /* Adjust the timers acorrding to the round trip time */ ! 553: if(run_timer(&tcb->rtt_timer)) ! 554: if(seq_ge(seg->ack, tcb->rttseq)) { ! 555: tcphalt(&tcb->rtt_timer); ! 556: if((tcb->flags&RETRAN) == 0) { ! 557: tcb->backoff = 0; ! 558: rtt = tcb->rtt_timer.start - tcb->rtt_timer.count; ! 559: rtt *= MSPTICK; ! 560: if(rtt > tcb->srtt && ! 561: (tcb->state == Syn_sent || tcb->state == Syn_received)) ! 562: tcb->srtt = rtt; ! 563: else { ! 564: tcb->srtt = ((AGAIN-1)*tcb->srtt + rtt) / AGAIN; ! 565: rtt = abs(rtt - tcb->srtt); ! 566: tcb->mdev = ((DGAIN-1)*tcb->mdev + rtt) / DGAIN; ! 567: } ! 568: } ! 569: } ! 570: ! 571: if((tcb->flags & SYNACK) == 0){ ! 572: tcb->flags |= SYNACK; ! 573: acked--; ! 574: tcb->sndcnt--; ! 575: } ! 576: ! 577: pullb(&tcb->sndq, acked); ! 578: ! 579: tcb->sndcnt -= acked; ! 580: tcb->snd.una = seg->ack; ! 581: if(seq_gt(seg->ack, tcb->snd.up)) ! 582: tcb->snd.up = seg->ack; ! 583: ! 584: tcphalt(&tcb->timer); ! 585: if(tcb->snd.una != tcb->snd.nxt) ! 586: tcpgo(&tcb->timer); ! 587: ! 588: if(seq_lt(tcb->snd.ptr, tcb->snd.una)) ! 589: tcb->snd.ptr = tcb->snd.una; ! 590: ! 591: tcb->flags &= ~RETRAN; ! 592: tcb->backoff = 0; ! 593: ! 594: if(tcb->sndfull && tcb->sndcnt < Streamhi/2){ ! 595: wakeup(&tcb->sndr); ! 596: tcb->sndfull = 0; ! 597: } ! 598: } ! 599: ! 600: int ! 601: in_window(Tcpctl *tcb, int seq) ! 602: { ! 603: return seq_within(seq, tcb->rcv.nxt, tcb->rcv.nxt+tcb->rcv.wnd-1); ! 604: } ! 605: ! 606: void ! 607: proc_syn(Ipconv *s, char tos, Tcp *seg) ! 608: { ! 609: Tcpctl *tcb = &s->tcpctl; ! 610: ushort mtu; ! 611: ! 612: ! 613: tcb->flags |= FORCE; ! 614: ! 615: if(PREC(tos) > PREC(tcb->tos)) ! 616: tcb->tos = tos; ! 617: ! 618: tcb->rcv.up = tcb->rcv.nxt = seg->seq + 1; ! 619: tcb->snd.wl1 = tcb->irs = seg->seq; ! 620: tcb->snd.wnd = seg->wnd; ! 621: ! 622: if(seg->mss != 0) ! 623: tcb->mss = seg->mss; ! 624: ! 625: tcb->max_snd = seg->wnd; ! 626: /* FIX MTU!!! */ ! 627: if((mtu = 1500) != 0) { ! 628: mtu -= TCP_HDRSIZE + TCP_EHSIZE + TCP_PHDRSIZE; ! 629: tcb->cwind = tcb->mss = MIN(mtu, tcb->mss); ! 630: } ! 631: } ! 632: ! 633: /* Generate an initial sequence number and put a SYN on the send queue */ ! 634: void ! 635: tcpsndsyn(Tcpctl *tcb) ! 636: { ! 637: static int start; ! 638: ! 639: if(start == 0) ! 640: start = rtctime(); ! 641: else ! 642: start += 250000; ! 643: tcb->iss = start; ! 644: tcb->rttseq = tcb->iss; ! 645: tcb->snd.wl2 = tcb->iss; ! 646: tcb->snd.una = tcb->iss; ! 647: tcb->snd.ptr = tcb->snd.nxt = tcb->rttseq; ! 648: tcb->sndcnt++; ! 649: tcb->flags |= FORCE; ! 650: } ! 651: ! 652: void ! 653: add_reseq(Tcpctl *tcb, char tos, Tcp *seg, Block *bp, ushort length) ! 654: { ! 655: Reseq *rp, *rp1; ! 656: ! 657: rp = malloc(sizeof(Reseq)); ! 658: if(rp == 0){ ! 659: freeb(bp); /* bp always consumed by add_reseq */ ! 660: return; ! 661: } ! 662: ! 663: rp->seg = *seg; ! 664: rp->tos = tos; ! 665: rp->bp = bp; ! 666: rp->length = length; ! 667: ! 668: /* Place on reassembly list sorting by starting seq number */ ! 669: rp1 = tcb->reseq; ! 670: if(rp1 == 0 || seq_lt(seg->seq, rp1->seg.seq)) { ! 671: rp->next = rp1; ! 672: tcb->reseq = rp; ! 673: return; ! 674: } ! 675: ! 676: for(;;) { ! 677: if(rp1->next == 0 || seq_lt(seg->seq, rp1->next->seg.seq)) { ! 678: rp->next = rp1->next; ! 679: rp1->next = rp; ! 680: break; ! 681: } ! 682: rp1 = rp1->next; ! 683: } ! 684: } ! 685: ! 686: void ! 687: get_reseq(Tcpctl *tcb, char *tos, Tcp *seg, Block **bp, ushort *length) ! 688: { ! 689: Reseq *rp; ! 690: ! 691: rp = tcb->reseq; ! 692: if(rp == 0) ! 693: return; ! 694: ! 695: tcb->reseq = rp->next; ! 696: ! 697: *tos = rp->tos; ! 698: *seg = rp->seg; ! 699: *bp = rp->bp; ! 700: *length = rp->length; ! 701: ! 702: free(rp); ! 703: } ! 704: ! 705: int ! 706: trim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length) ! 707: { ! 708: Block *nbp; ! 709: long dupcnt; ! 710: long excess; ! 711: ushort len; ! 712: char accept; ! 713: ! 714: accept = 0; ! 715: len = *length; ! 716: if(seg->flags & SYN) ! 717: len++; ! 718: if(seg->flags & FIN) ! 719: len++; ! 720: ! 721: if(tcb->rcv.wnd == 0) { ! 722: if(len == 0) ! 723: if(seg->seq == tcb->rcv.nxt) ! 724: return 0; ! 725: } ! 726: else { ! 727: /* Some part of the segment should be in the window */ ! 728: if(in_window(tcb,seg->seq)) ! 729: accept++; ! 730: else ! 731: if(len != 0) { ! 732: if(in_window(tcb, seg->seq+len-1) || ! 733: seq_within(tcb->rcv.nxt, seg->seq,seg->seq+len-1)) ! 734: accept++; ! 735: } ! 736: } ! 737: if(!accept) { ! 738: freeb(*bp); ! 739: return -1; ! 740: } ! 741: dupcnt = tcb->rcv.nxt - seg->seq; ! 742: if(dupcnt > 0){ ! 743: tcb->rerecv += dupcnt; ! 744: if(seg->flags & SYN){ ! 745: seg->flags &= ~SYN; ! 746: seg->seq++; ! 747: ! 748: if (seg->up > 1) ! 749: seg->up--; ! 750: else ! 751: seg->flags &= ~URG; ! 752: dupcnt--; ! 753: } ! 754: if(dupcnt > 0){ ! 755: pullb(bp, (ushort)dupcnt); ! 756: seg->seq += dupcnt; ! 757: *length -= dupcnt; ! 758: ! 759: if (seg->up > dupcnt) ! 760: seg->up -= dupcnt; ! 761: else { ! 762: seg->flags &= ~URG; ! 763: seg->up = 0; ! 764: } ! 765: } ! 766: } ! 767: excess = seg->seq + *length - (tcb->rcv.nxt + tcb->rcv.wnd); ! 768: if(excess > 0) { ! 769: tcb->rerecv += excess; ! 770: *length -= excess; ! 771: nbp = copyb(*bp, *length); ! 772: freeb(*bp); ! 773: *bp = nbp; ! 774: seg->flags &= ~FIN; ! 775: } ! 776: return 0; ! 777: } ! 778: ! 779: int ! 780: pullb(Block **bph, int count) ! 781: { ! 782: int n, bytes; ! 783: Block *bp; ! 784: ! 785: bytes = 0; ! 786: if(bph == 0) ! 787: return 0; ! 788: ! 789: while(*bph && count != 0) { ! 790: bp = *bph; ! 791: n = MIN(count, BLEN(bp)); ! 792: bytes += n; ! 793: count -= n; ! 794: bp->rptr += n; ! 795: if(BLEN(bp) == 0) { ! 796: *bph = bp->next; ! 797: bp->next = 0; ! 798: freeb(bp); ! 799: } ! 800: } ! 801: return bytes; ! 802: } ! 803: ! 804: int ! 805: dupb(Block **hp, Block *bp, int offset, int count) ! 806: { ! 807: int i, blen, bytes = 0; ! 808: uchar *addr; ! 809: ! 810: *hp = allocb(count); ! 811: if(*hp == 0) ! 812: return 0; ! 813: ! 814: /* Correct to front of data area */ ! 815: while(bp && offset && offset >= BLEN(bp)) { ! 816: offset -= BLEN(bp); ! 817: bp = bp->next; ! 818: } ! 819: if(bp == 0) ! 820: return 0; ! 821: ! 822: addr = bp->rptr + offset; ! 823: blen = BLEN(bp) - offset; ! 824: ! 825: while(count) { ! 826: i = MIN(count, blen); ! 827: memmove((*hp)->wptr, addr, i); ! 828: (*hp)->wptr += i; ! 829: bytes += i; ! 830: count -= i; ! 831: bp = bp->next; ! 832: if(!bp) ! 833: break; ! 834: blen = BLEN(bp); ! 835: addr = bp->rptr; ! 836: } ! 837: ! 838: return bytes; ! 839: } ! 840: ! 841: static void ! 842: cleartcp(struct Tctl *a) ! 843: { ! 844: memset(a, 0, sizeof(struct Tctl)); ! 845: } ! 846: ! 847: void ! 848: init_tcpctl(Ipconv *s) ! 849: { ! 850: ! 851: Tcpctl *tcb = &s->tcpctl; ! 852: ! 853: cleartcp(tcb); ! 854: ! 855: tcb->cwind = tcb->mss = tcp_mss; ! 856: tcb->ssthresh = 65535; ! 857: tcb->srtt = tcp_irtt; ! 858: ! 859: tcb->timer.start = tcb->srtt / MSPTICK; ! 860: tcb->timer.func = tcptimeout; ! 861: tcb->timer.arg = s; ! 862: tcb->rtt_timer.start = MAX_TIME; ! 863: tcb->acktimer.start = TCP_ACK / MSPTICK; ! 864: tcb->acktimer.func = tcpacktimer; ! 865: tcb->acktimer.arg = s; ! 866: } ! 867: ! 868: /* ! 869: * called with tcb locked ! 870: */ ! 871: void ! 872: localclose(Ipconv *s, char *reason) ! 873: { ! 874: Reseq *rp,*rp1; ! 875: Tcpctl *tcb = &s->tcpctl; ! 876: Block *bp; ! 877: ! 878: tcphalt(&tcb->timer); ! 879: tcphalt(&tcb->rtt_timer); ! 880: s->err = reason; ! 881: ! 882: /* flush receive queue */ ! 883: while(bp = getb(&tcb->rcvq)) ! 884: freeb(bp); ! 885: ! 886: /* Flush reassembly queue; nothing more can arrive */ ! 887: for(rp = tcb->reseq;rp != 0;rp = rp1){ ! 888: rp1 = rp->next; ! 889: freeb(rp->bp); ! 890: free(rp); ! 891: } ! 892: ! 893: tcb->reseq = 0; ! 894: s->err = reason; ! 895: if(tcb->sndq != 0){ ! 896: freeb(tcb->sndq); ! 897: tcb->sndq = 0; ! 898: } ! 899: tcpsetstate(s, Closed); ! 900: } ! 901: ! 902: int ! 903: seq_within(ulong x, ulong low, ulong high) ! 904: { ! 905: if(low <= high){ ! 906: if(low <= x && x <= high) ! 907: return 1; ! 908: } ! 909: else { ! 910: if(low >= x && x >= high) ! 911: return 1; ! 912: } ! 913: return 0; ! 914: } ! 915: ! 916: int ! 917: seq_lt(ulong x, ulong y) ! 918: { ! 919: return x < y; ! 920: } ! 921: ! 922: int ! 923: seq_le(ulong x, ulong y) ! 924: { ! 925: return x <= y; ! 926: } ! 927: ! 928: int ! 929: seq_gt(ulong x, ulong y) ! 930: { ! 931: return x > y; ! 932: } ! 933: ! 934: int ! 935: seq_ge(ulong x, ulong y) ! 936: { ! 937: return x >= y; ! 938: } ! 939: ! 940: void ! 941: tcpsetstate(Ipconv *s, char newstate) ! 942: { ! 943: Tcpctl *tcb; ! 944: char oldstate; ! 945: ! 946: tcb = &s->tcpctl; ! 947: ! 948: oldstate = tcb->state; ! 949: tcb->state = newstate; ! 950: tcpxstate(s, oldstate, newstate); ! 951: } ! 952: ! 953: Block * ! 954: htontcp(Tcp *tcph, Block *data, Tcphdr *ph) ! 955: { ! 956: int dlen; ! 957: Tcphdr *h; ! 958: Block *bp; ! 959: ushort csum; ! 960: ushort hdrlen; ! 961: ! 962: hdrlen = TCP_HDRSIZE; ! 963: if(tcph->mss) ! 964: hdrlen += MSS_LENGTH; ! 965: ! 966: if(data) { ! 967: dlen = blen(data); ! 968: data = padb(data, hdrlen + TCP_PKT); ! 969: if(data == 0) ! 970: return 0; ! 971: /* If we collected blocks delimit the end of the chain */ ! 972: for(bp = data; bp->next; bp = bp->next) ! 973: bp->flags &= ~S_DELIM; ! 974: bp->flags |= S_DELIM; ! 975: } ! 976: else { ! 977: dlen = 0; ! 978: data = allocb(hdrlen + TCP_PKT); ! 979: if(data == 0) ! 980: return 0; ! 981: data->wptr += hdrlen + TCP_PKT; ! 982: data->flags |= S_DELIM; ! 983: } ! 984: ! 985: ! 986: memmove(data->rptr, ph, TCP_PKT); ! 987: ! 988: h = (Tcphdr *)(data->rptr); ! 989: h->proto = IP_TCPPROTO; ! 990: h->frag[0] = 0; ! 991: h->frag[1] = 0; ! 992: hnputs(h->tcplen, hdrlen + dlen); ! 993: hnputs(h->tcpsport, tcph->source); ! 994: hnputs(h->tcpdport, tcph->dest); ! 995: hnputl(h->tcpseq, tcph->seq); ! 996: hnputl(h->tcpack, tcph->ack); ! 997: hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags); ! 998: hnputs(h->tcpwin, tcph->wnd); ! 999: h->tcpcksum[0] = 0; ! 1000: h->tcpcksum[1] = 0; ! 1001: h->Unused = 0; ! 1002: hnputs(h->tcpurg, tcph->up); ! 1003: ! 1004: if(tcph->mss != 0){ ! 1005: h->tcpopt[0] = MSS_KIND; ! 1006: h->tcpopt[1] = MSS_LENGTH; ! 1007: hnputs(h->tcpmss, tcph->mss); ! 1008: } ! 1009: csum = ptcl_csum(data, TCP_EHSIZE+TCP_IPLEN, hdrlen+dlen+TCP_PHDRSIZE); ! 1010: hnputs(h->tcpcksum, csum); ! 1011: ! 1012: return data; ! 1013: } ! 1014: ! 1015: int ! 1016: ntohtcp(Tcp *tcph, Block **bpp) ! 1017: { ! 1018: ushort hdrlen; ! 1019: ushort i, optlen; ! 1020: Tcphdr *h; ! 1021: uchar *optr; ! 1022: ! 1023: *bpp = pullup(*bpp, TCP_PKT+TCP_HDRSIZE); ! 1024: if(*bpp == 0) ! 1025: return -1; ! 1026: ! 1027: h = (Tcphdr *)((*bpp)->rptr); ! 1028: tcph->source = nhgets(h->tcpsport); ! 1029: tcph->dest = nhgets(h->tcpdport); ! 1030: tcph->seq = nhgetl(h->tcpseq); ! 1031: tcph->ack = nhgetl(h->tcpack); ! 1032: ! 1033: hdrlen = (h->tcpflag[0] & 0xf0) >> 2; ! 1034: if(hdrlen < TCP_HDRSIZE) { ! 1035: freeb(*bpp); ! 1036: return -1; ! 1037: } ! 1038: ! 1039: tcph->flags = h->tcpflag[1]; ! 1040: tcph->wnd = nhgets(h->tcpwin); ! 1041: tcph->up = nhgets(h->tcpurg); ! 1042: tcph->mss = 0; ! 1043: ! 1044: *bpp = pullup(*bpp, hdrlen+TCP_PKT); ! 1045: if(!*bpp) ! 1046: return -1; ! 1047: ! 1048: optr = h->tcpopt; ! 1049: for(i = TCP_HDRSIZE; i < hdrlen;) { ! 1050: switch(*optr++){ ! 1051: case EOL_KIND: ! 1052: return hdrlen; ! 1053: case NOOP_KIND: ! 1054: i++; ! 1055: break; ! 1056: case MSS_KIND: ! 1057: optlen = *optr++; ! 1058: if(optlen == MSS_LENGTH) ! 1059: tcph->mss = nhgets(optr); ! 1060: i += optlen; ! 1061: break; ! 1062: } ! 1063: } ! 1064: return hdrlen; ! 1065: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.