1 /* tcp_output.c 4.1 81/10/30 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/mbuf.h" 6 #include "../h/socket.h" 7 #include "../inet/inet.h" 8 #include "../inet/inet_host.h" 9 #include "../inet/inet_systm.h" 10 #include "../inet/imp.h" 11 #include "../inet/ip.h" 12 #include "../inet/tcp.h" 13 #include "../inet/tcp_fsm.h" 14 15 send(tp) /* send data */ 16 register struct tcb *tp; 17 { 18 register struct ucb *up; 19 register unsigned long last, wind; 20 struct mbuf *m; 21 int flags = 0, forced, sent; 22 struct mbuf *tcp_sndcopy(); 23 int len; 24 25 COUNT(SEND); 26 up = tp->t_ucb; 27 tp->snd_lst = tp->snd_nxt; 28 forced = 0; 29 m = NULL; 30 31 if (tp->snd_nxt == tp->iss) { /* first data to be sent */ 32 flags |= TH_SYN; 33 tp->snd_lst++; 34 } 35 36 /* get seq # of last datum in send buffer */ 37 38 last = tp->snd_off; 39 for (m = up->uc_sbuf; m != NULL; m = m->m_next) 40 last += m->m_len; 41 42 /* no data to send in buffer */ 43 44 if (tp->snd_nxt > last) { 45 46 /* should we send FIN? don't unless haven't already sent one */ 47 48 if ((tp->tc_flags&TC_SND_FIN) && 49 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 50 51 flags |= TH_FIN; 52 tp->seq_fin = tp->snd_lst++; 53 } 54 55 } else { /* there is data to send */ 56 57 /* send data only if there is a window defined */ 58 59 if (tp->tc_flags&TC_SYN_ACKED) { 60 61 wind = tp->snd_una + tp->snd_wnd; 62 63 /* use window to limit send */ 64 65 tp->snd_lst = min(last, wind); 66 67 /* make sure we don't do ip fragmentation */ 68 69 if ((len = tp->snd_lst - tp->snd_nxt) > 1024) 70 tp->snd_lst -= len - 1024; 71 72 /* set persist timer */ 73 74 if (tp->snd_lst >= wind) 75 tp->t_persist = T_PERS; 76 } 77 78 /* check if window is closed and must force a byte out */ 79 80 if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { 81 tp->snd_lst = tp->snd_nxt + 1; 82 forced = 1; 83 } 84 85 /* copy data to send from send buffer */ 86 87 m = tcp_sndcopy(tp, max(tp->iss+1,tp->snd_nxt), tp->snd_lst); 88 89 /* see if EOL should be sent */ 90 91 if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 92 flags |= TH_EOL; 93 94 /* must send FIN and no more data left to send after this */ 95 96 if ((tp->tc_flags&TC_SND_FIN) && !forced && 97 tp->snd_lst == last && 98 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 99 100 flags |= TH_FIN; 101 tp->seq_fin = tp->snd_lst++; 102 } 103 } 104 105 if (tp->snd_nxt < tp->snd_lst) { /* something to send */ 106 107 if (tp->tc_flags & TC_SND_URG) 108 flags |= TH_URG; 109 sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 110 /* set timers for retransmission if necessary */ 111 112 if (!forced) { 113 tp->t_rexmt = tp->t_xmtime; 114 tp->t_rexmt_val = tp->snd_lst; 115 116 if ((tp->tc_flags&TC_REXMT) == 0) { 117 tp->t_rexmttl = T_REXMTTL; 118 tp->t_rtl_val = tp->snd_lst; 119 } 120 121 } 122 123 /* update seq for next send if this one got out */ 124 125 if (sent) 126 tp->snd_nxt = tp->snd_lst; 127 128 129 /* if last timed message has been acked, start timing 130 this one */ 131 132 if ((tp->tc_flags&TC_SYN_ACKED) && tp->snd_una > tp->t_xmt_val) { 133 tp->t_xmt = 0; 134 tp->t_xmt_val = tp->snd_lst; 135 } 136 137 tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 138 tp->snd_hi = max(tp->snd_nxt, tp->snd_hi); 139 return (1); 140 } 141 142 return(0); 143 } 144 145 tcp_sndctl(tp) /* send a control msg */ 146 struct tcb *tp; 147 { 148 COUNT(SEND_CTL); 149 if (!send(tp)) { 150 tcp_sndnull(tp); 151 return(0); 152 } 153 return(1); 154 } 155 156 int printhave = 0; 157 158 tcp_sndwin(tp) 159 struct tcb *tp; 160 { 161 int ihave; 162 int hehas; 163 164 if (tp->rcv_adv) { 165 /* figure out window we would advertise */ 166 ihave = tp->t_ucb->uc_rhiwat - 167 (tp->t_ucb->uc_rcc + tp->seqcnt); 168 hehas = tp->rcv_adv - tp->rcv_nxt; 169 if (printhave) 170 printf("ihave %d, hehas %d\n", ihave, hehas); 171 if (hehas > 32 && 172 (100*(ihave-hehas)/tp->t_ucb->uc_rhiwat) < 35) 173 return; 174 if (printhave) 175 printf("update him\n"); 176 } 177 if (send(tp)) 178 return (1); 179 tcp_sndnull(tp); 180 return (0); 181 } 182 tcp_sndnull(tp) /* send only control information */ 183 register struct tcb *tp; 184 { 185 COUNT(SEND_NULL); 186 187 tcp_output(tp, 0, 0, (struct mbuf *)0); 188 tp->tc_flags &= ~TC_ACK_DUE; 189 } 190 191 tcp_sndrst(tp, n) /* send a reset */ 192 register struct tcb *tp; 193 register struct th *n; 194 { 195 COUNT(SEND_RST); 196 /* don't send a reset in response to a reset */ 197 198 if (n->th_flags&TH_RST) 199 return; 200 201 tp->tc_flags |= TC_SND_RST; 202 203 if (n->th_flags&TH_ACK) 204 tp->snd_nxt = n->t_ackno; 205 206 tp->tc_flags &= ~TC_SYN_RCVD; 207 tcp_sndnull(tp); 208 tp->tc_flags &= ~TC_SND_RST; 209 } 210 211 /* 212 * Create template to be used to send tcp packets on a connection. 213 * Call after host entry created, allocates an mbuf and fills 214 * in a skeletal tcp/ip header, minimizing the amount of work 215 * necessary when the connection is used. 216 */ 217 struct th * 218 tcp_template(tp) 219 struct tcb *tp; 220 { 221 register struct host *h = tp->t_ucb->uc_host; 222 register struct mbuf *m; 223 register struct th *n; 224 register struct ip *ip; 225 226 if (h == 0) 227 return (0); 228 m = m_get(1); 229 if (m == 0) 230 return (0); 231 m->m_off = MMAXOFF - sizeof (struct th); 232 m->m_len = sizeof (struct th); 233 n = mtod(m, struct th *); 234 n->t_next = n->t_prev = 0; 235 n->t_x1 = 0; 236 n->t_pr = TCPROTO; 237 n->t_len = htons(sizeof (struct th) - sizeof (struct ip)); 238 n->t_s.s_addr = n_lhost.s_addr; 239 n->t_d.s_addr = h->h_addr.s_addr; 240 n->t_src = htons(tp->t_lport); 241 n->t_dst = htons(tp->t_fport); 242 n->t_seq = 0; 243 n->t_ackno = 0; 244 n->t_x2 = 0; 245 n->t_off = 5; 246 n->th_flags = 0; 247 n->t_win = 0; 248 n->t_sum = 0; 249 n->t_urp = 0; 250 return (n); 251 } 252 253 tcp_output(tp, flags, len, dat) 254 register struct tcb *tp; 255 register int flags; 256 int len; 257 struct mbuf *dat; 258 { 259 register struct mbuf *m; 260 register struct th *t; 261 register struct ip *ip; 262 int i; 263 #ifdef TCPDEBUG 264 struct tcp_debug tdb; 265 #endif 266 COUNT(SEND_TCP); 267 268 if ((t = tp->t_ucb->uc_template) == 0) 269 return (0); 270 MGET(m, 0); 271 if (m == 0) 272 return (0); 273 m->m_off = MMAXOFF - sizeof(struct th); 274 m->m_len = sizeof (struct th); 275 m->m_next = dat; 276 if (flags & TH_SYN) 277 len--; 278 if (flags & TH_FIN) 279 len--; 280 bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th)); 281 t = mtod(m, struct th *); 282 if (tp->tc_flags&TC_SND_RST) { 283 flags &= ~TH_SYN; 284 flags |= TH_RST; 285 } 286 if (tp->tc_flags&TC_SYN_RCVD) 287 flags |= TH_ACK; 288 t->th_flags = flags; 289 if (flags & TH_URG) 290 t->t_urp = htons(tp->snd_urp); 291 t->t_win = 292 tp->t_ucb->uc_rhiwat - (tp->t_ucb->uc_rcc + tp->seqcnt); 293 if (tp->rcv_nxt + t->t_win > tp->rcv_adv) 294 tp->rcv_adv = tp->rcv_nxt + t->t_win; 295 if (len) 296 t->t_len = htons(len + TCPSIZE); 297 t->t_win = htons(t->t_win); 298 #ifdef TCPDEBUG 299 if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 300 t->t_seq = tp->snd_nxt; 301 t->t_ackno = tp->rcv_nxt; 302 tdb_setup(tp, t, INSEND, &tdb); 303 tdb_stuff(&tdb, -2); 304 } 305 #endif 306 t->t_seq = htonl(tp->snd_nxt); 307 t->t_ackno = htonl(tp->rcv_nxt); 308 t->t_sum = cksum(m, len + sizeof(struct th)); 309 ip = (struct ip *)t; 310 ip->ip_v = IPVERSION; 311 ip->ip_hl = 5; 312 ip->ip_tos = 0; 313 ip->ip_len = len + sizeof(struct th); 314 ip->ip_id = ip_id++; 315 ip->ip_off = 0; 316 ip->ip_ttl = MAXTTL; 317 i = ip_send(ip); 318 #ifdef notdef 319 if (tp->t_ucb->uc_flags & UDEBUG) { 320 w.w_dat = (char *)t; 321 w.w_stype = i; 322 tcp_debug(tp, &w, INRECV, -1); 323 } 324 #endif 325 return(i); 326 } 327 328 firstempty(tp) 329 register struct tcb *tp; 330 { 331 register struct th *p, *q; 332 COUNT(FIRSTEMPTY); 333 334 if ((p = tp->t_rcv_next) == (struct th *)tp || tp->rcv_nxt < p->t_seq) 335 return (tp->rcv_nxt); 336 while ((q = p->t_next) != (struct th *)tp && 337 (t_end(p) + 1) == q->t_seq) 338 p = q; 339 return (t_end(p) + 1); 340 } 341 342 /* SHOULD BE A MACRO, AFTER KEEP TRACK OF ASS Q SPACE */ 343 344 struct mbuf * 345 tcp_sndcopy(tp, start, end) 346 struct tcb *tp; 347 u_long start, end; 348 { 349 register struct mbuf *m, *n, **np; 350 u_long off; 351 register int len; 352 int adj; 353 struct mbuf *top, *p; 354 COUNT(SND_COPY); 355 356 /* 357 printf("st %x end %x off %x\n", start, end, tp->snd_off); 358 */ 359 if (start >= end) 360 return(NULL); 361 off = tp->snd_off; 362 m = tp->t_ucb->uc_sbuf; 363 while (m != NULL && start >= (off + m->m_len)) { 364 off += m->m_len; 365 m = m->m_next; 366 } 367 np = ⊤ 368 top = 0; 369 adj = start - off; 370 len = end - start; 371 while (m && len > 0) { 372 MGET(n, 1); 373 *np = n; 374 if (n == 0) 375 goto nospace; 376 n->m_len = MIN(len, m->m_len - adj); 377 if (m->m_off > MMAXOFF) { 378 p = mtod(m, struct mbuf *); 379 n->m_off = ((int)p - (int)n) + adj; 380 mprefcnt[mtopf(p)]++; 381 } else { 382 n->m_off = MMINOFF; 383 bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t), 384 n->m_len); 385 } 386 len -= n->m_len; 387 adj = 0; 388 m = m->m_next; 389 /* SHOULD TRY PACKING INTO SMALL MBUFS HERE */ 390 np = &n->m_next; 391 } 392 /* SHOULD NEVER RUN OUT OF m WHEN LEN */ 393 if (len) 394 printf("snd_copy: m %x len %d\n", m, len); 395 return (top); 396 nospace: 397 printf("snd_copy: no space\n"); 398 m_freem(top); 399 return (0); 400 } 401 402 tcp_enq(p, prev) 403 register struct th *p; 404 register struct th *prev; 405 { 406 407 p->t_prev = prev; 408 p->t_next = prev->t_next; 409 prev->t_next->t_prev = p; 410 prev->t_next = p; 411 } 412 413 tcp_deq(p) 414 register struct th *p; 415 { 416 417 p->t_prev->t_next = p->t_next; 418 p->t_next->t_prev = p->t_prev; 419 } 420