1 /* 2 * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $Id: tcp_subr.c,v 1.1 94/10/20 10:53:41 root Exp $ 34 */ 35 36 #include "sys/param.h" 37 #include "systm.h" 38 #include "malloc.h" 39 #include "mbuf.h" 40 #include "sys/file.h" 41 #include "socketvar.h" 42 #include "protosw.h" 43 #include "sys/errno.h" 44 #include "prototypes.h" 45 46 #include "route.h" 47 #include "if.h" 48 49 #include "in.h" 50 #include "in_systm.h" 51 #include "ip.h" 52 #include "in_pcb.h" 53 #include "ip_var.h" 54 #include "ip_icmp.h" 55 #include "tcp.h" 56 #include "tcp_fsm.h" 57 #include "tcp_seq.h" 58 #include "tcp_timer.h" 59 #include "tcp_var.h" 60 #include "tcpip.h" 61 62 /* patchable/settable parameters for tcp */ 63 int tcp_ttl = TCP_TTL; 64 int tcp_mssdflt = TCP_MSS; 65 int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; 66 67 extern struct inpcb *tcp_last_inpcb; 68 69 /* 70 * Tcp initialization 71 */ 72 tcp_init() 73 { 74 75 tcp_iss = 1; /* wrong */ 76 tcb.inp_next = tcb.inp_prev = &tcb; 77 if (max_protohdr < sizeof(struct tcpiphdr)) 78 max_protohdr = sizeof(struct tcpiphdr); 79 if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN) 80 panic("tcp_init"); 81 } 82 83 /* 84 * Create template to be used to send tcp packets on a connection. 85 * Call after host entry created, allocates an mbuf and fills 86 * in a skeletal tcp/ip header, minimizing the amount of work 87 * necessary when the connection is used. 88 */ 89 struct tcpiphdr * 90 tcp_template(tp) 91 struct tcpcb *tp; 92 { 93 register struct inpcb *inp = tp->t_inpcb; 94 register struct mbuf *m; 95 register struct tcpiphdr *n; 96 97 if ((n = tp->t_template) == 0) { 98 m = m_get(M_DONTWAIT, MT_HEADER); 99 if (m == NULL) 100 return (0); 101 m->m_len = sizeof (struct tcpiphdr); 102 n = mtod(m, struct tcpiphdr *); 103 } 104 n->ti_next = n->ti_prev = 0; 105 n->ti_x1 = 0; 106 n->ti_pr = IPPROTO_TCP; 107 n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); 108 n->ti_src = inp->inp_laddr; 109 n->ti_dst = inp->inp_faddr; 110 n->ti_sport = inp->inp_lport; 111 n->ti_dport = inp->inp_fport; 112 n->ti_seq = 0; 113 n->ti_ack = 0; 114 n->ti_x2 = 0; 115 n->ti_off = 5; 116 n->ti_flags = 0; 117 n->ti_win = 0; 118 n->ti_sum = 0; 119 n->ti_urp = 0; 120 return (n); 121 } 122 123 /* 124 * Send a single message to the TCP at address specified by 125 * the given TCP/IP header. If m == 0, then we make a copy 126 * of the tcpiphdr at ti and send directly to the addressed host. 127 * This is used to force keep alive messages out using the TCP 128 * template for a connection tp->t_template. If flags are given 129 * then we send a message back to the TCP which originated the 130 * segment ti, and discard the mbuf containing it and any other 131 * attached mbufs. 132 * 133 * In any case the ack and sequence number of the transmitted 134 * segment are as specified by the parameters. 135 */ 136 tcp_respond(tp, ti, m, ack, seq, flags) 137 struct tcpcb *tp; 138 register struct tcpiphdr *ti; 139 register struct mbuf *m; 140 tcp_seq ack, seq; 141 int flags; 142 { 143 register int tlen; 144 int win = 0; 145 struct route *ro = 0; 146 147 if (tp) { 148 win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); 149 ro = &tp->t_inpcb->inp_route; 150 } 151 if (m == 0) { 152 m = m_gethdr(M_DONTWAIT, MT_HEADER); 153 if (m == NULL) 154 return; 155 #ifdef TCP_COMPAT_42 156 tlen = 1; 157 #else 158 tlen = 0; 159 #endif 160 m->m_data += max_linkhdr; 161 *mtod(m, struct tcpiphdr *) = *ti; 162 ti = mtod(m, struct tcpiphdr *); 163 flags = TH_ACK; 164 } else { 165 m_freem(m->m_next); 166 m->m_next = 0; 167 m->m_data = (caddr_t)ti; 168 m->m_len = sizeof (struct tcpiphdr); 169 tlen = 0; 170 #define xchg(a,b,type) { type t; t=a; a=b; b=t; } 171 xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); 172 xchg(ti->ti_dport, ti->ti_sport, u_short); 173 #undef xchg 174 } 175 ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); 176 tlen += sizeof (struct tcpiphdr); 177 m->m_len = tlen; 178 m->m_pkthdr.len = tlen; 179 m->m_pkthdr.rcvif = (struct ifnet *) 0; 180 ti->ti_next = ti->ti_prev = 0; 181 ti->ti_x1 = 0; 182 ti->ti_seq = htonl(seq); 183 ti->ti_ack = htonl(ack); 184 ti->ti_x2 = 0; 185 ti->ti_off = sizeof (struct tcphdr) >> 2; 186 ti->ti_flags = flags; 187 ti->ti_win = htons((u_short)win); 188 ti->ti_urp = 0; 189 ti->ti_sum = in_cksum(m, tlen); 190 ((struct ip *)ti)->ip_len = tlen; 191 ((struct ip *)ti)->ip_ttl = tcp_ttl; 192 (void) ip_output(m, (struct mbuf *)0, ro, 0); 193 } 194 195 /* 196 * Create a new TCP control block, making an 197 * empty reassembly queue and hooking it to the argument 198 * protocol control block. 199 */ 200 struct tcpcb * 201 tcp_newtcpcb(inp) 202 struct inpcb *inp; 203 { 204 struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB); 205 register struct tcpcb *tp; 206 207 if (m == NULL) 208 return ((struct tcpcb *)0); 209 tp = mtod(m, struct tcpcb *); 210 tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 211 tp->t_maxseg = tcp_mssdflt; 212 213 tp->t_flags = 0; /* sends options! */ 214 tp->t_inpcb = inp; 215 /* 216 * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no 217 * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives 218 * reasonable initial retransmit time. 219 */ 220 tp->t_srtt = TCPTV_SRTTBASE; 221 tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; 222 tp->t_rttmin = TCPTV_MIN; 223 TCPT_RANGESET(tp->t_rxtcur, 224 ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, 225 TCPTV_MIN, TCPTV_REXMTMAX); 226 tp->snd_cwnd = TCP_MAXWIN; 227 tp->snd_ssthresh = TCP_MAXWIN; 228 inp->inp_ip.ip_ttl = tcp_ttl; 229 inp->inp_ppcb = (caddr_t)tp; 230 return (tp); 231 } 232 233 /* 234 * Drop a TCP connection, reporting 235 * the specified error. If connection is synchronized, 236 * then send a RST to peer. 237 */ 238 struct tcpcb * 239 tcp_drop(tp, errno) 240 register struct tcpcb *tp; 241 int errno; 242 { 243 struct socket *so = tp->t_inpcb->inp_socket; 244 245 if (TCPS_HAVERCVDSYN(tp->t_state)) { 246 tp->t_state = TCPS_CLOSED; 247 (void) tcp_output(tp); 248 tcpstat.tcps_drops++; 249 } else 250 tcpstat.tcps_conndrops++; 251 if (errno == ETIMEDOUT && tp->t_softerror) 252 errno = tp->t_softerror; 253 so->so_error = errno; 254 return (tcp_close(tp)); 255 } 256 257 /* 258 * Close a TCP control block: 259 * discard all space held by the tcp 260 * discard internet protocol block 261 * wake up any sleepers 262 */ 263 struct tcpcb * 264 tcp_close(tp) 265 register struct tcpcb *tp; 266 { 267 register struct tcpiphdr *t; 268 struct inpcb *inp = tp->t_inpcb; 269 struct socket *so = inp->inp_socket; 270 register struct mbuf *m; 271 #ifdef RTV_RTT 272 register struct rtentry *rt; 273 274 /* 275 * If we sent enough data to get some meaningful characteristics, 276 * save them in the routing entry. 'Enough' is arbitrarily 277 * defined as the sendpipesize (default 4K) * 16. This would 278 * give us 16 rtt samples assuming we only get one sample per 279 * window (the usual case on a long haul net). 16 samples is 280 * enough for the srtt filter to converge to within 5% of the correct 281 * value; fewer samples and we could save a very bogus rtt. 282 * 283 * Don't update the default route's characteristics and don't 284 * update anything that the user "locked". 285 */ 286 if (SEQ_LT(tp->iss + so->so_snd.sb_hiwat * 16, tp->snd_max) && 287 (rt = inp->inp_route.ro_rt) && 288 ((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) { 289 register u_long i; 290 291 if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) { 292 i = tp->t_srtt * 293 (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); 294 if (rt->rt_rmx.rmx_rtt && i) 295 /* 296 * filter this update to half the old & half 297 * the new values, converting scale. 298 * See route.h and tcp_var.h for a 299 * description of the scaling constants. 300 */ 301 rt->rt_rmx.rmx_rtt = 302 (rt->rt_rmx.rmx_rtt + i) / 2; 303 else 304 rt->rt_rmx.rmx_rtt = i; 305 } 306 if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) { 307 i = tp->t_rttvar * 308 (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); 309 if (rt->rt_rmx.rmx_rttvar && i) 310 rt->rt_rmx.rmx_rttvar = 311 (rt->rt_rmx.rmx_rttvar + i) / 2; 312 else 313 rt->rt_rmx.rmx_rttvar = i; 314 } 315 /* 316 * update the pipelimit (ssthresh) if it has been updated 317 * already or if a pipesize was specified & the threshhold 318 * got below half the pipesize. I.e., wait for bad news 319 * before we start updating, then update on both good 320 * and bad news. 321 */ 322 if ((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 && 323 (i = tp->snd_ssthresh) && rt->rt_rmx.rmx_ssthresh || 324 i < (rt->rt_rmx.rmx_sendpipe / 2)) { 325 /* 326 * convert the limit from user data bytes to 327 * packets then to packet data bytes. 328 */ 329 i = (i + tp->t_maxseg / 2) / tp->t_maxseg; 330 if (i < 2) 331 i = 2; 332 i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr)); 333 if (rt->rt_rmx.rmx_ssthresh) 334 rt->rt_rmx.rmx_ssthresh = 335 (rt->rt_rmx.rmx_ssthresh + i) / 2; 336 else 337 rt->rt_rmx.rmx_ssthresh = i; 338 } 339 } 340 #endif RTV_RTT 341 /* free the reassembly queue, if any */ 342 t = tp->seg_next; 343 while (t != (struct tcpiphdr *)tp) { 344 t = (struct tcpiphdr *)t->ti_next; 345 m = REASS_MBUF((struct tcpiphdr *)t->ti_prev); 346 remque(t->ti_prev); 347 m_freem(m); 348 } 349 if (tp->t_template) 350 (void) m_free(dtom(tp->t_template)); 351 (void) m_free(dtom(tp)); 352 inp->inp_ppcb = 0; 353 soisdisconnected(so); 354 /* clobber input pcb cache if we're closing the cached connection */ 355 if (inp == tcp_last_inpcb) 356 tcp_last_inpcb = &tcb; 357 in_pcbdetach(inp); 358 tcpstat.tcps_closed++; 359 return ((struct tcpcb *)0); 360 } 361 362 tcp_drain() 363 { 364 365 } 366 367 /* 368 * Notify a tcp user of an asynchronous error; 369 * store error as soft error, but wake up user 370 * (for now, won't do anything until can select for soft error). 371 */ 372 tcp_notify(inp, error) 373 register struct inpcb *inp; 374 int error; 375 { 376 377 ((struct tcpcb *)inp->inp_ppcb)->t_softerror = error; 378 wakeup((caddr_t) &inp->inp_socket->so_timeo); 379 sorwakeup(inp->inp_socket); 380 sowwakeup(inp->inp_socket); 381 } 382 383 tcp_ctlinput(cmd, sa, ip) 384 int cmd; 385 struct sockaddr *sa; 386 register struct ip *ip; 387 { 388 register struct tcphdr *th; 389 extern struct in_addr zeroin_addr; 390 extern u_char inetctlerrmap[]; 391 int (*notify)() = tcp_notify, tcp_quench(); 392 393 if (cmd == PRC_QUENCH) 394 notify = tcp_quench; 395 else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) 396 return; 397 if (ip) { 398 th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 399 in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport, 400 cmd, notify); 401 } else 402 in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify); 403 } 404 405 /* 406 * When a source quench is received, close congestion window 407 * to one segment. We will gradually open it again as we proceed. 408 */ 409 tcp_quench(inp) 410 struct inpcb *inp; 411 { 412 struct tcpcb *tp = intotcpcb(inp); 413 414 if (tp) 415 tp->snd_cwnd = tp->t_maxseg; 416 } 417