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