1*6279Swnj /* tcp_output.c 4.35 82/03/20 */ 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; 466149Ssam 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 /* 55*6279Swnj * Determine length of data that should 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) 636149Ssam return (0); /* past FIN */ 645088Swnj if (len > tp->t_maxseg) 655088Swnj len = tp->t_maxseg; 66*6279Swnj 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; 70*6279Swnj if (flags & (TH_SYN|TH_RST|TH_FIN)) 715075Swnj goto send; 72*6279Swnj if (SEQ_GT(tp->snd_up, tp->snd_una)) 73*6279Swnj goto send; 744678Swnj 755075Swnj /* 76*6279Swnj * Sender silly window avoidance. If can send all data, 77*6279Swnj * a maximum segment, at least 1/4 of window do it, 78*6279Swnj * or are forced, do it; otherwise don't bother. 79*6279Swnj */ 80*6279Swnj if (len) { 81*6279Swnj if (len == tp->t_maxseg || off+len >= so->so_snd.sb_cc) 82*6279Swnj goto send; 83*6279Swnj if (len * 4 >= tp->snd_wnd) /* a lot */ 84*6279Swnj goto send; 85*6279Swnj if (tp->t_force) 86*6279Swnj goto send; 87*6279Swnj } 88*6279Swnj 89*6279Swnj /* 905285Sroot * Send if we owe peer an ACK. 915075Swnj */ 925441Swnj if (tp->t_flags&TF_ACKNOW) 935075Swnj goto send; 944678Swnj 955441Swnj #ifdef TCPTRUEOOB 965075Swnj /* 975441Swnj * Send if an out of band data or ack should be transmitted. 985441Swnj */ 995441Swnj if (tp->t_oobflags&(TCPOOB_OWEACK|TCPOOB_NEEDACK))) 1005441Swnj goto send; 1015441Swnj #endif 1025441Swnj 1035441Swnj /* 1045075Swnj * Calculate available window in i, and also amount 1055075Swnj * of window known to peer (as advertised window less 1065075Swnj * next expected input.) If this is 35% or more of the 1075075Swnj * maximum possible window, then want to send a segment to peer. 1085075Swnj */ 1095088Swnj win = sbspace(&so->so_rcv); 1105088Swnj if (win > 0 && 1115088Swnj ((100*(win-(tp->rcv_adv-tp->rcv_nxt))/so->so_rcv.sb_hiwat) >= 35)) 1125075Swnj goto send; 1134678Swnj 1145075Swnj /* 1155075Swnj * No reason to send a segment, just return. 1165075Swnj */ 1175110Swnj return (0); 1184678Swnj 1195075Swnj send: 1205075Swnj /* 1215075Swnj * Grab a header mbuf, attaching a copy of data to 1225075Swnj * be transmitted, and initialize the header from 1235075Swnj * the template for sends on this connection. 1245075Swnj */ 1254677Swnj MGET(m, 0); 1264677Swnj if (m == 0) 1274677Swnj return (0); 1285245Sroot m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 1294885Swnj m->m_len = sizeof (struct tcpiphdr); 1305075Swnj if (len) { 1315075Swnj m->m_next = m_copy(so->so_snd.sb_mb, off, len); 1325075Swnj if (m->m_next == 0) 1335075Swnj len = 0; 1345075Swnj } 1355075Swnj ti = mtod(m, struct tcpiphdr *); 1365075Swnj if (tp->t_template == 0) 1375075Swnj panic("tcp_output"); 1385110Swnj bcopy((caddr_t)tp->t_template, (caddr_t)ti, sizeof (struct tcpiphdr)); 1395075Swnj 1405075Swnj /* 1415075Swnj * Fill in fields, remembering maximum advertised 1425075Swnj * window for use in delaying messages about window sizes. 1435075Swnj */ 1445245Sroot ti->ti_seq = tp->snd_nxt; 1455245Sroot ti->ti_ack = tp->rcv_nxt; 1465245Sroot #if vax 1475245Sroot ti->ti_seq = htonl(ti->ti_seq); 1485245Sroot ti->ti_ack = htonl(ti->ti_ack); 1495245Sroot #endif 1505441Swnj /* 1515441Swnj * Before ESTABLISHED, force sending of initial options 1525441Swnj * unless TCP set to not do any options. 1535441Swnj */ 1545441Swnj if (tp->t_state < TCPS_ESTABLISHED) { 1555441Swnj if (tp->t_flags&TF_NOOPT) 1565441Swnj goto noopt; 1575441Swnj opt = tcp_initopt; 1585441Swnj optlen = sizeof (tcp_initopt); 1595441Swnj *(u_short *)(opt + 2) = so->so_rcv.sb_hiwat / 2; 1605441Swnj #if vax 1615441Swnj *(u_short *)(opt + 2) = htons(*(u_short *)(opt + 2)); 1625441Swnj #endif 1635441Swnj } else { 1645441Swnj if (tp->t_tcpopt == 0) 1655441Swnj goto noopt; 1665441Swnj opt = mtod(tp->t_tcpopt, u_char *); 1675441Swnj optlen = tp->t_tcpopt->m_len; 1685441Swnj } 1695441Swnj #ifndef TCPTRUEOOB 1705441Swnj if (opt) 1715441Swnj #else 1725441Swnj if (opt || (tp->t_oobflags&(TCPOOB_OWEACK|TCPOOB_NEEDACK))) 1735441Swnj #endif 1745441Swnj { 1755110Swnj m0 = m->m_next; 1765584Sroot m->m_next = m_get(M_DONTWAIT); 1775088Swnj if (m->m_next == 0) { 1785088Swnj (void) m_free(m); 1795441Swnj m_freem(m0); 1805088Swnj return (0); 1815088Swnj } 1825088Swnj m->m_next->m_next = m0; 1835441Swnj m0 = m->m_next; 1845441Swnj m0->m_off = MMINOFF; 1855441Swnj m0->m_len = optlen; 1866162Ssam bcopy((caddr_t)opt, mtod(m0, caddr_t), optlen); 1875441Swnj opt = (u_char *)(mtod(m0, caddr_t) + optlen); 1885441Swnj #ifdef TCPTRUEOOB 1895441Swnj if (tp->t_oobflags&TCPOOB_OWEACK) { 1905441Swnj printf("tp %x send OOBACK for %x\n", tp->t_iobseq); 1915441Swnj *opt++ = TCPOPT_OOBACK; 1925441Swnj *opt++ = 3; 1935441Swnj *opt++ = tp->t_iobseq; 1945441Swnj m0->m_len += 3; 1955441Swnj tp->t_oobflags &= ~TCPOOB_OWEACK; 1965441Swnj /* sender should rexmt oob to force ack repeat */ 1975441Swnj } 1985441Swnj if (tp->t_oobflags&TCPOOB_NEEDACK) { 1995441Swnj printf("tp %x send OOBDATA seq %x data %x\n", tp->t_oobseq, tp->t_oobc); 2005441Swnj *opt++ = TCPOPT_OOBDATA; 2015548Swnj *opt++ = 8; 2025441Swnj *opt++ = tp->t_oobseq; 2035441Swnj *opt++ = tp->t_oobc; 2045548Swnj *(tcp_seq *)opt = tp->t_oobmark - tp->snd_nxt; 2055548Swnj #ifdef vax 2065548Swnj *(tcp_seq *)opt = htonl((unsigned)*(tcp_seq *)opt); 2075548Swnj #endif 2085548Swnj m0->m_len += 8; 2095441Swnj TCPT_RANGESET(tp->t_timer[TCPT_OOBREXMT], 2105441Swnj tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 2115441Swnj } 2125441Swnj #endif 2135441Swnj while (m0->m_len & 0x3) { 2145441Swnj *opt++ = TCPOPT_EOL; 2155441Swnj m0->m_len++; 2165441Swnj } 2175441Swnj optlen = m0->m_len; 2185441Swnj ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; 2195088Swnj } 2205441Swnj noopt: 2215088Swnj ti->ti_flags = flags; 2225075Swnj win = sbspace(&so->so_rcv); 223*6279Swnj if (win < so->so_rcv.sb_hiwat / 4) /* avoid silly window */ 224*6279Swnj win = 0; 2255075Swnj if (win > 0) 226*6279Swnj #if vax 2275110Swnj ti->ti_win = htons((u_short)win); 228*6279Swnj #else 229*6279Swnj ti->ti_win = win; 230*6279Swnj #endif 2315088Swnj if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { 2325420Swnj ti->ti_urp = tp->snd_up - tp->snd_nxt; 2335420Swnj #if vax 2345420Swnj ti->ti_urp = htons(ti->ti_urp); 2355420Swnj #endif 2365075Swnj ti->ti_flags |= TH_URG; 2375075Swnj } else 2385075Swnj /* 2395075Swnj * If no urgent pointer to send, then we pull 2405075Swnj * the urgent pointer to the left edge of the send window 2415075Swnj * so that it doesn't drift into the send window on sequence 2425075Swnj * number wraparound. 2435075Swnj */ 2445088Swnj tp->snd_up = tp->snd_una; /* drag it along */ 2455088Swnj /* PUSH */ 2465075Swnj 2475075Swnj /* 2485075Swnj * Put TCP length in extended header, and then 2495075Swnj * checksum extended header and data. 2505075Swnj */ 2515441Swnj if (len + optlen) { 2525441Swnj ti->ti_len = sizeof (struct tcphdr) + optlen + len; 2535441Swnj #if vax 2545441Swnj ti->ti_len = htons((u_short)ti->ti_len); 2555441Swnj #endif 2565441Swnj } 2576162Ssam ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + (int)optlen + len); 2585075Swnj 2595075Swnj /* 2605088Swnj * Advance snd_nxt over sequence space of this segment 2615088Swnj */ 2625088Swnj if (flags & (TH_SYN|TH_FIN)) 2635245Sroot tp->snd_nxt++; 2645088Swnj tp->snd_nxt += len; 2655088Swnj 2665088Swnj /* 2675163Swnj * If this transmission closes the window, 2685245Sroot * start persistance timer at 2 round trip times 2695245Sroot * but at least TCPTV_PERSMIN ticks. 2705088Swnj */ 2715276Swnj if (TCPS_HAVERCVDSYN(tp->t_state) && 2725299Sroot SEQ_GEQ(tp->snd_nxt, tp->snd_una+tp->snd_wnd) && 2735245Sroot tp->t_timer[TCPT_PERSIST] == 0) 2745245Sroot TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], 2755245Sroot 2 * tp->t_srtt, TCPTV_PERSMIN, TCPTV_MAX); 2765088Swnj 2775088Swnj /* 2785163Swnj * Time this transmission if not a retransmission and 2795163Swnj * not currently timing anything. 2805163Swnj */ 2815163Swnj if (SEQ_GT(tp->snd_nxt, tp->snd_max) && tp->t_rtt == 0) { 2825163Swnj tp->t_rtt = 1; 2835163Swnj tp->t_rtseq = tp->snd_nxt - len; 2845163Swnj } 2855163Swnj 2865163Swnj /* 2875163Swnj * Set retransmit timer if not currently set. 2885245Sroot * Initial value for retransmit timer to tcp_beta*tp->t_srtt. 2895163Swnj * Initialize shift counter which is used for exponential 2905163Swnj * backoff of retransmit time. 2915163Swnj */ 2925245Sroot if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) { 2935245Sroot TCPT_RANGESET(tp->t_timer[TCPT_REXMT], 2945245Sroot tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 2955299Sroot tp->t_rtt = 0; 2965163Swnj tp->t_rxtshift = 0; 2975163Swnj } 2985163Swnj 2995163Swnj /* 3005268Sroot * Trace. 3015268Sroot */ 3025268Sroot if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 3035268Sroot tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0); 3045268Sroot 3055268Sroot /* 3065075Swnj * Fill in IP length and desired time to live and 3075075Swnj * send to IP level. 3085075Swnj */ 3095441Swnj ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + optlen + len; 3105075Swnj ((struct ip *)ti)->ip_ttl = TCP_TTL; 3116212Swnj if (ip_output(m, tp->t_ipopt, 0) == 0) 3125088Swnj return (0); 3135075Swnj 3145075Swnj /* 3155075Swnj * Data sent (as far as we can tell). 3165075Swnj * If this advertises a larger window than any other segment, 3175245Sroot * then remember the size of the advertised window. 3185088Swnj * Drop send for purpose of ACK requirements. 3195075Swnj */ 3205252Sroot if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) 3215075Swnj tp->rcv_adv = tp->rcv_nxt + win; 3225088Swnj tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); 3235245Sroot if (SEQ_GT(tp->snd_nxt, tp->snd_max)) 3245245Sroot tp->snd_max = tp->snd_nxt; 3255088Swnj return (1); 3264677Swnj } 327