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