add patchable udp ttl
[unix-history] / usr / src / sys / netinet / tcp_subr.c
CommitLineData
8ae0e4b4 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
8ae0e4b4
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
10604dba 6 * @(#)tcp_subr.c 7.5 (Berkeley) %G%
8ae0e4b4 7 */
ecaa4e6f 8
20666ad3
JB
9#include "param.h"
10#include "systm.h"
11#include "mbuf.h"
12#include "socket.h"
13#include "socketvar.h"
14#include "protosw.h"
15#include "errno.h"
f4d55810 16
c124e997 17#include "../net/route.h"
f4d55810
SL
18#include "../net/if.h"
19
20666ad3
JB
20#include "in.h"
21#include "in_pcb.h"
22#include "in_systm.h"
23#include "ip.h"
24#include "ip_var.h"
25#include "ip_icmp.h"
26#include "tcp.h"
27#include "tcp_fsm.h"
28#include "tcp_seq.h"
29#include "tcp_timer.h"
30#include "tcp_var.h"
31#include "tcpip.h"
ecaa4e6f 32
10604dba
MK
33int tcp_ttl = TCP_TTL;
34float tcp_alpha = TCP_ALPHA;
35float tcp_beta = TCP_BETA;
36
ecaa4e6f
BJ
37/*
38 * Tcp initialization
39 */
40tcp_init()
41{
42
43 tcp_iss = 1; /* wrong */
44 tcb.inp_next = tcb.inp_prev = &tcb;
45}
46
47/*
48 * Create template to be used to send tcp packets on a connection.
49 * Call after host entry created, allocates an mbuf and fills
50 * in a skeletal tcp/ip header, minimizing the amount of work
51 * necessary when the connection is used.
52 */
53struct tcpiphdr *
54tcp_template(tp)
55 struct tcpcb *tp;
56{
57 register struct inpcb *inp = tp->t_inpcb;
58 register struct mbuf *m;
59 register struct tcpiphdr *n;
60
ece01391
MK
61 if ((n = tp->t_template) == 0) {
62 m = m_get(M_WAIT, MT_HEADER);
63 if (m == NULL)
64 return (0);
65 m->m_off = MMAXOFF - sizeof (struct tcpiphdr);
66 m->m_len = sizeof (struct tcpiphdr);
67 n = mtod(m, struct tcpiphdr *);
68 }
ecaa4e6f
BJ
69 n->ti_next = n->ti_prev = 0;
70 n->ti_x1 = 0;
71 n->ti_pr = IPPROTO_TCP;
72 n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
73 n->ti_src = inp->inp_laddr;
74 n->ti_dst = inp->inp_faddr;
75 n->ti_sport = inp->inp_lport;
76 n->ti_dport = inp->inp_fport;
77 n->ti_seq = 0;
0974b45c 78 n->ti_ack = 0;
ecaa4e6f
BJ
79 n->ti_x2 = 0;
80 n->ti_off = 5;
81 n->ti_flags = 0;
82 n->ti_win = 0;
83 n->ti_sum = 0;
84 n->ti_urp = 0;
85 return (n);
86}
87
88/*
405c9168
BJ
89 * Send a single message to the TCP at address specified by
90 * the given TCP/IP header. If flags==0, then we make a copy
91 * of the tcpiphdr at ti and send directly to the addressed host.
92 * This is used to force keep alive messages out using the TCP
93 * template for a connection tp->t_template. If flags are given
94 * then we send a message back to the TCP which originated the
95 * segment ti, and discard the mbuf containing it and any other
96 * attached mbufs.
97 *
98 * In any case the ack and sequence number of the transmitted
99 * segment are as specified by the parameters.
ecaa4e6f 100 */
8e65fd66
BJ
101tcp_respond(tp, ti, ack, seq, flags)
102 struct tcpcb *tp;
ecaa4e6f 103 register struct tcpiphdr *ti;
0974b45c 104 tcp_seq ack, seq;
ecaa4e6f
BJ
105 int flags;
106{
8b6ad229 107 register struct mbuf *m;
1e977657 108 int win = 0, tlen;
c124e997 109 struct route *ro = 0;
8b6ad229 110 extern int tcp_keeplen;
ecaa4e6f 111
c124e997 112 if (tp) {
8e65fd66 113 win = sbspace(&tp->t_inpcb->inp_socket->so_rcv);
c124e997
SL
114 ro = &tp->t_inpcb->inp_route;
115 }
405c9168 116 if (flags == 0) {
cce93e4b 117 m = m_get(M_DONTWAIT, MT_HEADER);
5cdc4d65 118 if (m == NULL)
405c9168 119 return;
8b6ad229
MK
120 tlen = tcp_keeplen;
121 m->m_len = sizeof (struct tcpiphdr) + tlen;
405c9168
BJ
122 *mtod(m, struct tcpiphdr *) = *ti;
123 ti = mtod(m, struct tcpiphdr *);
124 flags = TH_ACK;
125 } else {
4aed14e3 126 m = dtom(ti);
405c9168
BJ
127 m_freem(m->m_next);
128 m->m_next = 0;
1acff8ec 129 m->m_off = (int)ti - (int)m;
8b6ad229 130 tlen = 0;
405c9168 131 m->m_len = sizeof (struct tcpiphdr);
0974b45c 132#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
405c9168
BJ
133 xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long);
134 xchg(ti->ti_dport, ti->ti_sport, u_short);
ecaa4e6f 135#undef xchg
405c9168 136 }
0974b45c
BJ
137 ti->ti_next = ti->ti_prev = 0;
138 ti->ti_x1 = 0;
af8f6a21 139 ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
2c48b3f8
BJ
140 ti->ti_seq = htonl(seq);
141 ti->ti_ack = htonl(ack);
0974b45c
BJ
142 ti->ti_x2 = 0;
143 ti->ti_off = sizeof (struct tcphdr) >> 2;
ecaa4e6f 144 ti->ti_flags = flags;
af8f6a21 145 ti->ti_win = htons((u_short)win);
8e65fd66 146 ti->ti_urp = 0;
f3cdd721 147 ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + tlen);
1e977657 148 ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + tlen;
10604dba 149 ((struct ip *)ti)->ip_ttl = tcp_ttl;
c124e997 150 (void) ip_output(m, (struct mbuf *)0, ro, 0);
ecaa4e6f 151}
a6503abf 152
0974b45c
BJ
153/*
154 * Create a new TCP control block, making an
155 * empty reassembly queue and hooking it to the argument
156 * protocol control block.
157 */
a6503abf
BJ
158struct tcpcb *
159tcp_newtcpcb(inp)
160 struct inpcb *inp;
161{
cce93e4b 162 struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
a6503abf 163 register struct tcpcb *tp;
a6503abf 164
5cdc4d65
SL
165 if (m == NULL)
166 return ((struct tcpcb *)0);
a6503abf 167 tp = mtod(m, struct tcpcb *);
a6503abf 168 tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
247c6a81 169 tp->t_maxseg = TCP_MSS;
3e60e1e6 170 tp->t_flags = 0; /* sends options! */
a6503abf 171 tp->t_inpcb = inp;
247c6a81 172 tp->t_srtt = TCPTV_SRTTBASE;
05586739 173 tp->snd_cwnd = sbspace(&inp->inp_socket->so_snd);
a6503abf
BJ
174 inp->inp_ppcb = (caddr_t)tp;
175 return (tp);
176}
177
0974b45c
BJ
178/*
179 * Drop a TCP connection, reporting
180 * the specified error. If connection is synchronized,
181 * then send a RST to peer.
182 */
0e3936fa 183struct tcpcb *
a6503abf 184tcp_drop(tp, errno)
0e3936fa 185 register struct tcpcb *tp;
a6503abf
BJ
186 int errno;
187{
188 struct socket *so = tp->t_inpcb->inp_socket;
189
d3504cc0 190 if (TCPS_HAVERCVDSYN(tp->t_state)) {
a6503abf 191 tp->t_state = TCPS_CLOSED;
39d536e6 192 (void) tcp_output(tp);
35f3fc10
MK
193 tcpstat.tcps_drops++;
194 } else
195 tcpstat.tcps_conndrops++;
a6503abf 196 so->so_error = errno;
0e3936fa 197 return (tcp_close(tp));
a6503abf
BJ
198}
199
0974b45c
BJ
200/*
201 * Close a TCP control block:
202 * discard all space held by the tcp
203 * discard internet protocol block
204 * wake up any sleepers
205 */
0e3936fa 206struct tcpcb *
a6503abf
BJ
207tcp_close(tp)
208 register struct tcpcb *tp;
209{
210 register struct tcpiphdr *t;
364801f5
BJ
211 struct inpcb *inp = tp->t_inpcb;
212 struct socket *so = inp->inp_socket;
13e2480b 213 register struct mbuf *m;
a6503abf 214
a6503abf 215 t = tp->seg_next;
13e2480b
SL
216 while (t != (struct tcpiphdr *)tp) {
217 t = (struct tcpiphdr *)t->ti_next;
218 m = dtom(t->ti_prev);
219 remque(t->ti_prev);
220 m_freem(m);
221 }
0974b45c 222 if (tp->t_template)
a6503abf 223 (void) m_free(dtom(tp->t_template));
0974b45c
BJ
224 if (tp->t_tcpopt)
225 (void) m_free(dtom(tp->t_tcpopt));
a6503abf 226 (void) m_free(dtom(tp));
364801f5 227 inp->inp_ppcb = 0;
4aed14e3 228 soisdisconnected(so);
86676257 229 in_pcbdetach(inp);
35f3fc10 230 tcpstat.tcps_closed++;
0e3936fa 231 return ((struct tcpcb *)0);
a6503abf
BJ
232}
233
a6503abf
BJ
234tcp_drain()
235{
a6503abf 236
a6503abf
BJ
237}
238
be841dc3
MK
239/*
240 * Notify a tcp user of an asynchronous error;
241 * just wake up so that he can collect error status.
242 */
243tcp_notify(inp)
244 register struct inpcb *inp;
245{
246
247 wakeup((caddr_t) &inp->inp_socket->so_timeo);
248 sorwakeup(inp->inp_socket);
249 sowwakeup(inp->inp_socket);
250}
7c626d4d 251tcp_ctlinput(cmd, sa)
72e4f44e 252 int cmd;
7c626d4d 253 struct sockaddr *sa;
a6503abf 254{
39674d5f 255 extern u_char inetctlerrmap[];
7c626d4d 256 struct sockaddr_in *sin;
62a291b2 257 int tcp_quench(), in_rtchange();
39674d5f 258
7c626d4d
MK
259 if ((unsigned)cmd > PRC_NCMDS)
260 return;
261 if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
262 return;
263 sin = (struct sockaddr_in *)sa;
264 if (sin->sin_addr.s_addr == INADDR_ANY)
39674d5f 265 return;
39674d5f 266
7c626d4d 267 switch (cmd) {
39674d5f
SL
268
269 case PRC_QUENCH:
7c626d4d 270 in_pcbnotify(&tcb, &sin->sin_addr, 0, tcp_quench);
62a291b2
MK
271 break;
272
7c626d4d 273 case PRC_ROUTEDEAD:
62a291b2
MK
274 case PRC_REDIRECT_NET:
275 case PRC_REDIRECT_HOST:
7c626d4d
MK
276 case PRC_REDIRECT_TOSNET:
277 case PRC_REDIRECT_TOSHOST:
278 in_pcbnotify(&tcb, &sin->sin_addr, 0, in_rtchange);
39674d5f
SL
279 break;
280
39674d5f 281 default:
62a291b2
MK
282 if (inetctlerrmap[cmd] == 0)
283 return; /* XXX */
7c626d4d 284 in_pcbnotify(&tcb, &sin->sin_addr, (int)inetctlerrmap[cmd],
be841dc3 285 tcp_notify);
39674d5f 286 }
a6503abf 287}
05586739
MK
288
289/*
290 * When a source quench is received, close congestion window
291 * to 80% of the outstanding data (but not less than one segment).
292 */
293tcp_quench(inp)
294 struct inpcb *inp;
295{
296 struct tcpcb *tp = intotcpcb(inp);
297
7c626d4d
MK
298 if (tp)
299 tp->snd_cwnd = MAX(8 * (tp->snd_nxt - tp->snd_una) / 10,
300 tp->t_maxseg);
05586739 301}