1 /* tcp_output.c 4.19 81/11/26 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/mbuf.h" 6 #include "../h/socket.h" 7 #include "../h/socketvar.h" 8 #include "../net/in.h" 9 #include "../net/in_pcb.h" 10 #include "../net/in_systm.h" 11 #include "../net/ip.h" 12 #include "../net/ip_var.h" 13 #include "../net/tcp.h" 14 #define TCPOUTFLAGS 15 #include "../net/tcp_fsm.h" 16 #include "../net/tcp_seq.h" 17 #include "../net/tcp_timer.h" 18 #include "../net/tcp_var.h" 19 #include "../net/tcpip.h" 20 #include "/usr/include/errno.h" 21 22 /* 23 * Tcp output routine: figure out what should be sent 24 * and, if nothing, send a null segment anyways if force is nonzero 25 * (e.g. to be sure to send an ACK). 26 * 27 * This routine can be called only after SYNs have been exchanged. 28 */ 29 tcp_output(tp) 30 register struct tcpcb *tp; 31 { 32 register struct socket *so = tp->t_inpcb->inp_socket; 33 register int len; 34 struct mbuf *m0; 35 int off, flags; 36 register struct mbuf *m; 37 register struct tcpiphdr *ti; 38 int win; 39 40 COUNT(TCP_OUTPUT); 41 42 /* 43 * Determine length of data that can be transmitted, 44 * and flags that will be used. 45 * If there is some data or critical controls (SYN, RST) 46 * to send, then transmit; otherwise, investigate further. 47 */ 48 off = tp->snd_nxt - tp->snd_una; 49 len = MIN(so->so_snd.sb_cc, tp->snd_wnd) - off; 50 if (len > tp->t_maxseg) 51 len = tp->t_maxseg; 52 flags = tcp_outflags[tp->t_state]; 53 if (len || (flags & (TH_SYN|TH_RST))) 54 goto send; 55 56 /* 57 * See if we owe peer an ACK or have a unacked FIN to send. 58 */ 59 if (tp->t_flags & TF_ACKNOW) 60 goto send; 61 if ((so->so_state & SS_CANTSENDMORE) && 62 TCPS_OURFINNOTACKED(tp->t_state)) 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; 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, 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 = htonl(tp->snd_nxt); 107 ti->ti_ack = htonl(tp->rcv_nxt); 108 if (tp->t_tcpopt) { 109 m->m_next = m_get(0); 110 if (m->m_next == 0) { 111 (void) m_free(m); 112 return (0); 113 } 114 m->m_next->m_next = m0; 115 m->m_off = MMINOFF; 116 m->m_len = tp->t_tcpopt->m_len; 117 bcopy(mtod(tp->t_tcpopt, caddr_t), mtod(m, caddr_t), 118 tp->t_tcpopt->m_len); 119 ti->ti_off = (sizeof (struct tcphdr)+tp->t_tcpopt->m_len) >> 2; 120 } 121 ti->ti_flags = flags; 122 win = sbspace(&so->so_rcv); 123 if (win > 0) 124 ti->ti_win = htons(win); 125 if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { 126 ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt)); 127 ti->ti_flags |= TH_URG; 128 } else 129 /* 130 * If no urgent pointer to send, then we pull 131 * the urgent pointer to the left edge of the send window 132 * so that it doesn't drift into the send window on sequence 133 * number wraparound. 134 */ 135 tp->snd_up = tp->snd_una; /* drag it along */ 136 /* PUSH */ 137 138 /* 139 * Put TCP length in extended header, and then 140 * checksum extended header and data. 141 */ 142 if (len) 143 ti->ti_len = htons((u_short)(len + sizeof (struct tcphdr))); 144 ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + len); 145 146 /* 147 * Advance snd_nxt over sequence space of this segment 148 */ 149 if (flags & (TH_SYN|TH_FIN)) 150 len++; 151 tp->snd_nxt += len; 152 153 /* 154 * Arrange for retransmit and time this transmit if 155 * not already a retransmit and sending either data, 156 * SYN or FIN. 157 */ 158 if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { 159 tp->rxt_seq = tp->snd_nxt - len; 160 tp->rxt_time = 0; 161 tp->rxt_cnt = 0; 162 tp->t_timer[TCPT_REXMT] = 0; /* XXX */ 163 } 164 165 /* 166 * Fill in IP length and desired time to live and 167 * send to IP level. 168 */ 169 ((struct ip *)ti)->ip_len = len + sizeof (struct tcpiphdr); 170 ((struct ip *)ti)->ip_ttl = TCP_TTL; 171 if (ip_output(m, tp->t_ipopt) == 0) 172 return (0); 173 174 /* 175 * Data sent (as far as we can tell). 176 * If this advertises a larger window than any other segment, 177 * then record its sequence to be used in suppressing messages. 178 * Drop send for purpose of ACK requirements. 179 */ 180 if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) 181 tp->rcv_adv = tp->rcv_nxt + win; 182 tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); 183 tp->snd_max = tp->snd_nxt; 184 return (1); 185 } 186