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