1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 * 12 * @(#)tcp_subr.c 7.13 (Berkeley) 12/07/87 13 */ 14 15 #include "param.h" 16 #include "systm.h" 17 #include "mbuf.h" 18 #include "socket.h" 19 #include "socketvar.h" 20 #include "protosw.h" 21 #include "errno.h" 22 23 #include "../net/route.h" 24 #include "../net/if.h" 25 26 #include "in.h" 27 #include "in_pcb.h" 28 #include "in_systm.h" 29 #include "ip.h" 30 #include "ip_var.h" 31 #include "ip_icmp.h" 32 #include "tcp.h" 33 #include "tcp_fsm.h" 34 #include "tcp_seq.h" 35 #include "tcp_timer.h" 36 #include "tcp_var.h" 37 #include "tcpip.h" 38 39 int tcp_ttl = TCP_TTL; 40 41 /* 42 * Tcp initialization 43 */ 44 tcp_init() 45 { 46 47 tcp_iss = 1; /* wrong */ 48 tcb.inp_next = tcb.inp_prev = &tcb; 49 } 50 51 /* 52 * Create template to be used to send tcp packets on a connection. 53 * Call after host entry created, allocates an mbuf and fills 54 * in a skeletal tcp/ip header, minimizing the amount of work 55 * necessary when the connection is used. 56 */ 57 struct tcpiphdr * 58 tcp_template(tp) 59 struct tcpcb *tp; 60 { 61 register struct inpcb *inp = tp->t_inpcb; 62 register struct mbuf *m; 63 register struct tcpiphdr *n; 64 65 if ((n = tp->t_template) == 0) { 66 m = m_get(M_DONTWAIT, MT_HEADER); 67 if (m == NULL) 68 return (0); 69 m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 70 m->m_len = sizeof (struct tcpiphdr); 71 n = mtod(m, struct tcpiphdr *); 72 } 73 n->ti_next = n->ti_prev = 0; 74 n->ti_x1 = 0; 75 n->ti_pr = IPPROTO_TCP; 76 n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); 77 n->ti_src = inp->inp_laddr; 78 n->ti_dst = inp->inp_faddr; 79 n->ti_sport = inp->inp_lport; 80 n->ti_dport = inp->inp_fport; 81 n->ti_seq = 0; 82 n->ti_ack = 0; 83 n->ti_x2 = 0; 84 n->ti_off = 5; 85 n->ti_flags = 0; 86 n->ti_win = 0; 87 n->ti_sum = 0; 88 n->ti_urp = 0; 89 return (n); 90 } 91 92 /* 93 * Send a single message to the TCP at address specified by 94 * the given TCP/IP header. If flags==0, then we make a copy 95 * of the tcpiphdr at ti and send directly to the addressed host. 96 * This is used to force keep alive messages out using the TCP 97 * template for a connection tp->t_template. If flags are given 98 * then we send a message back to the TCP which originated the 99 * segment ti, and discard the mbuf containing it and any other 100 * attached mbufs. 101 * 102 * In any case the ack and sequence number of the transmitted 103 * segment are as specified by the parameters. 104 */ 105 tcp_respond(tp, ti, ack, seq, flags) 106 struct tcpcb *tp; 107 register struct tcpiphdr *ti; 108 tcp_seq ack, seq; 109 int flags; 110 { 111 register struct mbuf *m; 112 int win = 0, tlen; 113 struct route *ro = 0; 114 115 if (tp) { 116 win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); 117 ro = &tp->t_inpcb->inp_route; 118 } 119 if (flags == 0) { 120 m = m_get(M_DONTWAIT, MT_HEADER); 121 if (m == NULL) 122 return; 123 #ifdef TCP_COMPAT_42 124 tlen = 1; 125 #else 126 tlen = 0; 127 #endif 128 m->m_len = sizeof (struct tcpiphdr) + tlen; 129 *mtod(m, struct tcpiphdr *) = *ti; 130 ti = mtod(m, struct tcpiphdr *); 131 flags = TH_ACK; 132 } else { 133 m = dtom(ti); 134 m_freem(m->m_next); 135 m->m_next = 0; 136 m->m_off = (int)ti - (int)m; 137 tlen = 0; 138 m->m_len = sizeof (struct tcpiphdr); 139 #define xchg(a,b,type) { type t; t=a; a=b; b=t; } 140 xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); 141 xchg(ti->ti_dport, ti->ti_sport, u_short); 142 #undef xchg 143 } 144 ti->ti_next = ti->ti_prev = 0; 145 ti->ti_x1 = 0; 146 ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); 147 ti->ti_seq = htonl(seq); 148 ti->ti_ack = htonl(ack); 149 ti->ti_x2 = 0; 150 ti->ti_off = sizeof (struct tcphdr) >> 2; 151 ti->ti_flags = flags; 152 ti->ti_win = htons((u_short)win); 153 ti->ti_urp = 0; 154 ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + tlen); 155 ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + tlen; 156 ((struct ip *)ti)->ip_ttl = tcp_ttl; 157 (void) ip_output(m, (struct mbuf *)0, ro, 0); 158 } 159 160 /* 161 * Create a new TCP control block, making an 162 * empty reassembly queue and hooking it to the argument 163 * protocol control block. 164 */ 165 struct tcpcb * 166 tcp_newtcpcb(inp) 167 struct inpcb *inp; 168 { 169 struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB); 170 register struct tcpcb *tp; 171 172 if (m == NULL) 173 return ((struct tcpcb *)0); 174 tp = mtod(m, struct tcpcb *); 175 tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 176 tp->t_maxseg = TCP_MSS; 177 tp->t_flags = 0; /* sends options! */ 178 tp->t_inpcb = inp; 179 /* 180 * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no 181 * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives 182 * reasonable initial retransmit time. 183 */ 184 tp->t_srtt = TCPTV_SRTTBASE; 185 tp->t_rttvar = TCPTV_SRTTDFLT << 2; 186 TCPT_RANGESET(tp->t_rxtcur, 187 ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, 188 TCPTV_MIN, TCPTV_REXMTMAX); 189 tp->snd_cwnd = sbspace(&inp->inp_socket->so_snd); 190 tp->snd_ssthresh = 65535; /* XXX */ 191 inp->inp_ppcb = (caddr_t)tp; 192 return (tp); 193 } 194 195 /* 196 * Drop a TCP connection, reporting 197 * the specified error. If connection is synchronized, 198 * then send a RST to peer. 199 */ 200 struct tcpcb * 201 tcp_drop(tp, errno) 202 register struct tcpcb *tp; 203 int errno; 204 { 205 struct socket *so = tp->t_inpcb->inp_socket; 206 207 if (TCPS_HAVERCVDSYN(tp->t_state)) { 208 tp->t_state = TCPS_CLOSED; 209 (void) tcp_output(tp); 210 tcpstat.tcps_drops++; 211 } else 212 tcpstat.tcps_conndrops++; 213 so->so_error = errno; 214 return (tcp_close(tp)); 215 } 216 217 /* 218 * Close a TCP control block: 219 * discard all space held by the tcp 220 * discard internet protocol block 221 * wake up any sleepers 222 */ 223 struct tcpcb * 224 tcp_close(tp) 225 register struct tcpcb *tp; 226 { 227 register struct tcpiphdr *t; 228 struct inpcb *inp = tp->t_inpcb; 229 struct socket *so = inp->inp_socket; 230 register struct mbuf *m; 231 232 t = tp->seg_next; 233 while (t != (struct tcpiphdr *)tp) { 234 t = (struct tcpiphdr *)t->ti_next; 235 m = dtom(t->ti_prev); 236 remque(t->ti_prev); 237 m_freem(m); 238 } 239 if (tp->t_template) 240 (void) m_free(dtom(tp->t_template)); 241 (void) m_free(dtom(tp)); 242 inp->inp_ppcb = 0; 243 soisdisconnected(so); 244 in_pcbdetach(inp); 245 tcpstat.tcps_closed++; 246 return ((struct tcpcb *)0); 247 } 248 249 tcp_drain() 250 { 251 252 } 253 254 /* 255 * Notify a tcp user of an asynchronous error; 256 * just wake up so that he can collect error status. 257 */ 258 tcp_notify(inp) 259 register struct inpcb *inp; 260 { 261 262 wakeup((caddr_t) &inp->inp_socket->so_timeo); 263 sorwakeup(inp->inp_socket); 264 sowwakeup(inp->inp_socket); 265 } 266 tcp_ctlinput(cmd, sa) 267 int cmd; 268 struct sockaddr *sa; 269 { 270 extern u_char inetctlerrmap[]; 271 struct sockaddr_in *sin; 272 int tcp_quench(), in_rtchange(); 273 274 if ((unsigned)cmd > PRC_NCMDS) 275 return; 276 if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 277 return; 278 sin = (struct sockaddr_in *)sa; 279 if (sin->sin_addr.s_addr == INADDR_ANY) 280 return; 281 282 switch (cmd) { 283 284 case PRC_QUENCH: 285 in_pcbnotify(&tcb, &sin->sin_addr, 0, tcp_quench); 286 break; 287 288 case PRC_ROUTEDEAD: 289 case PRC_REDIRECT_NET: 290 case PRC_REDIRECT_HOST: 291 case PRC_REDIRECT_TOSNET: 292 case PRC_REDIRECT_TOSHOST: 293 in_pcbnotify(&tcb, &sin->sin_addr, 0, in_rtchange); 294 break; 295 296 default: 297 if (inetctlerrmap[cmd] == 0) 298 return; /* XXX */ 299 in_pcbnotify(&tcb, &sin->sin_addr, (int)inetctlerrmap[cmd], 300 tcp_notify); 301 } 302 } 303 304 /* 305 * When a source quench is received, close congestion window 306 * to one segment. We will gradually open it again as we proceed. 307 */ 308 tcp_quench(inp) 309 struct inpcb *inp; 310 { 311 struct tcpcb *tp = intotcpcb(inp); 312 313 if (tp) 314 tp->snd_cwnd = tp->t_maxseg; 315 } 316