1*6149Ssam /* tcp_output.c 4.32 82/03/12 */ 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; 46*6149Ssam int off, flags, win; 475075Swnj register struct mbuf *m; 485075Swnj register struct tcpiphdr *ti; 495441Swnj u_char *opt; 505441Swnj unsigned optlen = 0; 514678Swnj 525075Swnj COUNT(TCP_OUTPUT); 534678Swnj 545075Swnj /* 555088Swnj * Determine length of data that can be transmitted, 565088Swnj * and flags that will be used. 575088Swnj * If there is some data or critical controls (SYN, RST) 585088Swnj * to send, then transmit; otherwise, investigate further. 595075Swnj */ 605075Swnj off = tp->snd_nxt - tp->snd_una; 615163Swnj len = MIN(so->so_snd.sb_cc, tp->snd_wnd+tp->t_force) - off; 625285Sroot if (len < 0) 63*6149Ssam return (0); /* past FIN */ 645088Swnj if (len > tp->t_maxseg) 655088Swnj len = tp->t_maxseg; 665088Swnj flags = tcp_outflags[tp->t_state]; 675299Sroot if (tp->snd_nxt + len < tp->snd_una + so->so_snd.sb_cc) 685163Swnj flags &= ~TH_FIN; 695285Sroot if (len || (flags & (TH_SYN|TH_RST|TH_FIN))) 705075Swnj goto send; 714678Swnj 725075Swnj /* 735285Sroot * Send if we owe peer an ACK. 745075Swnj */ 755441Swnj if (tp->t_flags&TF_ACKNOW) 765075Swnj goto send; 774678Swnj 785441Swnj #ifdef TCPTRUEOOB 795075Swnj /* 805441Swnj * Send if an out of band data or ack should be transmitted. 815441Swnj */ 825441Swnj if (tp->t_oobflags&(TCPOOB_OWEACK|TCPOOB_NEEDACK))) 835441Swnj goto send; 845441Swnj #endif 855441Swnj 865441Swnj /* 875075Swnj * Calculate available window in i, and also amount 885075Swnj * of window known to peer (as advertised window less 895075Swnj * next expected input.) If this is 35% or more of the 905075Swnj * maximum possible window, then want to send a segment to peer. 915075Swnj */ 925088Swnj win = sbspace(&so->so_rcv); 935088Swnj if (win > 0 && 945088Swnj ((100*(win-(tp->rcv_adv-tp->rcv_nxt))/so->so_rcv.sb_hiwat) >= 35)) 955075Swnj goto send; 964678Swnj 975075Swnj /* 985075Swnj * No reason to send a segment, just return. 995075Swnj */ 1005110Swnj return (0); 1014678Swnj 1025075Swnj send: 1035075Swnj /* 1045075Swnj * Grab a header mbuf, attaching a copy of data to 1055075Swnj * be transmitted, and initialize the header from 1065075Swnj * the template for sends on this connection. 1075075Swnj */ 1084677Swnj MGET(m, 0); 1094677Swnj if (m == 0) 1104677Swnj return (0); 1115245Sroot m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 1124885Swnj m->m_len = sizeof (struct tcpiphdr); 1135075Swnj if (len) { 1145075Swnj m->m_next = m_copy(so->so_snd.sb_mb, off, len); 1155075Swnj if (m->m_next == 0) 1165075Swnj len = 0; 1175075Swnj } 1185075Swnj ti = mtod(m, struct tcpiphdr *); 1195075Swnj if (tp->t_template == 0) 1205075Swnj panic("tcp_output"); 1215110Swnj bcopy((caddr_t)tp->t_template, (caddr_t)ti, sizeof (struct tcpiphdr)); 1225075Swnj 1235075Swnj /* 1245075Swnj * Fill in fields, remembering maximum advertised 1255075Swnj * window for use in delaying messages about window sizes. 1265075Swnj */ 1275245Sroot ti->ti_seq = tp->snd_nxt; 1285245Sroot ti->ti_ack = tp->rcv_nxt; 1295245Sroot #if vax 1305245Sroot ti->ti_seq = htonl(ti->ti_seq); 1315245Sroot ti->ti_ack = htonl(ti->ti_ack); 1325245Sroot #endif 1335441Swnj /* 1345441Swnj * Before ESTABLISHED, force sending of initial options 1355441Swnj * unless TCP set to not do any options. 1365441Swnj */ 1375441Swnj if (tp->t_state < TCPS_ESTABLISHED) { 1385441Swnj if (tp->t_flags&TF_NOOPT) 1395441Swnj goto noopt; 1405441Swnj opt = tcp_initopt; 1415441Swnj optlen = sizeof (tcp_initopt); 1425441Swnj *(u_short *)(opt + 2) = so->so_rcv.sb_hiwat / 2; 1435441Swnj #if vax 1445441Swnj *(u_short *)(opt + 2) = htons(*(u_short *)(opt + 2)); 1455441Swnj #endif 1465441Swnj } else { 1475441Swnj if (tp->t_tcpopt == 0) 1485441Swnj goto noopt; 1495441Swnj opt = mtod(tp->t_tcpopt, u_char *); 1505441Swnj optlen = tp->t_tcpopt->m_len; 1515441Swnj } 1525441Swnj #ifndef TCPTRUEOOB 1535441Swnj if (opt) 1545441Swnj #else 1555441Swnj if (opt || (tp->t_oobflags&(TCPOOB_OWEACK|TCPOOB_NEEDACK))) 1565441Swnj #endif 1575441Swnj { 1585110Swnj m0 = m->m_next; 1595584Sroot m->m_next = m_get(M_DONTWAIT); 1605088Swnj if (m->m_next == 0) { 1615088Swnj (void) m_free(m); 1625441Swnj m_freem(m0); 1635088Swnj return (0); 1645088Swnj } 1655088Swnj m->m_next->m_next = m0; 1665441Swnj m0 = m->m_next; 1675441Swnj m0->m_off = MMINOFF; 1685441Swnj m0->m_len = optlen; 1695441Swnj bcopy(opt, mtod(m0, caddr_t), optlen); 1705441Swnj opt = (u_char *)(mtod(m0, caddr_t) + optlen); 1715441Swnj #ifdef TCPTRUEOOB 1725441Swnj if (tp->t_oobflags&TCPOOB_OWEACK) { 1735441Swnj printf("tp %x send OOBACK for %x\n", tp->t_iobseq); 1745441Swnj *opt++ = TCPOPT_OOBACK; 1755441Swnj *opt++ = 3; 1765441Swnj *opt++ = tp->t_iobseq; 1775441Swnj m0->m_len += 3; 1785441Swnj tp->t_oobflags &= ~TCPOOB_OWEACK; 1795441Swnj /* sender should rexmt oob to force ack repeat */ 1805441Swnj } 1815441Swnj if (tp->t_oobflags&TCPOOB_NEEDACK) { 1825441Swnj printf("tp %x send OOBDATA seq %x data %x\n", tp->t_oobseq, tp->t_oobc); 1835441Swnj *opt++ = TCPOPT_OOBDATA; 1845548Swnj *opt++ = 8; 1855441Swnj *opt++ = tp->t_oobseq; 1865441Swnj *opt++ = tp->t_oobc; 1875548Swnj *(tcp_seq *)opt = tp->t_oobmark - tp->snd_nxt; 1885548Swnj #ifdef vax 1895548Swnj *(tcp_seq *)opt = htonl((unsigned)*(tcp_seq *)opt); 1905548Swnj #endif 1915548Swnj m0->m_len += 8; 1925441Swnj TCPT_RANGESET(tp->t_timer[TCPT_OOBREXMT], 1935441Swnj tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 1945441Swnj } 1955441Swnj #endif 1965441Swnj while (m0->m_len & 0x3) { 1975441Swnj *opt++ = TCPOPT_EOL; 1985441Swnj m0->m_len++; 1995441Swnj } 2005441Swnj optlen = m0->m_len; 2015441Swnj ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; 2025088Swnj } 2035441Swnj noopt: 2045088Swnj ti->ti_flags = flags; 2055075Swnj win = sbspace(&so->so_rcv); 2065075Swnj if (win > 0) 2075110Swnj ti->ti_win = htons((u_short)win); 2085088Swnj if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { 2095420Swnj ti->ti_urp = tp->snd_up - tp->snd_nxt; 2105420Swnj #if vax 2115420Swnj ti->ti_urp = htons(ti->ti_urp); 2125420Swnj #endif 2135075Swnj ti->ti_flags |= TH_URG; 2145075Swnj } else 2155075Swnj /* 2165075Swnj * If no urgent pointer to send, then we pull 2175075Swnj * the urgent pointer to the left edge of the send window 2185075Swnj * so that it doesn't drift into the send window on sequence 2195075Swnj * number wraparound. 2205075Swnj */ 2215088Swnj tp->snd_up = tp->snd_una; /* drag it along */ 2225088Swnj /* PUSH */ 2235075Swnj 2245075Swnj /* 2255075Swnj * Put TCP length in extended header, and then 2265075Swnj * checksum extended header and data. 2275075Swnj */ 2285441Swnj if (len + optlen) { 2295441Swnj ti->ti_len = sizeof (struct tcphdr) + optlen + len; 2305441Swnj #if vax 2315441Swnj ti->ti_len = htons((u_short)ti->ti_len); 2325441Swnj #endif 2335441Swnj } 2345441Swnj ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + optlen + len); 2355075Swnj 2365075Swnj /* 2375088Swnj * Advance snd_nxt over sequence space of this segment 2385088Swnj */ 2395088Swnj if (flags & (TH_SYN|TH_FIN)) 2405245Sroot tp->snd_nxt++; 2415088Swnj tp->snd_nxt += len; 2425088Swnj 2435088Swnj /* 2445163Swnj * If this transmission closes the window, 2455245Sroot * start persistance timer at 2 round trip times 2465245Sroot * but at least TCPTV_PERSMIN ticks. 2475088Swnj */ 2485276Swnj if (TCPS_HAVERCVDSYN(tp->t_state) && 2495299Sroot SEQ_GEQ(tp->snd_nxt, tp->snd_una+tp->snd_wnd) && 2505245Sroot tp->t_timer[TCPT_PERSIST] == 0) 2515245Sroot TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], 2525245Sroot 2 * tp->t_srtt, TCPTV_PERSMIN, TCPTV_MAX); 2535088Swnj 2545088Swnj /* 2555163Swnj * Time this transmission if not a retransmission and 2565163Swnj * not currently timing anything. 2575163Swnj */ 2585163Swnj if (SEQ_GT(tp->snd_nxt, tp->snd_max) && tp->t_rtt == 0) { 2595163Swnj tp->t_rtt = 1; 2605163Swnj tp->t_rtseq = tp->snd_nxt - len; 2615163Swnj } 2625163Swnj 2635163Swnj /* 2645163Swnj * Set retransmit timer if not currently set. 2655245Sroot * Initial value for retransmit timer to tcp_beta*tp->t_srtt. 2665163Swnj * Initialize shift counter which is used for exponential 2675163Swnj * backoff of retransmit time. 2685163Swnj */ 2695245Sroot if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) { 2705245Sroot TCPT_RANGESET(tp->t_timer[TCPT_REXMT], 2715245Sroot tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 2725299Sroot tp->t_rtt = 0; 2735163Swnj tp->t_rxtshift = 0; 2745163Swnj } 2755163Swnj 2765163Swnj /* 2775268Sroot * Trace. 2785268Sroot */ 2795268Sroot if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 2805268Sroot tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0); 2815268Sroot 2825268Sroot /* 2835075Swnj * Fill in IP length and desired time to live and 2845075Swnj * send to IP level. 2855075Swnj */ 2865441Swnj ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + optlen + len; 2875075Swnj ((struct ip *)ti)->ip_ttl = TCP_TTL; 2885420Swnj if (ip_output(m, tp->t_ipopt) == 0) 2895088Swnj return (0); 2905075Swnj 2915075Swnj /* 2925075Swnj * Data sent (as far as we can tell). 2935075Swnj * If this advertises a larger window than any other segment, 2945245Sroot * then remember the size of the advertised window. 2955088Swnj * Drop send for purpose of ACK requirements. 2965075Swnj */ 2975252Sroot if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) 2985075Swnj tp->rcv_adv = tp->rcv_nxt + win; 2995088Swnj tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); 3005245Sroot if (SEQ_GT(tp->snd_nxt, tp->snd_max)) 3015245Sroot tp->snd_max = tp->snd_nxt; 3025088Swnj return (1); 3034677Swnj } 304