1*5441Swnj /* tcp_output.c 4.29 82/01/17 */ 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 */ 25*5441Swnj 264678Swnj /* 27*5441Swnj * Initial options: indicate max segment length 1/2 of space 28*5441Swnj * allocated for receive; if TCPTRUEOOB is defined, indicate 29*5441Swnj * willingness to do true out-of-band. 30*5441Swnj */ 31*5441Swnj #ifndef TCPTRUEOOB 32*5441Swnj u_char tcp_initopt[4] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, }; 33*5441Swnj #else 34*5441Swnj u_char tcp_initopt[6] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, TCPOPT_WILLOOB, 2 }; 35*5441Swnj #endif 36*5441Swnj 37*5441Swnj /* 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; 49*5441Swnj int win, force; 50*5441Swnj u_char *opt; 51*5441Swnj 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 */ 76*5441Swnj if (tp->t_flags&TF_ACKNOW) 775075Swnj goto send; 784678Swnj 79*5441Swnj #ifdef TCPTRUEOOB 805075Swnj /* 81*5441Swnj * Send if an out of band data or ack should be transmitted. 82*5441Swnj */ 83*5441Swnj if (tp->t_oobflags&(TCPOOB_OWEACK|TCPOOB_NEEDACK))) 84*5441Swnj goto send; 85*5441Swnj #endif 86*5441Swnj 87*5441Swnj /* 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 134*5441Swnj /* 135*5441Swnj * Before ESTABLISHED, force sending of initial options 136*5441Swnj * unless TCP set to not do any options. 137*5441Swnj */ 138*5441Swnj if (tp->t_state < TCPS_ESTABLISHED) { 139*5441Swnj if (tp->t_flags&TF_NOOPT) 140*5441Swnj goto noopt; 141*5441Swnj opt = tcp_initopt; 142*5441Swnj optlen = sizeof (tcp_initopt); 143*5441Swnj *(u_short *)(opt + 2) = so->so_rcv.sb_hiwat / 2; 144*5441Swnj #if vax 145*5441Swnj *(u_short *)(opt + 2) = htons(*(u_short *)(opt + 2)); 146*5441Swnj #endif 147*5441Swnj } else { 148*5441Swnj if (tp->t_tcpopt == 0) 149*5441Swnj goto noopt; 150*5441Swnj opt = mtod(tp->t_tcpopt, u_char *); 151*5441Swnj optlen = tp->t_tcpopt->m_len; 152*5441Swnj } 153*5441Swnj #ifndef TCPTRUEOOB 154*5441Swnj if (opt) 155*5441Swnj #else 156*5441Swnj if (opt || (tp->t_oobflags&(TCPOOB_OWEACK|TCPOOB_NEEDACK))) 157*5441Swnj #endif 158*5441Swnj { 1595110Swnj m0 = m->m_next; 1605088Swnj m->m_next = m_get(0); 1615088Swnj if (m->m_next == 0) { 1625088Swnj (void) m_free(m); 163*5441Swnj m_freem(m0); 1645088Swnj return (0); 1655088Swnj } 1665088Swnj m->m_next->m_next = m0; 167*5441Swnj m0 = m->m_next; 168*5441Swnj m0->m_off = MMINOFF; 169*5441Swnj m0->m_len = optlen; 170*5441Swnj bcopy(opt, mtod(m0, caddr_t), optlen); 171*5441Swnj opt = (u_char *)(mtod(m0, caddr_t) + optlen); 172*5441Swnj #ifdef TCPTRUEOOB 173*5441Swnj if (tp->t_oobflags&TCPOOB_OWEACK) { 174*5441Swnj printf("tp %x send OOBACK for %x\n", tp->t_iobseq); 175*5441Swnj *opt++ = TCPOPT_OOBACK; 176*5441Swnj *opt++ = 3; 177*5441Swnj *opt++ = tp->t_iobseq; 178*5441Swnj m0->m_len += 3; 179*5441Swnj tp->t_oobflags &= ~TCPOOB_OWEACK; 180*5441Swnj /* sender should rexmt oob to force ack repeat */ 181*5441Swnj } 182*5441Swnj if (tp->t_oobflags&TCPOOB_NEEDACK) { 183*5441Swnj printf("tp %x send OOBDATA seq %x data %x\n", tp->t_oobseq, tp->t_oobc); 184*5441Swnj *opt++ = TCPOPT_OOBDATA; 185*5441Swnj *opt++ = 4; 186*5441Swnj *opt++ = tp->t_oobseq; 187*5441Swnj *opt++ = tp->t_oobc; 188*5441Swnj m0->m_len += 4; 189*5441Swnj TCPT_RANGESET(tp->t_timer[TCPT_OOBREXMT], 190*5441Swnj tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 191*5441Swnj } 192*5441Swnj #endif 193*5441Swnj while (m0->m_len & 0x3) { 194*5441Swnj *opt++ = TCPOPT_EOL; 195*5441Swnj m0->m_len++; 196*5441Swnj } 197*5441Swnj optlen = m0->m_len; 198*5441Swnj ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; 1995088Swnj } 200*5441Swnj noopt: 2015088Swnj ti->ti_flags = flags; 2025075Swnj win = sbspace(&so->so_rcv); 2035075Swnj if (win > 0) 2045110Swnj ti->ti_win = htons((u_short)win); 2055088Swnj if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { 2065420Swnj ti->ti_urp = tp->snd_up - tp->snd_nxt; 2075420Swnj #if vax 2085420Swnj ti->ti_urp = htons(ti->ti_urp); 2095420Swnj #endif 2105075Swnj ti->ti_flags |= TH_URG; 2115075Swnj } else 2125075Swnj /* 2135075Swnj * If no urgent pointer to send, then we pull 2145075Swnj * the urgent pointer to the left edge of the send window 2155075Swnj * so that it doesn't drift into the send window on sequence 2165075Swnj * number wraparound. 2175075Swnj */ 2185088Swnj tp->snd_up = tp->snd_una; /* drag it along */ 2195088Swnj /* PUSH */ 2205075Swnj 2215075Swnj /* 2225075Swnj * Put TCP length in extended header, and then 2235075Swnj * checksum extended header and data. 2245075Swnj */ 225*5441Swnj if (len + optlen) { 226*5441Swnj ti->ti_len = sizeof (struct tcphdr) + optlen + len; 227*5441Swnj #if vax 228*5441Swnj ti->ti_len = htons((u_short)ti->ti_len); 229*5441Swnj #endif 230*5441Swnj } 231*5441Swnj ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + optlen + len); 2325075Swnj 2335075Swnj /* 2345088Swnj * Advance snd_nxt over sequence space of this segment 2355088Swnj */ 2365088Swnj if (flags & (TH_SYN|TH_FIN)) 2375245Sroot tp->snd_nxt++; 2385088Swnj tp->snd_nxt += len; 2395088Swnj 2405088Swnj /* 2415163Swnj * If this transmission closes the window, 2425245Sroot * start persistance timer at 2 round trip times 2435245Sroot * but at least TCPTV_PERSMIN ticks. 2445088Swnj */ 2455276Swnj if (TCPS_HAVERCVDSYN(tp->t_state) && 2465299Sroot SEQ_GEQ(tp->snd_nxt, tp->snd_una+tp->snd_wnd) && 2475245Sroot tp->t_timer[TCPT_PERSIST] == 0) 2485245Sroot TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], 2495245Sroot 2 * tp->t_srtt, TCPTV_PERSMIN, TCPTV_MAX); 2505088Swnj 2515088Swnj /* 2525163Swnj * Time this transmission if not a retransmission and 2535163Swnj * not currently timing anything. 2545163Swnj */ 2555163Swnj if (SEQ_GT(tp->snd_nxt, tp->snd_max) && tp->t_rtt == 0) { 2565163Swnj tp->t_rtt = 1; 2575163Swnj tp->t_rtseq = tp->snd_nxt - len; 2585163Swnj } 2595163Swnj 2605163Swnj /* 2615163Swnj * Set retransmit timer if not currently set. 2625245Sroot * Initial value for retransmit timer to tcp_beta*tp->t_srtt. 2635163Swnj * Initialize shift counter which is used for exponential 2645163Swnj * backoff of retransmit time. 2655163Swnj */ 2665245Sroot if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) { 2675245Sroot TCPT_RANGESET(tp->t_timer[TCPT_REXMT], 2685245Sroot tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 2695299Sroot tp->t_rtt = 0; 2705163Swnj tp->t_rxtshift = 0; 2715163Swnj } 2725163Swnj 2735163Swnj /* 2745268Sroot * Trace. 2755268Sroot */ 2765268Sroot if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 2775268Sroot tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0); 2785268Sroot 2795268Sroot /* 2805075Swnj * Fill in IP length and desired time to live and 2815075Swnj * send to IP level. 2825075Swnj */ 283*5441Swnj ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + optlen + len; 2845075Swnj ((struct ip *)ti)->ip_ttl = TCP_TTL; 2855420Swnj if (ip_output(m, tp->t_ipopt) == 0) 2865088Swnj return (0); 2875075Swnj 2885075Swnj /* 2895075Swnj * Data sent (as far as we can tell). 2905075Swnj * If this advertises a larger window than any other segment, 2915245Sroot * then remember the size of the advertised window. 2925088Swnj * Drop send for purpose of ACK requirements. 2935075Swnj */ 2945252Sroot if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) 2955075Swnj tp->rcv_adv = tp->rcv_nxt + win; 2965088Swnj tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); 2975245Sroot if (SEQ_GT(tp->snd_nxt, tp->snd_max)) 2985245Sroot tp->snd_max = tp->snd_nxt; 2995088Swnj return (1); 3004677Swnj } 301