1*5584Sroot /* tcp_output.c 4.31 82/01/19 */ 24677Swnj 34677Swnj #include "../h/param.h" 44677Swnj #include "../h/systm.h" 54677Swnj #include "../h/mbuf.h" 65163Swnj #include "../h/protosw.h" 74677Swnj #include "../h/socket.h" 84804Swnj #include "../h/socketvar.h" 95088Swnj #include "../net/in.h" 105088Swnj #include "../net/in_pcb.h" 115088Swnj #include "../net/in_systm.h" 124804Swnj #include "../net/ip.h" 134900Swnj #include "../net/ip_var.h" 144804Swnj #include "../net/tcp.h" 155088Swnj #define TCPOUTFLAGS 165088Swnj #include "../net/tcp_fsm.h" 175088Swnj #include "../net/tcp_seq.h" 185088Swnj #include "../net/tcp_timer.h" 194804Swnj #include "../net/tcp_var.h" 205088Swnj #include "../net/tcpip.h" 215268Sroot #include "../net/tcp_debug.h" 225110Swnj #include "../errno.h" 234677Swnj 245245Sroot char *tcpstates[]; /* XXX */ 255441Swnj 264678Swnj /* 275441Swnj * Initial options: indicate max segment length 1/2 of space 285441Swnj * allocated for receive; if TCPTRUEOOB is defined, indicate 295441Swnj * willingness to do true out-of-band. 305441Swnj */ 315441Swnj #ifndef TCPTRUEOOB 325441Swnj u_char tcp_initopt[4] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, }; 335441Swnj #else 345441Swnj u_char tcp_initopt[6] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, TCPOPT_WILLOOB, 2 }; 355441Swnj #endif 365441Swnj 375441Swnj /* 385245Sroot * Tcp output routine: figure out what should be sent and send it. 394678Swnj */ 405075Swnj tcp_output(tp) 415075Swnj register struct tcpcb *tp; 424678Swnj { 435075Swnj register struct socket *so = tp->t_inpcb->inp_socket; 445075Swnj register int len; 455075Swnj struct mbuf *m0; 465075Swnj int off, flags; 475075Swnj register struct mbuf *m; 485075Swnj register struct tcpiphdr *ti; 495441Swnj int win, force; 505441Swnj u_char *opt; 515441Swnj unsigned optlen = 0; 524678Swnj 535075Swnj COUNT(TCP_OUTPUT); 544678Swnj 555075Swnj /* 565088Swnj * Determine length of data that can be transmitted, 575088Swnj * and flags that will be used. 585088Swnj * If there is some data or critical controls (SYN, RST) 595088Swnj * to send, then transmit; otherwise, investigate further. 605075Swnj */ 615075Swnj off = tp->snd_nxt - tp->snd_una; 625163Swnj len = MIN(so->so_snd.sb_cc, tp->snd_wnd+tp->t_force) - off; 635285Sroot if (len < 0) 645285Sroot return; /* past FIN */ 655088Swnj if (len > tp->t_maxseg) 665088Swnj len = tp->t_maxseg; 675088Swnj flags = tcp_outflags[tp->t_state]; 685299Sroot if (tp->snd_nxt + len < tp->snd_una + so->so_snd.sb_cc) 695163Swnj flags &= ~TH_FIN; 705285Sroot if (len || (flags & (TH_SYN|TH_RST|TH_FIN))) 715075Swnj goto send; 724678Swnj 735075Swnj /* 745285Sroot * Send if we owe peer an ACK. 755075Swnj */ 765441Swnj if (tp->t_flags&TF_ACKNOW) 775075Swnj goto send; 784678Swnj 795441Swnj #ifdef TCPTRUEOOB 805075Swnj /* 815441Swnj * Send if an out of band data or ack should be transmitted. 825441Swnj */ 835441Swnj if (tp->t_oobflags&(TCPOOB_OWEACK|TCPOOB_NEEDACK))) 845441Swnj goto send; 855441Swnj #endif 865441Swnj 875441Swnj /* 885075Swnj * Calculate available window in i, and also amount 895075Swnj * of window known to peer (as advertised window less 905075Swnj * next expected input.) If this is 35% or more of the 915075Swnj * maximum possible window, then want to send a segment to peer. 925075Swnj */ 935088Swnj win = sbspace(&so->so_rcv); 945088Swnj if (win > 0 && 955088Swnj ((100*(win-(tp->rcv_adv-tp->rcv_nxt))/so->so_rcv.sb_hiwat) >= 35)) 965075Swnj goto send; 974678Swnj 985075Swnj /* 995075Swnj * No reason to send a segment, just return. 1005075Swnj */ 1015110Swnj return (0); 1024678Swnj 1035075Swnj send: 1045075Swnj /* 1055075Swnj * Grab a header mbuf, attaching a copy of data to 1065075Swnj * be transmitted, and initialize the header from 1075075Swnj * the template for sends on this connection. 1085075Swnj */ 1094677Swnj MGET(m, 0); 1104677Swnj if (m == 0) 1114677Swnj return (0); 1125245Sroot m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 1134885Swnj m->m_len = sizeof (struct tcpiphdr); 1145075Swnj if (len) { 1155075Swnj m->m_next = m_copy(so->so_snd.sb_mb, off, len); 1165075Swnj if (m->m_next == 0) 1175075Swnj len = 0; 1185075Swnj } 1195075Swnj ti = mtod(m, struct tcpiphdr *); 1205075Swnj if (tp->t_template == 0) 1215075Swnj panic("tcp_output"); 1225110Swnj bcopy((caddr_t)tp->t_template, (caddr_t)ti, sizeof (struct tcpiphdr)); 1235075Swnj 1245075Swnj /* 1255075Swnj * Fill in fields, remembering maximum advertised 1265075Swnj * window for use in delaying messages about window sizes. 1275075Swnj */ 1285245Sroot ti->ti_seq = tp->snd_nxt; 1295245Sroot ti->ti_ack = tp->rcv_nxt; 1305245Sroot #if vax 1315245Sroot ti->ti_seq = htonl(ti->ti_seq); 1325245Sroot ti->ti_ack = htonl(ti->ti_ack); 1335245Sroot #endif 1345441Swnj /* 1355441Swnj * Before ESTABLISHED, force sending of initial options 1365441Swnj * unless TCP set to not do any options. 1375441Swnj */ 1385441Swnj if (tp->t_state < TCPS_ESTABLISHED) { 1395441Swnj if (tp->t_flags&TF_NOOPT) 1405441Swnj goto noopt; 1415441Swnj opt = tcp_initopt; 1425441Swnj optlen = sizeof (tcp_initopt); 1435441Swnj *(u_short *)(opt + 2) = so->so_rcv.sb_hiwat / 2; 1445441Swnj #if vax 1455441Swnj *(u_short *)(opt + 2) = htons(*(u_short *)(opt + 2)); 1465441Swnj #endif 1475441Swnj } else { 1485441Swnj if (tp->t_tcpopt == 0) 1495441Swnj goto noopt; 1505441Swnj opt = mtod(tp->t_tcpopt, u_char *); 1515441Swnj optlen = tp->t_tcpopt->m_len; 1525441Swnj } 1535441Swnj #ifndef TCPTRUEOOB 1545441Swnj if (opt) 1555441Swnj #else 1565441Swnj if (opt || (tp->t_oobflags&(TCPOOB_OWEACK|TCPOOB_NEEDACK))) 1575441Swnj #endif 1585441Swnj { 1595110Swnj m0 = m->m_next; 160*5584Sroot m->m_next = m_get(M_DONTWAIT); 1615088Swnj if (m->m_next == 0) { 1625088Swnj (void) m_free(m); 1635441Swnj m_freem(m0); 1645088Swnj return (0); 1655088Swnj } 1665088Swnj m->m_next->m_next = m0; 1675441Swnj m0 = m->m_next; 1685441Swnj m0->m_off = MMINOFF; 1695441Swnj m0->m_len = optlen; 1705441Swnj bcopy(opt, mtod(m0, caddr_t), optlen); 1715441Swnj opt = (u_char *)(mtod(m0, caddr_t) + optlen); 1725441Swnj #ifdef TCPTRUEOOB 1735441Swnj if (tp->t_oobflags&TCPOOB_OWEACK) { 1745441Swnj printf("tp %x send OOBACK for %x\n", tp->t_iobseq); 1755441Swnj *opt++ = TCPOPT_OOBACK; 1765441Swnj *opt++ = 3; 1775441Swnj *opt++ = tp->t_iobseq; 1785441Swnj m0->m_len += 3; 1795441Swnj tp->t_oobflags &= ~TCPOOB_OWEACK; 1805441Swnj /* sender should rexmt oob to force ack repeat */ 1815441Swnj } 1825441Swnj if (tp->t_oobflags&TCPOOB_NEEDACK) { 1835441Swnj printf("tp %x send OOBDATA seq %x data %x\n", tp->t_oobseq, tp->t_oobc); 1845441Swnj *opt++ = TCPOPT_OOBDATA; 1855548Swnj *opt++ = 8; 1865441Swnj *opt++ = tp->t_oobseq; 1875441Swnj *opt++ = tp->t_oobc; 1885548Swnj *(tcp_seq *)opt = tp->t_oobmark - tp->snd_nxt; 1895548Swnj #ifdef vax 1905548Swnj *(tcp_seq *)opt = htonl((unsigned)*(tcp_seq *)opt); 1915548Swnj #endif 1925548Swnj m0->m_len += 8; 1935441Swnj TCPT_RANGESET(tp->t_timer[TCPT_OOBREXMT], 1945441Swnj tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 1955441Swnj } 1965441Swnj #endif 1975441Swnj while (m0->m_len & 0x3) { 1985441Swnj *opt++ = TCPOPT_EOL; 1995441Swnj m0->m_len++; 2005441Swnj } 2015441Swnj optlen = m0->m_len; 2025441Swnj ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; 2035088Swnj } 2045441Swnj noopt: 2055088Swnj ti->ti_flags = flags; 2065075Swnj win = sbspace(&so->so_rcv); 2075075Swnj if (win > 0) 2085110Swnj ti->ti_win = htons((u_short)win); 2095088Swnj if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { 2105420Swnj ti->ti_urp = tp->snd_up - tp->snd_nxt; 2115420Swnj #if vax 2125420Swnj ti->ti_urp = htons(ti->ti_urp); 2135420Swnj #endif 2145075Swnj ti->ti_flags |= TH_URG; 2155075Swnj } else 2165075Swnj /* 2175075Swnj * If no urgent pointer to send, then we pull 2185075Swnj * the urgent pointer to the left edge of the send window 2195075Swnj * so that it doesn't drift into the send window on sequence 2205075Swnj * number wraparound. 2215075Swnj */ 2225088Swnj tp->snd_up = tp->snd_una; /* drag it along */ 2235088Swnj /* PUSH */ 2245075Swnj 2255075Swnj /* 2265075Swnj * Put TCP length in extended header, and then 2275075Swnj * checksum extended header and data. 2285075Swnj */ 2295441Swnj if (len + optlen) { 2305441Swnj ti->ti_len = sizeof (struct tcphdr) + optlen + len; 2315441Swnj #if vax 2325441Swnj ti->ti_len = htons((u_short)ti->ti_len); 2335441Swnj #endif 2345441Swnj } 2355441Swnj ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + optlen + len); 2365075Swnj 2375075Swnj /* 2385088Swnj * Advance snd_nxt over sequence space of this segment 2395088Swnj */ 2405088Swnj if (flags & (TH_SYN|TH_FIN)) 2415245Sroot tp->snd_nxt++; 2425088Swnj tp->snd_nxt += len; 2435088Swnj 2445088Swnj /* 2455163Swnj * If this transmission closes the window, 2465245Sroot * start persistance timer at 2 round trip times 2475245Sroot * but at least TCPTV_PERSMIN ticks. 2485088Swnj */ 2495276Swnj if (TCPS_HAVERCVDSYN(tp->t_state) && 2505299Sroot SEQ_GEQ(tp->snd_nxt, tp->snd_una+tp->snd_wnd) && 2515245Sroot tp->t_timer[TCPT_PERSIST] == 0) 2525245Sroot TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], 2535245Sroot 2 * tp->t_srtt, TCPTV_PERSMIN, TCPTV_MAX); 2545088Swnj 2555088Swnj /* 2565163Swnj * Time this transmission if not a retransmission and 2575163Swnj * not currently timing anything. 2585163Swnj */ 2595163Swnj if (SEQ_GT(tp->snd_nxt, tp->snd_max) && tp->t_rtt == 0) { 2605163Swnj tp->t_rtt = 1; 2615163Swnj tp->t_rtseq = tp->snd_nxt - len; 2625163Swnj } 2635163Swnj 2645163Swnj /* 2655163Swnj * Set retransmit timer if not currently set. 2665245Sroot * Initial value for retransmit timer to tcp_beta*tp->t_srtt. 2675163Swnj * Initialize shift counter which is used for exponential 2685163Swnj * backoff of retransmit time. 2695163Swnj */ 2705245Sroot if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) { 2715245Sroot TCPT_RANGESET(tp->t_timer[TCPT_REXMT], 2725245Sroot tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 2735299Sroot tp->t_rtt = 0; 2745163Swnj tp->t_rxtshift = 0; 2755163Swnj } 2765163Swnj 2775163Swnj /* 2785268Sroot * Trace. 2795268Sroot */ 2805268Sroot if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 2815268Sroot tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0); 2825268Sroot 2835268Sroot /* 2845075Swnj * Fill in IP length and desired time to live and 2855075Swnj * send to IP level. 2865075Swnj */ 2875441Swnj ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + optlen + len; 2885075Swnj ((struct ip *)ti)->ip_ttl = TCP_TTL; 2895420Swnj if (ip_output(m, tp->t_ipopt) == 0) 2905088Swnj return (0); 2915075Swnj 2925075Swnj /* 2935075Swnj * Data sent (as far as we can tell). 2945075Swnj * If this advertises a larger window than any other segment, 2955245Sroot * then remember the size of the advertised window. 2965088Swnj * Drop send for purpose of ACK requirements. 2975075Swnj */ 2985252Sroot if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) 2995075Swnj tp->rcv_adv = tp->rcv_nxt + win; 3005088Swnj tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); 3015245Sroot if (SEQ_GT(tp->snd_nxt, tp->snd_max)) 3025245Sroot tp->snd_max = tp->snd_nxt; 3035088Swnj return (1); 3044677Swnj } 305