1 /* tcp_output.c 4.5 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 if (tp->snd_nxt >= tp->snd_lst) 107 return (0); 108 } else { 109 if (tp->tc_flags&TC_SYN_ACKED) { 110 wind = tp->snd_una + tp->snd_wnd; 111 tp->snd_lst = min(last, wind); 112 if ((len = tp->snd_lst - tp->snd_nxt) > 1024) 113 tp->snd_lst -= len - 1024; 114 if (tp->snd_lst >= wind) 115 tp->t_persist = T_PERS; 116 } 117 if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) { 118 tp->snd_lst = tp->snd_nxt + 1; 119 forced = 1; 120 } else if (tp->snd_nxt >= tp->snd_lst) 121 return (0); 122 m = tcp_sndcopy(tp, MAX(tp->iss+1,tp->snd_nxt), tp->snd_lst); 123 if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst) 124 flags |= TH_EOL; 125 if ((tp->tc_flags&TC_SND_FIN) && !forced && 126 tp->snd_lst == last && 127 (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) { 128 flags |= TH_FIN; 129 tp->seq_fin = tp->snd_lst++; 130 } 131 } 132 if (tp->tc_flags & TC_SND_URG) 133 flags |= TH_URG; 134 sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m); 135 if (!forced) { 136 tp->t_rexmt = tp->t_xmtime; 137 tp->t_rexmt_val = tp->snd_lst; 138 if ((tp->tc_flags&TC_REXMT) == 0) { 139 tp->t_rexmttl = T_REXMTTL; 140 tp->t_rtl_val = tp->snd_lst; 141 } 142 } 143 if (sent) 144 tp->snd_nxt = tp->snd_lst; 145 if ((tp->tc_flags&TC_SYN_ACKED) && 146 tp->snd_una > tp->t_xmt_val) { 147 tp->t_xmt = 0; 148 tp->t_xmt_val = tp->snd_lst; 149 } 150 tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE); 151 tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi); 152 return (1); 153 } 154 155 /* 156 * Create template to be used to send tcp packets on a connection. 157 * Call after host entry created, allocates an mbuf and fills 158 * in a skeletal tcp/ip header, minimizing the amount of work 159 * necessary when the connection is used. 160 */ 161 struct th * 162 tcp_template(tp) 163 struct tcb *tp; 164 { 165 register struct host *h = tp->t_ucb->uc_host; 166 register struct mbuf *m; 167 register struct th *n; 168 register struct ip *ip; 169 170 if (h == 0) 171 return (0); 172 m = m_get(1); 173 if (m == 0) 174 return (0); 175 m->m_off = MMAXOFF - sizeof (struct th); 176 m->m_len = sizeof (struct th); 177 n = mtod(m, struct th *); 178 n->t_next = n->t_prev = 0; 179 n->t_x1 = 0; 180 n->t_pr = TCPROTO; 181 n->t_len = htons(sizeof (struct th) - sizeof (struct ip)); 182 n->t_s.s_addr = n_lhost.s_addr; 183 n->t_d.s_addr = h->h_addr.s_addr; 184 n->t_src = htons(tp->t_lport); 185 n->t_dst = htons(tp->t_fport); 186 n->t_seq = 0; 187 n->t_ackno = 0; 188 n->t_x2 = 0; 189 n->t_off = 5; 190 n->th_flags = 0; 191 n->t_win = 0; 192 n->t_sum = 0; 193 n->t_urp = 0; 194 return (n); 195 } 196 197 tcp_output(tp, flags, len, dat) 198 register struct tcb *tp; 199 register int flags; 200 int len; 201 struct mbuf *dat; 202 { 203 register struct mbuf *m; 204 register struct th *t; 205 register struct ip *ip; 206 int i; 207 #ifdef TCPDEBUG 208 struct tcp_debug tdb; 209 #endif 210 COUNT(SEND_TCP); 211 212 if ((t = tp->t_ucb->uc_template) == 0) 213 return (0); 214 MGET(m, 0); 215 if (m == 0) 216 return (0); 217 m->m_off = MMAXOFF - sizeof(struct th); 218 m->m_len = sizeof (struct th); 219 m->m_next = dat; 220 if (flags & TH_SYN) 221 len--; 222 if (flags & TH_FIN) 223 len--; 224 bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th)); 225 t = mtod(m, struct th *); 226 if (tp->tc_flags&TC_SND_RST) { 227 flags &= ~TH_SYN; 228 flags |= TH_RST; 229 } 230 if (tp->tc_flags&TC_SYN_RCVD) 231 flags |= TH_ACK; 232 t->th_flags = flags; 233 if (flags & TH_URG) 234 t->t_urp = htons(tp->snd_urp); 235 t->t_win = 236 tp->t_ucb->uc_rhiwat - (tp->t_ucb->uc_rcc + tp->seqcnt); 237 if (tp->rcv_nxt + t->t_win > tp->rcv_adv) 238 tp->rcv_adv = tp->rcv_nxt + t->t_win; 239 if (len) 240 t->t_len = htons(len + TCPSIZE); 241 t->t_win = htons(t->t_win); 242 #ifdef TCPDEBUG 243 if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 244 t->t_seq = tp->snd_nxt; 245 t->t_ackno = tp->rcv_nxt; 246 tdb_setup(tp, t, INSEND, &tdb); 247 tdb_stuff(&tdb, -2); 248 } 249 #endif 250 t->t_seq = htonl(tp->snd_nxt); 251 t->t_ackno = htonl(tp->rcv_nxt); 252 t->t_sum = cksum(m, len + sizeof(struct th)); 253 ip = (struct ip *)t; 254 ip->ip_v = IPVERSION; 255 ip->ip_hl = 5; 256 ip->ip_tos = 0; 257 ip->ip_len = len + sizeof(struct th); 258 ip->ip_id = ip_id++; 259 ip->ip_off = 0; 260 ip->ip_ttl = MAXTTL; 261 i = ip_send(ip); 262 return(i); 263 } 264 265 firstempty(tp) 266 register struct tcb *tp; 267 { 268 register struct th *p, *q; 269 COUNT(FIRSTEMPTY); 270 271 if ((p = tp->t_rcv_next) == (struct th *)tp || tp->rcv_nxt < p->t_seq) 272 return (tp->rcv_nxt); 273 while ((q = p->t_next) != (struct th *)tp && 274 (t_end(p) + 1) == q->t_seq) 275 p = q; 276 return (t_end(p) + 1); 277 } 278 279 struct mbuf * 280 tcp_sndcopy(tp, start, end) 281 struct tcb *tp; 282 u_long start, end; 283 { 284 register struct mbuf *m, *n, **np; 285 u_long off; 286 register int len; 287 int adj; 288 struct mbuf *top, *p; 289 COUNT(SND_COPY); 290 291 if (start >= end) 292 return(NULL); 293 off = tp->snd_off; 294 m = tp->t_ucb->uc_sbuf; 295 while (m != NULL && start >= (off + m->m_len)) { 296 off += m->m_len; 297 m = m->m_next; 298 } 299 np = ⊤ 300 top = 0; 301 adj = start - off; 302 len = end - start; 303 while (m && len > 0) { 304 MGET(n, 1); 305 *np = n; 306 if (n == 0) 307 goto nospace; 308 n->m_len = MIN(len, m->m_len - adj); 309 if (m->m_off > MMAXOFF) { 310 p = mtod(m, struct mbuf *); 311 n->m_off = ((int)p - (int)n) + adj; 312 mprefcnt[mtopf(p)]++; 313 } else { 314 n->m_off = MMINOFF; 315 bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t), 316 n->m_len); 317 } 318 len -= n->m_len; 319 adj = 0; 320 m = m->m_next; 321 /* SHOULD TRY PACKING INTO SMALL MBUFS HERE */ 322 np = &n->m_next; 323 } 324 /* SHOULD NEVER RUN OUT OF m WHEN LEN */ 325 if (len) 326 printf("snd_copy: m %x len %d\n", m, len); 327 return (top); 328 nospace: 329 printf("snd_copy: no space\n"); 330 m_freem(top); 331 return (0); 332 } 333