1 /* tcp_output.c 4.18 81/11/25 */ 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/inet.h" 9 #include "../net/inet_pcb.h" 10 #include "../net/inet_systm.h" 11 #include "../net/imp.h" 12 #include "../net/ip.h" 13 #include "../net/ip_var.h" 14 #include "../net/tcp.h" 15 #include "../net/tcp_var.h" 16 #include "../net/tcp_fsm.h" 17 #include "/usr/include/errno.h" 18 19 /* 20 * Tcp output routine: figure out what should be sent 21 * and, if nothing, send a null segment anyways if force is nonzero 22 * (e.g. to be sure to send an ACK). 23 * 24 * This routine can be called only after SYNs have been exchanged. 25 */ 26 tcp_output(tp) 27 register struct tcpcb *tp; 28 { 29 register struct socket *so = tp->t_inpcb->inp_socket; 30 register int len; 31 struct mbuf *m0; 32 int off, flags; 33 register struct mbuf *m; 34 register struct tcpiphdr *ti; 35 int win; 36 37 COUNT(TCP_OUTPUT); 38 39 /* 40 * Determine length of data that can be transmitted. 41 * If will transmit to end of data and no more data 42 * is coming, then send FIN also. 43 * Make a copy of the data (if any). If no data 44 * and not forced to transmit, just return. 45 */ 46 off = tp->snd_nxt - tp->snd_una; 47 len = MIN(so->so_snd.sb_cc, tp->snd_wnd) - off; 48 if (len > tp->mtu) 49 len = tp->mtu; 50 if (len == so->so_snd.sb_cc && (so->so_state & SS_CANTSNDMORE)) 51 flags = TH_FIN; 52 else 53 flags = 0; 54 if (len) 55 goto send; 56 57 /* 58 * No data to send: see if something else makes us want to send. 59 * First check if we owe peer and ack or have a unacked FIN to send. 60 */ 61 if (tp->t_flags & TF_OWEACK) 62 goto send; 63 if ((so->so_state & SS_CANTSNDMORE) && 64 TCPS_OURFINISACKED(tp->t_state) == 0) 65 goto send; 66 if (tp->t_state == TCPS_SYN_SENT) { 67 flags = TH_SYN; 68 goto send; 69 } 70 if (tp->t_state == TCPS_CLOSED) { 71 flags = TH_RST; 72 goto send; 73 } 74 75 /* 76 * Calculate available window in i, and also amount 77 * of window known to peer (as advertised window less 78 * next expected input.) If this is 35% or more of the 79 * maximum possible window, then want to send a segment to peer. 80 */ 81 i = sbspace(&so->so_rcv) - tp->seqcnt; 82 if (i > 0 && 83 ((100*(i-(tp->rcv_adv-tp->rcv_nxt))/so->so_rcv.sb_hiwat) >= 35)) 84 goto send; 85 86 /* 87 * No reason to send a segment, just return. 88 */ 89 return; 90 91 send: 92 /* 93 * Grab a header mbuf, attaching a copy of data to 94 * be transmitted, and initialize the header from 95 * the template for sends on this connection. 96 */ 97 MGET(m, 0); 98 if (m == 0) 99 return (0); 100 m->m_off = MMAXOFF - sizeof(struct tcpiphdr); 101 m->m_len = sizeof (struct tcpiphdr); 102 if (len) { 103 m->m_next = m_copy(so->so_snd.sb_mb, off, len); 104 if (m->m_next == 0) 105 len = 0; 106 } 107 ti = mtod(m, struct tcpiphdr *); 108 if (tp->t_template == 0) 109 panic("tcp_output"); 110 bcopy((caddr_t)tp->t_template, ti, sizeof (struct tcpiphdr)); 111 112 /* 113 * Fill in fields, remembering maximum advertised 114 * window for use in delaying messages about window sizes. 115 */ 116 ti->ti_seq = htonl(tp->snd_nxt); 117 ti->ti_ackno = htonl(tp->rcv_nxt); 118 /* OPTIONS */ 119 if (flags & TH_SYN) 120 ti->ti_flags = flags; 121 else 122 ti->ti_flags = flags | TH_ACK; 123 win = sbspace(&so->so_rcv); 124 if (win > 0) 125 ti->ti_win = htons(win); 126 if (SEQ_GT(tp->snd_urp, tp->snd_nxt)) 127 ti->ti_urp = htons((u_short)(tp->snd_urp - tp->snd_nxt)); 128 ti->ti_flags |= TH_URG; 129 } else 130 /* 131 * If no urgent pointer to send, then we pull 132 * the urgent pointer to the left edge of the send window 133 * so that it doesn't drift into the send window on sequence 134 * number wraparound. 135 */ 136 tp->snd_urp = tp->snd_una; /* drag it along */ 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 = inet_cksum(m, sizeof (struct tcpiphdr) + len); 145 146 /* 147 * Fill in IP length and desired time to live and 148 * send to IP level. 149 */ 150 ((struct ip *)ti)->ip_len = len + sizeof (struct tcpiphdr); 151 ((struct ip *)ti)->ip_ttl = TCP_TTL; 152 if (ip_output(m) == 0) 153 return; 154 155 /* 156 * Data sent (as far as we can tell). 157 * If this advertises a larger window than any other segment, 158 * then record its sequence to be used in suppressing messages. 159 * Advance snd_nxt to reflect transmitted sequence space, 160 * drop send for purpose of ACK requirements, 161 * and time transmission if not a retransmit. 162 */ 163 if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) 164 tp->rcv_adv = tp->rcv_nxt + win; 165 tp->snd_nxt += len; 166 tp->t_flags &= ~(TF_OWEACK|TF_DELACK); 167 if (flags & TH_FIN) 168 tp->snd_nxt++; 169 if (SEQ_GT(tp->snd_nxt, tp->snd_hi)) { 170 tp->snd_hi = tp->snd_nxt; 171 /* TIME TRANSMIT */ 172 } 173 return; 174 } 175