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