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