|
|
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: #define DPRINT if(tcpdbg) print ! 11: ! 12: extern int tcpdbg; ! 13: extern ushort tcp_mss; ! 14: int tcptimertype; ! 15: ! 16: void ! 17: tcpoutput(Ipconv *s) ! 18: { ! 19: Tcp seg; ! 20: int qlen; ! 21: Tcphdr ph; ! 22: Tcpctl *tcb; ! 23: Block *hbp,*dbp, *sndq; ! 24: ushort ssize, dsize, usable, sent; ! 25: ! 26: tcb = &s->tcpctl; ! 27: ! 28: switch(tcb->state) { ! 29: case Listen: ! 30: case Closed: ! 31: return; ! 32: } ! 33: ! 34: for(;;) { ! 35: qlen = tcb->sndcnt; ! 36: sent = tcb->snd.ptr - tcb->snd.una; ! 37: sndq = tcb->sndq; ! 38: ! 39: /* Don't send anything else until our SYN has been acked */ ! 40: if(sent != 0) ! 41: if((tcb->flags & SYNACK) == 0) ! 42: break; ! 43: ! 44: /* Compute usable segment based on offered window and limit ! 45: * window probes to one ! 46: */ ! 47: if(tcb->snd.wnd == 0){ ! 48: if(sent != 0) { ! 49: if ((tcb->flags&FORCE) == 0) ! 50: break; ! 51: tcb->snd.ptr = tcb->snd.una; ! 52: } ! 53: usable = 1; ! 54: } ! 55: else { ! 56: usable = MIN(tcb->snd.wnd,tcb->cwind) - sent; ! 57: if(sent != 0) ! 58: if(qlen - sent < tcb->mss) ! 59: usable = 0; ! 60: } ! 61: ! 62: ssize = MIN(qlen - sent, usable); ! 63: ssize = MIN(ssize, tcb->mss); ! 64: dsize = ssize; ! 65: seg.up = 0; ! 66: ! 67: if(ssize == 0) ! 68: if((tcb->flags&FORCE) == 0) ! 69: break; ! 70: ! 71: tcphalt(&tcb->acktimer); ! 72: ! 73: tcb->flags &= ~FORCE; ! 74: tcprcvwin(s); ! 75: ! 76: /* By default we will generate an ack */ ! 77: seg.source = s->psrc; ! 78: seg.dest = s->pdst; ! 79: seg.flags = ACK; ! 80: seg.mss = 0; ! 81: ! 82: switch(tcb->state){ ! 83: case Syn_sent: ! 84: seg.flags = 0; ! 85: /* No break */ ! 86: case Syn_received: ! 87: if(tcb->snd.ptr == tcb->iss){ ! 88: seg.flags |= SYN; ! 89: dsize--; ! 90: seg.mss = tcp_mss; ! 91: } ! 92: break; ! 93: } ! 94: tcb->last_ack = tcb->rcv.nxt; ! 95: seg.seq = tcb->snd.ptr; ! 96: seg.ack = tcb->rcv.nxt; ! 97: seg.wnd = tcb->rcv.wnd; ! 98: ! 99: /* Pull out data to send */ ! 100: dbp = 0; ! 101: if(dsize != 0){ ! 102: if(dupb(&dbp, sndq, sent, dsize) != dsize) { ! 103: seg.flags |= FIN; ! 104: dsize--; ! 105: } ! 106: DPRINT("dupb: %d\n", dbp->rptr[0]); ! 107: } ! 108: ! 109: if(sent+dsize == qlen) ! 110: seg.flags |= PSH; ! 111: ! 112: /* ! 113: * keep track of balance of resent data */ ! 114: if(tcb->snd.ptr < tcb->snd.nxt) ! 115: tcb->resent += MIN(tcb->snd.nxt - tcb->snd.ptr,(int)ssize); ! 116: ! 117: tcb->snd.ptr += ssize; ! 118: ! 119: /* Pull up the send pointer so we can accept acks for this window */ ! 120: if(seq_gt(tcb->snd.ptr,tcb->snd.nxt)) ! 121: tcb->snd.nxt = tcb->snd.ptr; ! 122: ! 123: /* Fill in fields of pseudo IP header */ ! 124: hnputl(ph.tcpdst, s->dst); ! 125: if(s->src == 0) ! 126: s->src = ipgetsrc(ph.tcpdst); ! 127: hnputl(ph.tcpsrc, s->src); ! 128: hnputs(ph.tcpsport, s->psrc); ! 129: hnputs(ph.tcpdport, s->pdst); ! 130: ! 131: /* Build header, link data and compute cksum */ ! 132: if((hbp = htontcp(&seg, dbp, &ph)) == 0) { ! 133: freeb(dbp); ! 134: return; ! 135: } ! 136: ! 137: /* Start the transmission timers if there is new data and we ! 138: * expect acknowledges ! 139: */ ! 140: if(ssize != 0){ ! 141: tcb->timer.start = backoff(tcb->backoff) * ! 142: (2 * tcb->mdev + tcb->srtt + MSPTICK) / MSPTICK; ! 143: if(!run_timer(&tcb->timer)) ! 144: tcpgo(&tcb->timer); ! 145: ! 146: /* If round trip timer isn't running, start it */ ! 147: if(!run_timer(&tcb->rtt_timer)){ ! 148: tcpgo(&tcb->rtt_timer); ! 149: tcb->rttseq = tcb->snd.ptr; ! 150: } ! 151: } ! 152: ipmuxoput(0, hbp); ! 153: } ! 154: } ! 155: ! 156: /* ! 157: * the BSD convention (hack?) for keep alives. resend last byte acked. ! 158: */ ! 159: void ! 160: tcpkeepalive(Ipconv *s) ! 161: { ! 162: Tcp seg; ! 163: Tcphdr ph; ! 164: Tcpctl *tcb; ! 165: Block *hbp,*dbp; ! 166: ! 167: tcb = &s->tcpctl; ! 168: ! 169: dbp = 0; ! 170: seg.up = 0; ! 171: seg.source = s->psrc; ! 172: seg.dest = s->pdst; ! 173: seg.flags = ACK|PSH; ! 174: seg.mss = 0; ! 175: seg.seq = tcb->snd.una-1; ! 176: seg.ack = tcb->rcv.nxt; ! 177: seg.wnd = tcb->rcv.wnd; ! 178: tcb->last_ack = tcb->rcv.nxt; ! 179: if(tcb->state == Finwait2){ ! 180: seg.flags |= FIN; ! 181: } else { ! 182: dbp = allocb(1); ! 183: dbp->wptr++; ! 184: } ! 185: ! 186: /* Fill in fields of pseudo IP header */ ! 187: hnputl(ph.tcpdst, s->dst); ! 188: if(s->src == 0) ! 189: s->src = ipgetsrc(ph.tcpdst); ! 190: hnputl(ph.tcpsrc, s->src); ! 191: hnputs(ph.tcpsport, s->psrc); ! 192: hnputs(ph.tcpdport, s->pdst); ! 193: ! 194: /* Build header, link data and compute cksum */ ! 195: if((hbp = htontcp(&seg, dbp, &ph)) == 0) { ! 196: freeb(dbp); ! 197: return; ! 198: } ! 199: ! 200: ipmuxoput(0, hbp); ! 201: } ! 202: ! 203: void ! 204: tcprxmit(Ipconv *s) ! 205: { ! 206: Tcpctl *tcb; ! 207: ! 208: tcb = &s->tcpctl; ! 209: qlock(tcb); ! 210: tcb->flags |= RETRAN|FORCE; ! 211: tcb->snd.ptr = tcb->snd.una; ! 212: ! 213: /* Pull window down to a single packet and halve the slow ! 214: * start threshold ! 215: */ ! 216: tcb->ssthresh = tcb->cwind / 2; ! 217: tcb->ssthresh = MAX(tcb->ssthresh, tcb->mss); ! 218: ! 219: tcb->cwind = tcb->mss; ! 220: tcpoutput(s); ! 221: qunlock(tcb); ! 222: } ! 223: ! 224: void ! 225: tcptimeout(void *arg) ! 226: { ! 227: Tcpctl *tcb; ! 228: Ipconv *s; ! 229: ! 230: s = (Ipconv *)arg; ! 231: tcb = &s->tcpctl; ! 232: switch(tcb->state){ ! 233: default: ! 234: tcb->backoff++; ! 235: if (tcb->backoff >= MAXBACKOFF && tcb->snd.wnd > 0) { ! 236: qlock(tcb); ! 237: localclose(s, Etimedout); ! 238: qunlock(tcb); ! 239: break; ! 240: } ! 241: tcprxmit(s); ! 242: break; ! 243: ! 244: case Finwait2: ! 245: if(--(tcb->kacounter) == 0){ ! 246: qlock(tcb); ! 247: localclose(s, Etimedout); ! 248: qunlock(tcb); ! 249: } else { ! 250: qlock(tcb); ! 251: tcpkeepalive(s); ! 252: qunlock(tcb); ! 253: tcpgo(&tcb->timer); ! 254: } ! 255: break; ! 256: ! 257: case Time_wait: ! 258: qlock(tcb); ! 259: localclose(s, 0); ! 260: qunlock(tcb); ! 261: break; ! 262: } ! 263: } ! 264: ! 265: int ! 266: backoff(int n) ! 267: { ! 268: if(tcptimertype == 1) ! 269: return n+1; ! 270: ! 271: if(n <= 6) ! 272: return 1 << n; ! 273: ! 274: return 64; ! 275: } ! 276: ! 277: void ! 278: tcpacktimer(Ipconv *s) ! 279: { ! 280: Tcpctl *tcb = &s->tcpctl; ! 281: ! 282: qlock(tcb); ! 283: tcb->flags |= FORCE; ! 284: tcprcvwin(s); ! 285: tcpoutput(s); ! 286: qunlock(tcb); ! 287: } ! 288: ! 289: void ! 290: tcprcvwin(Ipconv *s) /* Call with tcb locked */ ! 291: { ! 292: int w; ! 293: Tcpctl *tcb; ! 294: ! 295: tcb = &s->tcpctl; ! 296: qlock(s); ! 297: if(s->readq) { ! 298: w = Streamhi - s->readq->next->len; ! 299: if(w < 0) ! 300: tcb->rcv.wnd = 0; ! 301: else ! 302: tcb->rcv.wnd = w; ! 303: } ! 304: else ! 305: tcb->rcv.wnd = Streamhi; ! 306: qunlock(s); ! 307: } ! 308: ! 309: /* ! 310: * Network byte order functions ! 311: */ ! 312: ! 313: void ! 314: hnputs(uchar *ptr, ushort val) ! 315: { ! 316: ptr[0] = val>>8; ! 317: ptr[1] = val; ! 318: } ! 319: ! 320: void ! 321: hnputl(uchar *ptr, ulong val) ! 322: { ! 323: ptr[0] = val>>24; ! 324: ptr[1] = val>>16; ! 325: ptr[2] = val>>8; ! 326: ptr[3] = val; ! 327: } ! 328: ! 329: ulong ! 330: nhgetl(uchar *ptr) ! 331: { ! 332: return ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]); ! 333: } ! 334: ! 335: ushort ! 336: nhgets(uchar *ptr) ! 337: { ! 338: return ((ptr[0]<<8) | ptr[1]); ! 339: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.