|
|
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.