1 /* tcp_output.c 4.10 81/11/08 */ 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_systm.h" 12 #include "../net/imp.h" 13 #include "../net/ip.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 * Special routines to send control messages. 21 */ 22 tcp_sndctl(tp) 23 struct tcb *tp; 24 { 25 COUNT(TCP_SNDCTL); 26 27 if (tcp_send(tp)) 28 return (1); 29 tcp_sndnull(tp); 30 return (0); 31 } 32 33 tcp_sndwin(tp) 34 struct tcb *tp; 35 { 36 int ihave, hehas; 37 register struct socket *so = tp->t_socket; 38 COUNT(TCP_SNDWIN); 39 40 if (tp->rcv_adv) { 41 ihave = so->so_rcv.sb_hiwat - 42 (so->so_rcv.sb_cc + tp->seqcnt); 43 hehas = tp->rcv_adv - tp->rcv_nxt; 44 if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35) 45 return; 46 } 47 if (tcp_send(tp)) 48 return (1); 49 tcp_sndnull(tp); 50 return (0); 51 } 52 53 tcp_sndnull(tp) 54 register struct tcb *tp; 55 { 56 COUNT(TCP_SNDNULL); 57 58 tcp_output(tp, 0, 0, (struct mbuf *)0); 59 tp->tc_flags &= ~TC_ACK_DUE; 60 } 61 62 tcp_sndrst(tp, n) 63 register struct tcb *tp; 64 register struct th *n; 65 { 66 COUNT(TCP_SNDRST); 67 68 /* don't send a reset in response to a reset */ 69 if (n->th_flags&TH_RST) 70 return; 71 tp->tc_flags |= TC_SND_RST; 72 if (n->th_flags&TH_ACK) 73 tp->snd_nxt = n->t_ackno; 74 tp->tc_flags &= ~TC_SYN_RCVD; 75 tcp_sndnull(tp); 76 tp->tc_flags &= ~TC_SND_RST; 77 } 78 79 /* 80 * Tcp segment output routine. 81 */ 82 tcp_send(tp) 83 register struct tcb *tp; 84 { 85 register struct socket *so; 86 register unsigned long last, wind; 87 struct mbuf *m; 88 int flags = 0, forced, sent; 89 struct mbuf *tcp_sndcopy(); 90 int len; 91 92 COUNT(TCP_SEND); 93 so = tp->t_socket; 94 tp->snd_lst = tp->snd_nxt; 95 forced = 0; 96 m = NULL; 97 if (tp->snd_nxt == tp->iss) { 98 flags |= TH_SYN; 99 tp->snd_lst++; 100 } 101 last = tp->snd_off; 102 for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next) 103 last += m->m_len; 104 if (tp->snd_nxt > last) { 105 if ((tp->tc_flags&TC_SND_FIN) && 106 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 107 108 flags |= TH_FIN; 109 tp->seq_fin = tp->snd_lst++; 110 } 111 } else { 112 if (tp->tc_flags&TC_SYN_ACKED) { 113 wind = tp->snd_una + tp->snd_wnd; 114 tp->snd_lst = min(last, wind); 115 if ((len = tp->snd_lst - tp->snd_nxt) > 1024) 116 tp->snd_lst -= len - 1024; 117 if (tp->snd_lst >= wind) 118 tp->t_persist = T_PERS; 119 } 120 if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { 121 tp->snd_lst = tp->snd_nxt + 1; 122 forced = 1; 123 } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0) 124 return (0); 125 m = tcp_sndcopy(tp, MAX(tp->iss+1,tp->snd_nxt), tp->snd_lst); 126 if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 127 flags |= TH_EOL; 128 if ((tp->tc_flags&TC_SND_FIN) && !forced && 129 tp->snd_lst == last && 130 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 131 flags |= TH_FIN; 132 tp->seq_fin = tp->snd_lst++; 133 } 134 } 135 if (tp->snd_nxt >= tp->snd_lst) 136 return (0); 137 if (tp->tc_flags & TC_SND_URG) 138 flags |= TH_URG; 139 sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 140 if (!forced) { 141 tp->t_rexmt = tp->t_xmtime; 142 tp->t_rexmt_val = tp->snd_lst; 143 if ((tp->tc_flags&TC_REXMT) == 0) { 144 tp->t_rexmttl = T_REXMTTL; 145 tp->t_rtl_val = tp->snd_lst; 146 } 147 } 148 if (sent) 149 tp->snd_nxt = tp->snd_lst; 150 if ((tp->tc_flags&TC_SYN_ACKED) && 151 tp->snd_una > tp->t_xmt_val) { 152 tp->t_xmt = 0; 153 tp->t_xmt_val = tp->snd_lst; 154 } 155 tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 156 tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi); 157 return (1); 158 } 159 160 /* 161 * Create template to be used to send tcp packets on a connection. 162 * Call after host entry created, allocates an mbuf and fills 163 * in a skeletal tcp/ip header, minimizing the amount of work 164 * necessary when the connection is used. 165 */ 166 struct th * 167 tcp_template(tp) 168 struct tcb *tp; 169 { 170 register struct host *h = tp->t_host; 171 register struct mbuf *m; 172 register struct th *n; 173 register struct ip *ip; 174 175 if (h == 0) 176 return (0); 177 m = m_get(1); 178 if (m == 0) 179 return (0); 180 m->m_off = MMAXOFF - sizeof (struct th); 181 m->m_len = sizeof (struct th); 182 n = mtod(m, struct th *); 183 n->t_next = n->t_prev = 0; 184 n->t_x1 = 0; 185 n->t_pr = IPPROTO_TCP; 186 n->t_len = htons(sizeof (struct th) - sizeof (struct ip)); 187 n->t_s.s_addr = n_lhost.s_addr; 188 n->t_d.s_addr = h->h_addr.s_addr; 189 n->t_src = htons(tp->t_lport); 190 n->t_dst = htons(tp->t_fport); 191 n->t_seq = 0; 192 n->t_ackno = 0; 193 n->t_x2 = 0; 194 n->t_off = 5; 195 n->th_flags = 0; 196 n->t_win = 0; 197 n->t_sum = 0; 198 n->t_urp = 0; 199 return (n); 200 } 201 202 tcp_output(tp, flags, len, dat) 203 register struct tcb *tp; 204 register int flags; 205 int len; 206 struct mbuf *dat; 207 { 208 register struct th *t; /* known to be r9 */ 209 register struct mbuf *m; 210 register struct ip *ip; 211 int i; 212 #ifdef TCPDEBUG 213 struct tcp_debug tdb; 214 #endif 215 COUNT(TCP_OUTPUT); 216 217 if ((t = tp->t_template) == 0) 218 return (0); 219 MGET(m, 0); 220 if (m == 0) 221 return (0); 222 m->m_off = MMAXOFF - sizeof(struct th); 223 m->m_len = sizeof (struct th); 224 m->m_next = dat; 225 if (flags & TH_SYN) 226 len--; 227 if (flags & TH_FIN) 228 len--; 229 bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th)); 230 t = mtod(m, struct th *); 231 if (tp->tc_flags&TC_SND_RST) { 232 flags &= ~TH_SYN; 233 flags |= TH_RST; 234 } 235 if (tp->tc_flags&TC_SYN_RCVD) 236 flags |= TH_ACK; 237 t->th_flags = flags; 238 if (flags & TH_URG) 239 t->t_urp = htons(tp->snd_urp); 240 t->t_win = 241 tp->t_socket->so_rcv.sb_hiwat - 242 (tp->t_socket->so_rcv.sb_cc + tp->seqcnt); 243 if (tp->rcv_nxt + t->t_win > tp->rcv_adv) 244 tp->rcv_adv = tp->rcv_nxt + t->t_win; 245 if (len) 246 t->t_len = htons(len + TCPSIZE); 247 t->t_win = htons(t->t_win); 248 #ifdef TCPDEBUG 249 if ((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug) { 250 t->t_seq = tp->snd_nxt; 251 t->t_ackno = tp->rcv_nxt; 252 tdb_setup(tp, t, INSEND, &tdb); 253 tdb_stuff(&tdb, -2); 254 } 255 #endif 256 t->t_seq = htonl(tp->snd_nxt); 257 t->t_ackno = htonl(tp->rcv_nxt); 258 t->t_sum = 0; /* gratuitous? */ 259 CKSUM_TCPSET(m, t, r9, sizeof (struct th) + len); 260 ip = (struct ip *)t; 261 ip->ip_v = IPVERSION; 262 ip->ip_hl = 5; 263 ip->ip_tos = 0; 264 ip->ip_len = len + sizeof(struct th); 265 ip->ip_id = ip_id++; 266 ip->ip_off = 0; 267 ip->ip_ttl = MAXTTL; 268 i = ip_send(ip); 269 return (i); 270 } 271 272 firstempty(tp) 273 register struct tcb *tp; 274 { 275 register struct th *p, *q; 276 COUNT(FIRSTEMPTY); 277 278 if ((p = tp->tcb_hd.seg_next) == (struct th *)tp || 279 tp->rcv_nxt < p->t_seq) 280 return (tp->rcv_nxt); 281 while ((q = p->t_next) != (struct th *)tp && 282 (t_end(p) + 1) == q->t_seq) 283 p = q; 284 return (t_end(p) + 1); 285 } 286 287 struct mbuf * 288 tcp_sndcopy(tp, start, end) 289 struct tcb *tp; 290 u_long start, end; 291 { 292 register struct mbuf *m, *n, **np; 293 u_long off; 294 register int len; 295 int adj; 296 struct mbuf *top, *p; 297 COUNT(TCP_SNDCOPY); 298 299 if (start >= end) 300 return (NULL); 301 off = tp->snd_off; 302 m = tp->t_socket->so_snd.sb_mb; 303 while (m != NULL && start >= (off + m->m_len)) { 304 off += m->m_len; 305 m = m->m_next; 306 } 307 np = ⊤ 308 top = 0; 309 adj = start - off; 310 len = end - start; 311 while (m && len > 0) { 312 MGET(n, 1); 313 *np = n; 314 if (n == 0) 315 goto nospace; 316 n->m_len = MIN(len, m->m_len - adj); 317 if (m->m_off > MMAXOFF) { 318 p = mtod(m, struct mbuf *); 319 n->m_off = ((int)p - (int)n) + adj; 320 mprefcnt[mtopf(p)]++; 321 } else { 322 n->m_off = MMINOFF; 323 bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t), 324 n->m_len); 325 } 326 len -= n->m_len; 327 adj = 0; 328 m = m->m_next; 329 /* SHOULD TRY PACKING INTO SMALL MBUFS HERE */ 330 np = &n->m_next; 331 } 332 /* SHOULD NEVER RUN OUT OF m WHEN LEN */ 333 if (len) 334 printf("snd_copy: m %x len %d\n", m, len); 335 return (top); 336 nospace: 337 printf("snd_copy: no space\n"); 338 m_freem(top); 339 return (0); 340 } 341 342 tcp_fasttimo() 343 { 344 345 } 346