2019-06-04 16:11:33 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2005-08-10 11:14:34 +08:00
|
|
|
/*
|
|
|
|
* net/dccp/proto.c
|
|
|
|
*
|
|
|
|
* An implementation of the DCCP protocol
|
|
|
|
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/dccp.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/skbuff.h>
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/in.h>
|
|
|
|
#include <linux/if_arp.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/random.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2005-08-10 11:14:34 +08:00
|
|
|
#include <net/checksum.h>
|
|
|
|
|
2005-12-27 12:43:12 +08:00
|
|
|
#include <net/inet_sock.h>
|
2017-08-16 22:03:15 +08:00
|
|
|
#include <net/inet_common.h>
|
2005-08-10 11:14:34 +08:00
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/xfrm.h>
|
|
|
|
|
2007-10-24 11:23:30 +08:00
|
|
|
#include <asm/ioctls.h>
|
2005-08-10 11:14:34 +08:00
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/timer.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/poll.h>
|
|
|
|
|
|
|
|
#include "ccid.h"
|
|
|
|
#include "dccp.h"
|
[DCCP]: Initial feature negotiation implementation
Still needs more work, but boots and doesn't crashes, even
does some negotiation!
18:38:52.174934 127.0.0.1.43458 > 127.0.0.1.5001: request <change_l ack_ratio 2, change_r ccid 2, change_l ccid 2>
18:38:52.218526 127.0.0.1.5001 > 127.0.0.1.43458: response <nop, nop, change_l ack_ratio 2, confirm_r ccid 2 2, confirm_l ccid 2 2, confirm_r ack_ratio 2>
18:38:52.185398 127.0.0.1.43458 > 127.0.0.1.5001: <nop, confirm_r ack_ratio 2, ack_vector0 0x00, elapsed_time 212>
:-)
Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 09:43:56 +08:00
|
|
|
#include "feat.h"
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2017-12-29 10:47:55 +08:00
|
|
|
#define CREATE_TRACE_POINTS
|
|
|
|
#include "trace.h"
|
|
|
|
|
2005-08-27 03:05:31 +08:00
|
|
|
DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2005-12-14 15:24:16 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_statistics);
|
|
|
|
|
2021-10-14 21:41:26 +08:00
|
|
|
DEFINE_PER_CPU(unsigned int, dccp_orphan_count);
|
|
|
|
EXPORT_PER_CPU_SYMBOL_GPL(dccp_orphan_count);
|
2005-12-14 15:24:16 +08:00
|
|
|
|
2008-11-20 16:40:07 +08:00
|
|
|
struct inet_hashinfo dccp_hashinfo;
|
2006-03-21 13:24:19 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_hashinfo);
|
|
|
|
|
2006-11-21 04:30:17 +08:00
|
|
|
/* the maximum queue length for tx in packets. 0 is no limit */
|
|
|
|
int sysctl_dccp_tx_qlen __read_mostly = 5;
|
|
|
|
|
2010-10-05 12:24:09 +08:00
|
|
|
#ifdef CONFIG_IP_DCCP_DEBUG
|
|
|
|
static const char *dccp_state_name(const int state)
|
|
|
|
{
|
|
|
|
static const char *const dccp_state_names[] = {
|
|
|
|
[DCCP_OPEN] = "OPEN",
|
|
|
|
[DCCP_REQUESTING] = "REQUESTING",
|
|
|
|
[DCCP_PARTOPEN] = "PARTOPEN",
|
|
|
|
[DCCP_LISTEN] = "LISTEN",
|
|
|
|
[DCCP_RESPOND] = "RESPOND",
|
|
|
|
[DCCP_CLOSING] = "CLOSING",
|
|
|
|
[DCCP_ACTIVE_CLOSEREQ] = "CLOSEREQ",
|
|
|
|
[DCCP_PASSIVE_CLOSE] = "PASSIVE_CLOSE",
|
|
|
|
[DCCP_PASSIVE_CLOSEREQ] = "PASSIVE_CLOSEREQ",
|
|
|
|
[DCCP_TIME_WAIT] = "TIME_WAIT",
|
|
|
|
[DCCP_CLOSED] = "CLOSED",
|
|
|
|
};
|
|
|
|
|
|
|
|
if (state >= DCCP_MAX_STATES)
|
|
|
|
return "INVALID STATE!";
|
|
|
|
else
|
|
|
|
return dccp_state_names[state];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-03-21 13:58:56 +08:00
|
|
|
void dccp_set_state(struct sock *sk, const int state)
|
|
|
|
{
|
|
|
|
const int oldstate = sk->sk_state;
|
|
|
|
|
2007-11-28 21:34:53 +08:00
|
|
|
dccp_pr_debug("%s(%p) %s --> %s\n", dccp_role(sk), sk,
|
2006-03-21 13:58:56 +08:00
|
|
|
dccp_state_name(oldstate), dccp_state_name(state));
|
|
|
|
WARN_ON(state == oldstate);
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case DCCP_OPEN:
|
|
|
|
if (oldstate != DCCP_OPEN)
|
|
|
|
DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
|
2008-12-08 17:15:26 +08:00
|
|
|
/* Client retransmits all Confirm options until entering OPEN */
|
|
|
|
if (oldstate == DCCP_PARTOPEN)
|
|
|
|
dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
|
2006-03-21 13:58:56 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DCCP_CLOSED:
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
if (oldstate == DCCP_OPEN || oldstate == DCCP_ACTIVE_CLOSEREQ ||
|
|
|
|
oldstate == DCCP_CLOSING)
|
2006-03-21 13:58:56 +08:00
|
|
|
DCCP_INC_STATS(DCCP_MIB_ESTABRESETS);
|
|
|
|
|
|
|
|
sk->sk_prot->unhash(sk);
|
|
|
|
if (inet_csk(sk)->icsk_bind_hash != NULL &&
|
|
|
|
!(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
|
[SOCK] proto: Add hashinfo member to struct proto
This way we can remove TCP and DCCP specific versions of
sk->sk_prot->get_port: both v4 and v6 use inet_csk_get_port
sk->sk_prot->hash: inet_hash is directly used, only v6 need
a specific version to deal with mapped sockets
sk->sk_prot->unhash: both v4 and v6 use inet_hash directly
struct inet_connection_sock_af_ops also gets a new member, bind_conflict, so
that inet_csk_get_port can find the per family routine.
Now only the lookup routines receive as a parameter a struct inet_hashtable.
With this we further reuse code, reducing the difference among INET transport
protocols.
Eventually work has to be done on UDP and SCTP to make them share this
infrastructure and get as a bonus inet_diag interfaces so that iproute can be
used with these protocols.
net-2.6/net/ipv4/inet_hashtables.c:
struct proto | +8
struct inet_connection_sock_af_ops | +8
2 structs changed
__inet_hash_nolisten | +18
__inet_hash | -210
inet_put_port | +8
inet_bind_bucket_create | +1
__inet_hash_connect | -8
5 functions changed, 27 bytes added, 218 bytes removed, diff: -191
net-2.6/net/core/sock.c:
proto_seq_show | +3
1 function changed, 3 bytes added, diff: +3
net-2.6/net/ipv4/inet_connection_sock.c:
inet_csk_get_port | +15
1 function changed, 15 bytes added, diff: +15
net-2.6/net/ipv4/tcp.c:
tcp_set_state | -7
1 function changed, 7 bytes removed, diff: -7
net-2.6/net/ipv4/tcp_ipv4.c:
tcp_v4_get_port | -31
tcp_v4_hash | -48
tcp_v4_destroy_sock | -7
tcp_v4_syn_recv_sock | -2
tcp_unhash | -179
5 functions changed, 267 bytes removed, diff: -267
net-2.6/net/ipv6/inet6_hashtables.c:
__inet6_hash | +8
1 function changed, 8 bytes added, diff: +8
net-2.6/net/ipv4/inet_hashtables.c:
inet_unhash | +190
inet_hash | +242
2 functions changed, 432 bytes added, diff: +432
vmlinux:
16 functions changed, 485 bytes added, 492 bytes removed, diff: -7
/home/acme/git/net-2.6/net/ipv6/tcp_ipv6.c:
tcp_v6_get_port | -31
tcp_v6_hash | -7
tcp_v6_syn_recv_sock | -9
3 functions changed, 47 bytes removed, diff: -47
/home/acme/git/net-2.6/net/dccp/proto.c:
dccp_destroy_sock | -7
dccp_unhash | -179
dccp_hash | -49
dccp_set_state | -7
dccp_done | +1
5 functions changed, 1 bytes added, 242 bytes removed, diff: -241
/home/acme/git/net-2.6/net/dccp/ipv4.c:
dccp_v4_get_port | -31
dccp_v4_request_recv_sock | -2
2 functions changed, 33 bytes removed, diff: -33
/home/acme/git/net-2.6/net/dccp/ipv6.c:
dccp_v6_get_port | -31
dccp_v6_hash | -7
dccp_v6_request_recv_sock | +5
3 functions changed, 5 bytes added, 38 bytes removed, diff: -33
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-02-03 20:06:04 +08:00
|
|
|
inet_put_port(sk);
|
2020-08-24 06:36:59 +08:00
|
|
|
fallthrough;
|
2006-03-21 13:58:56 +08:00
|
|
|
default:
|
|
|
|
if (oldstate == DCCP_OPEN)
|
|
|
|
DCCP_DEC_STATS(DCCP_MIB_CURRESTAB);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Change state AFTER socket is unhashed to avoid closed
|
|
|
|
* socket sitting in hash tables.
|
|
|
|
*/
|
2017-12-20 11:12:53 +08:00
|
|
|
inet_sk_set_state(sk, state);
|
2006-03-21 13:58:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(dccp_set_state);
|
|
|
|
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
static void dccp_finish_passive_close(struct sock *sk)
|
|
|
|
{
|
|
|
|
switch (sk->sk_state) {
|
|
|
|
case DCCP_PASSIVE_CLOSE:
|
|
|
|
/* Node (client or server) has received Close packet. */
|
|
|
|
dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
|
|
|
|
dccp_set_state(sk, DCCP_CLOSED);
|
|
|
|
break;
|
|
|
|
case DCCP_PASSIVE_CLOSEREQ:
|
|
|
|
/*
|
|
|
|
* Client received CloseReq. We set the `active' flag so that
|
|
|
|
* dccp_send_close() retransmits the Close as per RFC 4340, 8.3.
|
|
|
|
*/
|
|
|
|
dccp_send_close(sk, 1);
|
|
|
|
dccp_set_state(sk, DCCP_CLOSING);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-21 13:58:56 +08:00
|
|
|
void dccp_done(struct sock *sk)
|
|
|
|
{
|
|
|
|
dccp_set_state(sk, DCCP_CLOSED);
|
|
|
|
dccp_clear_xmit_timers(sk);
|
|
|
|
|
|
|
|
sk->sk_shutdown = SHUTDOWN_MASK;
|
|
|
|
|
|
|
|
if (!sock_flag(sk, SOCK_DEAD))
|
|
|
|
sk->sk_state_change(sk);
|
|
|
|
else
|
|
|
|
inet_csk_destroy_sock(sk);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(dccp_done);
|
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
const char *dccp_packet_name(const int type)
|
|
|
|
{
|
2009-08-06 01:42:58 +08:00
|
|
|
static const char *const dccp_packet_names[] = {
|
2005-08-10 11:14:34 +08:00
|
|
|
[DCCP_PKT_REQUEST] = "REQUEST",
|
|
|
|
[DCCP_PKT_RESPONSE] = "RESPONSE",
|
|
|
|
[DCCP_PKT_DATA] = "DATA",
|
|
|
|
[DCCP_PKT_ACK] = "ACK",
|
|
|
|
[DCCP_PKT_DATAACK] = "DATAACK",
|
|
|
|
[DCCP_PKT_CLOSEREQ] = "CLOSEREQ",
|
|
|
|
[DCCP_PKT_CLOSE] = "CLOSE",
|
|
|
|
[DCCP_PKT_RESET] = "RESET",
|
|
|
|
[DCCP_PKT_SYNC] = "SYNC",
|
|
|
|
[DCCP_PKT_SYNCACK] = "SYNCACK",
|
|
|
|
};
|
|
|
|
|
|
|
|
if (type >= DCCP_NR_PKT_TYPES)
|
|
|
|
return "INVALID";
|
|
|
|
else
|
|
|
|
return dccp_packet_names[type];
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(dccp_packet_name);
|
|
|
|
|
2022-10-20 06:36:00 +08:00
|
|
|
void dccp_destruct_common(struct sock *sk)
|
2017-08-16 22:03:15 +08:00
|
|
|
{
|
|
|
|
struct dccp_sock *dp = dccp_sk(sk);
|
|
|
|
|
|
|
|
ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
|
|
|
|
dp->dccps_hc_tx_ccid = NULL;
|
2022-10-20 06:36:00 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(dccp_destruct_common);
|
|
|
|
|
|
|
|
static void dccp_sk_destruct(struct sock *sk)
|
|
|
|
{
|
|
|
|
dccp_destruct_common(sk);
|
2017-08-16 22:03:15 +08:00
|
|
|
inet_sock_destruct(sk);
|
|
|
|
}
|
|
|
|
|
2006-03-21 14:00:37 +08:00
|
|
|
int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
|
2006-03-21 13:23:15 +08:00
|
|
|
{
|
|
|
|
struct dccp_sock *dp = dccp_sk(sk);
|
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
|
2023-06-15 03:47:05 +08:00
|
|
|
pr_warn_once("DCCP is deprecated and scheduled to be removed in 2025, "
|
|
|
|
"please contact the netdev mailing list\n");
|
|
|
|
|
2007-11-25 07:42:53 +08:00
|
|
|
icsk->icsk_rto = DCCP_TIMEOUT_INIT;
|
|
|
|
icsk->icsk_syn_retries = sysctl_dccp_request_retries;
|
|
|
|
sk->sk_state = DCCP_CLOSED;
|
|
|
|
sk->sk_write_space = dccp_write_space;
|
2017-08-16 22:03:15 +08:00
|
|
|
sk->sk_destruct = dccp_sk_destruct;
|
2007-11-25 07:42:53 +08:00
|
|
|
icsk->icsk_sync_mss = dccp_sync_mss;
|
2008-09-09 19:27:22 +08:00
|
|
|
dp->dccps_mss_cache = 536;
|
2007-11-25 07:42:53 +08:00
|
|
|
dp->dccps_rate_last = jiffies;
|
|
|
|
dp->dccps_role = DCCP_ROLE_UNDEFINED;
|
|
|
|
dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
|
2010-12-04 20:38:01 +08:00
|
|
|
dp->dccps_tx_qlen = sysctl_dccp_tx_qlen;
|
2007-11-25 07:42:53 +08:00
|
|
|
|
|
|
|
dccp_init_xmit_timers(sk);
|
|
|
|
|
2008-11-05 15:55:49 +08:00
|
|
|
INIT_LIST_HEAD(&dp->dccps_featneg);
|
2008-12-08 17:15:26 +08:00
|
|
|
/* control socket doesn't need feat nego */
|
|
|
|
if (likely(ctl_sock_initialized))
|
|
|
|
return dccp_feat_init(sk);
|
2006-03-21 13:23:15 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(dccp_init_sock);
|
|
|
|
|
2008-06-15 08:04:49 +08:00
|
|
|
void dccp_destroy_sock(struct sock *sk)
|
2006-03-21 13:23:15 +08:00
|
|
|
{
|
|
|
|
struct dccp_sock *dp = dccp_sk(sk);
|
|
|
|
|
2017-08-15 05:10:25 +08:00
|
|
|
__skb_queue_purge(&sk->sk_write_queue);
|
2006-03-21 13:23:15 +08:00
|
|
|
if (sk->sk_send_head != NULL) {
|
|
|
|
kfree_skb(sk->sk_send_head);
|
|
|
|
sk->sk_send_head = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clean up a referenced DCCP bind bucket. */
|
|
|
|
if (inet_csk(sk)->icsk_bind_hash != NULL)
|
[SOCK] proto: Add hashinfo member to struct proto
This way we can remove TCP and DCCP specific versions of
sk->sk_prot->get_port: both v4 and v6 use inet_csk_get_port
sk->sk_prot->hash: inet_hash is directly used, only v6 need
a specific version to deal with mapped sockets
sk->sk_prot->unhash: both v4 and v6 use inet_hash directly
struct inet_connection_sock_af_ops also gets a new member, bind_conflict, so
that inet_csk_get_port can find the per family routine.
Now only the lookup routines receive as a parameter a struct inet_hashtable.
With this we further reuse code, reducing the difference among INET transport
protocols.
Eventually work has to be done on UDP and SCTP to make them share this
infrastructure and get as a bonus inet_diag interfaces so that iproute can be
used with these protocols.
net-2.6/net/ipv4/inet_hashtables.c:
struct proto | +8
struct inet_connection_sock_af_ops | +8
2 structs changed
__inet_hash_nolisten | +18
__inet_hash | -210
inet_put_port | +8
inet_bind_bucket_create | +1
__inet_hash_connect | -8
5 functions changed, 27 bytes added, 218 bytes removed, diff: -191
net-2.6/net/core/sock.c:
proto_seq_show | +3
1 function changed, 3 bytes added, diff: +3
net-2.6/net/ipv4/inet_connection_sock.c:
inet_csk_get_port | +15
1 function changed, 15 bytes added, diff: +15
net-2.6/net/ipv4/tcp.c:
tcp_set_state | -7
1 function changed, 7 bytes removed, diff: -7
net-2.6/net/ipv4/tcp_ipv4.c:
tcp_v4_get_port | -31
tcp_v4_hash | -48
tcp_v4_destroy_sock | -7
tcp_v4_syn_recv_sock | -2
tcp_unhash | -179
5 functions changed, 267 bytes removed, diff: -267
net-2.6/net/ipv6/inet6_hashtables.c:
__inet6_hash | +8
1 function changed, 8 bytes added, diff: +8
net-2.6/net/ipv4/inet_hashtables.c:
inet_unhash | +190
inet_hash | +242
2 functions changed, 432 bytes added, diff: +432
vmlinux:
16 functions changed, 485 bytes added, 492 bytes removed, diff: -7
/home/acme/git/net-2.6/net/ipv6/tcp_ipv6.c:
tcp_v6_get_port | -31
tcp_v6_hash | -7
tcp_v6_syn_recv_sock | -9
3 functions changed, 47 bytes removed, diff: -47
/home/acme/git/net-2.6/net/dccp/proto.c:
dccp_destroy_sock | -7
dccp_unhash | -179
dccp_hash | -49
dccp_set_state | -7
dccp_done | +1
5 functions changed, 1 bytes added, 242 bytes removed, diff: -241
/home/acme/git/net-2.6/net/dccp/ipv4.c:
dccp_v4_get_port | -31
dccp_v4_request_recv_sock | -2
2 functions changed, 33 bytes removed, diff: -33
/home/acme/git/net-2.6/net/dccp/ipv6.c:
dccp_v6_get_port | -31
dccp_v6_hash | -7
dccp_v6_request_recv_sock | +5
3 functions changed, 5 bytes added, 38 bytes removed, diff: -33
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-02-03 20:06:04 +08:00
|
|
|
inet_put_port(sk);
|
2006-03-21 13:23:15 +08:00
|
|
|
|
|
|
|
kfree(dp->dccps_service_list);
|
|
|
|
dp->dccps_service_list = NULL;
|
|
|
|
|
dccp ccid-2: Phase out the use of boolean Ack Vector sysctl
This removes the use of the sysctl and the minisock variable for the Send Ack
Vector feature, as it now is handled fully dynamically via feature negotiation
(i.e. when CCID-2 is enabled, Ack Vectors are automatically enabled as per
RFC 4341, 4.).
Using a sysctl in parallel to this implementation would open the door to
crashes, since much of the code relies on tests of the boolean minisock /
sysctl variable. Thus, this patch replaces all tests of type
if (dccp_msk(sk)->dccpms_send_ack_vector)
/* ... */
with
if (dp->dccps_hc_rx_ackvec != NULL)
/* ... */
The dccps_hc_rx_ackvec is allocated by the dccp_hdlr_ackvec() when feature
negotiation concluded that Ack Vectors are to be used on the half-connection.
Otherwise, it is NULL (due to dccp_init_sock/dccp_create_openreq_child),
so that the test is a valid one.
The activation handler for Ack Vectors is called as soon as the feature
negotiation has concluded at the
* server when the Ack marking the transition RESPOND => OPEN arrives;
* client after it has sent its ACK, marking the transition REQUEST => PARTOPEN.
Adding the sequence number of the Response packet to the Ack Vector has been
removed, since
(a) connection establishment implies that the Response has been received;
(b) the CCIDs only look at packets received in the (PART)OPEN state, i.e.
this entry will always be ignored;
(c) it can not be used for anything useful - to detect loss for instance, only
packets received after the loss can serve as pseudo-dupacks.
There was a FIXME to change the error code when dccp_ackvec_add() fails.
I removed this after finding out that:
* the check whether ackno < ISN is already made earlier,
* this Response is likely the 1st packet with an Ackno that the client gets,
* so when dccp_ackvec_add() fails, the reason is likely not a packet error.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-12-08 17:19:06 +08:00
|
|
|
if (dp->dccps_hc_rx_ackvec != NULL) {
|
2006-03-21 13:23:15 +08:00
|
|
|
dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
|
|
|
|
dp->dccps_hc_rx_ackvec = NULL;
|
|
|
|
}
|
|
|
|
ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
|
2017-08-16 22:03:15 +08:00
|
|
|
dp->dccps_hc_rx_ccid = NULL;
|
2006-03-21 13:23:15 +08:00
|
|
|
|
|
|
|
/* clean up feature negotiation state */
|
2008-11-05 15:56:30 +08:00
|
|
|
dccp_feat_list_purge(&dp->dccps_featneg);
|
2006-03-21 13:23:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(dccp_destroy_sock);
|
|
|
|
|
2007-11-25 08:14:15 +08:00
|
|
|
static inline int dccp_need_reset(int state)
|
|
|
|
{
|
|
|
|
return state != DCCP_CLOSED && state != DCCP_LISTEN &&
|
|
|
|
state != DCCP_REQUESTING;
|
|
|
|
}
|
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
int dccp_disconnect(struct sock *sk, int flags)
|
|
|
|
{
|
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
struct inet_sock *inet = inet_sk(sk);
|
2017-12-06 04:58:35 +08:00
|
|
|
struct dccp_sock *dp = dccp_sk(sk);
|
2005-08-10 11:14:34 +08:00
|
|
|
const int old_state = sk->sk_state;
|
|
|
|
|
|
|
|
if (old_state != DCCP_CLOSED)
|
|
|
|
dccp_set_state(sk, DCCP_CLOSED);
|
|
|
|
|
2007-11-25 08:14:15 +08:00
|
|
|
/*
|
|
|
|
* This corresponds to the ABORT function of RFC793, sec. 3.8
|
|
|
|
* TCP uses a RST segment, DCCP a Reset packet with Code 2, "Aborted".
|
|
|
|
*/
|
2005-08-10 11:14:34 +08:00
|
|
|
if (old_state == DCCP_LISTEN) {
|
|
|
|
inet_csk_listen_stop(sk);
|
2007-11-25 08:14:15 +08:00
|
|
|
} else if (dccp_need_reset(old_state)) {
|
|
|
|
dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
|
|
|
|
sk->sk_err = ECONNRESET;
|
2005-08-10 11:14:34 +08:00
|
|
|
} else if (old_state == DCCP_REQUESTING)
|
|
|
|
sk->sk_err = ECONNRESET;
|
|
|
|
|
|
|
|
dccp_clear_xmit_timers(sk);
|
2017-12-06 04:58:35 +08:00
|
|
|
ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
|
|
|
|
dp->dccps_hc_rx_ccid = NULL;
|
2008-08-23 19:28:27 +08:00
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
__skb_queue_purge(&sk->sk_receive_queue);
|
2008-08-23 19:28:27 +08:00
|
|
|
__skb_queue_purge(&sk->sk_write_queue);
|
2005-08-10 11:14:34 +08:00
|
|
|
if (sk->sk_send_head != NULL) {
|
|
|
|
__kfree_skb(sk->sk_send_head);
|
|
|
|
sk->sk_send_head = NULL;
|
|
|
|
}
|
|
|
|
|
2009-10-15 14:30:45 +08:00
|
|
|
inet->inet_dport = 0;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2022-11-19 09:49:14 +08:00
|
|
|
inet_bhash2_reset_saddr(sk);
|
2005-08-10 11:14:34 +08:00
|
|
|
|
|
|
|
sk->sk_shutdown = 0;
|
|
|
|
sock_reset_flag(sk, SOCK_DONE);
|
|
|
|
|
|
|
|
icsk->icsk_backoff = 0;
|
|
|
|
inet_csk_delack_init(sk);
|
|
|
|
__sk_dst_reset(sk);
|
|
|
|
|
2009-10-15 14:30:45 +08:00
|
|
|
WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2021-06-28 06:48:21 +08:00
|
|
|
sk_error_report(sk);
|
2019-05-12 18:39:49 +08:00
|
|
|
return 0;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
2005-12-14 15:24:16 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_disconnect);
|
|
|
|
|
2018-06-29 00:43:44 +08:00
|
|
|
/*
|
|
|
|
* Wait for a DCCP event.
|
|
|
|
*
|
|
|
|
* Note that we don't need to lock the socket, as the upper poll layers
|
|
|
|
* take care of normal races (between the test and the event) and we don't
|
|
|
|
* go look at any of the socket buffers directly.
|
|
|
|
*/
|
|
|
|
__poll_t dccp_poll(struct file *file, struct socket *sock,
|
|
|
|
poll_table *wait)
|
2005-08-24 12:54:23 +08:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
2023-08-18 09:58:20 +08:00
|
|
|
__poll_t mask;
|
|
|
|
u8 shutdown;
|
|
|
|
int state;
|
2005-08-24 12:54:23 +08:00
|
|
|
|
2018-10-23 19:40:39 +08:00
|
|
|
sock_poll_wait(file, sock, wait);
|
2023-08-18 09:58:20 +08:00
|
|
|
|
|
|
|
state = inet_sk_state_load(sk);
|
|
|
|
if (state == DCCP_LISTEN)
|
2005-08-24 12:54:23 +08:00
|
|
|
return inet_csk_listen_poll(sk);
|
|
|
|
|
|
|
|
/* Socket is not locked. We are protected from async events
|
|
|
|
by poll logic and correct handling of state changes
|
|
|
|
made by another threads is impossible in any case.
|
|
|
|
*/
|
|
|
|
|
|
|
|
mask = 0;
|
2023-08-18 09:58:20 +08:00
|
|
|
if (READ_ONCE(sk->sk_err))
|
2018-02-12 06:34:03 +08:00
|
|
|
mask = EPOLLERR;
|
2023-08-18 09:58:20 +08:00
|
|
|
shutdown = READ_ONCE(sk->sk_shutdown);
|
2005-08-24 12:54:23 +08:00
|
|
|
|
2023-08-18 09:58:20 +08:00
|
|
|
if (shutdown == SHUTDOWN_MASK || state == DCCP_CLOSED)
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLHUP;
|
2023-08-18 09:58:20 +08:00
|
|
|
if (shutdown & RCV_SHUTDOWN)
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;
|
2005-08-24 12:54:23 +08:00
|
|
|
|
|
|
|
/* Connected? */
|
2023-08-18 09:58:20 +08:00
|
|
|
if ((1 << state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
|
2005-08-24 12:54:23 +08:00
|
|
|
if (atomic_read(&sk->sk_rmem_alloc) > 0)
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLIN | EPOLLRDNORM;
|
2005-08-24 12:54:23 +08:00
|
|
|
|
2023-08-18 09:58:20 +08:00
|
|
|
if (!(shutdown & SEND_SHUTDOWN)) {
|
2013-07-23 11:26:31 +08:00
|
|
|
if (sk_stream_is_writeable(sk)) {
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLOUT | EPOLLWRNORM;
|
2005-08-24 12:54:23 +08:00
|
|
|
} else { /* send SIGIO later */
|
2015-11-30 12:03:10 +08:00
|
|
|
sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
|
2005-08-24 12:54:23 +08:00
|
|
|
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
|
|
|
|
|
|
|
/* Race breaker. If space is freed after
|
|
|
|
* wspace test but before the flags are set,
|
|
|
|
* IO signal will be lost.
|
|
|
|
*/
|
2013-07-23 11:26:31 +08:00
|
|
|
if (sk_stream_is_writeable(sk))
|
2018-02-12 06:34:03 +08:00
|
|
|
mask |= EPOLLOUT | EPOLLWRNORM;
|
2005-08-24 12:54:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mask;
|
|
|
|
}
|
2018-06-29 00:43:44 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_poll);
|
2005-12-14 15:24:16 +08:00
|
|
|
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 23:27:42 +08:00
|
|
|
int dccp_ioctl(struct sock *sk, int cmd, int *karg)
|
2005-08-10 11:14:34 +08:00
|
|
|
{
|
2007-10-24 11:23:30 +08:00
|
|
|
int rc = -ENOTCONN;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
if (sk->sk_state == DCCP_LISTEN)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
switch (cmd) {
|
2020-07-21 00:06:14 +08:00
|
|
|
case SIOCOUTQ: {
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 23:27:42 +08:00
|
|
|
*karg = sk_wmem_alloc_get(sk);
|
2020-07-21 00:06:14 +08:00
|
|
|
/* Using sk_wmem_alloc here because sk_wmem_queued is not used by DCCP and
|
|
|
|
* always 0, comparably to UDP.
|
|
|
|
*/
|
|
|
|
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 23:27:42 +08:00
|
|
|
rc = 0;
|
2020-07-21 00:06:14 +08:00
|
|
|
}
|
|
|
|
break;
|
2007-10-24 11:23:30 +08:00
|
|
|
case SIOCINQ: {
|
|
|
|
struct sk_buff *skb;
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 23:27:42 +08:00
|
|
|
*karg = 0;
|
2007-10-24 11:23:30 +08:00
|
|
|
|
|
|
|
skb = skb_peek(&sk->sk_receive_queue);
|
|
|
|
if (skb != NULL) {
|
|
|
|
/*
|
|
|
|
* We will only return the amount of this packet since
|
|
|
|
* that is all that will be read.
|
|
|
|
*/
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 23:27:42 +08:00
|
|
|
*karg = skb->len;
|
2007-10-24 11:23:30 +08:00
|
|
|
}
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 23:27:42 +08:00
|
|
|
rc = 0;
|
2007-10-24 11:23:30 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = -ENOIOCTLCMD;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
release_sock(sk);
|
|
|
|
return rc;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
2005-12-14 15:24:16 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_ioctl);
|
|
|
|
|
2006-03-21 11:23:32 +08:00
|
|
|
static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
|
2020-07-23 14:09:07 +08:00
|
|
|
sockptr_t optval, unsigned int optlen)
|
2005-09-17 07:58:40 +08:00
|
|
|
{
|
|
|
|
struct dccp_sock *dp = dccp_sk(sk);
|
|
|
|
struct dccp_service_list *sl = NULL;
|
|
|
|
|
2006-12-11 02:01:18 +08:00
|
|
|
if (service == DCCP_SERVICE_INVALID_VALUE ||
|
2005-09-17 07:58:40 +08:00
|
|
|
optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (optlen > sizeof(service)) {
|
|
|
|
sl = kmalloc(optlen, GFP_KERNEL);
|
|
|
|
if (sl == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
sl->dccpsl_nr = optlen / sizeof(u32) - 1;
|
2020-07-29 00:38:35 +08:00
|
|
|
if (copy_from_sockptr_offset(sl->dccpsl_list, optval,
|
|
|
|
sizeof(service), optlen - sizeof(service)) ||
|
2005-09-17 07:58:40 +08:00
|
|
|
dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
|
|
|
|
kfree(sl);
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
dp->dccps_service = service;
|
|
|
|
|
2005-11-09 01:41:34 +08:00
|
|
|
kfree(dp->dccps_service_list);
|
2005-09-17 07:58:40 +08:00
|
|
|
|
|
|
|
dp->dccps_service_list = sl;
|
|
|
|
release_sock(sk);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-17 14:53:48 +08:00
|
|
|
static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
|
|
|
|
{
|
|
|
|
u8 *list, len;
|
|
|
|
int i, rc;
|
|
|
|
|
|
|
|
if (cscov < 0 || cscov > 15)
|
|
|
|
return -EINVAL;
|
|
|
|
/*
|
|
|
|
* Populate a list of permissible values, in the range cscov...15. This
|
|
|
|
* is necessary since feature negotiation of single values only works if
|
|
|
|
* both sides incidentally choose the same value. Since the list starts
|
|
|
|
* lowest-value first, negotiation will pick the smallest shared value.
|
|
|
|
*/
|
|
|
|
if (cscov == 0)
|
|
|
|
return 0;
|
|
|
|
len = 16 - cscov;
|
|
|
|
|
|
|
|
list = kmalloc(len, GFP_KERNEL);
|
|
|
|
if (list == NULL)
|
|
|
|
return -ENOBUFS;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
list[i] = cscov++;
|
|
|
|
|
|
|
|
rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
|
|
|
|
|
|
|
|
if (rc == 0) {
|
|
|
|
if (rx)
|
|
|
|
dccp_sk(sk)->dccps_pcrlen = cscov;
|
|
|
|
else
|
|
|
|
dccp_sk(sk)->dccps_pcslen = cscov;
|
|
|
|
}
|
|
|
|
kfree(list);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-11-24 08:02:31 +08:00
|
|
|
static int dccp_setsockopt_ccid(struct sock *sk, int type,
|
2020-07-23 14:09:07 +08:00
|
|
|
sockptr_t optval, unsigned int optlen)
|
2008-11-24 08:02:31 +08:00
|
|
|
{
|
|
|
|
u8 *val;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-07-23 14:09:07 +08:00
|
|
|
val = memdup_sockptr(optval, optlen);
|
2010-05-22 06:25:19 +08:00
|
|
|
if (IS_ERR(val))
|
|
|
|
return PTR_ERR(val);
|
2008-11-24 08:02:31 +08:00
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
|
|
|
|
rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
|
|
|
|
|
|
|
|
if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
|
|
|
|
rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
kfree(val);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2006-03-21 14:45:21 +08:00
|
|
|
static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
|
2020-07-23 14:09:07 +08:00
|
|
|
sockptr_t optval, unsigned int optlen)
|
2005-08-10 11:14:34 +08:00
|
|
|
{
|
2006-11-14 22:57:34 +08:00
|
|
|
struct dccp_sock *dp = dccp_sk(sk);
|
|
|
|
int val, err = 0;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2008-11-17 14:56:55 +08:00
|
|
|
switch (optname) {
|
|
|
|
case DCCP_SOCKOPT_PACKET_SIZE:
|
|
|
|
DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
|
|
|
|
return 0;
|
|
|
|
case DCCP_SOCKOPT_CHANGE_L:
|
|
|
|
case DCCP_SOCKOPT_CHANGE_R:
|
|
|
|
DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
|
|
|
|
return 0;
|
2008-11-24 08:02:31 +08:00
|
|
|
case DCCP_SOCKOPT_CCID:
|
|
|
|
case DCCP_SOCKOPT_RX_CCID:
|
|
|
|
case DCCP_SOCKOPT_TX_CCID:
|
|
|
|
return dccp_setsockopt_ccid(sk, optname, optval, optlen);
|
2008-11-17 14:56:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (optlen < (int)sizeof(int))
|
2005-08-28 15:51:32 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2020-07-23 14:09:07 +08:00
|
|
|
if (copy_from_sockptr(&val, optval, sizeof(int)))
|
2005-08-28 15:51:32 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
2005-09-17 07:58:40 +08:00
|
|
|
if (optname == DCCP_SOCKOPT_SERVICE)
|
|
|
|
return dccp_setsockopt_service(sk, val, optval, optlen);
|
2005-08-28 15:51:32 +08:00
|
|
|
|
2005-09-17 07:58:40 +08:00
|
|
|
lock_sock(sk);
|
2005-08-28 15:51:32 +08:00
|
|
|
switch (optname) {
|
2007-12-13 22:25:01 +08:00
|
|
|
case DCCP_SOCKOPT_SERVER_TIMEWAIT:
|
|
|
|
if (dp->dccps_role != DCCP_ROLE_SERVER)
|
|
|
|
err = -EOPNOTSUPP;
|
|
|
|
else
|
|
|
|
dp->dccps_server_timewait = (val != 0);
|
|
|
|
break;
|
2008-11-17 14:53:48 +08:00
|
|
|
case DCCP_SOCKOPT_SEND_CSCOV:
|
|
|
|
err = dccp_setsockopt_cscov(sk, val, false);
|
2008-09-04 13:30:19 +08:00
|
|
|
break;
|
2008-11-17 14:53:48 +08:00
|
|
|
case DCCP_SOCKOPT_RECV_CSCOV:
|
|
|
|
err = dccp_setsockopt_cscov(sk, val, true);
|
2008-09-04 13:30:19 +08:00
|
|
|
break;
|
2010-12-04 20:38:01 +08:00
|
|
|
case DCCP_SOCKOPT_QPOLICY_ID:
|
|
|
|
if (sk->sk_state != DCCP_CLOSED)
|
|
|
|
err = -EISCONN;
|
|
|
|
else if (val < 0 || val >= DCCPQ_POLICY_MAX)
|
|
|
|
err = -EINVAL;
|
|
|
|
else
|
|
|
|
dp->dccps_qpolicy = val;
|
|
|
|
break;
|
|
|
|
case DCCP_SOCKOPT_QPOLICY_TXQLEN:
|
|
|
|
if (val < 0)
|
|
|
|
err = -EINVAL;
|
|
|
|
else
|
|
|
|
dp->dccps_tx_qlen = val;
|
|
|
|
break;
|
2005-08-28 15:51:32 +08:00
|
|
|
default:
|
|
|
|
err = -ENOPROTOOPT;
|
|
|
|
break;
|
|
|
|
}
|
2008-09-09 19:27:22 +08:00
|
|
|
release_sock(sk);
|
2008-11-17 14:56:55 +08:00
|
|
|
|
2005-08-28 15:51:32 +08:00
|
|
|
return err;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
2020-07-23 14:09:07 +08:00
|
|
|
int dccp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
|
|
|
|
unsigned int optlen)
|
2006-03-21 14:45:21 +08:00
|
|
|
{
|
|
|
|
if (level != SOL_DCCP)
|
|
|
|
return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
|
|
|
|
optname, optval,
|
|
|
|
optlen);
|
|
|
|
return do_dccp_setsockopt(sk, level, optname, optval, optlen);
|
|
|
|
}
|
2006-03-21 14:48:35 +08:00
|
|
|
|
2005-12-14 15:24:16 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_setsockopt);
|
|
|
|
|
2005-09-17 07:58:40 +08:00
|
|
|
static int dccp_getsockopt_service(struct sock *sk, int len,
|
2006-03-21 11:23:32 +08:00
|
|
|
__be32 __user *optval,
|
2005-09-17 07:58:40 +08:00
|
|
|
int __user *optlen)
|
|
|
|
{
|
|
|
|
const struct dccp_sock *dp = dccp_sk(sk);
|
|
|
|
const struct dccp_service_list *sl;
|
|
|
|
int err = -ENOENT, slen = 0, total_len = sizeof(u32);
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
if ((sl = dp->dccps_service_list) != NULL) {
|
|
|
|
slen = sl->dccpsl_nr * sizeof(u32);
|
|
|
|
total_len += slen;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
if (total_len > len)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
if (put_user(total_len, optlen) ||
|
|
|
|
put_user(dp->dccps_service, optval) ||
|
|
|
|
(sl != NULL && copy_to_user(optval + 1, sl->dccpsl_list, slen)))
|
|
|
|
err = -EFAULT;
|
|
|
|
out:
|
|
|
|
release_sock(sk);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-03-21 14:45:21 +08:00
|
|
|
static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
|
2005-08-14 09:42:25 +08:00
|
|
|
char __user *optval, int __user *optlen)
|
2005-08-10 11:14:34 +08:00
|
|
|
{
|
2005-08-28 15:51:32 +08:00
|
|
|
struct dccp_sock *dp;
|
|
|
|
int val, len;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2005-08-28 15:51:32 +08:00
|
|
|
if (get_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
|
2007-03-29 02:54:32 +08:00
|
|
|
if (len < (int)sizeof(int))
|
2005-08-28 15:51:32 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
dp = dccp_sk(sk);
|
|
|
|
|
|
|
|
switch (optname) {
|
|
|
|
case DCCP_SOCKOPT_PACKET_SIZE:
|
2006-11-29 05:33:36 +08:00
|
|
|
DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
|
2006-11-29 05:42:03 +08:00
|
|
|
return 0;
|
2005-09-18 15:19:32 +08:00
|
|
|
case DCCP_SOCKOPT_SERVICE:
|
|
|
|
return dccp_getsockopt_service(sk, len,
|
2006-03-21 11:23:32 +08:00
|
|
|
(__be32 __user *)optval, optlen);
|
2007-10-05 05:39:22 +08:00
|
|
|
case DCCP_SOCKOPT_GET_CUR_MPS:
|
2023-08-04 00:30:21 +08:00
|
|
|
val = READ_ONCE(dp->dccps_mss_cache);
|
2007-10-05 05:39:22 +08:00
|
|
|
break;
|
2008-11-12 16:47:26 +08:00
|
|
|
case DCCP_SOCKOPT_AVAILABLE_CCIDS:
|
|
|
|
return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
|
2008-11-24 08:04:59 +08:00
|
|
|
case DCCP_SOCKOPT_TX_CCID:
|
|
|
|
val = ccid_get_current_tx_ccid(dp);
|
|
|
|
if (val < 0)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
break;
|
|
|
|
case DCCP_SOCKOPT_RX_CCID:
|
|
|
|
val = ccid_get_current_rx_ccid(dp);
|
|
|
|
if (val < 0)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
break;
|
2007-12-13 22:25:01 +08:00
|
|
|
case DCCP_SOCKOPT_SERVER_TIMEWAIT:
|
|
|
|
val = dp->dccps_server_timewait;
|
|
|
|
break;
|
2006-11-11 03:43:06 +08:00
|
|
|
case DCCP_SOCKOPT_SEND_CSCOV:
|
|
|
|
val = dp->dccps_pcslen;
|
|
|
|
break;
|
|
|
|
case DCCP_SOCKOPT_RECV_CSCOV:
|
|
|
|
val = dp->dccps_pcrlen;
|
|
|
|
break;
|
2010-12-04 20:38:01 +08:00
|
|
|
case DCCP_SOCKOPT_QPOLICY_ID:
|
|
|
|
val = dp->dccps_qpolicy;
|
|
|
|
break;
|
|
|
|
case DCCP_SOCKOPT_QPOLICY_TXQLEN:
|
|
|
|
val = dp->dccps_tx_qlen;
|
|
|
|
break;
|
2005-09-18 15:19:32 +08:00
|
|
|
case 128 ... 191:
|
|
|
|
return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
|
|
|
|
len, (u32 __user *)optval, optlen);
|
|
|
|
case 192 ... 255:
|
|
|
|
return ccid_hc_tx_getsockopt(dp->dccps_hc_tx_ccid, sk, optname,
|
|
|
|
len, (u32 __user *)optval, optlen);
|
2005-08-28 15:51:32 +08:00
|
|
|
default:
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
}
|
|
|
|
|
2007-12-13 22:27:14 +08:00
|
|
|
len = sizeof(val);
|
2005-08-28 15:51:32 +08:00
|
|
|
if (put_user(len, optlen) || copy_to_user(optval, &val, len))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return 0;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
2006-03-21 14:45:21 +08:00
|
|
|
int dccp_getsockopt(struct sock *sk, int level, int optname,
|
|
|
|
char __user *optval, int __user *optlen)
|
|
|
|
{
|
|
|
|
if (level != SOL_DCCP)
|
|
|
|
return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
|
|
|
|
optname, optval,
|
|
|
|
optlen);
|
|
|
|
return do_dccp_getsockopt(sk, level, optname, optval, optlen);
|
|
|
|
}
|
2006-03-21 14:48:35 +08:00
|
|
|
|
2005-12-14 15:24:16 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_getsockopt);
|
|
|
|
|
2010-12-04 20:38:01 +08:00
|
|
|
static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb)
|
|
|
|
{
|
2014-12-11 11:22:04 +08:00
|
|
|
struct cmsghdr *cmsg;
|
2010-12-04 20:38:01 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Assign an (opaque) qpolicy priority value to skb->priority.
|
|
|
|
*
|
|
|
|
* We are overloading this skb field for use with the qpolicy subystem.
|
|
|
|
* The skb->priority is normally used for the SO_PRIORITY option, which
|
|
|
|
* is initialised from sk_priority. Since the assignment of sk_priority
|
|
|
|
* to skb->priority happens later (on layer 3), we overload this field
|
|
|
|
* for use with queueing priorities as long as the skb is on layer 4.
|
|
|
|
* The default priority value (if nothing is set) is 0.
|
|
|
|
*/
|
|
|
|
skb->priority = 0;
|
|
|
|
|
2014-12-11 11:22:04 +08:00
|
|
|
for_each_cmsghdr(cmsg, msg) {
|
2010-12-04 20:38:01 +08:00
|
|
|
if (!CMSG_OK(msg, cmsg))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (cmsg->cmsg_level != SOL_DCCP)
|
|
|
|
continue;
|
|
|
|
|
2010-12-04 20:39:13 +08:00
|
|
|
if (cmsg->cmsg_type <= DCCP_SCM_QPOLICY_MAX &&
|
|
|
|
!dccp_qpolicy_param_ok(skb->sk, cmsg->cmsg_type))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2010-12-04 20:38:01 +08:00
|
|
|
switch (cmsg->cmsg_type) {
|
|
|
|
case DCCP_SCM_PRIORITY:
|
|
|
|
if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32)))
|
|
|
|
return -EINVAL;
|
|
|
|
skb->priority = *(__u32 *)CMSG_DATA(cmsg);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-02 15:37:48 +08:00
|
|
|
int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
2005-08-10 11:14:34 +08:00
|
|
|
{
|
|
|
|
const struct dccp_sock *dp = dccp_sk(sk);
|
|
|
|
const int flags = msg->msg_flags;
|
|
|
|
const int noblock = flags & MSG_DONTWAIT;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
int rc, size;
|
|
|
|
long timeo;
|
|
|
|
|
2017-12-29 10:47:55 +08:00
|
|
|
trace_dccp_probe(sk, len);
|
|
|
|
|
2023-08-04 00:30:21 +08:00
|
|
|
if (len > READ_ONCE(dp->dccps_mss_cache))
|
2005-08-10 11:14:34 +08:00
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
2006-11-21 04:30:17 +08:00
|
|
|
|
2005-08-10 11:30:56 +08:00
|
|
|
timeo = sock_sndtimeo(sk, noblock);
|
2005-08-10 11:14:34 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We have to use sk_stream_wait_connect here to set sk_write_pending,
|
|
|
|
* so that the trick in dccp_rcv_request_sent_state_process.
|
|
|
|
*/
|
|
|
|
/* Wait for a connection to finish. */
|
2007-09-27 06:36:08 +08:00
|
|
|
if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN))
|
2005-08-10 11:14:34 +08:00
|
|
|
if ((rc = sk_stream_wait_connect(sk, &timeo)) != 0)
|
2005-08-10 11:30:56 +08:00
|
|
|
goto out_release;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
|
|
|
size = sk->sk_prot->max_header + len;
|
|
|
|
release_sock(sk);
|
|
|
|
skb = sock_alloc_send_skb(sk, size, noblock, &rc);
|
|
|
|
lock_sock(sk);
|
|
|
|
if (skb == NULL)
|
|
|
|
goto out_release;
|
|
|
|
|
2022-07-29 19:00:27 +08:00
|
|
|
if (dccp_qpolicy_full(sk)) {
|
|
|
|
rc = -EAGAIN;
|
|
|
|
goto out_discard;
|
|
|
|
}
|
|
|
|
|
2018-03-07 03:57:01 +08:00
|
|
|
if (sk->sk_state == DCCP_CLOSED) {
|
|
|
|
rc = -ENOTCONN;
|
|
|
|
goto out_discard;
|
|
|
|
}
|
|
|
|
|
2023-08-04 00:30:21 +08:00
|
|
|
/* We need to check dccps_mss_cache after socket is locked. */
|
|
|
|
if (len > dp->dccps_mss_cache) {
|
|
|
|
rc = -EMSGSIZE;
|
|
|
|
goto out_discard;
|
|
|
|
}
|
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
skb_reserve(skb, sk->sk_prot->max_header);
|
2014-04-07 09:25:44 +08:00
|
|
|
rc = memcpy_from_msg(skb_put(skb, len), msg, len);
|
2005-08-10 11:30:56 +08:00
|
|
|
if (rc != 0)
|
|
|
|
goto out_discard;
|
|
|
|
|
2010-12-04 20:38:01 +08:00
|
|
|
rc = dccp_msghdr_parse(msg, skb);
|
|
|
|
if (rc != 0)
|
|
|
|
goto out_discard;
|
|
|
|
|
|
|
|
dccp_qpolicy_push(sk, skb);
|
dccp: Refine the wait-for-ccid mechanism
This extends the existing wait-for-ccid routine so that it may be used with
different types of CCID, addressing the following problems:
1) The queue-drain mechanism only works with rate-based CCIDs. If CCID-2 for
example has a full TX queue and becomes network-limited just as the
application wants to close, then waiting for CCID-2 to become unblocked
could lead to an indefinite delay (i.e., application "hangs").
2) Since each TX CCID in turn uses a feedback mechanism, there may be changes
in its sending policy while the queue is being drained. This can lead to
further delays during which the application will not be able to terminate.
3) The minimum wait time for CCID-3/4 can be expected to be the queue length
times the current inter-packet delay. For example if tx_qlen=100 and a delay
of 15 ms is used for each packet, then the application would have to wait
for a minimum of 1.5 seconds before being allowed to exit.
4) There is no way for the user/application to control this behaviour. It would
be good to use the timeout argument of dccp_close() as an upper bound. Then
the maximum time that an application is willing to wait for its CCIDs to can
be set via the SO_LINGER option.
These problems are addressed by giving the CCID a grace period of up to the
`timeout' value.
The wait-for-ccid function is, as before, used when the application
(a) has read all the data in its receive buffer and
(b) if SO_LINGER was set with a non-zero linger time, or
(c) the socket is either in the OPEN (active close) or in the PASSIVE_CLOSEREQ
state (client application closes after receiving CloseReq).
In addition, there is a catch-all case of __skb_queue_purge() after waiting for
the CCID. This is necessary since the write queue may still have data when
(a) the host has been passively-closed,
(b) abnormal termination (unread data, zero linger time),
(c) wait-for-ccid could not finish within the given time limit.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
2010-10-28 03:16:27 +08:00
|
|
|
/*
|
|
|
|
* The xmit_timer is set if the TX CCID is rate-based and will expire
|
|
|
|
* when congestion control permits to release further packets into the
|
|
|
|
* network. Window-based CCIDs do not use this timer.
|
|
|
|
*/
|
|
|
|
if (!timer_pending(&dp->dccps_xmit_timer))
|
|
|
|
dccp_write_xmit(sk);
|
2005-08-10 11:14:34 +08:00
|
|
|
out_release:
|
|
|
|
release_sock(sk);
|
|
|
|
return rc ? : len;
|
2005-08-10 11:30:56 +08:00
|
|
|
out_discard:
|
|
|
|
kfree_skb(skb);
|
2005-08-10 11:14:34 +08:00
|
|
|
goto out_release;
|
|
|
|
}
|
|
|
|
|
2005-12-14 15:24:16 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_sendmsg);
|
|
|
|
|
net: remove noblock parameter from recvmsg() entities
The internal recvmsg() functions have two parameters 'flags' and 'noblock'
that were merged inside skb_recv_datagram(). As a follow up patch to commit
f4b41f062c42 ("net: remove noblock parameter from skb_recv_datagram()")
this patch removes the separate 'noblock' parameter for recvmsg().
Analogue to the referenced patch for skb_recv_datagram() the 'flags' and
'noblock' parameters are unnecessarily split up with e.g.
err = sk->sk_prot->recvmsg(sk, msg, size, flags & MSG_DONTWAIT,
flags & ~MSG_DONTWAIT, &addr_len);
or in
err = INDIRECT_CALL_2(sk->sk_prot->recvmsg, tcp_recvmsg, udp_recvmsg,
sk, msg, size, flags & MSG_DONTWAIT,
flags & ~MSG_DONTWAIT, &addr_len);
instead of simply using only flags all the time and check for MSG_DONTWAIT
where needed (to preserve for the formerly separated no(n)block condition).
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://lore.kernel.org/r/20220411124955.154876-1-socketcan@hartkopp.net
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2022-04-11 20:49:55 +08:00
|
|
|
int dccp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
|
|
|
|
int *addr_len)
|
2005-08-10 11:14:34 +08:00
|
|
|
{
|
|
|
|
const struct dccp_hdr *dh;
|
|
|
|
long timeo;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
2005-08-14 07:35:17 +08:00
|
|
|
if (sk->sk_state == DCCP_LISTEN) {
|
|
|
|
len = -ENOTCONN;
|
2005-08-10 11:14:34 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
net: remove noblock parameter from recvmsg() entities
The internal recvmsg() functions have two parameters 'flags' and 'noblock'
that were merged inside skb_recv_datagram(). As a follow up patch to commit
f4b41f062c42 ("net: remove noblock parameter from skb_recv_datagram()")
this patch removes the separate 'noblock' parameter for recvmsg().
Analogue to the referenced patch for skb_recv_datagram() the 'flags' and
'noblock' parameters are unnecessarily split up with e.g.
err = sk->sk_prot->recvmsg(sk, msg, size, flags & MSG_DONTWAIT,
flags & ~MSG_DONTWAIT, &addr_len);
or in
err = INDIRECT_CALL_2(sk->sk_prot->recvmsg, tcp_recvmsg, udp_recvmsg,
sk, msg, size, flags & MSG_DONTWAIT,
flags & ~MSG_DONTWAIT, &addr_len);
instead of simply using only flags all the time and check for MSG_DONTWAIT
where needed (to preserve for the formerly separated no(n)block condition).
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://lore.kernel.org/r/20220411124955.154876-1-socketcan@hartkopp.net
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2022-04-11 20:49:55 +08:00
|
|
|
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
|
2005-08-10 11:14:34 +08:00
|
|
|
|
|
|
|
do {
|
2005-08-14 07:35:17 +08:00
|
|
|
struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2005-08-14 07:35:17 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
goto verify_sock_status;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2005-08-14 07:35:17 +08:00
|
|
|
dh = dccp_hdr(skb);
|
2005-08-10 11:14:34 +08:00
|
|
|
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
switch (dh->dccph_type) {
|
|
|
|
case DCCP_PKT_DATA:
|
|
|
|
case DCCP_PKT_DATAACK:
|
2005-08-14 07:35:17 +08:00
|
|
|
goto found_ok_skb;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
case DCCP_PKT_CLOSE:
|
|
|
|
case DCCP_PKT_CLOSEREQ:
|
|
|
|
if (!(flags & MSG_PEEK))
|
|
|
|
dccp_finish_passive_close(sk);
|
2020-08-24 06:36:59 +08:00
|
|
|
fallthrough;
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
case DCCP_PKT_RESET:
|
|
|
|
dccp_pr_debug("found fin (%s) ok!\n",
|
|
|
|
dccp_packet_name(dh->dccph_type));
|
2005-08-14 07:35:17 +08:00
|
|
|
len = 0;
|
|
|
|
goto found_fin_ok;
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
default:
|
|
|
|
dccp_pr_debug("packet_type=%s\n",
|
|
|
|
dccp_packet_name(dh->dccph_type));
|
2013-12-31 04:37:29 +08:00
|
|
|
sk_eat_skb(sk, skb);
|
2005-08-14 07:35:17 +08:00
|
|
|
}
|
|
|
|
verify_sock_status:
|
|
|
|
if (sock_flag(sk, SOCK_DONE)) {
|
|
|
|
len = 0;
|
2005-08-10 11:14:34 +08:00
|
|
|
break;
|
2005-08-14 07:35:17 +08:00
|
|
|
}
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2005-08-14 07:35:17 +08:00
|
|
|
if (sk->sk_err) {
|
|
|
|
len = sock_error(sk);
|
|
|
|
break;
|
|
|
|
}
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2005-08-14 07:35:17 +08:00
|
|
|
if (sk->sk_shutdown & RCV_SHUTDOWN) {
|
|
|
|
len = 0;
|
|
|
|
break;
|
|
|
|
}
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2005-08-14 07:35:17 +08:00
|
|
|
if (sk->sk_state == DCCP_CLOSED) {
|
|
|
|
if (!sock_flag(sk, SOCK_DONE)) {
|
|
|
|
/* This occurs when user tries to read
|
|
|
|
* from never connected socket.
|
|
|
|
*/
|
|
|
|
len = -ENOTCONN;
|
2005-08-10 11:14:34 +08:00
|
|
|
break;
|
|
|
|
}
|
2005-08-14 07:35:17 +08:00
|
|
|
len = 0;
|
|
|
|
break;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
2005-08-14 07:35:17 +08:00
|
|
|
if (!timeo) {
|
|
|
|
len = -EAGAIN;
|
|
|
|
break;
|
|
|
|
}
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2005-08-14 07:35:17 +08:00
|
|
|
if (signal_pending(current)) {
|
|
|
|
len = sock_intr_errno(timeo);
|
|
|
|
break;
|
|
|
|
}
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2015-07-25 00:19:25 +08:00
|
|
|
sk_wait_data(sk, &timeo, NULL);
|
2005-08-10 11:14:34 +08:00
|
|
|
continue;
|
|
|
|
found_ok_skb:
|
2005-08-14 07:35:17 +08:00
|
|
|
if (len > skb->len)
|
|
|
|
len = skb->len;
|
|
|
|
else if (len < skb->len)
|
|
|
|
msg->msg_flags |= MSG_TRUNC;
|
|
|
|
|
2014-11-06 05:46:40 +08:00
|
|
|
if (skb_copy_datagram_msg(skb, 0, msg, len)) {
|
2005-08-14 07:35:17 +08:00
|
|
|
/* Exception. Bailout! */
|
|
|
|
len = -EFAULT;
|
|
|
|
break;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
2010-02-11 04:26:18 +08:00
|
|
|
if (flags & MSG_TRUNC)
|
|
|
|
len = skb->len;
|
2005-08-10 11:14:34 +08:00
|
|
|
found_fin_ok:
|
|
|
|
if (!(flags & MSG_PEEK))
|
2013-12-31 04:37:29 +08:00
|
|
|
sk_eat_skb(sk, skb);
|
2005-08-10 11:14:34 +08:00
|
|
|
break;
|
2005-08-14 07:35:17 +08:00
|
|
|
} while (1);
|
2005-08-10 11:14:34 +08:00
|
|
|
out:
|
|
|
|
release_sock(sk);
|
2005-08-14 07:35:17 +08:00
|
|
|
return len;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
2005-12-14 15:24:16 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_recvmsg);
|
|
|
|
|
|
|
|
int inet_dccp_listen(struct socket *sock, int backlog)
|
2005-08-10 11:14:34 +08:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
unsigned char old_state;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
if (sock->state != SS_UNCONNECTED || sock->type != SOCK_DCCP)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
old_state = sk->sk_state;
|
|
|
|
if (!((1 << old_state) & (DCCPF_CLOSED | DCCPF_LISTEN)))
|
|
|
|
goto out;
|
|
|
|
|
2019-11-06 06:11:54 +08:00
|
|
|
WRITE_ONCE(sk->sk_max_ack_backlog, backlog);
|
2005-08-10 11:14:34 +08:00
|
|
|
/* Really, if the socket is already in listen state
|
|
|
|
* we can only allow the backlog to be adjusted.
|
|
|
|
*/
|
|
|
|
if (old_state != DCCP_LISTEN) {
|
2021-11-22 18:16:22 +08:00
|
|
|
struct dccp_sock *dp = dccp_sk(sk);
|
|
|
|
|
|
|
|
dp->dccps_role = DCCP_ROLE_LISTEN;
|
|
|
|
|
|
|
|
/* do not start to listen if feature negotiation setup fails */
|
|
|
|
if (dccp_feat_finalise_settings(dp)) {
|
|
|
|
err = -EPROTO;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = inet_csk_listen_start(sk);
|
2005-08-10 11:14:34 +08:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
err = 0;
|
|
|
|
|
|
|
|
out:
|
|
|
|
release_sock(sk);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2005-12-14 15:24:16 +08:00
|
|
|
EXPORT_SYMBOL_GPL(inet_dccp_listen);
|
|
|
|
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
static void dccp_terminate_connection(struct sock *sk)
|
2005-08-10 11:14:34 +08:00
|
|
|
{
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
u8 next_state = DCCP_CLOSED;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
switch (sk->sk_state) {
|
|
|
|
case DCCP_PASSIVE_CLOSE:
|
|
|
|
case DCCP_PASSIVE_CLOSEREQ:
|
|
|
|
dccp_finish_passive_close(sk);
|
|
|
|
break;
|
|
|
|
case DCCP_PARTOPEN:
|
|
|
|
dccp_pr_debug("Stop PARTOPEN timer (%p)\n", sk);
|
|
|
|
inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
|
2020-08-24 06:36:59 +08:00
|
|
|
fallthrough;
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
case DCCP_OPEN:
|
|
|
|
dccp_send_close(sk, 1);
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2007-12-13 22:25:01 +08:00
|
|
|
if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER &&
|
|
|
|
!dccp_sk(sk)->dccps_server_timewait)
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
next_state = DCCP_ACTIVE_CLOSEREQ;
|
|
|
|
else
|
|
|
|
next_state = DCCP_CLOSING;
|
2020-08-24 06:36:59 +08:00
|
|
|
fallthrough;
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
default:
|
|
|
|
dccp_set_state(sk, next_state);
|
|
|
|
}
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void dccp_close(struct sock *sk, long timeout)
|
|
|
|
{
|
2006-08-27 10:16:45 +08:00
|
|
|
struct dccp_sock *dp = dccp_sk(sk);
|
2005-08-10 11:14:34 +08:00
|
|
|
struct sk_buff *skb;
|
2007-12-17 08:06:03 +08:00
|
|
|
u32 data_was_unread = 0;
|
2006-05-06 08:09:13 +08:00
|
|
|
int state;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
sk->sk_shutdown = SHUTDOWN_MASK;
|
|
|
|
|
|
|
|
if (sk->sk_state == DCCP_LISTEN) {
|
|
|
|
dccp_set_state(sk, DCCP_CLOSED);
|
|
|
|
|
|
|
|
/* Special case. */
|
|
|
|
inet_csk_listen_stop(sk);
|
|
|
|
|
|
|
|
goto adjudge_to_death;
|
|
|
|
}
|
|
|
|
|
2006-08-27 10:16:45 +08:00
|
|
|
sk_stop_timer(sk, &dp->dccps_xmit_timer);
|
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
/*
|
|
|
|
* We need to flush the recv. buffs. We do this only on the
|
|
|
|
* descriptor close, not protocol-sourced closes, because the
|
|
|
|
*reader process may not have drained the data yet!
|
|
|
|
*/
|
|
|
|
while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
|
2007-12-17 08:06:03 +08:00
|
|
|
data_was_unread += skb->len;
|
2005-08-10 11:14:34 +08:00
|
|
|
__kfree_skb(skb);
|
|
|
|
}
|
|
|
|
|
2016-11-03 09:04:24 +08:00
|
|
|
/* If socket has been already reset kill it. */
|
|
|
|
if (sk->sk_state == DCCP_CLOSED)
|
|
|
|
goto adjudge_to_death;
|
|
|
|
|
2007-12-17 08:06:03 +08:00
|
|
|
if (data_was_unread) {
|
|
|
|
/* Unread data was tossed, send an appropriate Reset Code */
|
2010-10-12 02:44:42 +08:00
|
|
|
DCCP_WARN("ABORT with %u bytes unread\n", data_was_unread);
|
2007-12-17 08:06:03 +08:00
|
|
|
dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
|
|
|
|
dccp_set_state(sk, DCCP_CLOSED);
|
|
|
|
} else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
|
2005-08-10 11:14:34 +08:00
|
|
|
/* Check zero linger _after_ checking for unread data. */
|
|
|
|
sk->sk_prot->disconnect(sk, 0);
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
} else if (sk->sk_state != DCCP_CLOSED) {
|
dccp: Refine the wait-for-ccid mechanism
This extends the existing wait-for-ccid routine so that it may be used with
different types of CCID, addressing the following problems:
1) The queue-drain mechanism only works with rate-based CCIDs. If CCID-2 for
example has a full TX queue and becomes network-limited just as the
application wants to close, then waiting for CCID-2 to become unblocked
could lead to an indefinite delay (i.e., application "hangs").
2) Since each TX CCID in turn uses a feedback mechanism, there may be changes
in its sending policy while the queue is being drained. This can lead to
further delays during which the application will not be able to terminate.
3) The minimum wait time for CCID-3/4 can be expected to be the queue length
times the current inter-packet delay. For example if tx_qlen=100 and a delay
of 15 ms is used for each packet, then the application would have to wait
for a minimum of 1.5 seconds before being allowed to exit.
4) There is no way for the user/application to control this behaviour. It would
be good to use the timeout argument of dccp_close() as an upper bound. Then
the maximum time that an application is willing to wait for its CCIDs to can
be set via the SO_LINGER option.
These problems are addressed by giving the CCID a grace period of up to the
`timeout' value.
The wait-for-ccid function is, as before, used when the application
(a) has read all the data in its receive buffer and
(b) if SO_LINGER was set with a non-zero linger time, or
(c) the socket is either in the OPEN (active close) or in the PASSIVE_CLOSEREQ
state (client application closes after receiving CloseReq).
In addition, there is a catch-all case of __skb_queue_purge() after waiting for
the CCID. This is necessary since the write queue may still have data when
(a) the host has been passively-closed,
(b) abnormal termination (unread data, zero linger time),
(c) wait-for-ccid could not finish within the given time limit.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
2010-10-28 03:16:27 +08:00
|
|
|
/*
|
|
|
|
* Normal connection termination. May need to wait if there are
|
|
|
|
* still packets in the TX queue that are delayed by the CCID.
|
|
|
|
*/
|
|
|
|
dccp_flush_write_queue(sk, &timeout);
|
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close
* PASSIVE_CLOSE - which is entered when a host receives a Close;
* PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq.
Here is a detailed account of what the patch does in each state.
1) Receiving CloseReq
The pseudo-code in 8.5 says:
Step 13: Process CloseReq
If P.type == CloseReq and S.state < CLOSEREQ,
Generate Close
S.state := CLOSING
Set CLOSING timer.
This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN.
* CLOSED: silently ignore - it may be a late or duplicate CloseReq;
* LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client);
* REQUEST: perform Step 13 directly (no need to enqueue packet);
* OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data.
When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored.
I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where
the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it
gets the Reset, so ignoring the CloseReq while in state CLOSING is sane.
2) Receiving Close
The code below from 8.5 is unconditional.
Step 14: Process Close
If P.type == Close,
Generate Reset(Closed)
Tear down connection
Drop packet and return
Thus we need to consider all states:
* CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives;
* LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection");
* REQUEST: perform Step 14 directly (no need to enqueue packet);
* RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that;
* OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data;
* CLOSEREQ: server performed active-close -- perform Step 14;
* CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment);
* PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close);
* TIMEWAIT: packet is ignored.
Note that the condition of receiving a packet in state CLOSED here is different from the condition "there
is no socket for such a connection": the socket still exists, but its state indicates it is unusable.
Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that
sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-28 21:59:48 +08:00
|
|
|
dccp_terminate_connection(sk);
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
dccp: Refine the wait-for-ccid mechanism
This extends the existing wait-for-ccid routine so that it may be used with
different types of CCID, addressing the following problems:
1) The queue-drain mechanism only works with rate-based CCIDs. If CCID-2 for
example has a full TX queue and becomes network-limited just as the
application wants to close, then waiting for CCID-2 to become unblocked
could lead to an indefinite delay (i.e., application "hangs").
2) Since each TX CCID in turn uses a feedback mechanism, there may be changes
in its sending policy while the queue is being drained. This can lead to
further delays during which the application will not be able to terminate.
3) The minimum wait time for CCID-3/4 can be expected to be the queue length
times the current inter-packet delay. For example if tx_qlen=100 and a delay
of 15 ms is used for each packet, then the application would have to wait
for a minimum of 1.5 seconds before being allowed to exit.
4) There is no way for the user/application to control this behaviour. It would
be good to use the timeout argument of dccp_close() as an upper bound. Then
the maximum time that an application is willing to wait for its CCIDs to can
be set via the SO_LINGER option.
These problems are addressed by giving the CCID a grace period of up to the
`timeout' value.
The wait-for-ccid function is, as before, used when the application
(a) has read all the data in its receive buffer and
(b) if SO_LINGER was set with a non-zero linger time, or
(c) the socket is either in the OPEN (active close) or in the PASSIVE_CLOSEREQ
state (client application closes after receiving CloseReq).
In addition, there is a catch-all case of __skb_queue_purge() after waiting for
the CCID. This is necessary since the write queue may still have data when
(a) the host has been passively-closed,
(b) abnormal termination (unread data, zero linger time),
(c) wait-for-ccid could not finish within the given time limit.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
2010-10-28 03:16:27 +08:00
|
|
|
/*
|
|
|
|
* Flush write queue. This may be necessary in several cases:
|
|
|
|
* - we have been closed by the peer but still have application data;
|
|
|
|
* - abortive termination (unread data or zero linger time),
|
|
|
|
* - normal termination but queue could not be flushed within time limit
|
|
|
|
*/
|
|
|
|
__skb_queue_purge(&sk->sk_write_queue);
|
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
sk_stream_wait_close(sk, timeout);
|
|
|
|
|
|
|
|
adjudge_to_death:
|
2006-05-06 08:09:13 +08:00
|
|
|
state = sk->sk_state;
|
|
|
|
sock_hold(sk);
|
|
|
|
sock_orphan(sk);
|
|
|
|
|
2005-08-24 12:50:06 +08:00
|
|
|
/*
|
|
|
|
* It is the last release_sock in its life. It will remove backlog.
|
|
|
|
*/
|
2005-08-10 11:14:34 +08:00
|
|
|
release_sock(sk);
|
|
|
|
/*
|
|
|
|
* Now socket is owned by kernel and we acquire BH lock
|
|
|
|
* to finish close. No need to check for user refs.
|
|
|
|
*/
|
|
|
|
local_bh_disable();
|
|
|
|
bh_lock_sock(sk);
|
2008-07-26 12:43:18 +08:00
|
|
|
WARN_ON(sock_owned_by_user(sk));
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2021-10-14 21:41:26 +08:00
|
|
|
this_cpu_inc(dccp_orphan_count);
|
2008-12-30 15:04:08 +08:00
|
|
|
|
2006-05-06 08:09:13 +08:00
|
|
|
/* Have we already been destroyed by a softirq or backlog? */
|
|
|
|
if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED)
|
|
|
|
goto out;
|
2005-08-24 12:50:06 +08:00
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
if (sk->sk_state == DCCP_CLOSED)
|
|
|
|
inet_csk_destroy_sock(sk);
|
|
|
|
|
|
|
|
/* Otherwise, socket is reprieved until protocol close. */
|
|
|
|
|
2006-05-06 08:09:13 +08:00
|
|
|
out:
|
2005-08-10 11:14:34 +08:00
|
|
|
bh_unlock_sock(sk);
|
|
|
|
local_bh_enable();
|
|
|
|
sock_put(sk);
|
|
|
|
}
|
|
|
|
|
2005-12-14 15:24:16 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_close);
|
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
void dccp_shutdown(struct sock *sk, int how)
|
|
|
|
{
|
[DCCP]: Honour and make use of shutdown option set by user
This extends the DCCP socket API by honouring any shutdown(2) option set by the user.
The behaviour is, as much as possible, made consistent with the API for TCP's shutdown.
This patch exploits the information provided by the user via the socket API to reduce
processing costs:
* if the read end is closed (SHUT_RD), it is not necessary to deliver to input CCID;
* if the write end is closed (SHUT_WR), the same idea applies, but with a difference -
as long as the TX queue has not been drained, we need to receive feedback to keep
congestion-control rates up to date. Hence SHUT_WR is honoured only after the last
packet (under congestion control) has been sent;
* although SHUT_RDWR seems nonsensical, it is nevertheless supported in the same manner
as for TCP (and agrees with test for SHUTDOWN_MASK in dccp_poll() in net/dccp/proto.c).
Furthermore, most of the code already honours the sk_shutdown flags (dccp_recvmsg() for
instance sets the read length to 0 if SHUT_RD had been called); CCID handling is now added
to this by the present patch.
There will also no longer be any delivery when the socket is in the final stages, i.e. when
one of dccp_close(), dccp_fin(), or dccp_done() has been called - which is fine since at
that stage the connection is its final stages.
Motivation and background are on http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/shutdown
A FIXME has been added to notify the other end if SHUT_RD has been set (RFC 4340, 11.7).
Note: There is a comment in inet_shutdown() in net/ipv4/af_inet.c which asks to "make
sure the socket is a TCP socket". This should probably be extended to mean
`TCP or DCCP socket' (the code is also used by UDP and raw sockets).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-11-21 19:56:48 +08:00
|
|
|
dccp_pr_debug("called shutdown(%x)\n", how);
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
2005-12-14 15:24:16 +08:00
|
|
|
EXPORT_SYMBOL_GPL(dccp_shutdown);
|
|
|
|
|
2014-10-01 12:48:03 +08:00
|
|
|
static inline int __init dccp_mib_init(void)
|
2005-08-10 11:14:34 +08:00
|
|
|
{
|
2014-05-06 06:55:55 +08:00
|
|
|
dccp_statistics = alloc_percpu(struct dccp_mib);
|
|
|
|
if (!dccp_statistics)
|
|
|
|
return -ENOMEM;
|
|
|
|
return 0;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
2008-04-10 18:48:43 +08:00
|
|
|
static inline void dccp_mib_exit(void)
|
2006-03-21 13:24:42 +08:00
|
|
|
{
|
2014-05-06 06:55:55 +08:00
|
|
|
free_percpu(dccp_statistics);
|
2006-03-21 13:24:42 +08:00
|
|
|
}
|
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
static int thash_entries;
|
|
|
|
module_param(thash_entries, int, 0444);
|
|
|
|
MODULE_PARM_DESC(thash_entries, "Number of ehash buckets");
|
|
|
|
|
2005-08-14 09:42:25 +08:00
|
|
|
#ifdef CONFIG_IP_DCCP_DEBUG
|
2011-12-19 22:08:01 +08:00
|
|
|
bool dccp_debug;
|
2008-08-23 19:28:27 +08:00
|
|
|
module_param(dccp_debug, bool, 0644);
|
2005-08-10 11:14:34 +08:00
|
|
|
MODULE_PARM_DESC(dccp_debug, "Enable debug messages");
|
2005-12-14 15:24:16 +08:00
|
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(dccp_debug);
|
2005-08-14 09:42:25 +08:00
|
|
|
#endif
|
2005-08-10 11:14:34 +08:00
|
|
|
|
|
|
|
static int __init dccp_init(void)
|
|
|
|
{
|
|
|
|
unsigned long goal;
|
2018-12-28 16:34:29 +08:00
|
|
|
unsigned long nr_pages = totalram_pages();
|
2005-08-10 11:14:34 +08:00
|
|
|
int ehash_order, bhash_order, i;
|
2008-11-26 13:17:14 +08:00
|
|
|
int rc;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2008-04-13 09:35:41 +08:00
|
|
|
BUILD_BUG_ON(sizeof(struct dccp_skb_cb) >
|
2019-12-10 02:31:43 +08:00
|
|
|
sizeof_field(struct sk_buff, cb));
|
2018-12-25 04:57:17 +08:00
|
|
|
rc = inet_hashinfo2_init_mod(&dccp_hashinfo);
|
|
|
|
if (rc)
|
2021-10-14 21:41:26 +08:00
|
|
|
goto out_fail;
|
2018-12-25 04:57:17 +08:00
|
|
|
rc = -ENOBUFS;
|
2005-08-14 07:34:54 +08:00
|
|
|
dccp_hashinfo.bind_bucket_cachep =
|
|
|
|
kmem_cache_create("dccp_bind_bucket",
|
|
|
|
sizeof(struct inet_bind_bucket), 0,
|
2021-07-19 18:44:37 +08:00
|
|
|
SLAB_HWCACHE_ALIGN | SLAB_ACCOUNT, NULL);
|
2005-08-10 11:14:34 +08:00
|
|
|
if (!dccp_hashinfo.bind_bucket_cachep)
|
2020-06-09 22:18:16 +08:00
|
|
|
goto out_free_hashinfo2;
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
dccp_hashinfo.bind2_bucket_cachep =
|
|
|
|
kmem_cache_create("dccp_bind2_bucket",
|
|
|
|
sizeof(struct inet_bind2_bucket), 0,
|
|
|
|
SLAB_HWCACHE_ALIGN | SLAB_ACCOUNT, NULL);
|
|
|
|
if (!dccp_hashinfo.bind2_bucket_cachep)
|
|
|
|
goto out_free_bind_bucket_cachep;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Size and allocate the main established and bind bucket
|
|
|
|
* hash tables.
|
|
|
|
*
|
|
|
|
* The methodology is similar to that of the buffer cache.
|
|
|
|
*/
|
2018-12-28 16:34:20 +08:00
|
|
|
if (nr_pages >= (128 * 1024))
|
|
|
|
goal = nr_pages >> (21 - PAGE_SHIFT);
|
2005-08-10 11:14:34 +08:00
|
|
|
else
|
2018-12-28 16:34:20 +08:00
|
|
|
goal = nr_pages >> (23 - PAGE_SHIFT);
|
2005-08-10 11:14:34 +08:00
|
|
|
|
|
|
|
if (thash_entries)
|
2005-08-14 07:34:54 +08:00
|
|
|
goal = (thash_entries *
|
|
|
|
sizeof(struct inet_ehash_bucket)) >> PAGE_SHIFT;
|
2005-08-10 11:14:34 +08:00
|
|
|
for (ehash_order = 0; (1UL << ehash_order) < goal; ehash_order++)
|
|
|
|
;
|
|
|
|
do {
|
2009-10-09 08:16:19 +08:00
|
|
|
unsigned long hash_size = (1UL << ehash_order) * PAGE_SIZE /
|
2005-08-10 11:14:34 +08:00
|
|
|
sizeof(struct inet_ehash_bucket);
|
2009-10-09 08:16:19 +08:00
|
|
|
|
|
|
|
while (hash_size & (hash_size - 1))
|
|
|
|
hash_size--;
|
|
|
|
dccp_hashinfo.ehash_mask = hash_size - 1;
|
2005-08-10 11:14:34 +08:00
|
|
|
dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
|
2009-07-30 06:04:10 +08:00
|
|
|
__get_free_pages(GFP_ATOMIC|__GFP_NOWARN, ehash_order);
|
2005-08-10 11:14:34 +08:00
|
|
|
} while (!dccp_hashinfo.ehash && --ehash_order > 0);
|
|
|
|
|
|
|
|
if (!dccp_hashinfo.ehash) {
|
2006-11-21 04:39:23 +08:00
|
|
|
DCCP_CRIT("Failed to allocate DCCP established hash table");
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
goto out_free_bind2_bucket_cachep;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
tcp/dccp: remove twchain
TCP listener refactoring, part 3 :
Our goal is to hash SYN_RECV sockets into main ehash for fast lookup,
and parallel SYN processing.
Current inet_ehash_bucket contains two chains, one for ESTABLISH (and
friend states) sockets, another for TIME_WAIT sockets only.
As the hash table is sized to get at most one socket per bucket, it
makes little sense to have separate twchain, as it makes the lookup
slightly more complicated, and doubles hash table memory usage.
If we make sure all socket types have the lookup keys at the same
offsets, we can use a generic and faster lookup. It turns out TIME_WAIT
and ESTABLISHED sockets already have common lookup fields for IPv4.
[ INET_TW_MATCH() is no longer needed ]
I'll provide a follow-up to factorize IPv6 lookup as well, to remove
INET6_TW_MATCH()
This way, SYN_RECV pseudo sockets will be supported the same.
A new sock_gen_put() helper is added, doing either a sock_put() or
inet_twsk_put() [ and will support SYN_RECV later ].
Note this helper should only be called in real slow path, when rcu
lookup found a socket that was moved to another identity (freed/reused
immediately), but could eventually be used in other contexts, like
sock_edemux()
Before patch :
dmesg | grep "TCP established"
TCP established hash table entries: 524288 (order: 11, 8388608 bytes)
After patch :
TCP established hash table entries: 524288 (order: 10, 4194304 bytes)
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-03 15:22:02 +08:00
|
|
|
for (i = 0; i <= dccp_hashinfo.ehash_mask; i++)
|
2008-11-17 11:40:17 +08:00
|
|
|
INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].chain, i);
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2007-11-07 18:40:20 +08:00
|
|
|
if (inet_ehash_locks_alloc(&dccp_hashinfo))
|
|
|
|
goto out_free_dccp_ehash;
|
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
bhash_order = ehash_order;
|
|
|
|
|
|
|
|
do {
|
|
|
|
dccp_hashinfo.bhash_size = (1UL << bhash_order) * PAGE_SIZE /
|
|
|
|
sizeof(struct inet_bind_hashbucket);
|
2005-08-14 07:34:54 +08:00
|
|
|
if ((dccp_hashinfo.bhash_size > (64 * 1024)) &&
|
|
|
|
bhash_order > 0)
|
2005-08-10 11:14:34 +08:00
|
|
|
continue;
|
|
|
|
dccp_hashinfo.bhash = (struct inet_bind_hashbucket *)
|
2009-07-30 06:04:10 +08:00
|
|
|
__get_free_pages(GFP_ATOMIC|__GFP_NOWARN, bhash_order);
|
2005-08-10 11:14:34 +08:00
|
|
|
} while (!dccp_hashinfo.bhash && --bhash_order >= 0);
|
|
|
|
|
|
|
|
if (!dccp_hashinfo.bhash) {
|
2006-11-21 04:39:23 +08:00
|
|
|
DCCP_CRIT("Failed to allocate DCCP bind hash table");
|
2007-11-07 18:40:20 +08:00
|
|
|
goto out_free_dccp_locks;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
dccp_hashinfo.bhash2 = (struct inet_bind_hashbucket *)
|
|
|
|
__get_free_pages(GFP_ATOMIC | __GFP_NOWARN, bhash_order);
|
|
|
|
|
|
|
|
if (!dccp_hashinfo.bhash2) {
|
|
|
|
DCCP_CRIT("Failed to allocate DCCP bind2 hash table");
|
|
|
|
goto out_free_dccp_bhash;
|
|
|
|
}
|
|
|
|
|
2005-08-10 11:14:34 +08:00
|
|
|
for (i = 0; i < dccp_hashinfo.bhash_size; i++) {
|
|
|
|
spin_lock_init(&dccp_hashinfo.bhash[i].lock);
|
|
|
|
INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain);
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
spin_lock_init(&dccp_hashinfo.bhash2[i].lock);
|
|
|
|
INIT_HLIST_HEAD(&dccp_hashinfo.bhash2[i].chain);
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
tcp: Introduce optional per-netns ehash.
The more sockets we have in the hash table, the longer we spend looking
up the socket. While running a number of small workloads on the same
host, they penalise each other and cause performance degradation.
The root cause might be a single workload that consumes much more
resources than the others. It often happens on a cloud service where
different workloads share the same computing resource.
On EC2 c5.24xlarge instance (196 GiB memory and 524288 (1Mi / 2) ehash
entries), after running iperf3 in different netns, creating 24Mi sockets
without data transfer in the root netns causes about 10% performance
regression for the iperf3's connection.
thash_entries sockets length Gbps
524288 1 1 50.7
24Mi 48 45.1
It is basically related to the length of the list of each hash bucket.
For testing purposes to see how performance drops along the length,
I set 131072 (1Mi / 8) to thash_entries, and here's the result.
thash_entries sockets length Gbps
131072 1 1 50.7
1Mi 8 49.9
2Mi 16 48.9
4Mi 32 47.3
8Mi 64 44.6
16Mi 128 40.6
24Mi 192 36.3
32Mi 256 32.5
40Mi 320 27.0
48Mi 384 25.0
To resolve the socket lookup degradation, we introduce an optional
per-netns hash table for TCP, but it's just ehash, and we still share
the global bhash, bhash2 and lhash2.
With a smaller ehash, we can look up non-listener sockets faster and
isolate such noisy neighbours. In addition, we can reduce lock contention.
We can control the ehash size by a new sysctl knob. However, depending
on workloads, it will require very sensitive tuning, so we disable the
feature by default (net.ipv4.tcp_child_ehash_entries == 0). Moreover,
we can fall back to using the global ehash in case we fail to allocate
enough memory for a new ehash. The maximum size is 16Mi, which is large
enough that even if we have 48Mi sockets, the average list length is 3,
and regression would be less than 1%.
We can check the current ehash size by another read-only sysctl knob,
net.ipv4.tcp_ehash_entries. A negative value means the netns shares
the global ehash (per-netns ehash is disabled or failed to allocate
memory).
# dmesg | cut -d ' ' -f 5- | grep "established hash"
TCP established hash table entries: 524288 (order: 10, 4194304 bytes, vmalloc hugepage)
# sysctl net.ipv4.tcp_ehash_entries
net.ipv4.tcp_ehash_entries = 524288 # can be changed by thash_entries
# sysctl net.ipv4.tcp_child_ehash_entries
net.ipv4.tcp_child_ehash_entries = 0 # disabled by default
# ip netns add test1
# ip netns exec test1 sysctl net.ipv4.tcp_ehash_entries
net.ipv4.tcp_ehash_entries = -524288 # share the global ehash
# sysctl -w net.ipv4.tcp_child_ehash_entries=100
net.ipv4.tcp_child_ehash_entries = 100
# ip netns add test2
# ip netns exec test2 sysctl net.ipv4.tcp_ehash_entries
net.ipv4.tcp_ehash_entries = 128 # own a per-netns ehash with 2^n buckets
When more than two processes in the same netns create per-netns ehash
concurrently with different sizes, we need to guarantee the size in
one of the following ways:
1) Share the global ehash and create per-netns ehash
First, unshare() with tcp_child_ehash_entries==0. It creates dedicated
netns sysctl knobs where we can safely change tcp_child_ehash_entries
and clone()/unshare() to create a per-netns ehash.
2) Control write on sysctl by BPF
We can use BPF_PROG_TYPE_CGROUP_SYSCTL to allow/deny read/write on
sysctl knobs.
Note that the global ehash allocated at the boot time is spread over
available NUMA nodes, but inet_pernet_hashinfo_alloc() will allocate
pages for each per-netns ehash depending on the current process's NUMA
policy. By default, the allocation is done in the local node only, so
the per-netns hash table could fully reside on a random node. Thus,
depending on the NUMA policy the netns is created with and the CPU the
current thread is running on, we could see some performance differences
for highly optimised networking applications.
Note also that the default values of two sysctl knobs depend on the ehash
size and should be tuned carefully:
tcp_max_tw_buckets : tcp_child_ehash_entries / 2
tcp_max_syn_backlog : max(128, tcp_child_ehash_entries / 128)
As a bonus, we can dismantle netns faster. Currently, while destroying
netns, we call inet_twsk_purge(), which walks through the global ehash.
It can be potentially big because it can have many sockets other than
TIME_WAIT in all netns. Splitting ehash changes that situation, where
it's only necessary for inet_twsk_purge() to clean up TIME_WAIT sockets
in each netns.
With regard to this, we do not free the per-netns ehash in inet_twsk_kill()
to avoid UAF while iterating the per-netns ehash in inet_twsk_purge().
Instead, we do it in tcp_sk_exit_batch() after calling tcp_twsk_purge() to
keep it protocol-family-independent.
In the future, we could optimise ehash lookup/iteration further by removing
netns comparison for the per-netns ehash.
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-09-08 09:10:22 +08:00
|
|
|
dccp_hashinfo.pernet = false;
|
|
|
|
|
2006-03-21 13:24:42 +08:00
|
|
|
rc = dccp_mib_init();
|
2006-03-21 09:16:01 +08:00
|
|
|
if (rc)
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
goto out_free_dccp_bhash2;
|
2005-08-10 11:14:34 +08:00
|
|
|
|
2006-03-21 09:16:17 +08:00
|
|
|
rc = dccp_ackvec_init();
|
2005-08-10 11:14:34 +08:00
|
|
|
if (rc)
|
2006-03-21 13:25:11 +08:00
|
|
|
goto out_free_dccp_mib;
|
2006-03-21 09:16:17 +08:00
|
|
|
|
2006-03-21 11:25:02 +08:00
|
|
|
rc = dccp_sysctl_init();
|
2006-03-21 09:16:17 +08:00
|
|
|
if (rc)
|
|
|
|
goto out_ackvec_exit;
|
2007-09-26 13:40:13 +08:00
|
|
|
|
2009-01-05 13:42:53 +08:00
|
|
|
rc = ccid_initialize_builtins();
|
|
|
|
if (rc)
|
|
|
|
goto out_sysctl_exit;
|
|
|
|
|
2007-09-26 13:40:13 +08:00
|
|
|
dccp_timestamping_init();
|
2010-03-15 04:13:19 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2009-01-05 13:42:53 +08:00
|
|
|
out_sysctl_exit:
|
|
|
|
dccp_sysctl_exit();
|
2006-03-21 09:16:17 +08:00
|
|
|
out_ackvec_exit:
|
|
|
|
dccp_ackvec_exit();
|
2006-03-21 13:25:11 +08:00
|
|
|
out_free_dccp_mib:
|
2006-03-21 13:24:42 +08:00
|
|
|
dccp_mib_exit();
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
out_free_dccp_bhash2:
|
|
|
|
free_pages((unsigned long)dccp_hashinfo.bhash2, bhash_order);
|
2005-08-10 11:14:34 +08:00
|
|
|
out_free_dccp_bhash:
|
|
|
|
free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
|
2007-11-07 18:40:20 +08:00
|
|
|
out_free_dccp_locks:
|
|
|
|
inet_ehash_locks_free(&dccp_hashinfo);
|
2005-08-10 11:14:34 +08:00
|
|
|
out_free_dccp_ehash:
|
|
|
|
free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order);
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
out_free_bind2_bucket_cachep:
|
|
|
|
kmem_cache_destroy(dccp_hashinfo.bind2_bucket_cachep);
|
2005-08-10 11:14:34 +08:00
|
|
|
out_free_bind_bucket_cachep:
|
|
|
|
kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
|
2020-06-09 22:18:16 +08:00
|
|
|
out_free_hashinfo2:
|
|
|
|
inet_hashinfo2_free_mod(&dccp_hashinfo);
|
2010-03-15 04:13:19 +08:00
|
|
|
out_fail:
|
|
|
|
dccp_hashinfo.bhash = NULL;
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
dccp_hashinfo.bhash2 = NULL;
|
2010-03-15 04:13:19 +08:00
|
|
|
dccp_hashinfo.ehash = NULL;
|
|
|
|
dccp_hashinfo.bind_bucket_cachep = NULL;
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
dccp_hashinfo.bind2_bucket_cachep = NULL;
|
2010-03-15 04:13:19 +08:00
|
|
|
return rc;
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit dccp_fini(void)
|
|
|
|
{
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
int bhash_order = get_order(dccp_hashinfo.bhash_size *
|
|
|
|
sizeof(struct inet_bind_hashbucket));
|
|
|
|
|
2009-01-05 13:42:53 +08:00
|
|
|
ccid_cleanup_builtins();
|
2006-03-21 13:24:42 +08:00
|
|
|
dccp_mib_exit();
|
net: Add a bhash2 table hashed by port and address
The current bind hashtable (bhash) is hashed by port only.
In the socket bind path, we have to check for bind conflicts by
traversing the specified port's inet_bind_bucket while holding the
hashbucket's spinlock (see inet_csk_get_port() and
inet_csk_bind_conflict()). In instances where there are tons of
sockets hashed to the same port at different addresses, the bind
conflict check is time-intensive and can cause softirq cpu lockups,
as well as stops new tcp connections since __inet_inherit_port()
also contests for the spinlock.
This patch adds a second bind table, bhash2, that hashes by
port and sk->sk_rcv_saddr (ipv4) and sk->sk_v6_rcv_saddr (ipv6).
Searching the bhash2 table leads to significantly faster conflict
resolution and less time holding the hashbucket spinlock.
Please note a few things:
* There can be the case where the a socket's address changes after it
has been bound. There are two cases where this happens:
1) The case where there is a bind() call on INADDR_ANY (ipv4) or
IPV6_ADDR_ANY (ipv6) and then a connect() call. The kernel will
assign the socket an address when it handles the connect()
2) In inet_sk_reselect_saddr(), which is called when rebuilding the
sk header and a few pre-conditions are met (eg rerouting fails).
In these two cases, we need to update the bhash2 table by removing the
entry for the old address, and add a new entry reflecting the updated
address.
* The bhash2 table must have its own lock, even though concurrent
accesses on the same port are protected by the bhash lock. Bhash2 must
have its own lock to protect against cases where sockets on different
ports hash to different bhash hashbuckets but to the same bhash2
hashbucket.
This brings up a few stipulations:
1) When acquiring both the bhash and the bhash2 lock, the bhash2 lock
will always be acquired after the bhash lock and released before the
bhash lock is released.
2) There are no nested bhash2 hashbucket locks. A bhash2 lock is always
acquired+released before another bhash2 lock is acquired+released.
* The bhash table cannot be superseded by the bhash2 table because for
bind requests on INADDR_ANY (ipv4) or IPV6_ADDR_ANY (ipv6), every socket
bound to that port must be checked for a potential conflict. The bhash
table is the only source of port->socket associations.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-08-23 02:10:21 +08:00
|
|
|
free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
|
|
|
|
free_pages((unsigned long)dccp_hashinfo.bhash2, bhash_order);
|
2005-08-14 07:35:39 +08:00
|
|
|
free_pages((unsigned long)dccp_hashinfo.ehash,
|
2009-10-09 08:16:19 +08:00
|
|
|
get_order((dccp_hashinfo.ehash_mask + 1) *
|
2005-08-14 07:35:39 +08:00
|
|
|
sizeof(struct inet_ehash_bucket)));
|
2007-11-07 18:40:20 +08:00
|
|
|
inet_ehash_locks_free(&dccp_hashinfo);
|
2005-08-10 11:14:34 +08:00
|
|
|
kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
|
2006-03-21 09:16:17 +08:00
|
|
|
dccp_ackvec_exit();
|
2006-03-21 11:25:02 +08:00
|
|
|
dccp_sysctl_exit();
|
2020-06-09 22:18:16 +08:00
|
|
|
inet_hashinfo2_free_mod(&dccp_hashinfo);
|
2005-08-10 11:14:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(dccp_init);
|
|
|
|
module_exit(dccp_fini);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>");
|
|
|
|
MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");
|