1 /* tcp_output.c 4.11 81/11/14 */ 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_cksum.h" 9 #include "../net/inet.h" 10 #include "../net/inet_host.h" 11 #include "../net/inet_pcb.h" 12 #include "../net/inet_systm.h" 13 #include "../net/imp.h" 14 #include "../net/ip.h" 15 #include "../net/tcp.h" 16 #include "../net/tcp_var.h" 17 #include "../net/tcp_fsm.h" 18 #include "/usr/include/errno.h" 19 20 /* 21 * Special routines to send control messages. 22 */ 23 tcp_sndctl(tp) 24 struct tcpcb *tp; 25 { 26 COUNT(TCP_SNDCTL); 27 28 if (tcp_send(tp)) 29 return (1); 30 tcp_sndnull(tp); 31 return (0); 32 } 33 34 tcp_sndwin(tp) 35 struct tcpcb *tp; 36 { 37 int ihave, hehas; 38 COUNT(TCP_SNDWIN); 39 40 if (tp->rcv_adv) { 41 register struct socket *so = tp->t_inpcb->inp_socket; 42 43 ihave = so->so_rcv.sb_hiwat - 44 (so->so_rcv.sb_cc + tp->seqcnt); 45 hehas = tp->rcv_adv - tp->rcv_nxt; 46 if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35) 47 return; 48 } 49 if (tcp_send(tp)) 50 return (1); 51 tcp_sndnull(tp); 52 return (0); 53 } 54 55 tcp_sndnull(tp) 56 register struct tcpcb *tp; 57 { 58 COUNT(TCP_SNDNULL); 59 60 tcp_output(tp, 0, 0, (struct mbuf *)0); 61 tp->tc_flags &= ~TC_ACK_DUE; 62 } 63 64 tcp_sndrst(tp, n) 65 register struct tcpcb *tp; 66 register struct tcpiphdr *n; 67 { 68 COUNT(TCP_SNDRST); 69 70 /* don't send a reset in response to a reset */ 71 if (n->th_flags&TH_RST) 72 return; 73 tp->tc_flags |= TC_SND_RST; 74 if (n->th_flags&TH_ACK) 75 tp->snd_nxt = n->t_ackno; 76 tp->tc_flags &= ~TC_SYN_RCVD; 77 tcp_sndnull(tp); 78 tp->tc_flags &= ~TC_SND_RST; 79 } 80 81 /* 82 * Tcp segment output routine. 83 */ 84 tcp_send(tp) 85 register struct tcpcb *tp; 86 { 87 register unsigned long last, wind; 88 register struct socket *so = tp->t_inpcb->inp_socket; 89 struct mbuf *m; 90 int flags = 0, forced, sent, len; 91 92 COUNT(TCP_SEND); 93 tp->snd_lst = tp->snd_nxt; 94 forced = 0; 95 m = NULL; 96 if (tp->snd_nxt == tp->iss) { 97 flags |= TH_SYN; 98 tp->snd_lst++; 99 } 100 last = tp->snd_off; 101 for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next) 102 last += m->m_len; 103 if (tp->snd_nxt > last) { 104 if ((tp->tc_flags&TC_SND_FIN) && 105 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 106 107 flags |= TH_FIN; 108 tp->seq_fin = tp->snd_lst++; 109 } 110 } else { 111 if (tp->tc_flags&TC_SYN_ACKED) { 112 wind = tp->snd_una + tp->snd_wnd; 113 tp->snd_lst = min(last, wind); 114 if ((len = tp->snd_lst - tp->snd_nxt) > 1024) 115 tp->snd_lst -= len - 1024; 116 if (tp->snd_lst >= wind) 117 tp->t_persist = T_PERS; 118 } 119 if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { 120 tp->snd_lst = tp->snd_nxt + 1; 121 forced = 1; 122 } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0) 123 return (0); 124 m = sb_copy(&so->so_snd, 125 MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off, 126 tp->snd_lst - tp->snd_off); 127 if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 128 flags |= TH_EOL; 129 if ((tp->tc_flags&TC_SND_FIN) && !forced && 130 tp->snd_lst == last && 131 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 132 flags |= TH_FIN; 133 tp->seq_fin = tp->snd_lst++; 134 } 135 } 136 if (tp->snd_nxt >= tp->snd_lst) 137 return (0); 138 if (tp->tc_flags & TC_SND_URG) 139 flags |= TH_URG; 140 sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 141 if (!forced) { 142 tp->t_rexmt = tp->t_xmtime; 143 tp->t_rexmt_val = tp->snd_lst; 144 if ((tp->tc_flags&TC_REXMT) == 0) { 145 tp->t_rexmttl = T_REXMTTL; 146 tp->t_rtl_val = tp->snd_lst; 147 } 148 } 149 if (sent) 150 tp->snd_nxt = tp->snd_lst; 151 if ((tp->tc_flags&TC_SYN_ACKED) && 152 tp->snd_una > tp->t_xmt_val) { 153 tp->t_xmt = 0; 154 tp->t_xmt_val = tp->snd_lst; 155 } 156 tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 157 tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi); 158 return (1); 159 } 160 161 /* 162 * Create template to be used to send tcp packets on a connection. 163 * Call after host entry created, allocates an mbuf and fills 164 * in a skeletal tcp/ip header, minimizing the amount of work 165 * necessary when the connection is used. 166 */ 167 struct tcpiphdr * 168 tcp_template(tp) 169 struct tcpcb *tp; 170 { 171 register struct inpcb *inp = tp->t_inpcb; 172 register struct in_host *h = inp->inp_fhost; 173 register struct mbuf *m; 174 register struct tcpiphdr *n; 175 176 if (h == 0) 177 return (0); 178 m = m_get(1); 179 if (m == 0) 180 return (0); 181 m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 182 m->m_len = sizeof (struct tcpiphdr); 183 n = mtod(m, struct tcpiphdr *); 184 n->t_next = n->t_prev = 0; 185 n->t_x1 = 0; 186 n->t_pr = IPPROTO_TCP; 187 n->t_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); 188 n->t_s.s_addr = n_lhost.s_addr; 189 n->t_d.s_addr = h->h_addr.s_addr; 190 n->t_src = htons(inp->inp_lport); 191 n->t_dst = htons(inp->inp_fport); 192 n->t_seq = 0; 193 n->t_ackno = 0; 194 n->t_x2 = 0; 195 n->t_off = 5; 196 n->th_flags = 0; 197 n->t_win = 0; 198 n->t_sum = 0; 199 n->t_urp = 0; 200 return (n); 201 } 202 203 tcp_output(tp, flags, len, dat) 204 register struct tcpcb *tp; 205 register int flags; 206 int len; 207 struct mbuf *dat; 208 { 209 register struct tcpiphdr *t; /* known to be r9 */ 210 register struct mbuf *m; 211 struct socket *so = tp->t_inpcb->inp_socket; 212 register struct ip *ip; 213 int i; 214 #ifdef TCPDEBUG 215 struct tcp_debug tdb; 216 #endif 217 COUNT(TCP_OUTPUT); 218 219 if ((t = tp->t_template) == 0) 220 return (0); 221 MGET(m, 0); 222 if (m == 0) 223 return (0); 224 m->m_off = MMAXOFF - sizeof(struct tcpiphdr); 225 m->m_len = sizeof (struct tcpiphdr); 226 m->m_next = dat; 227 if (flags & TH_SYN) 228 len--; 229 if (flags & TH_FIN) 230 len--; 231 bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr)); 232 t = mtod(m, struct tcpiphdr *); 233 if (tp->tc_flags&TC_SND_RST) { 234 flags &= ~TH_SYN; 235 flags |= TH_RST; 236 } 237 if (tp->tc_flags&TC_SYN_RCVD) 238 flags |= TH_ACK; 239 t->th_flags = flags; 240 if (flags & TH_URG) 241 t->t_urp = htons(tp->snd_urp); 242 t->t_win = 243 so->so_rcv.sb_hiwat - 244 (so->so_rcv.sb_cc + tp->seqcnt); 245 if (tp->rcv_nxt + t->t_win > tp->rcv_adv) 246 tp->rcv_adv = tp->rcv_nxt + t->t_win; 247 if (len) 248 t->t_len = htons(len + TCPSIZE); 249 t->t_win = htons(t->t_win); 250 #ifdef TCPDEBUG 251 if ((so->so_options & SO_DEBUG) || tcpconsdebug) { 252 t->t_seq = tp->snd_nxt; 253 t->t_ackno = tp->rcv_nxt; 254 tdb_setup(tp, t, INSEND, &tdb); 255 tdb_stuff(&tdb, -2); 256 } 257 #endif 258 t->t_seq = htonl(tp->snd_nxt); 259 t->t_ackno = htonl(tp->rcv_nxt); 260 t->t_sum = 0; /* gratuitous? */ 261 CKSUM_TCPSET(m, t, r9, sizeof (struct tcpiphdr) + len); 262 ip = (struct ip *)t; 263 ip->ip_v = IPVERSION; 264 ip->ip_hl = 5; 265 ip->ip_tos = 0; 266 ip->ip_len = len + sizeof(struct tcpiphdr); 267 ip->ip_id = ip_id++; 268 ip->ip_off = 0; 269 ip->ip_ttl = MAXTTL; 270 i = ip_send(ip); 271 return (i); 272 } 273 274 tcp_fasttimo() 275 { 276 277 } 278