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