Deleted Added
full compact
tcp_usrreq.c (27845) tcp_usrreq.c (28270)
1/*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. 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 * From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94
1/*
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. 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 * From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94
34 * $Id: tcp_usrreq.c,v 1.31 1997/04/27 20:01:14 wollman Exp $
34 * $Id: tcp_usrreq.c,v 1.32 1997/08/02 14:32:58 bde Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/sysctl.h>
41#include <sys/mbuf.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/protosw.h>
45
46#include <net/if.h>
47#include <net/route.h>
48
49#include <netinet/in.h>
50#include <netinet/in_systm.h>
51#include <netinet/in_pcb.h>
52#include <netinet/in_var.h>
53#include <netinet/ip_var.h>
54#include <netinet/tcp.h>
55#include <netinet/tcp_fsm.h>
56#include <netinet/tcp_seq.h>
57#include <netinet/tcp_timer.h>
58#include <netinet/tcp_var.h>
59#include <netinet/tcpip.h>
60#ifdef TCPDEBUG
61#include <netinet/tcp_debug.h>
62#endif
63
64/*
65 * TCP protocol interface to socket abstraction.
66 */
67extern char *tcpstates[]; /* XXX ??? */
68
69static int tcp_attach __P((struct socket *, struct proc *));
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/sysctl.h>
41#include <sys/mbuf.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/protosw.h>
45
46#include <net/if.h>
47#include <net/route.h>
48
49#include <netinet/in.h>
50#include <netinet/in_systm.h>
51#include <netinet/in_pcb.h>
52#include <netinet/in_var.h>
53#include <netinet/ip_var.h>
54#include <netinet/tcp.h>
55#include <netinet/tcp_fsm.h>
56#include <netinet/tcp_seq.h>
57#include <netinet/tcp_timer.h>
58#include <netinet/tcp_var.h>
59#include <netinet/tcpip.h>
60#ifdef TCPDEBUG
61#include <netinet/tcp_debug.h>
62#endif
63
64/*
65 * TCP protocol interface to socket abstraction.
66 */
67extern char *tcpstates[]; /* XXX ??? */
68
69static int tcp_attach __P((struct socket *, struct proc *));
70static int tcp_connect __P((struct tcpcb *, struct mbuf *,
70static int tcp_connect __P((struct tcpcb *, struct sockaddr *,
71 struct proc *));
72static struct tcpcb *
73 tcp_disconnect __P((struct tcpcb *));
74static struct tcpcb *
75 tcp_usrclosed __P((struct tcpcb *));
76
77#ifdef TCPDEBUG
78#define TCPDEBUG0 int ostate
79#define TCPDEBUG1() ostate = tp ? tp->t_state : 0
80#define TCPDEBUG2(req) if (tp && (so->so_options & SO_DEBUG)) \
81 tcp_trace(TA_USER, ostate, tp, 0, req)
82#else
83#define TCPDEBUG0
84#define TCPDEBUG1()
85#define TCPDEBUG2(req)
86#endif
87
88/*
89 * TCP attaches to socket via pru_attach(), reserving space,
90 * and an internet control block.
91 */
92static int
93tcp_usr_attach(struct socket *so, int proto, struct proc *p)
94{
95 int s = splnet();
96 int error;
97 struct inpcb *inp = sotoinpcb(so);
98 struct tcpcb *tp = 0;
99 TCPDEBUG0;
100
101 TCPDEBUG1();
102 if (inp) {
103 error = EISCONN;
104 goto out;
105 }
106
107 error = tcp_attach(so, p);
108 if (error)
109 goto out;
110
111 if ((so->so_options & SO_LINGER) && so->so_linger == 0)
112 so->so_linger = TCP_LINGERTIME * hz;
113 tp = sototcpcb(so);
114out:
115 TCPDEBUG2(PRU_ATTACH);
116 splx(s);
117 return error;
118}
119
120/*
121 * pru_detach() detaches the TCP protocol from the socket.
122 * If the protocol state is non-embryonic, then can't
123 * do this directly: have to initiate a pru_disconnect(),
124 * which may finish later; embryonic TCB's can just
125 * be discarded here.
126 */
127static int
128tcp_usr_detach(struct socket *so)
129{
130 int s = splnet();
131 int error = 0;
132 struct inpcb *inp = sotoinpcb(so);
133 struct tcpcb *tp;
134 TCPDEBUG0;
135
136 if (inp == 0) {
137 splx(s);
138 return EINVAL; /* XXX */
139 }
140 tp = intotcpcb(inp);
141 TCPDEBUG1();
71 struct proc *));
72static struct tcpcb *
73 tcp_disconnect __P((struct tcpcb *));
74static struct tcpcb *
75 tcp_usrclosed __P((struct tcpcb *));
76
77#ifdef TCPDEBUG
78#define TCPDEBUG0 int ostate
79#define TCPDEBUG1() ostate = tp ? tp->t_state : 0
80#define TCPDEBUG2(req) if (tp && (so->so_options & SO_DEBUG)) \
81 tcp_trace(TA_USER, ostate, tp, 0, req)
82#else
83#define TCPDEBUG0
84#define TCPDEBUG1()
85#define TCPDEBUG2(req)
86#endif
87
88/*
89 * TCP attaches to socket via pru_attach(), reserving space,
90 * and an internet control block.
91 */
92static int
93tcp_usr_attach(struct socket *so, int proto, struct proc *p)
94{
95 int s = splnet();
96 int error;
97 struct inpcb *inp = sotoinpcb(so);
98 struct tcpcb *tp = 0;
99 TCPDEBUG0;
100
101 TCPDEBUG1();
102 if (inp) {
103 error = EISCONN;
104 goto out;
105 }
106
107 error = tcp_attach(so, p);
108 if (error)
109 goto out;
110
111 if ((so->so_options & SO_LINGER) && so->so_linger == 0)
112 so->so_linger = TCP_LINGERTIME * hz;
113 tp = sototcpcb(so);
114out:
115 TCPDEBUG2(PRU_ATTACH);
116 splx(s);
117 return error;
118}
119
120/*
121 * pru_detach() detaches the TCP protocol from the socket.
122 * If the protocol state is non-embryonic, then can't
123 * do this directly: have to initiate a pru_disconnect(),
124 * which may finish later; embryonic TCB's can just
125 * be discarded here.
126 */
127static int
128tcp_usr_detach(struct socket *so)
129{
130 int s = splnet();
131 int error = 0;
132 struct inpcb *inp = sotoinpcb(so);
133 struct tcpcb *tp;
134 TCPDEBUG0;
135
136 if (inp == 0) {
137 splx(s);
138 return EINVAL; /* XXX */
139 }
140 tp = intotcpcb(inp);
141 TCPDEBUG1();
142 if (tp->t_state > TCPS_LISTEN)
143 tp = tcp_disconnect(tp);
144 else
145 tp = tcp_close(tp);
142 tp = tcp_disconnect(tp);
146
147 TCPDEBUG2(PRU_DETACH);
148 splx(s);
149 return error;
150}
151
152#define COMMON_START() TCPDEBUG0; \
153 do { \
154 if (inp == 0) { \
155 splx(s); \
156 return EINVAL; \
157 } \
158 tp = intotcpcb(inp); \
159 TCPDEBUG1(); \
160 } while(0)
161
162#define COMMON_END(req) out: TCPDEBUG2(req); splx(s); return error; goto out
163
164
165/*
166 * Give the socket an address.
167 */
168static int
143
144 TCPDEBUG2(PRU_DETACH);
145 splx(s);
146 return error;
147}
148
149#define COMMON_START() TCPDEBUG0; \
150 do { \
151 if (inp == 0) { \
152 splx(s); \
153 return EINVAL; \
154 } \
155 tp = intotcpcb(inp); \
156 TCPDEBUG1(); \
157 } while(0)
158
159#define COMMON_END(req) out: TCPDEBUG2(req); splx(s); return error; goto out
160
161
162/*
163 * Give the socket an address.
164 */
165static int
169tcp_usr_bind(struct socket *so, struct mbuf *nam, struct proc *p)
166tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
170{
171 int s = splnet();
172 int error = 0;
173 struct inpcb *inp = sotoinpcb(so);
174 struct tcpcb *tp;
175 struct sockaddr_in *sinp;
176
177 COMMON_START();
178
179 /*
180 * Must check for multicast addresses and disallow binding
181 * to them.
182 */
167{
168 int s = splnet();
169 int error = 0;
170 struct inpcb *inp = sotoinpcb(so);
171 struct tcpcb *tp;
172 struct sockaddr_in *sinp;
173
174 COMMON_START();
175
176 /*
177 * Must check for multicast addresses and disallow binding
178 * to them.
179 */
183 sinp = mtod(nam, struct sockaddr_in *);
180 sinp = (struct sockaddr_in *)nam;
184 if (sinp->sin_family == AF_INET &&
185 IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
186 error = EAFNOSUPPORT;
187 goto out;
188 }
189 error = in_pcbbind(inp, nam, p);
190 if (error)
191 goto out;
192 COMMON_END(PRU_BIND);
193
194}
195
196/*
197 * Prepare to accept connections.
198 */
199static int
200tcp_usr_listen(struct socket *so, struct proc *p)
201{
202 int s = splnet();
203 int error = 0;
204 struct inpcb *inp = sotoinpcb(so);
205 struct tcpcb *tp;
206
207 COMMON_START();
208 if (inp->inp_lport == 0)
181 if (sinp->sin_family == AF_INET &&
182 IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
183 error = EAFNOSUPPORT;
184 goto out;
185 }
186 error = in_pcbbind(inp, nam, p);
187 if (error)
188 goto out;
189 COMMON_END(PRU_BIND);
190
191}
192
193/*
194 * Prepare to accept connections.
195 */
196static int
197tcp_usr_listen(struct socket *so, struct proc *p)
198{
199 int s = splnet();
200 int error = 0;
201 struct inpcb *inp = sotoinpcb(so);
202 struct tcpcb *tp;
203
204 COMMON_START();
205 if (inp->inp_lport == 0)
209 error = in_pcbbind(inp, (struct mbuf *)0, p);
206 error = in_pcbbind(inp, (struct sockaddr *)0, p);
210 if (error == 0)
211 tp->t_state = TCPS_LISTEN;
212 COMMON_END(PRU_LISTEN);
213}
214
215/*
216 * Initiate connection to peer.
217 * Create a template for use in transmissions on this connection.
218 * Enter SYN_SENT state, and mark socket as connecting.
219 * Start keep-alive timer, and seed output sequence space.
220 * Send initial segment on connection.
221 */
222static int
207 if (error == 0)
208 tp->t_state = TCPS_LISTEN;
209 COMMON_END(PRU_LISTEN);
210}
211
212/*
213 * Initiate connection to peer.
214 * Create a template for use in transmissions on this connection.
215 * Enter SYN_SENT state, and mark socket as connecting.
216 * Start keep-alive timer, and seed output sequence space.
217 * Send initial segment on connection.
218 */
219static int
223tcp_usr_connect(struct socket *so, struct mbuf *nam, struct proc *p)
220tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
224{
225 int s = splnet();
226 int error = 0;
227 struct inpcb *inp = sotoinpcb(so);
228 struct tcpcb *tp;
229 struct sockaddr_in *sinp;
230
231 COMMON_START();
232
233 /*
234 * Must disallow TCP ``connections'' to multicast addresses.
235 */
221{
222 int s = splnet();
223 int error = 0;
224 struct inpcb *inp = sotoinpcb(so);
225 struct tcpcb *tp;
226 struct sockaddr_in *sinp;
227
228 COMMON_START();
229
230 /*
231 * Must disallow TCP ``connections'' to multicast addresses.
232 */
236 sinp = mtod(nam, struct sockaddr_in *);
233 sinp = (struct sockaddr_in *)nam;
237 if (sinp->sin_family == AF_INET
238 && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
239 error = EAFNOSUPPORT;
240 goto out;
241 }
242
243 if ((error = tcp_connect(tp, nam, p)) != 0)
244 goto out;
245 error = tcp_output(tp);
246 COMMON_END(PRU_CONNECT);
247}
248
249/*
250 * Initiate disconnect from peer.
251 * If connection never passed embryonic stage, just drop;
252 * else if don't need to let data drain, then can just drop anyways,
253 * else have to begin TCP shutdown process: mark socket disconnecting,
254 * drain unread data, state switch to reflect user close, and
255 * send segment (e.g. FIN) to peer. Socket will be really disconnected
256 * when peer sends FIN and acks ours.
257 *
258 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
259 */
260static int
261tcp_usr_disconnect(struct socket *so)
262{
263 int s = splnet();
264 int error = 0;
265 struct inpcb *inp = sotoinpcb(so);
266 struct tcpcb *tp;
267
268 COMMON_START();
269 tp = tcp_disconnect(tp);
270 COMMON_END(PRU_DISCONNECT);
271}
272
273/*
274 * Accept a connection. Essentially all the work is
275 * done at higher levels; just return the address
276 * of the peer, storing through addr.
277 */
278static int
234 if (sinp->sin_family == AF_INET
235 && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
236 error = EAFNOSUPPORT;
237 goto out;
238 }
239
240 if ((error = tcp_connect(tp, nam, p)) != 0)
241 goto out;
242 error = tcp_output(tp);
243 COMMON_END(PRU_CONNECT);
244}
245
246/*
247 * Initiate disconnect from peer.
248 * If connection never passed embryonic stage, just drop;
249 * else if don't need to let data drain, then can just drop anyways,
250 * else have to begin TCP shutdown process: mark socket disconnecting,
251 * drain unread data, state switch to reflect user close, and
252 * send segment (e.g. FIN) to peer. Socket will be really disconnected
253 * when peer sends FIN and acks ours.
254 *
255 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
256 */
257static int
258tcp_usr_disconnect(struct socket *so)
259{
260 int s = splnet();
261 int error = 0;
262 struct inpcb *inp = sotoinpcb(so);
263 struct tcpcb *tp;
264
265 COMMON_START();
266 tp = tcp_disconnect(tp);
267 COMMON_END(PRU_DISCONNECT);
268}
269
270/*
271 * Accept a connection. Essentially all the work is
272 * done at higher levels; just return the address
273 * of the peer, storing through addr.
274 */
275static int
279tcp_usr_accept(struct socket *so, struct mbuf *nam)
276tcp_usr_accept(struct socket *so, struct sockaddr **nam)
280{
281 int s = splnet();
282 int error = 0;
283 struct inpcb *inp = sotoinpcb(so);
284 struct tcpcb *tp;
285
286 COMMON_START();
287 in_setpeeraddr(so, nam);
288 COMMON_END(PRU_ACCEPT);
289}
290
291/*
292 * Mark the connection as being incapable of further output.
293 */
294static int
295tcp_usr_shutdown(struct socket *so)
296{
297 int s = splnet();
298 int error = 0;
299 struct inpcb *inp = sotoinpcb(so);
300 struct tcpcb *tp;
301
302 COMMON_START();
303 socantsendmore(so);
304 tp = tcp_usrclosed(tp);
305 if (tp)
306 error = tcp_output(tp);
307 COMMON_END(PRU_SHUTDOWN);
308}
309
310/*
311 * After a receive, possibly send window update to peer.
312 */
313static int
314tcp_usr_rcvd(struct socket *so, int flags)
315{
316 int s = splnet();
317 int error = 0;
318 struct inpcb *inp = sotoinpcb(so);
319 struct tcpcb *tp;
320
321 COMMON_START();
322 tcp_output(tp);
323 COMMON_END(PRU_RCVD);
324}
325
326/*
327 * Do a send by putting data in output queue and updating urgent
328 * marker if URG set. Possibly send more data.
329 */
330static int
277{
278 int s = splnet();
279 int error = 0;
280 struct inpcb *inp = sotoinpcb(so);
281 struct tcpcb *tp;
282
283 COMMON_START();
284 in_setpeeraddr(so, nam);
285 COMMON_END(PRU_ACCEPT);
286}
287
288/*
289 * Mark the connection as being incapable of further output.
290 */
291static int
292tcp_usr_shutdown(struct socket *so)
293{
294 int s = splnet();
295 int error = 0;
296 struct inpcb *inp = sotoinpcb(so);
297 struct tcpcb *tp;
298
299 COMMON_START();
300 socantsendmore(so);
301 tp = tcp_usrclosed(tp);
302 if (tp)
303 error = tcp_output(tp);
304 COMMON_END(PRU_SHUTDOWN);
305}
306
307/*
308 * After a receive, possibly send window update to peer.
309 */
310static int
311tcp_usr_rcvd(struct socket *so, int flags)
312{
313 int s = splnet();
314 int error = 0;
315 struct inpcb *inp = sotoinpcb(so);
316 struct tcpcb *tp;
317
318 COMMON_START();
319 tcp_output(tp);
320 COMMON_END(PRU_RCVD);
321}
322
323/*
324 * Do a send by putting data in output queue and updating urgent
325 * marker if URG set. Possibly send more data.
326 */
327static int
331tcp_usr_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam,
332 struct mbuf *control, struct proc *p)
328tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
329 struct sockaddr *nam, struct mbuf *control, struct proc *p)
333{
334 int s = splnet();
335 int error = 0;
336 struct inpcb *inp = sotoinpcb(so);
337 struct tcpcb *tp;
338
339 COMMON_START();
340 if (control && control->m_len) {
341 m_freem(control); /* XXX shouldn't caller do this??? */
342 if (m)
343 m_freem(m);
344 return EINVAL;
345 }
346
347 if(!(flags & PRUS_OOB)) {
348 sbappend(&so->so_snd, m);
349 if (nam && tp->t_state < TCPS_SYN_SENT) {
350 /*
351 * Do implied connect if not yet connected,
352 * initialize window to default value, and
353 * initialize maxseg/maxopd using peer's cached
354 * MSS.
355 */
356 error = tcp_connect(tp, nam, p);
357 if (error)
358 goto out;
359 tp->snd_wnd = TTCP_CLIENT_SND_WND;
360 tcp_mss(tp, -1);
361 }
362
363 if (flags & PRUS_EOF) {
364 /*
365 * Close the send side of the connection after
366 * the data is sent.
367 */
368 socantsendmore(so);
369 tp = tcp_usrclosed(tp);
370 }
371 if (tp != NULL)
372 error = tcp_output(tp);
373 } else {
374 if (sbspace(&so->so_snd) < -512) {
375 m_freem(m);
376 error = ENOBUFS;
377 goto out;
378 }
379 /*
380 * According to RFC961 (Assigned Protocols),
381 * the urgent pointer points to the last octet
382 * of urgent data. We continue, however,
383 * to consider it to indicate the first octet
384 * of data past the urgent section.
385 * Otherwise, snd_up should be one lower.
386 */
387 sbappend(&so->so_snd, m);
388 if (nam && tp->t_state < TCPS_SYN_SENT) {
389 /*
390 * Do implied connect if not yet connected,
391 * initialize window to default value, and
392 * initialize maxseg/maxopd using peer's cached
393 * MSS.
394 */
395 error = tcp_connect(tp, nam, p);
396 if (error)
397 goto out;
398 tp->snd_wnd = TTCP_CLIENT_SND_WND;
399 tcp_mss(tp, -1);
400 }
401 tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
402 tp->t_force = 1;
403 error = tcp_output(tp);
404 tp->t_force = 0;
405 }
406 COMMON_END((flags & PRUS_OOB) ? PRU_SENDOOB :
407 ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
408}
409
410/*
411 * Abort the TCP.
412 */
413static int
414tcp_usr_abort(struct socket *so)
415{
416 int s = splnet();
417 int error = 0;
418 struct inpcb *inp = sotoinpcb(so);
419 struct tcpcb *tp;
420
421 COMMON_START();
422 tp = tcp_drop(tp, ECONNABORTED);
423 COMMON_END(PRU_ABORT);
424}
425
426/*
427 * Receive out-of-band data.
428 */
429static int
430tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
431{
432 int s = splnet();
433 int error = 0;
434 struct inpcb *inp = sotoinpcb(so);
435 struct tcpcb *tp;
436
437 COMMON_START();
438 if ((so->so_oobmark == 0 &&
439 (so->so_state & SS_RCVATMARK) == 0) ||
440 so->so_options & SO_OOBINLINE ||
441 tp->t_oobflags & TCPOOB_HADDATA) {
442 error = EINVAL;
443 goto out;
444 }
445 if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
446 error = EWOULDBLOCK;
447 goto out;
448 }
449 m->m_len = 1;
450 *mtod(m, caddr_t) = tp->t_iobc;
451 if ((flags & MSG_PEEK) == 0)
452 tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
453 COMMON_END(PRU_RCVOOB);
454}
455
456/* xxx - should be const */
457struct pr_usrreqs tcp_usrreqs = {
458 tcp_usr_abort, tcp_usr_accept, tcp_usr_attach, tcp_usr_bind,
459 tcp_usr_connect, pru_connect2_notsupp, in_control, tcp_usr_detach,
460 tcp_usr_disconnect, tcp_usr_listen, in_setpeeraddr, tcp_usr_rcvd,
461 tcp_usr_rcvoob, tcp_usr_send, pru_sense_null, tcp_usr_shutdown,
462 in_setsockaddr, sosend, soreceive, soselect
463};
464
465/*
466 * Common subroutine to open a TCP connection to remote host specified
467 * by struct sockaddr_in in mbuf *nam. Call in_pcbbind to assign a local
468 * port number if needed. Call in_pcbladdr to do the routing and to choose
469 * a local host address (interface). If there is an existing incarnation
470 * of the same connection in TIME-WAIT state and if the remote host was
471 * sending CC options and if the connection duration was < MSL, then
472 * truncate the previous TIME-WAIT state and proceed.
473 * Initialize connection parameters and enter SYN-SENT state.
474 */
475static int
476tcp_connect(tp, nam, p)
477 register struct tcpcb *tp;
330{
331 int s = splnet();
332 int error = 0;
333 struct inpcb *inp = sotoinpcb(so);
334 struct tcpcb *tp;
335
336 COMMON_START();
337 if (control && control->m_len) {
338 m_freem(control); /* XXX shouldn't caller do this??? */
339 if (m)
340 m_freem(m);
341 return EINVAL;
342 }
343
344 if(!(flags & PRUS_OOB)) {
345 sbappend(&so->so_snd, m);
346 if (nam && tp->t_state < TCPS_SYN_SENT) {
347 /*
348 * Do implied connect if not yet connected,
349 * initialize window to default value, and
350 * initialize maxseg/maxopd using peer's cached
351 * MSS.
352 */
353 error = tcp_connect(tp, nam, p);
354 if (error)
355 goto out;
356 tp->snd_wnd = TTCP_CLIENT_SND_WND;
357 tcp_mss(tp, -1);
358 }
359
360 if (flags & PRUS_EOF) {
361 /*
362 * Close the send side of the connection after
363 * the data is sent.
364 */
365 socantsendmore(so);
366 tp = tcp_usrclosed(tp);
367 }
368 if (tp != NULL)
369 error = tcp_output(tp);
370 } else {
371 if (sbspace(&so->so_snd) < -512) {
372 m_freem(m);
373 error = ENOBUFS;
374 goto out;
375 }
376 /*
377 * According to RFC961 (Assigned Protocols),
378 * the urgent pointer points to the last octet
379 * of urgent data. We continue, however,
380 * to consider it to indicate the first octet
381 * of data past the urgent section.
382 * Otherwise, snd_up should be one lower.
383 */
384 sbappend(&so->so_snd, m);
385 if (nam && tp->t_state < TCPS_SYN_SENT) {
386 /*
387 * Do implied connect if not yet connected,
388 * initialize window to default value, and
389 * initialize maxseg/maxopd using peer's cached
390 * MSS.
391 */
392 error = tcp_connect(tp, nam, p);
393 if (error)
394 goto out;
395 tp->snd_wnd = TTCP_CLIENT_SND_WND;
396 tcp_mss(tp, -1);
397 }
398 tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
399 tp->t_force = 1;
400 error = tcp_output(tp);
401 tp->t_force = 0;
402 }
403 COMMON_END((flags & PRUS_OOB) ? PRU_SENDOOB :
404 ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
405}
406
407/*
408 * Abort the TCP.
409 */
410static int
411tcp_usr_abort(struct socket *so)
412{
413 int s = splnet();
414 int error = 0;
415 struct inpcb *inp = sotoinpcb(so);
416 struct tcpcb *tp;
417
418 COMMON_START();
419 tp = tcp_drop(tp, ECONNABORTED);
420 COMMON_END(PRU_ABORT);
421}
422
423/*
424 * Receive out-of-band data.
425 */
426static int
427tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
428{
429 int s = splnet();
430 int error = 0;
431 struct inpcb *inp = sotoinpcb(so);
432 struct tcpcb *tp;
433
434 COMMON_START();
435 if ((so->so_oobmark == 0 &&
436 (so->so_state & SS_RCVATMARK) == 0) ||
437 so->so_options & SO_OOBINLINE ||
438 tp->t_oobflags & TCPOOB_HADDATA) {
439 error = EINVAL;
440 goto out;
441 }
442 if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
443 error = EWOULDBLOCK;
444 goto out;
445 }
446 m->m_len = 1;
447 *mtod(m, caddr_t) = tp->t_iobc;
448 if ((flags & MSG_PEEK) == 0)
449 tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
450 COMMON_END(PRU_RCVOOB);
451}
452
453/* xxx - should be const */
454struct pr_usrreqs tcp_usrreqs = {
455 tcp_usr_abort, tcp_usr_accept, tcp_usr_attach, tcp_usr_bind,
456 tcp_usr_connect, pru_connect2_notsupp, in_control, tcp_usr_detach,
457 tcp_usr_disconnect, tcp_usr_listen, in_setpeeraddr, tcp_usr_rcvd,
458 tcp_usr_rcvoob, tcp_usr_send, pru_sense_null, tcp_usr_shutdown,
459 in_setsockaddr, sosend, soreceive, soselect
460};
461
462/*
463 * Common subroutine to open a TCP connection to remote host specified
464 * by struct sockaddr_in in mbuf *nam. Call in_pcbbind to assign a local
465 * port number if needed. Call in_pcbladdr to do the routing and to choose
466 * a local host address (interface). If there is an existing incarnation
467 * of the same connection in TIME-WAIT state and if the remote host was
468 * sending CC options and if the connection duration was < MSL, then
469 * truncate the previous TIME-WAIT state and proceed.
470 * Initialize connection parameters and enter SYN-SENT state.
471 */
472static int
473tcp_connect(tp, nam, p)
474 register struct tcpcb *tp;
478 struct mbuf *nam;
475 struct sockaddr *nam;
479 struct proc *p;
480{
481 struct inpcb *inp = tp->t_inpcb, *oinp;
482 struct socket *so = inp->inp_socket;
483 struct tcpcb *otp;
476 struct proc *p;
477{
478 struct inpcb *inp = tp->t_inpcb, *oinp;
479 struct socket *so = inp->inp_socket;
480 struct tcpcb *otp;
484 struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
481 struct sockaddr_in *sin = (struct sockaddr_in *)nam;
485 struct sockaddr_in *ifaddr;
486 int error;
487 struct rmxp_tao *taop;
488 struct rmxp_tao tao_noncached;
489
490 if (inp->inp_lport == 0) {
482 struct sockaddr_in *ifaddr;
483 int error;
484 struct rmxp_tao *taop;
485 struct rmxp_tao tao_noncached;
486
487 if (inp->inp_lport == 0) {
491 error = in_pcbbind(inp, (struct mbuf *)0, p);
488 error = in_pcbbind(inp, (struct sockaddr *)0, p);
492 if (error)
493 return error;
494 }
495
496 /*
497 * Cannot simply call in_pcbconnect, because there might be an
498 * earlier incarnation of this same connection still in
499 * TIME_WAIT state, creating an ADDRINUSE error.
500 */
501 error = in_pcbladdr(inp, nam, &ifaddr);
502 if (error)
503 return error;
504 oinp = in_pcblookuphash(inp->inp_pcbinfo,
505 sin->sin_addr, sin->sin_port,
506 inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr
507 : ifaddr->sin_addr,
508 inp->inp_lport, 0);
509 if (oinp) {
510 if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
511 otp->t_state == TCPS_TIME_WAIT &&
512 otp->t_duration < TCPTV_MSL &&
513 (otp->t_flags & TF_RCVD_CC))
514 otp = tcp_close(otp);
515 else
516 return EADDRINUSE;
517 }
518 if (inp->inp_laddr.s_addr == INADDR_ANY)
519 inp->inp_laddr = ifaddr->sin_addr;
520 inp->inp_faddr = sin->sin_addr;
521 inp->inp_fport = sin->sin_port;
522 in_pcbrehash(inp);
523
524 tp->t_template = tcp_template(tp);
525 if (tp->t_template == 0) {
526 in_pcbdisconnect(inp);
527 return ENOBUFS;
528 }
529
530 /* Compute window scaling to request. */
531 while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
532 (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
533 tp->request_r_scale++;
534
535 soisconnecting(so);
536 tcpstat.tcps_connattempt++;
537 tp->t_state = TCPS_SYN_SENT;
538 tp->t_timer[TCPT_KEEP] = tcp_keepinit;
539 tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
540 tcp_sendseqinit(tp);
541
542 /*
543 * Generate a CC value for this connection and
544 * check whether CC or CCnew should be used.
545 */
546 if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
547 taop = &tao_noncached;
548 bzero(taop, sizeof(*taop));
549 }
550
551 tp->cc_send = CC_INC(tcp_ccgen);
552 if (taop->tao_ccsent != 0 &&
553 CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
554 taop->tao_ccsent = tp->cc_send;
555 } else {
556 taop->tao_ccsent = 0;
557 tp->t_flags |= TF_SENDCCNEW;
558 }
559
560 return 0;
561}
562
563int
564tcp_ctloutput(op, so, level, optname, mp, p)
565 int op;
566 struct socket *so;
567 int level, optname;
568 struct mbuf **mp;
569 struct proc *p;
570{
571 int error = 0, s;
572 struct inpcb *inp;
573 register struct tcpcb *tp;
574 register struct mbuf *m;
575 register int i;
576
577 s = splnet();
578 inp = sotoinpcb(so);
579 if (inp == NULL) {
580 splx(s);
581 if (op == PRCO_SETOPT && *mp)
582 (void) m_free(*mp);
583 return (ECONNRESET);
584 }
585 if (level != IPPROTO_TCP) {
586 error = ip_ctloutput(op, so, level, optname, mp, p);
587 splx(s);
588 return (error);
589 }
590 tp = intotcpcb(inp);
591
592 switch (op) {
593
594 case PRCO_SETOPT:
595 m = *mp;
596 switch (optname) {
597
598 case TCP_NODELAY:
599 if (m == NULL || m->m_len < sizeof (int))
600 error = EINVAL;
601 else if (*mtod(m, int *))
602 tp->t_flags |= TF_NODELAY;
603 else
604 tp->t_flags &= ~TF_NODELAY;
605 break;
606
607 case TCP_MAXSEG:
608 if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg)
609 tp->t_maxseg = i;
610 else
611 error = EINVAL;
612 break;
613
614 case TCP_NOOPT:
615 if (m == NULL || m->m_len < sizeof (int))
616 error = EINVAL;
617 else if (*mtod(m, int *))
618 tp->t_flags |= TF_NOOPT;
619 else
620 tp->t_flags &= ~TF_NOOPT;
621 break;
622
623 case TCP_NOPUSH:
624 if (m == NULL || m->m_len < sizeof (int))
625 error = EINVAL;
626 else if (*mtod(m, int *))
627 tp->t_flags |= TF_NOPUSH;
628 else
629 tp->t_flags &= ~TF_NOPUSH;
630 break;
631
632 default:
633 error = ENOPROTOOPT;
634 break;
635 }
636 if (m)
637 (void) m_free(m);
638 break;
639
640 case PRCO_GETOPT:
641 *mp = m = m_get(M_WAIT, MT_SOOPTS);
642 m->m_len = sizeof(int);
643
644 switch (optname) {
645 case TCP_NODELAY:
646 *mtod(m, int *) = tp->t_flags & TF_NODELAY;
647 break;
648 case TCP_MAXSEG:
649 *mtod(m, int *) = tp->t_maxseg;
650 break;
651 case TCP_NOOPT:
652 *mtod(m, int *) = tp->t_flags & TF_NOOPT;
653 break;
654 case TCP_NOPUSH:
655 *mtod(m, int *) = tp->t_flags & TF_NOPUSH;
656 break;
657 default:
658 error = ENOPROTOOPT;
659 break;
660 }
661 break;
662 }
663 splx(s);
664 return (error);
665}
666
667/*
668 * tcp_sendspace and tcp_recvspace are the default send and receive window
669 * sizes, respectively. These are obsolescent (this information should
670 * be set by the route).
671 */
672u_long tcp_sendspace = 1024*16;
673SYSCTL_INT(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace,
674 CTLFLAG_RW, &tcp_sendspace , 0, "");
675u_long tcp_recvspace = 1024*16;
676SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace,
677 CTLFLAG_RW, &tcp_recvspace , 0, "");
678
679/*
680 * Attach TCP protocol to socket, allocating
681 * internet protocol control block, tcp control block,
682 * bufer space, and entering LISTEN state if to accept connections.
683 */
684static int
685tcp_attach(so, p)
686 struct socket *so;
687 struct proc *p;
688{
689 register struct tcpcb *tp;
690 struct inpcb *inp;
691 int error;
692
693 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
694 error = soreserve(so, tcp_sendspace, tcp_recvspace);
695 if (error)
696 return (error);
697 }
698 error = in_pcballoc(so, &tcbinfo, p);
699 if (error)
700 return (error);
701 inp = sotoinpcb(so);
702 tp = tcp_newtcpcb(inp);
703 if (tp == 0) {
704 int nofd = so->so_state & SS_NOFDREF; /* XXX */
705
706 so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */
707 in_pcbdetach(inp);
708 so->so_state |= nofd;
709 return (ENOBUFS);
710 }
711 tp->t_state = TCPS_CLOSED;
712 return (0);
713}
714
715/*
716 * Initiate (or continue) disconnect.
717 * If embryonic state, just send reset (once).
718 * If in ``let data drain'' option and linger null, just drop.
719 * Otherwise (hard), mark socket disconnecting and drop
720 * current input data; switch states based on user close, and
721 * send segment to peer (with FIN).
722 */
723static struct tcpcb *
724tcp_disconnect(tp)
725 register struct tcpcb *tp;
726{
727 struct socket *so = tp->t_inpcb->inp_socket;
728
729 if (tp->t_state < TCPS_ESTABLISHED)
730 tp = tcp_close(tp);
731 else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
732 tp = tcp_drop(tp, 0);
733 else {
734 soisdisconnecting(so);
735 sbflush(&so->so_rcv);
736 tp = tcp_usrclosed(tp);
737 if (tp)
738 (void) tcp_output(tp);
739 }
740 return (tp);
741}
742
743/*
744 * User issued close, and wish to trail through shutdown states:
745 * if never received SYN, just forget it. If got a SYN from peer,
746 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
747 * If already got a FIN from peer, then almost done; go to LAST_ACK
748 * state. In all other cases, have already sent FIN to peer (e.g.
749 * after PRU_SHUTDOWN), and just have to play tedious game waiting
750 * for peer to send FIN or not respond to keep-alives, etc.
751 * We can let the user exit from the close as soon as the FIN is acked.
752 */
753static struct tcpcb *
754tcp_usrclosed(tp)
755 register struct tcpcb *tp;
756{
757
758 switch (tp->t_state) {
759
760 case TCPS_CLOSED:
761 case TCPS_LISTEN:
762 tp->t_state = TCPS_CLOSED;
763 tp = tcp_close(tp);
764 break;
765
766 case TCPS_SYN_SENT:
767 case TCPS_SYN_RECEIVED:
768 tp->t_flags |= TF_NEEDFIN;
769 break;
770
771 case TCPS_ESTABLISHED:
772 tp->t_state = TCPS_FIN_WAIT_1;
773 break;
774
775 case TCPS_CLOSE_WAIT:
776 tp->t_state = TCPS_LAST_ACK;
777 break;
778 }
779 if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
780 soisdisconnected(tp->t_inpcb->inp_socket);
781 /* To prevent the connection hanging in FIN_WAIT_2 forever. */
782 if (tp->t_state == TCPS_FIN_WAIT_2)
783 tp->t_timer[TCPT_2MSL] = tcp_maxidle;
784 }
785 return (tp);
786}
787
489 if (error)
490 return error;
491 }
492
493 /*
494 * Cannot simply call in_pcbconnect, because there might be an
495 * earlier incarnation of this same connection still in
496 * TIME_WAIT state, creating an ADDRINUSE error.
497 */
498 error = in_pcbladdr(inp, nam, &ifaddr);
499 if (error)
500 return error;
501 oinp = in_pcblookuphash(inp->inp_pcbinfo,
502 sin->sin_addr, sin->sin_port,
503 inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr
504 : ifaddr->sin_addr,
505 inp->inp_lport, 0);
506 if (oinp) {
507 if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&
508 otp->t_state == TCPS_TIME_WAIT &&
509 otp->t_duration < TCPTV_MSL &&
510 (otp->t_flags & TF_RCVD_CC))
511 otp = tcp_close(otp);
512 else
513 return EADDRINUSE;
514 }
515 if (inp->inp_laddr.s_addr == INADDR_ANY)
516 inp->inp_laddr = ifaddr->sin_addr;
517 inp->inp_faddr = sin->sin_addr;
518 inp->inp_fport = sin->sin_port;
519 in_pcbrehash(inp);
520
521 tp->t_template = tcp_template(tp);
522 if (tp->t_template == 0) {
523 in_pcbdisconnect(inp);
524 return ENOBUFS;
525 }
526
527 /* Compute window scaling to request. */
528 while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
529 (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
530 tp->request_r_scale++;
531
532 soisconnecting(so);
533 tcpstat.tcps_connattempt++;
534 tp->t_state = TCPS_SYN_SENT;
535 tp->t_timer[TCPT_KEEP] = tcp_keepinit;
536 tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
537 tcp_sendseqinit(tp);
538
539 /*
540 * Generate a CC value for this connection and
541 * check whether CC or CCnew should be used.
542 */
543 if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {
544 taop = &tao_noncached;
545 bzero(taop, sizeof(*taop));
546 }
547
548 tp->cc_send = CC_INC(tcp_ccgen);
549 if (taop->tao_ccsent != 0 &&
550 CC_GEQ(tp->cc_send, taop->tao_ccsent)) {
551 taop->tao_ccsent = tp->cc_send;
552 } else {
553 taop->tao_ccsent = 0;
554 tp->t_flags |= TF_SENDCCNEW;
555 }
556
557 return 0;
558}
559
560int
561tcp_ctloutput(op, so, level, optname, mp, p)
562 int op;
563 struct socket *so;
564 int level, optname;
565 struct mbuf **mp;
566 struct proc *p;
567{
568 int error = 0, s;
569 struct inpcb *inp;
570 register struct tcpcb *tp;
571 register struct mbuf *m;
572 register int i;
573
574 s = splnet();
575 inp = sotoinpcb(so);
576 if (inp == NULL) {
577 splx(s);
578 if (op == PRCO_SETOPT && *mp)
579 (void) m_free(*mp);
580 return (ECONNRESET);
581 }
582 if (level != IPPROTO_TCP) {
583 error = ip_ctloutput(op, so, level, optname, mp, p);
584 splx(s);
585 return (error);
586 }
587 tp = intotcpcb(inp);
588
589 switch (op) {
590
591 case PRCO_SETOPT:
592 m = *mp;
593 switch (optname) {
594
595 case TCP_NODELAY:
596 if (m == NULL || m->m_len < sizeof (int))
597 error = EINVAL;
598 else if (*mtod(m, int *))
599 tp->t_flags |= TF_NODELAY;
600 else
601 tp->t_flags &= ~TF_NODELAY;
602 break;
603
604 case TCP_MAXSEG:
605 if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg)
606 tp->t_maxseg = i;
607 else
608 error = EINVAL;
609 break;
610
611 case TCP_NOOPT:
612 if (m == NULL || m->m_len < sizeof (int))
613 error = EINVAL;
614 else if (*mtod(m, int *))
615 tp->t_flags |= TF_NOOPT;
616 else
617 tp->t_flags &= ~TF_NOOPT;
618 break;
619
620 case TCP_NOPUSH:
621 if (m == NULL || m->m_len < sizeof (int))
622 error = EINVAL;
623 else if (*mtod(m, int *))
624 tp->t_flags |= TF_NOPUSH;
625 else
626 tp->t_flags &= ~TF_NOPUSH;
627 break;
628
629 default:
630 error = ENOPROTOOPT;
631 break;
632 }
633 if (m)
634 (void) m_free(m);
635 break;
636
637 case PRCO_GETOPT:
638 *mp = m = m_get(M_WAIT, MT_SOOPTS);
639 m->m_len = sizeof(int);
640
641 switch (optname) {
642 case TCP_NODELAY:
643 *mtod(m, int *) = tp->t_flags & TF_NODELAY;
644 break;
645 case TCP_MAXSEG:
646 *mtod(m, int *) = tp->t_maxseg;
647 break;
648 case TCP_NOOPT:
649 *mtod(m, int *) = tp->t_flags & TF_NOOPT;
650 break;
651 case TCP_NOPUSH:
652 *mtod(m, int *) = tp->t_flags & TF_NOPUSH;
653 break;
654 default:
655 error = ENOPROTOOPT;
656 break;
657 }
658 break;
659 }
660 splx(s);
661 return (error);
662}
663
664/*
665 * tcp_sendspace and tcp_recvspace are the default send and receive window
666 * sizes, respectively. These are obsolescent (this information should
667 * be set by the route).
668 */
669u_long tcp_sendspace = 1024*16;
670SYSCTL_INT(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace,
671 CTLFLAG_RW, &tcp_sendspace , 0, "");
672u_long tcp_recvspace = 1024*16;
673SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace,
674 CTLFLAG_RW, &tcp_recvspace , 0, "");
675
676/*
677 * Attach TCP protocol to socket, allocating
678 * internet protocol control block, tcp control block,
679 * bufer space, and entering LISTEN state if to accept connections.
680 */
681static int
682tcp_attach(so, p)
683 struct socket *so;
684 struct proc *p;
685{
686 register struct tcpcb *tp;
687 struct inpcb *inp;
688 int error;
689
690 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
691 error = soreserve(so, tcp_sendspace, tcp_recvspace);
692 if (error)
693 return (error);
694 }
695 error = in_pcballoc(so, &tcbinfo, p);
696 if (error)
697 return (error);
698 inp = sotoinpcb(so);
699 tp = tcp_newtcpcb(inp);
700 if (tp == 0) {
701 int nofd = so->so_state & SS_NOFDREF; /* XXX */
702
703 so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */
704 in_pcbdetach(inp);
705 so->so_state |= nofd;
706 return (ENOBUFS);
707 }
708 tp->t_state = TCPS_CLOSED;
709 return (0);
710}
711
712/*
713 * Initiate (or continue) disconnect.
714 * If embryonic state, just send reset (once).
715 * If in ``let data drain'' option and linger null, just drop.
716 * Otherwise (hard), mark socket disconnecting and drop
717 * current input data; switch states based on user close, and
718 * send segment to peer (with FIN).
719 */
720static struct tcpcb *
721tcp_disconnect(tp)
722 register struct tcpcb *tp;
723{
724 struct socket *so = tp->t_inpcb->inp_socket;
725
726 if (tp->t_state < TCPS_ESTABLISHED)
727 tp = tcp_close(tp);
728 else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
729 tp = tcp_drop(tp, 0);
730 else {
731 soisdisconnecting(so);
732 sbflush(&so->so_rcv);
733 tp = tcp_usrclosed(tp);
734 if (tp)
735 (void) tcp_output(tp);
736 }
737 return (tp);
738}
739
740/*
741 * User issued close, and wish to trail through shutdown states:
742 * if never received SYN, just forget it. If got a SYN from peer,
743 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
744 * If already got a FIN from peer, then almost done; go to LAST_ACK
745 * state. In all other cases, have already sent FIN to peer (e.g.
746 * after PRU_SHUTDOWN), and just have to play tedious game waiting
747 * for peer to send FIN or not respond to keep-alives, etc.
748 * We can let the user exit from the close as soon as the FIN is acked.
749 */
750static struct tcpcb *
751tcp_usrclosed(tp)
752 register struct tcpcb *tp;
753{
754
755 switch (tp->t_state) {
756
757 case TCPS_CLOSED:
758 case TCPS_LISTEN:
759 tp->t_state = TCPS_CLOSED;
760 tp = tcp_close(tp);
761 break;
762
763 case TCPS_SYN_SENT:
764 case TCPS_SYN_RECEIVED:
765 tp->t_flags |= TF_NEEDFIN;
766 break;
767
768 case TCPS_ESTABLISHED:
769 tp->t_state = TCPS_FIN_WAIT_1;
770 break;
771
772 case TCPS_CLOSE_WAIT:
773 tp->t_state = TCPS_LAST_ACK;
774 break;
775 }
776 if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
777 soisdisconnected(tp->t_inpcb->inp_socket);
778 /* To prevent the connection hanging in FIN_WAIT_2 forever. */
779 if (tp->t_state == TCPS_FIN_WAIT_2)
780 tp->t_timer[TCPT_2MSL] = tcp_maxidle;
781 }
782 return (tp);
783}
784