|
|
1.1 root 1: /* tcp_output.c 6.1 83/07/29 */
2:
3: #include "sys/param.h"
4: #include "sys/stream.h"
5: #include "sys/inet/in.h"
6: #include "sys/inet/ip.h"
7: #include "sys/inet/ip_var.h"
8: #include "sys/inet/tcp.h"
9: #define TCPOUTFLAGS
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 tcp_busy; /* set/unset by tcp_output callers, to keep out timer */
17:
18: /*
19: * Initial options.
20: */
21: u_char tcp_initopt[4] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, };
22: extern tcpprintfs;
23:
24: /*
25: * Settable maximum tcp segment size.
26: */
27: extern int tcp_maxseg;
28:
29: /*
30: * Tcp output routine: figure out what should be sent and send it.
31: */
32: tcp_output(tp)
33: register struct tcpcb *tp;
34: {
35: register int len;
36: struct block *bp0;
37: int off, flags, win, error;
38: register struct block *bp;
39: register struct tcpiphdr *ti;
40: u_char *opt;
41: unsigned optlen = 0;
42: int sendalot;
43:
44: /*
45: * don't output if the template has been removed
46: */
47: if (tp->t_template == 0)
48: return (0);
49:
50: if(tcp_busy != 1)
51: panic("tcp_busy");
52:
53: /*
54: * Determine length of data that should be transmitted,
55: * and flags that will be used.
56: * If there is some data or critical controls (SYN, RST)
57: * to send, then transmit; otherwise, investigate further.
58: */
59: again:
60: sendalot = 0;
61: off = tp->snd_nxt - tp->snd_una;
62: len = MIN(sosndcc(tp), tp->snd_wnd+tp->t_force) - off;
63: if (len < 0)
64: return (0); /* ??? */ /* past FIN */
65: if (len > tp->t_maxseg) {
66: len = tp->t_maxseg;
67: sendalot = 1;
68: }
69:
70: flags = tcp_outflags[tp->t_state];
71: if (tp->snd_nxt + len < tp->snd_una + sosndcc(tp))
72: flags &= ~TH_FIN;
73: if (flags & (TH_SYN|TH_RST|TH_FIN))
74: goto send;
75: if (SEQ_GT(tp->snd_up, tp->snd_una))
76: goto send;
77:
78: /*
79: * Sender silly window avoidance. If can send all data,
80: * a maximum segment, at least 1/4 of window do it,
81: * or are forced, do it; otherwise don't bother.
82: */
83: if (len) {
84: if (len == tp->t_maxseg || off+len >= sosndcc(tp))
85: goto send;
86: if (len * 4 >= tp->snd_wnd) /* a lot */
87: goto send;
88: if (tp->t_force)
89: goto send;
90: }
91:
92: /*
93: * Send if we owe peer an ACK.
94: */
95: if (tp->t_flags&TF_ACKNOW)
96: goto send;
97:
98:
99: /*
100: * Calculate available window in i, and also amount
101: * of window known to peer (as advertised window less
102: * next expected input.) If this is 35% or more of the
103: * maximum possible window, then want to send a segment to peer.
104: */
105: win = sbrcvspace(tp);
106: if (win > 0 &&
107: ((100*(win-(tp->rcv_adv-tp->rcv_nxt))/sorcvhiwat(tp)) >= 35))
108: goto send;
109:
110: /*
111: * TCP window updates are not reliable, rather a polling protocol
112: * using ``persist'' packets is used to insure receipt of window
113: * updates. The three ``states'' for the output side are:
114: * idle not doing retransmits or persists
115: * persisting to move a zero window
116: * (re)transmitting and thereby not persisting
117: *
118: * tp->t_timer[TCPT_PERSIST]
119: * is set when we are in persist state.
120: * tp->t_force
121: * is set when we are called to send a persist packet.
122: * tp->t_timer[TCPT_REXMT]
123: * is set when we are retransmitting
124: * The output side is idle when both timers are zero.
125: *
126: * If send window is closed, there is data to transmit, and no
127: * retransmit or persist is pending, then go to persist state,
128: * arranging to force out a byte to get more current window information
129: * if nothing happens soon.
130: */
131: if (tp->snd_wnd == 0 && sosndcc(tp) &&
132: tp->t_timer[TCPT_REXMT] == 0 && tp->t_timer[TCPT_PERSIST] == 0) {
133: tp->t_rxtshift = 0;
134: tcp_setpersist(tp);
135: }
136:
137: /*
138: * No reason to send a segment, just return.
139: */
140: return (0);
141:
142: send:
143: /*
144: * Grab a header block, attaching a copy of data to
145: * be transmitted, and initialize the header from
146: * the template for sends on this connection.
147: */
148: bp = bp_get();
149: if (bp == NULL)
150: return (1);
151: bp->next = 0;
152: bp->wptr += sizeof (struct tcpiphdr);
153: if (len) {
154: bp->next = bp_copy(tp->so_wq->first, off, len);
155: if (bp->next == 0)
156: len = 0;
157: }
158: ti = (struct tcpiphdr *)bp->rptr;
159: if (tp->t_template == 0)
160: panic("tcp_output");
161: bcopy((caddr_t)tp->t_template->rptr,(caddr_t)ti, sizeof (struct tcpiphdr));
162:
163: /*
164: * Fill in fields, remembering maximum advertised
165: * window for use in delaying messages about window sizes.
166: */
167: ti->ti_seq = tp->snd_nxt;
168: ti->ti_ack = tp->rcv_nxt;
169: ti->ti_seq = htonl(ti->ti_seq);
170: ti->ti_ack = htonl(ti->ti_ack);
171: /*
172: * Before ESTABLISHED, force sending of initial options
173: * unless TCP set to not do any options.
174: */
175: if (tp->t_state < TCPS_ESTABLISHED) {
176: short maxseg;
177:
178: if (tp->t_flags&TF_NOOPT)
179: goto noopt;
180: if (in_netof(ti->ti_src) != in_netof(ti->ti_dst))
181: goto noopt;
182: opt = tcp_initopt;
183: optlen = sizeof (tcp_initopt);
184: maxseg = tcp_maxseg;
185: *(u_short *)(opt + 2) = htons(maxseg);
186: } else {
187: if (tp->t_tcpopt == 0)
188: goto noopt;
189: opt = (u_char *)tp->t_tcpopt->rptr;
190: optlen = BLEN(tp->t_tcpopt);
191: }
192: if (opt) {
193: bp0 = bp->next;
194: bp->next = bp_get();
195: if (bp->next == 0) {
196: freeb(bp);
197: bp_free(bp0);
198: return (1);
199: }
200: bp->next->next = bp0;
201: bp0 = bp->next;
202: bp0->wptr += optlen;
203: bcopy((caddr_t)opt, (caddr_t)bp0->rptr, optlen);
204: opt = (u_char *)((caddr_t)bp0->rptr + optlen);
205: while (BLEN(bp0) & 0x3) {
206: bp0->wptr++;
207: *opt++ = TCPOPT_EOL;
208: }
209: optlen = BLEN(bp0);
210: ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;
211: }
212: noopt:
213: ti->ti_flags = flags;
214: win = sbrcvspace(tp);
215: if (win < sorcvhiwat(tp) / 4) {
216: /*
217: * avoid wastefully small packets caused by small windows
218: */
219: win = 0;
220: }
221: if ((tp->so_state & SS_OPEN)==0 && tp->t_state > TCPS_CLOSE_WAIT) {
222: /*
223: * if the local process has disappeared, then open up
224: * the window to get the remote process to send something
225: * rather than hang waiting to send
226: */
227: win = 1;
228: }
229: if (win > 0)
230: ti->ti_win = htons((u_short)win);
231: if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
232: ti->ti_urp = tp->snd_up - tp->snd_nxt;
233: ti->ti_urp = htons(ti->ti_urp);
234: ti->ti_flags |= TH_URG;
235: } else
236: /*
237: * If no urgent pointer to send, then we pull
238: * the urgent pointer to the left edge of the send window
239: * so that it doesn't drift into the send window on sequence
240: * number wraparound.
241: */
242: tp->snd_up = tp->snd_una; /* drag it along */
243: /*
244: * If anything to send and we can send it all, set PUSH.
245: * (This will keep happy those implementations which only
246: * give data to the user when a buffer fills or a PUSH comes in.)
247: */
248: if (len && off+len == sosndcc(tp))
249: ti->ti_flags |= TH_PUSH;
250:
251: /*
252: * Put TCP length in extended header, and then
253: * checksum extended header and data.
254: */
255: if (len + optlen) {
256: ti->ti_len = sizeof (struct tcphdr) + optlen + len;
257: ti->ti_len = htons((u_short)ti->ti_len);
258: }
259: ti->ti_src = htonl(ti->ti_src);
260: ti->ti_dst = htonl(ti->ti_dst);
261: ti->ti_sport = htons(ti->ti_sport);
262: ti->ti_dport = htons(ti->ti_dport);
263: ti->ti_sum = in_cksum(bp, sizeof (struct tcpiphdr) + (int)optlen + len);
264: tcp_debug(ti, 1);
265: ti->ti_src = ntohl(ti->ti_src);
266: ti->ti_dst = ntohl(ti->ti_dst);
267:
268: /*
269: * In transmit state, time the transmission and arrange for
270: * the retransmit. In persist state, reset persist time for
271: * next persist.
272: */
273: if (tp->t_force == 0) {
274: /*
275: * Advance snd_nxt over sequence space of this segment.
276: */
277: if (flags & (TH_SYN|TH_FIN))
278: tp->snd_nxt++;
279: tp->snd_nxt += len;
280: if (SEQ_GT(tp->snd_nxt, tp->snd_max))
281: tp->snd_max = tp->snd_nxt;
282:
283: /*
284: * Time this transmission if not a retransmission and
285: * not currently timing anything.
286: */
287: if (SEQ_GT(tp->snd_nxt, tp->snd_max) && tp->t_rtt == 0) {
288: tp->t_rtt = 1;
289: tp->t_rtseq = tp->snd_nxt - len;
290: }
291:
292: /*
293: * Set retransmit timer if not currently set.
294: * Initial value for retransmit timer to tcp_beta*tp->t_srtt.
295: * Initialize shift counter which is used for exponential
296: * backoff of retransmit time.
297: */
298: if (tp->t_timer[TCPT_REXMT] == 0 &&
299: tp->snd_nxt != tp->snd_una) {
300: TCPT_RANGESET(tp->t_timer[TCPT_REXMT],
301: tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX);
302: tp->t_rtt = 0;
303: tp->t_rxtshift = 0;
304: }
305: tp->t_timer[TCPT_PERSIST] = 0;
306: } else {
307: if (SEQ_GT(tp->snd_una+1, tp->snd_max))
308: tp->snd_max = tp->snd_una+1;
309: }
310:
311: /*
312: * Fill in IP length and desired time to live and
313: * send to IP level.
314: */
315: ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + optlen + len;
316: ((struct ip *)ti)->ip_ttl = TCP_TTL;
317: error = tcp_ldout(bp);
318: if (error)
319: return (error);
320:
321:
322: /*
323: * Data sent (as far as we can tell).
324: * If this advertises a larger window than any other segment,
325: * then remember the size of the advertised window.
326: * Drop send for purpose of ACK requirements.
327: */
328: if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
329: tp->rcv_adv = tp->rcv_nxt + win;
330: tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
331: if (sendalot && tp->t_force == 0)
332: goto again;
333: return (0);
334: }
335:
336: tcp_setpersist(tp)
337: register struct tcpcb *tp;
338: {
339:
340: if (tp->t_timer[TCPT_REXMT])
341: panic("tcp_output REXMT");
342: /*
343: * Start/restart persistance timer.
344: */
345: TCPT_RANGESET(tp->t_timer[TCPT_PERSIST],
346: ((int)(tcp_beta * tp->t_srtt)) << tp->t_rxtshift,
347: TCPTV_PERSMIN, TCPTV_MAX);
348: tp->t_rxtshift++;
349: if (tp->t_rxtshift >= TCP_MAXRXTSHIFT)
350: tp->t_rxtshift = 0;
351: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.