1 /* tcp_output.c 4.27 81/12/22 */ 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 "../net/in.h" 10 #include "../net/in_pcb.h" 11 #include "../net/in_systm.h" 12 #include "../net/ip.h" 13 #include "../net/ip_var.h" 14 #include "../net/tcp.h" 15 #define TCPOUTFLAGS 16 #include "../net/tcp_fsm.h" 17 #include "../net/tcp_seq.h" 18 #include "../net/tcp_timer.h" 19 #include "../net/tcp_var.h" 20 #include "../net/tcpip.h" 21 #include "../net/tcp_debug.h" 22 #include "../errno.h" 23 24 char *tcpstates[]; /* XXX */ 25 /* 26 * Tcp output routine: figure out what should be sent and send it. 27 */ 28 tcp_output(tp) 29 register struct tcpcb *tp; 30 { 31 register struct socket *so = tp->t_inpcb->inp_socket; 32 register int len; 33 struct mbuf *m0; 34 int off, flags; 35 register struct mbuf *m; 36 register struct tcpiphdr *ti; 37 int win; 38 39 COUNT(TCP_OUTPUT); 40 41 /* 42 * Determine length of data that can be transmitted, 43 * and flags that will be used. 44 * If there is some data or critical controls (SYN, RST) 45 * to send, then transmit; otherwise, investigate further. 46 */ 47 off = tp->snd_nxt - tp->snd_una; 48 len = MIN(so->so_snd.sb_cc, tp->snd_wnd+tp->t_force) - off; 49 if (len < 0) 50 return; /* past FIN */ 51 if (len > tp->t_maxseg) 52 len = tp->t_maxseg; 53 flags = tcp_outflags[tp->t_state]; 54 if (tp->snd_nxt + len < tp->snd_una + so->so_snd.sb_cc) 55 flags &= ~TH_FIN; 56 if (len || (flags & (TH_SYN|TH_RST|TH_FIN))) 57 goto send; 58 59 /* 60 * Send if we owe peer an ACK. 61 */ 62 if (tp->t_flags & TF_ACKNOW) 63 goto send; 64 65 /* 66 * Calculate available window in i, and also amount 67 * of window known to peer (as advertised window less 68 * next expected input.) If this is 35% or more of the 69 * maximum possible window, then want to send a segment to peer. 70 */ 71 win = sbspace(&so->so_rcv); 72 if (win > 0 && 73 ((100*(win-(tp->rcv_adv-tp->rcv_nxt))/so->so_rcv.sb_hiwat) >= 35)) 74 goto send; 75 76 /* 77 * No reason to send a segment, just return. 78 */ 79 return (0); 80 81 send: 82 /* 83 * Grab a header mbuf, attaching a copy of data to 84 * be transmitted, and initialize the header from 85 * the template for sends on this connection. 86 */ 87 MGET(m, 0); 88 if (m == 0) 89 return (0); 90 m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 91 m->m_len = sizeof (struct tcpiphdr); 92 if (len) { 93 m->m_next = m_copy(so->so_snd.sb_mb, off, len); 94 if (m->m_next == 0) 95 len = 0; 96 } 97 ti = mtod(m, struct tcpiphdr *); 98 if (tp->t_template == 0) 99 panic("tcp_output"); 100 bcopy((caddr_t)tp->t_template, (caddr_t)ti, sizeof (struct tcpiphdr)); 101 102 /* 103 * Fill in fields, remembering maximum advertised 104 * window for use in delaying messages about window sizes. 105 */ 106 ti->ti_seq = tp->snd_nxt; 107 ti->ti_ack = tp->rcv_nxt; 108 #if vax 109 ti->ti_seq = htonl(ti->ti_seq); 110 ti->ti_ack = htonl(ti->ti_ack); 111 #endif 112 if (tp->t_tcpopt) { 113 m0 = m->m_next; 114 m->m_next = m_get(0); 115 if (m->m_next == 0) { 116 (void) m_free(m); 117 m_freem(m); 118 return (0); 119 } 120 m->m_next->m_next = m0; 121 m->m_off = MMINOFF; 122 m->m_len = tp->t_tcpopt->m_len; 123 bcopy(mtod(tp->t_tcpopt, caddr_t), mtod(m, caddr_t), 124 (unsigned)tp->t_tcpopt->m_len); 125 ti->ti_off = (sizeof (struct tcphdr)+tp->t_tcpopt->m_len) >> 2; 126 } 127 ti->ti_flags = flags; 128 win = sbspace(&so->so_rcv); 129 if (win > 0) 130 ti->ti_win = htons((u_short)win); 131 if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { 132 ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt)); 133 ti->ti_flags |= TH_URG; 134 } else 135 /* 136 * If no urgent pointer to send, then we pull 137 * the urgent pointer to the left edge of the send window 138 * so that it doesn't drift into the send window on sequence 139 * number wraparound. 140 */ 141 tp->snd_up = tp->snd_una; /* drag it along */ 142 /* PUSH */ 143 144 /* 145 * Put TCP length in extended header, and then 146 * checksum extended header and data. 147 */ 148 if (len) 149 ti->ti_len = htons((u_short)(len + sizeof (struct tcphdr))); 150 ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + len); 151 152 /* 153 * Advance snd_nxt over sequence space of this segment 154 */ 155 if (flags & (TH_SYN|TH_FIN)) 156 tp->snd_nxt++; 157 tp->snd_nxt += len; 158 159 /* 160 * If this transmission closes the window, 161 * start persistance timer at 2 round trip times 162 * but at least TCPTV_PERSMIN ticks. 163 */ 164 if (TCPS_HAVERCVDSYN(tp->t_state) && 165 SEQ_GEQ(tp->snd_nxt, tp->snd_una+tp->snd_wnd) && 166 tp->t_timer[TCPT_PERSIST] == 0) 167 TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], 168 2 * tp->t_srtt, TCPTV_PERSMIN, TCPTV_MAX); 169 170 /* 171 * Time this transmission if not a retransmission and 172 * not currently timing anything. 173 */ 174 if (SEQ_GT(tp->snd_nxt, tp->snd_max) && tp->t_rtt == 0) { 175 tp->t_rtt = 1; 176 tp->t_rtseq = tp->snd_nxt - len; 177 } 178 179 /* 180 * Set retransmit timer if not currently set. 181 * Initial value for retransmit timer to tcp_beta*tp->t_srtt. 182 * Initialize shift counter which is used for exponential 183 * backoff of retransmit time. 184 */ 185 if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) { 186 TCPT_RANGESET(tp->t_timer[TCPT_REXMT], 187 tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 188 tp->t_rtt = 0; 189 tp->t_rxtshift = 0; 190 } 191 192 /* 193 * Trace. 194 */ 195 if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 196 tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0); 197 198 /* 199 * Fill in IP length and desired time to live and 200 * send to IP level. 201 */ 202 ((struct ip *)ti)->ip_len = len + sizeof (struct tcpiphdr); 203 ((struct ip *)ti)->ip_ttl = TCP_TTL; 204 if (ip_output(m, tp->t_ipopt) == 0) { 205 printf("ip_output failed\n"); 206 return (0); 207 } 208 209 /* 210 * Data sent (as far as we can tell). 211 * If this advertises a larger window than any other segment, 212 * then remember the size of the advertised window. 213 * Drop send for purpose of ACK requirements. 214 */ 215 if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) 216 tp->rcv_adv = tp->rcv_nxt + win; 217 tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); 218 if (SEQ_GT(tp->snd_nxt, tp->snd_max)) 219 tp->snd_max = tp->snd_nxt; 220 return (1); 221 } 222