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