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