提交 571f3dd0 编写于 作者: D David S. Miller

Merge tag 'rxrpc-fixes-20230107' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: Fix race between call connection, data transmit and call disconnect

Here are patches to fix an oops[1] caused by a race between call
connection, initial packet transmission and call disconnection which
results in something like:

        kernel BUG at net/rxrpc/peer_object.c:413!

when the syzbot test is run.  The problem is that the connection procedure
is effectively split across two threads and can get expanded by taking an
interrupt, thereby adding the call to the peer error distribution list
*after* it has been disconnected (say by the rxrpc socket shutting down).

The easiest solution is to look at the fourth set of I/O thread
conversion/SACK table expansion patches that didn't get applied[2] and take
from it those patches that move call connection and disconnection into the
I/O thread.  Moving these things into the I/O thread means that the
sequencing is managed by all being done in the same thread - and the race
can no longer happen.

This is preferable to introducing an extra lock as adding an extra lock
would make the I/O thread have to wait for the app thread in yet another
place.

The changes can be considered as a number of logical parts:

 (1) Move all of the call state changes into the I/O thread.

 (2) Make client connection ID space per-local endpoint so that the I/O
     thread doesn't need locks to access it.

 (3) Move actual abort generation into the I/O thread and clean it up.  If
     sendmsg or recvmsg want to cause an abort, they have to delegate it.

 (4) Offload the setting up of the security context on a connection to the
     thread of one of the apps that's starting a call.  We don't want to be
     doing any sort of crypto in the I/O thread.

 (5) Connect calls (ie. assign them to channel slots on connections) in the
     I/O thread.  Calls are set up by sendmsg/kafs and passed to the I/O
     thread to connect.  Connections are allocated in the I/O thread after
     this.

 (6) Disconnect calls in the I/O thread.

I've also added a patch for an unrelated bug that cropped up during
testing, whereby a race can occur between an incoming call and socket
shutdown.

Note that whilst this fixes the original syzbot bug, another bug may get
triggered if this one is fixed:

        INFO: rcu detected stall in corrupted
        rcu: INFO: rcu_preempt detected expedited stalls on CPUs/tasks: { P5792 } 2657 jiffies s: 2825 root: 0x0/T
        rcu: blocking rcu_node structures (internal RCU debug):

It doesn't look this should be anything to do with rxrpc, though, as I've
tested an additional patch[3] that removes practically all the RCU usage
from rxrpc and it still occurs.  It seems likely that it is being caused by
something in the tunnelling setup that the syzbot test does, but there's
not enough info to go on.  It also seems unlikely to be anything to do with
the afs driver as the test doesn't use that.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -880,8 +880,8 @@ The kernel interface functions are as follows: ...@@ -880,8 +880,8 @@ The kernel interface functions are as follows:
notify_end_rx can be NULL or it can be used to specify a function to be notify_end_rx can be NULL or it can be used to specify a function to be
called when the call changes state to end the Tx phase. This function is called when the call changes state to end the Tx phase. This function is
called with the call-state spinlock held to prevent any reply or final ACK called with a spinlock held to prevent the last DATA packet from being
from being delivered first. transmitted until the function returns.
(#) Receive data from a call:: (#) Receive data from a call::
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include "internal.h" #include "internal.h"
#include "afs_cm.h" #include "afs_cm.h"
#include "protocol_yfs.h" #include "protocol_yfs.h"
#define RXRPC_TRACE_ONLY_DEFINE_ENUMS
#include <trace/events/rxrpc.h>
static int afs_deliver_cb_init_call_back_state(struct afs_call *); static int afs_deliver_cb_init_call_back_state(struct afs_call *);
static int afs_deliver_cb_init_call_back_state3(struct afs_call *); static int afs_deliver_cb_init_call_back_state3(struct afs_call *);
...@@ -191,7 +193,7 @@ static void afs_cm_destructor(struct afs_call *call) ...@@ -191,7 +193,7 @@ static void afs_cm_destructor(struct afs_call *call)
* Abort a service call from within an action function. * Abort a service call from within an action function.
*/ */
static void afs_abort_service_call(struct afs_call *call, u32 abort_code, int error, static void afs_abort_service_call(struct afs_call *call, u32 abort_code, int error,
const char *why) enum rxrpc_abort_reason why)
{ {
rxrpc_kernel_abort_call(call->net->socket, call->rxcall, rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
abort_code, error, why); abort_code, error, why);
...@@ -469,7 +471,7 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work) ...@@ -469,7 +471,7 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work)
if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0) if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0)
afs_send_empty_reply(call); afs_send_empty_reply(call);
else else
afs_abort_service_call(call, 1, 1, "K-1"); afs_abort_service_call(call, 1, 1, afs_abort_probeuuid_negative);
afs_put_call(call); afs_put_call(call);
_leave(""); _leave("");
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include "internal.h" #include "internal.h"
#include "afs_cm.h" #include "afs_cm.h"
#include "protocol_yfs.h" #include "protocol_yfs.h"
#define RXRPC_TRACE_ONLY_DEFINE_ENUMS
#include <trace/events/rxrpc.h>
struct workqueue_struct *afs_async_calls; struct workqueue_struct *afs_async_calls;
...@@ -397,7 +399,8 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) ...@@ -397,7 +399,8 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
error_do_abort: error_do_abort:
if (ret != -ECONNABORTED) { if (ret != -ECONNABORTED) {
rxrpc_kernel_abort_call(call->net->socket, rxcall, rxrpc_kernel_abort_call(call->net->socket, rxcall,
RX_USER_ABORT, ret, "KSD"); RX_USER_ABORT, ret,
afs_abort_send_data_error);
} else { } else {
len = 0; len = 0;
iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0); iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0);
...@@ -527,7 +530,8 @@ static void afs_deliver_to_call(struct afs_call *call) ...@@ -527,7 +530,8 @@ static void afs_deliver_to_call(struct afs_call *call)
case -ENOTSUPP: case -ENOTSUPP:
abort_code = RXGEN_OPCODE; abort_code = RXGEN_OPCODE;
rxrpc_kernel_abort_call(call->net->socket, call->rxcall, rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
abort_code, ret, "KIV"); abort_code, ret,
afs_abort_op_not_supported);
goto local_abort; goto local_abort;
case -EIO: case -EIO:
pr_err("kAFS: Call %u in bad state %u\n", pr_err("kAFS: Call %u in bad state %u\n",
...@@ -542,12 +546,14 @@ static void afs_deliver_to_call(struct afs_call *call) ...@@ -542,12 +546,14 @@ static void afs_deliver_to_call(struct afs_call *call)
if (state != AFS_CALL_CL_AWAIT_REPLY) if (state != AFS_CALL_CL_AWAIT_REPLY)
abort_code = RXGEN_SS_UNMARSHAL; abort_code = RXGEN_SS_UNMARSHAL;
rxrpc_kernel_abort_call(call->net->socket, call->rxcall, rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
abort_code, ret, "KUM"); abort_code, ret,
afs_abort_unmarshal_error);
goto local_abort; goto local_abort;
default: default:
abort_code = RX_CALL_DEAD; abort_code = RX_CALL_DEAD;
rxrpc_kernel_abort_call(call->net->socket, call->rxcall, rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
abort_code, ret, "KER"); abort_code, ret,
afs_abort_general_error);
goto local_abort; goto local_abort;
} }
} }
...@@ -619,7 +625,8 @@ long afs_wait_for_call_to_complete(struct afs_call *call, ...@@ -619,7 +625,8 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
/* Kill off the call if it's still live. */ /* Kill off the call if it's still live. */
_debug("call interrupted"); _debug("call interrupted");
if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall, if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
RX_USER_ABORT, -EINTR, "KWI")) RX_USER_ABORT, -EINTR,
afs_abort_interrupted))
afs_set_call_complete(call, -EINTR, 0); afs_set_call_complete(call, -EINTR, 0);
} }
} }
...@@ -836,7 +843,8 @@ void afs_send_empty_reply(struct afs_call *call) ...@@ -836,7 +843,8 @@ void afs_send_empty_reply(struct afs_call *call)
case -ENOMEM: case -ENOMEM:
_debug("oom"); _debug("oom");
rxrpc_kernel_abort_call(net->socket, call->rxcall, rxrpc_kernel_abort_call(net->socket, call->rxcall,
RXGEN_SS_MARSHAL, -ENOMEM, "KOO"); RXGEN_SS_MARSHAL, -ENOMEM,
afs_abort_oom);
fallthrough; fallthrough;
default: default:
_leave(" [error]"); _leave(" [error]");
...@@ -878,7 +886,8 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) ...@@ -878,7 +886,8 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
if (n == -ENOMEM) { if (n == -ENOMEM) {
_debug("oom"); _debug("oom");
rxrpc_kernel_abort_call(net->socket, call->rxcall, rxrpc_kernel_abort_call(net->socket, call->rxcall,
RXGEN_SS_MARSHAL, -ENOMEM, "KOO"); RXGEN_SS_MARSHAL, -ENOMEM,
afs_abort_oom);
} }
_leave(" [error]"); _leave(" [error]");
} }
...@@ -900,6 +909,7 @@ int afs_extract_data(struct afs_call *call, bool want_more) ...@@ -900,6 +909,7 @@ int afs_extract_data(struct afs_call *call, bool want_more)
ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter, ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter,
&call->iov_len, want_more, &remote_abort, &call->iov_len, want_more, &remote_abort,
&call->service_id); &call->service_id);
trace_afs_receive_data(call, call->iter, want_more, ret);
if (ret == 0 || ret == -EAGAIN) if (ret == 0 || ret == -EAGAIN)
return ret; return ret;
......
...@@ -15,6 +15,7 @@ struct key; ...@@ -15,6 +15,7 @@ struct key;
struct sock; struct sock;
struct socket; struct socket;
struct rxrpc_call; struct rxrpc_call;
enum rxrpc_abort_reason;
enum rxrpc_interruptibility { enum rxrpc_interruptibility {
RXRPC_INTERRUPTIBLE, /* Call is interruptible */ RXRPC_INTERRUPTIBLE, /* Call is interruptible */
...@@ -55,7 +56,7 @@ int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *, ...@@ -55,7 +56,7 @@ int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *, int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
struct iov_iter *, size_t *, bool, u32 *, u16 *); struct iov_iter *, size_t *, bool, u32 *, u16 *);
bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *, bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
u32, int, const char *); u32, int, enum rxrpc_abort_reason);
void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *); void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *);
void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *, void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *,
struct sockaddr_rxrpc *); struct sockaddr_rxrpc *);
......
...@@ -16,7 +16,107 @@ ...@@ -16,7 +16,107 @@
/* /*
* Declare tracing information enums and their string mappings for display. * Declare tracing information enums and their string mappings for display.
*/ */
#define rxrpc_abort_reasons \
/* AFS errors */ \
EM(afs_abort_general_error, "afs-error") \
EM(afs_abort_interrupted, "afs-intr") \
EM(afs_abort_oom, "afs-oom") \
EM(afs_abort_op_not_supported, "afs-op-notsupp") \
EM(afs_abort_probeuuid_negative, "afs-probeuuid-neg") \
EM(afs_abort_send_data_error, "afs-send-data") \
EM(afs_abort_unmarshal_error, "afs-unmarshal") \
/* rxperf errors */ \
EM(rxperf_abort_general_error, "rxperf-error") \
EM(rxperf_abort_oom, "rxperf-oom") \
EM(rxperf_abort_op_not_supported, "rxperf-op-notsupp") \
EM(rxperf_abort_unmarshal_error, "rxperf-unmarshal") \
/* RxKAD security errors */ \
EM(rxkad_abort_1_short_check, "rxkad1-short-check") \
EM(rxkad_abort_1_short_data, "rxkad1-short-data") \
EM(rxkad_abort_1_short_encdata, "rxkad1-short-encdata") \
EM(rxkad_abort_1_short_header, "rxkad1-short-hdr") \
EM(rxkad_abort_2_short_check, "rxkad2-short-check") \
EM(rxkad_abort_2_short_data, "rxkad2-short-data") \
EM(rxkad_abort_2_short_header, "rxkad2-short-hdr") \
EM(rxkad_abort_2_short_len, "rxkad2-short-len") \
EM(rxkad_abort_bad_checksum, "rxkad2-bad-cksum") \
EM(rxkad_abort_chall_key_expired, "rxkad-chall-key-exp") \
EM(rxkad_abort_chall_level, "rxkad-chall-level") \
EM(rxkad_abort_chall_no_key, "rxkad-chall-nokey") \
EM(rxkad_abort_chall_short, "rxkad-chall-short") \
EM(rxkad_abort_chall_version, "rxkad-chall-version") \
EM(rxkad_abort_resp_bad_callid, "rxkad-resp-bad-callid") \
EM(rxkad_abort_resp_bad_checksum, "rxkad-resp-bad-cksum") \
EM(rxkad_abort_resp_bad_param, "rxkad-resp-bad-param") \
EM(rxkad_abort_resp_call_ctr, "rxkad-resp-call-ctr") \
EM(rxkad_abort_resp_call_state, "rxkad-resp-call-state") \
EM(rxkad_abort_resp_key_expired, "rxkad-resp-key-exp") \
EM(rxkad_abort_resp_key_rejected, "rxkad-resp-key-rej") \
EM(rxkad_abort_resp_level, "rxkad-resp-level") \
EM(rxkad_abort_resp_nokey, "rxkad-resp-nokey") \
EM(rxkad_abort_resp_ooseq, "rxkad-resp-ooseq") \
EM(rxkad_abort_resp_short, "rxkad-resp-short") \
EM(rxkad_abort_resp_short_tkt, "rxkad-resp-short-tkt") \
EM(rxkad_abort_resp_tkt_aname, "rxkad-resp-tk-aname") \
EM(rxkad_abort_resp_tkt_expired, "rxkad-resp-tk-exp") \
EM(rxkad_abort_resp_tkt_future, "rxkad-resp-tk-future") \
EM(rxkad_abort_resp_tkt_inst, "rxkad-resp-tk-inst") \
EM(rxkad_abort_resp_tkt_len, "rxkad-resp-tk-len") \
EM(rxkad_abort_resp_tkt_realm, "rxkad-resp-tk-realm") \
EM(rxkad_abort_resp_tkt_short, "rxkad-resp-tk-short") \
EM(rxkad_abort_resp_tkt_sinst, "rxkad-resp-tk-sinst") \
EM(rxkad_abort_resp_tkt_sname, "rxkad-resp-tk-sname") \
EM(rxkad_abort_resp_unknown_tkt, "rxkad-resp-unknown-tkt") \
EM(rxkad_abort_resp_version, "rxkad-resp-version") \
/* rxrpc errors */ \
EM(rxrpc_abort_call_improper_term, "call-improper-term") \
EM(rxrpc_abort_call_reset, "call-reset") \
EM(rxrpc_abort_call_sendmsg, "call-sendmsg") \
EM(rxrpc_abort_call_sock_release, "call-sock-rel") \
EM(rxrpc_abort_call_sock_release_tba, "call-sock-rel-tba") \
EM(rxrpc_abort_call_timeout, "call-timeout") \
EM(rxrpc_abort_no_service_key, "no-serv-key") \
EM(rxrpc_abort_nomem, "nomem") \
EM(rxrpc_abort_service_not_offered, "serv-not-offered") \
EM(rxrpc_abort_shut_down, "shut-down") \
EM(rxrpc_abort_unsupported_security, "unsup-sec") \
EM(rxrpc_badmsg_bad_abort, "bad-abort") \
EM(rxrpc_badmsg_bad_jumbo, "bad-jumbo") \
EM(rxrpc_badmsg_short_ack, "short-ack") \
EM(rxrpc_badmsg_short_ack_info, "short-ack-info") \
EM(rxrpc_badmsg_short_hdr, "short-hdr") \
EM(rxrpc_badmsg_unsupported_packet, "unsup-pkt") \
EM(rxrpc_badmsg_zero_call, "zero-call") \
EM(rxrpc_badmsg_zero_seq, "zero-seq") \
EM(rxrpc_badmsg_zero_service, "zero-service") \
EM(rxrpc_eproto_ackr_outside_window, "ackr-out-win") \
EM(rxrpc_eproto_ackr_sack_overflow, "ackr-sack-over") \
EM(rxrpc_eproto_ackr_short_sack, "ackr-short-sack") \
EM(rxrpc_eproto_ackr_zero, "ackr-zero") \
EM(rxrpc_eproto_bad_upgrade, "bad-upgrade") \
EM(rxrpc_eproto_data_after_last, "data-after-last") \
EM(rxrpc_eproto_different_last, "diff-last") \
EM(rxrpc_eproto_early_reply, "early-reply") \
EM(rxrpc_eproto_improper_term, "improper-term") \
EM(rxrpc_eproto_no_client_call, "no-cl-call") \
EM(rxrpc_eproto_no_client_conn, "no-cl-conn") \
EM(rxrpc_eproto_no_service_call, "no-sv-call") \
EM(rxrpc_eproto_reupgrade, "re-upgrade") \
EM(rxrpc_eproto_rxnull_challenge, "rxnull-chall") \
EM(rxrpc_eproto_rxnull_response, "rxnull-resp") \
EM(rxrpc_eproto_tx_rot_last, "tx-rot-last") \
EM(rxrpc_eproto_unexpected_ack, "unex-ack") \
EM(rxrpc_eproto_unexpected_ackall, "unex-ackall") \
EM(rxrpc_eproto_unexpected_implicit_end, "unex-impl-end") \
EM(rxrpc_eproto_unexpected_reply, "unex-reply") \
EM(rxrpc_eproto_wrong_security, "wrong-sec") \
EM(rxrpc_recvmsg_excess_data, "recvmsg-excess") \
EM(rxrpc_recvmsg_short_data, "recvmsg-short") \
E_(rxrpc_sendmsg_late_send, "sendmsg-late")
#define rxrpc_call_poke_traces \ #define rxrpc_call_poke_traces \
EM(rxrpc_call_poke_abort, "Abort") \
EM(rxrpc_call_poke_complete, "Compl") \
EM(rxrpc_call_poke_error, "Error") \ EM(rxrpc_call_poke_error, "Error") \
EM(rxrpc_call_poke_idle, "Idle") \ EM(rxrpc_call_poke_idle, "Idle") \
EM(rxrpc_call_poke_start, "Start") \ EM(rxrpc_call_poke_start, "Start") \
...@@ -26,6 +126,7 @@ ...@@ -26,6 +126,7 @@
#define rxrpc_skb_traces \ #define rxrpc_skb_traces \
EM(rxrpc_skb_eaten_by_unshare, "ETN unshare ") \ EM(rxrpc_skb_eaten_by_unshare, "ETN unshare ") \
EM(rxrpc_skb_eaten_by_unshare_nomem, "ETN unshar-nm") \ EM(rxrpc_skb_eaten_by_unshare_nomem, "ETN unshar-nm") \
EM(rxrpc_skb_get_conn_secured, "GET conn-secd") \
EM(rxrpc_skb_get_conn_work, "GET conn-work") \ EM(rxrpc_skb_get_conn_work, "GET conn-work") \
EM(rxrpc_skb_get_local_work, "GET locl-work") \ EM(rxrpc_skb_get_local_work, "GET locl-work") \
EM(rxrpc_skb_get_reject_work, "GET rej-work ") \ EM(rxrpc_skb_get_reject_work, "GET rej-work ") \
...@@ -35,6 +136,7 @@ ...@@ -35,6 +136,7 @@
EM(rxrpc_skb_new_error_report, "NEW error-rpt") \ EM(rxrpc_skb_new_error_report, "NEW error-rpt") \
EM(rxrpc_skb_new_jumbo_subpacket, "NEW jumbo-sub") \ EM(rxrpc_skb_new_jumbo_subpacket, "NEW jumbo-sub") \
EM(rxrpc_skb_new_unshared, "NEW unshared ") \ EM(rxrpc_skb_new_unshared, "NEW unshared ") \
EM(rxrpc_skb_put_conn_secured, "PUT conn-secd") \
EM(rxrpc_skb_put_conn_work, "PUT conn-work") \ EM(rxrpc_skb_put_conn_work, "PUT conn-work") \
EM(rxrpc_skb_put_error_report, "PUT error-rep") \ EM(rxrpc_skb_put_error_report, "PUT error-rep") \
EM(rxrpc_skb_put_input, "PUT input ") \ EM(rxrpc_skb_put_input, "PUT input ") \
...@@ -76,7 +178,6 @@ ...@@ -76,7 +178,6 @@
#define rxrpc_peer_traces \ #define rxrpc_peer_traces \
EM(rxrpc_peer_free, "FREE ") \ EM(rxrpc_peer_free, "FREE ") \
EM(rxrpc_peer_get_accept, "GET accept ") \ EM(rxrpc_peer_get_accept, "GET accept ") \
EM(rxrpc_peer_get_activate_call, "GET act-call") \
EM(rxrpc_peer_get_bundle, "GET bundle ") \ EM(rxrpc_peer_get_bundle, "GET bundle ") \
EM(rxrpc_peer_get_client_conn, "GET cln-conn") \ EM(rxrpc_peer_get_client_conn, "GET cln-conn") \
EM(rxrpc_peer_get_input, "GET input ") \ EM(rxrpc_peer_get_input, "GET input ") \
...@@ -89,7 +190,6 @@ ...@@ -89,7 +190,6 @@
EM(rxrpc_peer_put_bundle, "PUT bundle ") \ EM(rxrpc_peer_put_bundle, "PUT bundle ") \
EM(rxrpc_peer_put_call, "PUT call ") \ EM(rxrpc_peer_put_call, "PUT call ") \
EM(rxrpc_peer_put_conn, "PUT conn ") \ EM(rxrpc_peer_put_conn, "PUT conn ") \
EM(rxrpc_peer_put_discard_tmp, "PUT disc-tmp") \
EM(rxrpc_peer_put_input, "PUT input ") \ EM(rxrpc_peer_put_input, "PUT input ") \
EM(rxrpc_peer_put_input_error, "PUT inpt-err") \ EM(rxrpc_peer_put_input_error, "PUT inpt-err") \
E_(rxrpc_peer_put_keepalive, "PUT keepaliv") E_(rxrpc_peer_put_keepalive, "PUT keepaliv")
...@@ -99,6 +199,7 @@ ...@@ -99,6 +199,7 @@
EM(rxrpc_bundle_get_client_call, "GET clt-call") \ EM(rxrpc_bundle_get_client_call, "GET clt-call") \
EM(rxrpc_bundle_get_client_conn, "GET clt-conn") \ EM(rxrpc_bundle_get_client_conn, "GET clt-conn") \
EM(rxrpc_bundle_get_service_conn, "GET svc-conn") \ EM(rxrpc_bundle_get_service_conn, "GET svc-conn") \
EM(rxrpc_bundle_put_call, "PUT call ") \
EM(rxrpc_bundle_put_conn, "PUT conn ") \ EM(rxrpc_bundle_put_conn, "PUT conn ") \
EM(rxrpc_bundle_put_discard, "PUT discard ") \ EM(rxrpc_bundle_put_discard, "PUT discard ") \
E_(rxrpc_bundle_new, "NEW ") E_(rxrpc_bundle_new, "NEW ")
...@@ -109,14 +210,14 @@ ...@@ -109,14 +210,14 @@
EM(rxrpc_conn_get_call_input, "GET inp-call") \ EM(rxrpc_conn_get_call_input, "GET inp-call") \
EM(rxrpc_conn_get_conn_input, "GET inp-conn") \ EM(rxrpc_conn_get_conn_input, "GET inp-conn") \
EM(rxrpc_conn_get_idle, "GET idle ") \ EM(rxrpc_conn_get_idle, "GET idle ") \
EM(rxrpc_conn_get_poke, "GET poke ") \ EM(rxrpc_conn_get_poke_abort, "GET pk-abort") \
EM(rxrpc_conn_get_poke_timer, "GET poke ") \
EM(rxrpc_conn_get_service_conn, "GET svc-conn") \ EM(rxrpc_conn_get_service_conn, "GET svc-conn") \
EM(rxrpc_conn_new_client, "NEW client ") \ EM(rxrpc_conn_new_client, "NEW client ") \
EM(rxrpc_conn_new_service, "NEW service ") \ EM(rxrpc_conn_new_service, "NEW service ") \
EM(rxrpc_conn_put_call, "PUT call ") \ EM(rxrpc_conn_put_call, "PUT call ") \
EM(rxrpc_conn_put_call_input, "PUT inp-call") \ EM(rxrpc_conn_put_call_input, "PUT inp-call") \
EM(rxrpc_conn_put_conn_input, "PUT inp-conn") \ EM(rxrpc_conn_put_conn_input, "PUT inp-conn") \
EM(rxrpc_conn_put_discard, "PUT discard ") \
EM(rxrpc_conn_put_discard_idle, "PUT disc-idl") \ EM(rxrpc_conn_put_discard_idle, "PUT disc-idl") \
EM(rxrpc_conn_put_local_dead, "PUT loc-dead") \ EM(rxrpc_conn_put_local_dead, "PUT loc-dead") \
EM(rxrpc_conn_put_noreuse, "PUT noreuse ") \ EM(rxrpc_conn_put_noreuse, "PUT noreuse ") \
...@@ -124,10 +225,10 @@ ...@@ -124,10 +225,10 @@
EM(rxrpc_conn_put_service_reaped, "PUT svc-reap") \ EM(rxrpc_conn_put_service_reaped, "PUT svc-reap") \
EM(rxrpc_conn_put_unbundle, "PUT unbundle") \ EM(rxrpc_conn_put_unbundle, "PUT unbundle") \
EM(rxrpc_conn_put_unidle, "PUT unidle ") \ EM(rxrpc_conn_put_unidle, "PUT unidle ") \
EM(rxrpc_conn_put_work, "PUT work ") \
EM(rxrpc_conn_queue_challenge, "QUE chall ") \ EM(rxrpc_conn_queue_challenge, "QUE chall ") \
EM(rxrpc_conn_queue_retry_work, "QUE retry-wk") \ EM(rxrpc_conn_queue_retry_work, "QUE retry-wk") \
EM(rxrpc_conn_queue_rx_work, "QUE rx-work ") \ EM(rxrpc_conn_queue_rx_work, "QUE rx-work ") \
EM(rxrpc_conn_queue_timer, "QUE timer ") \
EM(rxrpc_conn_see_new_service_conn, "SEE new-svc ") \ EM(rxrpc_conn_see_new_service_conn, "SEE new-svc ") \
EM(rxrpc_conn_see_reap_service, "SEE reap-svc") \ EM(rxrpc_conn_see_reap_service, "SEE reap-svc") \
E_(rxrpc_conn_see_work, "SEE work ") E_(rxrpc_conn_see_work, "SEE work ")
...@@ -138,16 +239,16 @@ ...@@ -138,16 +239,16 @@
EM(rxrpc_client_chan_activate, "ChActv") \ EM(rxrpc_client_chan_activate, "ChActv") \
EM(rxrpc_client_chan_disconnect, "ChDisc") \ EM(rxrpc_client_chan_disconnect, "ChDisc") \
EM(rxrpc_client_chan_pass, "ChPass") \ EM(rxrpc_client_chan_pass, "ChPass") \
EM(rxrpc_client_chan_wait_failed, "ChWtFl") \
EM(rxrpc_client_cleanup, "Clean ") \ EM(rxrpc_client_cleanup, "Clean ") \
EM(rxrpc_client_discard, "Discar") \ EM(rxrpc_client_discard, "Discar") \
EM(rxrpc_client_duplicate, "Duplic") \
EM(rxrpc_client_exposed, "Expose") \ EM(rxrpc_client_exposed, "Expose") \
EM(rxrpc_client_replace, "Replac") \ EM(rxrpc_client_replace, "Replac") \
EM(rxrpc_client_queue_new_call, "Q-Call") \
EM(rxrpc_client_to_active, "->Actv") \ EM(rxrpc_client_to_active, "->Actv") \
E_(rxrpc_client_to_idle, "->Idle") E_(rxrpc_client_to_idle, "->Idle")
#define rxrpc_call_traces \ #define rxrpc_call_traces \
EM(rxrpc_call_get_io_thread, "GET iothread") \
EM(rxrpc_call_get_input, "GET input ") \ EM(rxrpc_call_get_input, "GET input ") \
EM(rxrpc_call_get_kernel_service, "GET krnl-srv") \ EM(rxrpc_call_get_kernel_service, "GET krnl-srv") \
EM(rxrpc_call_get_notify_socket, "GET notify ") \ EM(rxrpc_call_get_notify_socket, "GET notify ") \
...@@ -160,6 +261,7 @@ ...@@ -160,6 +261,7 @@
EM(rxrpc_call_new_prealloc_service, "NEW prealloc") \ EM(rxrpc_call_new_prealloc_service, "NEW prealloc") \
EM(rxrpc_call_put_discard_prealloc, "PUT disc-pre") \ EM(rxrpc_call_put_discard_prealloc, "PUT disc-pre") \
EM(rxrpc_call_put_discard_error, "PUT disc-err") \ EM(rxrpc_call_put_discard_error, "PUT disc-err") \
EM(rxrpc_call_put_io_thread, "PUT iothread") \
EM(rxrpc_call_put_input, "PUT input ") \ EM(rxrpc_call_put_input, "PUT input ") \
EM(rxrpc_call_put_kernel, "PUT kernel ") \ EM(rxrpc_call_put_kernel, "PUT kernel ") \
EM(rxrpc_call_put_poke, "PUT poke ") \ EM(rxrpc_call_put_poke, "PUT poke ") \
...@@ -169,10 +271,12 @@ ...@@ -169,10 +271,12 @@
EM(rxrpc_call_put_sendmsg, "PUT sendmsg ") \ EM(rxrpc_call_put_sendmsg, "PUT sendmsg ") \
EM(rxrpc_call_put_unnotify, "PUT unnotify") \ EM(rxrpc_call_put_unnotify, "PUT unnotify") \
EM(rxrpc_call_put_userid_exists, "PUT u-exists") \ EM(rxrpc_call_put_userid_exists, "PUT u-exists") \
EM(rxrpc_call_put_userid, "PUT user-id ") \
EM(rxrpc_call_see_accept, "SEE accept ") \ EM(rxrpc_call_see_accept, "SEE accept ") \
EM(rxrpc_call_see_activate_client, "SEE act-clnt") \ EM(rxrpc_call_see_activate_client, "SEE act-clnt") \
EM(rxrpc_call_see_connect_failed, "SEE con-fail") \ EM(rxrpc_call_see_connect_failed, "SEE con-fail") \
EM(rxrpc_call_see_connected, "SEE connect ") \ EM(rxrpc_call_see_connected, "SEE connect ") \
EM(rxrpc_call_see_disconnected, "SEE disconn ") \
EM(rxrpc_call_see_distribute_error, "SEE dist-err") \ EM(rxrpc_call_see_distribute_error, "SEE dist-err") \
EM(rxrpc_call_see_input, "SEE input ") \ EM(rxrpc_call_see_input, "SEE input ") \
EM(rxrpc_call_see_release, "SEE release ") \ EM(rxrpc_call_see_release, "SEE release ") \
...@@ -376,6 +480,7 @@ ...@@ -376,6 +480,7 @@
#define EM(a, b) a, #define EM(a, b) a,
#define E_(a, b) a #define E_(a, b) a
enum rxrpc_abort_reason { rxrpc_abort_reasons } __mode(byte);
enum rxrpc_bundle_trace { rxrpc_bundle_traces } __mode(byte); enum rxrpc_bundle_trace { rxrpc_bundle_traces } __mode(byte);
enum rxrpc_call_poke_trace { rxrpc_call_poke_traces } __mode(byte); enum rxrpc_call_poke_trace { rxrpc_call_poke_traces } __mode(byte);
enum rxrpc_call_trace { rxrpc_call_traces } __mode(byte); enum rxrpc_call_trace { rxrpc_call_traces } __mode(byte);
...@@ -404,9 +509,13 @@ enum rxrpc_txqueue_trace { rxrpc_txqueue_traces } __mode(byte); ...@@ -404,9 +509,13 @@ enum rxrpc_txqueue_trace { rxrpc_txqueue_traces } __mode(byte);
*/ */
#undef EM #undef EM
#undef E_ #undef E_
#ifndef RXRPC_TRACE_ONLY_DEFINE_ENUMS
#define EM(a, b) TRACE_DEFINE_ENUM(a); #define EM(a, b) TRACE_DEFINE_ENUM(a);
#define E_(a, b) TRACE_DEFINE_ENUM(a); #define E_(a, b) TRACE_DEFINE_ENUM(a);
rxrpc_abort_reasons;
rxrpc_bundle_traces; rxrpc_bundle_traces;
rxrpc_call_poke_traces; rxrpc_call_poke_traces;
rxrpc_call_traces; rxrpc_call_traces;
...@@ -657,14 +766,14 @@ TRACE_EVENT(rxrpc_rx_done, ...@@ -657,14 +766,14 @@ TRACE_EVENT(rxrpc_rx_done,
); );
TRACE_EVENT(rxrpc_abort, TRACE_EVENT(rxrpc_abort,
TP_PROTO(unsigned int call_nr, const char *why, u32 cid, u32 call_id, TP_PROTO(unsigned int call_nr, enum rxrpc_abort_reason why,
rxrpc_seq_t seq, int abort_code, int error), u32 cid, u32 call_id, rxrpc_seq_t seq, int abort_code, int error),
TP_ARGS(call_nr, why, cid, call_id, seq, abort_code, error), TP_ARGS(call_nr, why, cid, call_id, seq, abort_code, error),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(unsigned int, call_nr ) __field(unsigned int, call_nr )
__array(char, why, 4 ) __field(enum rxrpc_abort_reason, why )
__field(u32, cid ) __field(u32, cid )
__field(u32, call_id ) __field(u32, call_id )
__field(rxrpc_seq_t, seq ) __field(rxrpc_seq_t, seq )
...@@ -673,8 +782,8 @@ TRACE_EVENT(rxrpc_abort, ...@@ -673,8 +782,8 @@ TRACE_EVENT(rxrpc_abort,
), ),
TP_fast_assign( TP_fast_assign(
memcpy(__entry->why, why, 4);
__entry->call_nr = call_nr; __entry->call_nr = call_nr;
__entry->why = why;
__entry->cid = cid; __entry->cid = cid;
__entry->call_id = call_id; __entry->call_id = call_id;
__entry->abort_code = abort_code; __entry->abort_code = abort_code;
...@@ -685,7 +794,8 @@ TRACE_EVENT(rxrpc_abort, ...@@ -685,7 +794,8 @@ TRACE_EVENT(rxrpc_abort,
TP_printk("c=%08x %08x:%08x s=%u a=%d e=%d %s", TP_printk("c=%08x %08x:%08x s=%u a=%d e=%d %s",
__entry->call_nr, __entry->call_nr,
__entry->cid, __entry->call_id, __entry->seq, __entry->cid, __entry->call_id, __entry->seq,
__entry->abort_code, __entry->error, __entry->why) __entry->abort_code, __entry->error,
__print_symbolic(__entry->why, rxrpc_abort_reasons))
); );
TRACE_EVENT(rxrpc_call_complete, TRACE_EVENT(rxrpc_call_complete,
...@@ -1521,30 +1631,6 @@ TRACE_EVENT(rxrpc_improper_term, ...@@ -1521,30 +1631,6 @@ TRACE_EVENT(rxrpc_improper_term,
__entry->abort_code) __entry->abort_code)
); );
TRACE_EVENT(rxrpc_rx_eproto,
TP_PROTO(struct rxrpc_call *call, rxrpc_serial_t serial,
const char *why),
TP_ARGS(call, serial, why),
TP_STRUCT__entry(
__field(unsigned int, call )
__field(rxrpc_serial_t, serial )
__field(const char *, why )
),
TP_fast_assign(
__entry->call = call ? call->debug_id : 0;
__entry->serial = serial;
__entry->why = why;
),
TP_printk("c=%08x EPROTO %08x %s",
__entry->call,
__entry->serial,
__entry->why)
);
TRACE_EVENT(rxrpc_connect_call, TRACE_EVENT(rxrpc_connect_call,
TP_PROTO(struct rxrpc_call *call), TP_PROTO(struct rxrpc_call *call),
...@@ -1842,6 +1928,8 @@ TRACE_EVENT(rxrpc_call_poked, ...@@ -1842,6 +1928,8 @@ TRACE_EVENT(rxrpc_call_poked,
#undef EM #undef EM
#undef E_ #undef E_
#endif /* RXRPC_TRACE_ONLY_DEFINE_ENUMS */
#endif /* _TRACE_RXRPC_H */ #endif /* _TRACE_RXRPC_H */
/* This part must be outside protection */ /* This part must be outside protection */
......
...@@ -10,6 +10,7 @@ rxrpc-y := \ ...@@ -10,6 +10,7 @@ rxrpc-y := \
call_accept.o \ call_accept.o \
call_event.o \ call_event.o \
call_object.o \ call_object.o \
call_state.o \
conn_client.o \ conn_client.o \
conn_event.o \ conn_event.o \
conn_object.o \ conn_object.o \
......
...@@ -155,10 +155,10 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len) ...@@ -155,10 +155,10 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
if (service_id) { if (service_id) {
write_lock(&local->services_lock); write_lock(&local->services_lock);
if (rcu_access_pointer(local->service)) if (local->service)
goto service_in_use; goto service_in_use;
rx->local = local; rx->local = local;
rcu_assign_pointer(local->service, rx); local->service = rx;
write_unlock(&local->services_lock); write_unlock(&local->services_lock);
rx->sk.sk_state = RXRPC_SERVER_BOUND; rx->sk.sk_state = RXRPC_SERVER_BOUND;
...@@ -328,7 +328,6 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, ...@@ -328,7 +328,6 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
mutex_unlock(&call->user_mutex); mutex_unlock(&call->user_mutex);
} }
rxrpc_put_peer(cp.peer, rxrpc_peer_put_discard_tmp);
_leave(" = %p", call); _leave(" = %p", call);
return call; return call;
} }
...@@ -374,13 +373,17 @@ EXPORT_SYMBOL(rxrpc_kernel_end_call); ...@@ -374,13 +373,17 @@ EXPORT_SYMBOL(rxrpc_kernel_end_call);
* @sock: The socket the call is on * @sock: The socket the call is on
* @call: The call to check * @call: The call to check
* *
* Allow a kernel service to find out whether a call is still alive - * Allow a kernel service to find out whether a call is still alive - whether
* ie. whether it has completed. * it has completed successfully and all received data has been consumed.
*/ */
bool rxrpc_kernel_check_life(const struct socket *sock, bool rxrpc_kernel_check_life(const struct socket *sock,
const struct rxrpc_call *call) const struct rxrpc_call *call)
{ {
return call->state != RXRPC_CALL_COMPLETE; if (!rxrpc_call_is_complete(call))
return true;
if (call->completion != RXRPC_CALL_SUCCEEDED)
return false;
return !skb_queue_empty(&call->recvmsg_queue);
} }
EXPORT_SYMBOL(rxrpc_kernel_check_life); EXPORT_SYMBOL(rxrpc_kernel_check_life);
...@@ -872,9 +875,9 @@ static int rxrpc_release_sock(struct sock *sk) ...@@ -872,9 +875,9 @@ static int rxrpc_release_sock(struct sock *sk)
sk->sk_state = RXRPC_CLOSE; sk->sk_state = RXRPC_CLOSE;
if (rx->local && rcu_access_pointer(rx->local->service) == rx) { if (rx->local && rx->local->service == rx) {
write_lock(&rx->local->services_lock); write_lock(&rx->local->services_lock);
rcu_assign_pointer(rx->local->service, NULL); rx->local->service = NULL;
write_unlock(&rx->local->services_lock); write_unlock(&rx->local->services_lock);
} }
...@@ -957,16 +960,9 @@ static const struct net_proto_family rxrpc_family_ops = { ...@@ -957,16 +960,9 @@ static const struct net_proto_family rxrpc_family_ops = {
static int __init af_rxrpc_init(void) static int __init af_rxrpc_init(void)
{ {
int ret = -1; int ret = -1;
unsigned int tmp;
BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof_field(struct sk_buff, cb)); BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof_field(struct sk_buff, cb));
get_random_bytes(&tmp, sizeof(tmp));
tmp &= 0x3fffffff;
if (tmp == 0)
tmp = 1;
idr_set_cursor(&rxrpc_client_conn_ids, tmp);
ret = -ENOMEM; ret = -ENOMEM;
rxrpc_call_jar = kmem_cache_create( rxrpc_call_jar = kmem_cache_create(
"rxrpc_call_jar", sizeof(struct rxrpc_call), 0, "rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
...@@ -1062,7 +1058,6 @@ static void __exit af_rxrpc_exit(void) ...@@ -1062,7 +1058,6 @@ static void __exit af_rxrpc_exit(void)
* are released. * are released.
*/ */
rcu_barrier(); rcu_barrier();
rxrpc_destroy_client_conn_ids();
destroy_workqueue(rxrpc_workqueue); destroy_workqueue(rxrpc_workqueue);
rxrpc_exit_security(); rxrpc_exit_security();
......
此差异已折叠。
...@@ -99,7 +99,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, ...@@ -99,7 +99,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
if (!call) if (!call)
return -ENOMEM; return -ENOMEM;
call->flags |= (1 << RXRPC_CALL_IS_SERVICE); call->flags |= (1 << RXRPC_CALL_IS_SERVICE);
call->state = RXRPC_CALL_SERVER_PREALLOC; rxrpc_set_call_state(call, RXRPC_CALL_SERVER_PREALLOC);
__set_bit(RXRPC_CALL_EV_INITIAL_PING, &call->events); __set_bit(RXRPC_CALL_EV_INITIAL_PING, &call->events);
trace_rxrpc_call(call->debug_id, refcount_read(&call->ref), trace_rxrpc_call(call->debug_id, refcount_read(&call->ref),
...@@ -280,7 +280,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx, ...@@ -280,7 +280,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
(peer_tail + 1) & (peer_tail + 1) &
(RXRPC_BACKLOG_MAX - 1)); (RXRPC_BACKLOG_MAX - 1));
rxrpc_new_incoming_peer(rx, local, peer); rxrpc_new_incoming_peer(local, peer);
} }
/* Now allocate and set up the connection */ /* Now allocate and set up the connection */
...@@ -326,11 +326,11 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx, ...@@ -326,11 +326,11 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
* If we want to report an error, we mark the skb with the packet type and * If we want to report an error, we mark the skb with the packet type and
* abort code and return false. * abort code and return false.
*/ */
int rxrpc_new_incoming_call(struct rxrpc_local *local, bool rxrpc_new_incoming_call(struct rxrpc_local *local,
struct rxrpc_peer *peer, struct rxrpc_peer *peer,
struct rxrpc_connection *conn, struct rxrpc_connection *conn,
struct sockaddr_rxrpc *peer_srx, struct sockaddr_rxrpc *peer_srx,
struct sk_buff *skb) struct sk_buff *skb)
{ {
const struct rxrpc_security *sec = NULL; const struct rxrpc_security *sec = NULL;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
...@@ -339,18 +339,17 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local, ...@@ -339,18 +339,17 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local,
_enter(""); _enter("");
/* Don't set up a call for anything other than the first DATA packet. */ /* Don't set up a call for anything other than a DATA packet. */
if (sp->hdr.seq != 1 || if (sp->hdr.type != RXRPC_PACKET_TYPE_DATA)
sp->hdr.type != RXRPC_PACKET_TYPE_DATA) return rxrpc_protocol_error(skb, rxrpc_eproto_no_service_call);
return 0; /* Just discard */
rcu_read_lock(); read_lock(&local->services_lock);
/* Weed out packets to services we're not offering. Packets that would /* Weed out packets to services we're not offering. Packets that would
* begin a call are explicitly rejected and the rest are just * begin a call are explicitly rejected and the rest are just
* discarded. * discarded.
*/ */
rx = rcu_dereference(local->service); rx = local->service;
if (!rx || (sp->hdr.serviceId != rx->srx.srx_service && if (!rx || (sp->hdr.serviceId != rx->srx.srx_service &&
sp->hdr.serviceId != rx->second_service) sp->hdr.serviceId != rx->second_service)
) { ) {
...@@ -363,16 +362,14 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local, ...@@ -363,16 +362,14 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local,
if (!conn) { if (!conn) {
sec = rxrpc_get_incoming_security(rx, skb); sec = rxrpc_get_incoming_security(rx, skb);
if (!sec) if (!sec)
goto reject; goto unsupported_security;
} }
spin_lock(&rx->incoming_lock); spin_lock(&rx->incoming_lock);
if (rx->sk.sk_state == RXRPC_SERVER_LISTEN_DISABLED || if (rx->sk.sk_state == RXRPC_SERVER_LISTEN_DISABLED ||
rx->sk.sk_state == RXRPC_CLOSE) { rx->sk.sk_state == RXRPC_CLOSE) {
trace_rxrpc_abort(0, "CLS", sp->hdr.cid, sp->hdr.callNumber, rxrpc_direct_abort(skb, rxrpc_abort_shut_down,
sp->hdr.seq, RX_INVALID_OPERATION, ESHUTDOWN); RX_INVALID_OPERATION, -ESHUTDOWN);
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
skb->priority = RX_INVALID_OPERATION;
goto no_call; goto no_call;
} }
...@@ -402,7 +399,7 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local, ...@@ -402,7 +399,7 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local,
spin_unlock(&conn->state_lock); spin_unlock(&conn->state_lock);
spin_unlock(&rx->incoming_lock); spin_unlock(&rx->incoming_lock);
rcu_read_unlock(); read_unlock(&local->services_lock);
if (hlist_unhashed(&call->error_link)) { if (hlist_unhashed(&call->error_link)) {
spin_lock(&call->peer->lock); spin_lock(&call->peer->lock);
...@@ -413,22 +410,24 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local, ...@@ -413,22 +410,24 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local,
_leave(" = %p{%d}", call, call->debug_id); _leave(" = %p{%d}", call, call->debug_id);
rxrpc_input_call_event(call, skb); rxrpc_input_call_event(call, skb);
rxrpc_put_call(call, rxrpc_call_put_input); rxrpc_put_call(call, rxrpc_call_put_input);
return 0; return true;
unsupported_service: unsupported_service:
trace_rxrpc_abort(0, "INV", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, read_unlock(&local->services_lock);
RX_INVALID_OPERATION, EOPNOTSUPP); return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
skb->priority = RX_INVALID_OPERATION; RX_INVALID_OPERATION, -EOPNOTSUPP);
goto reject; unsupported_security:
read_unlock(&local->services_lock);
return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
RX_INVALID_OPERATION, -EKEYREJECTED);
no_call: no_call:
spin_unlock(&rx->incoming_lock); spin_unlock(&rx->incoming_lock);
reject: read_unlock(&local->services_lock);
rcu_read_unlock();
_leave(" = f [%u]", skb->mark); _leave(" = f [%u]", skb->mark);
return -EPROTO; return false;
discard: discard:
rcu_read_unlock(); read_unlock(&local->services_lock);
return 0; return true;
} }
/* /*
......
...@@ -251,6 +251,41 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb) ...@@ -251,6 +251,41 @@ void rxrpc_resend(struct rxrpc_call *call, struct sk_buff *ack_skb)
_leave(""); _leave("");
} }
/*
* Start transmitting the reply to a service. This cancels the need to ACK the
* request if we haven't yet done so.
*/
static void rxrpc_begin_service_reply(struct rxrpc_call *call)
{
unsigned long now = jiffies;
rxrpc_set_call_state(call, RXRPC_CALL_SERVER_SEND_REPLY);
WRITE_ONCE(call->delay_ack_at, now + MAX_JIFFY_OFFSET);
if (call->ackr_reason == RXRPC_ACK_DELAY)
call->ackr_reason = 0;
trace_rxrpc_timer(call, rxrpc_timer_init_for_send_reply, now);
}
/*
* Close the transmission phase. After this point there is no more data to be
* transmitted in the call.
*/
static void rxrpc_close_tx_phase(struct rxrpc_call *call)
{
_debug("________awaiting reply/ACK__________");
switch (__rxrpc_call_state(call)) {
case RXRPC_CALL_CLIENT_SEND_REQUEST:
rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_REPLY);
break;
case RXRPC_CALL_SERVER_SEND_REPLY:
rxrpc_set_call_state(call, RXRPC_CALL_SERVER_AWAIT_ACK);
break;
default:
break;
}
}
static bool rxrpc_tx_window_has_space(struct rxrpc_call *call) static bool rxrpc_tx_window_has_space(struct rxrpc_call *call)
{ {
unsigned int winsize = min_t(unsigned int, call->tx_winsize, unsigned int winsize = min_t(unsigned int, call->tx_winsize,
...@@ -270,9 +305,11 @@ static void rxrpc_decant_prepared_tx(struct rxrpc_call *call) ...@@ -270,9 +305,11 @@ static void rxrpc_decant_prepared_tx(struct rxrpc_call *call)
{ {
struct rxrpc_txbuf *txb; struct rxrpc_txbuf *txb;
if (rxrpc_is_client_call(call) && if (!test_bit(RXRPC_CALL_EXPOSED, &call->flags)) {
!test_bit(RXRPC_CALL_EXPOSED, &call->flags)) if (list_empty(&call->tx_sendmsg))
return;
rxrpc_expose_client_call(call); rxrpc_expose_client_call(call);
}
while ((txb = list_first_entry_or_null(&call->tx_sendmsg, while ((txb = list_first_entry_or_null(&call->tx_sendmsg,
struct rxrpc_txbuf, call_link))) { struct rxrpc_txbuf, call_link))) {
...@@ -283,6 +320,9 @@ static void rxrpc_decant_prepared_tx(struct rxrpc_call *call) ...@@ -283,6 +320,9 @@ static void rxrpc_decant_prepared_tx(struct rxrpc_call *call)
call->tx_top = txb->seq; call->tx_top = txb->seq;
list_add_tail(&txb->call_link, &call->tx_buffer); list_add_tail(&txb->call_link, &call->tx_buffer);
if (txb->wire.flags & RXRPC_LAST_PACKET)
rxrpc_close_tx_phase(call);
rxrpc_transmit_one(call, txb); rxrpc_transmit_one(call, txb);
if (!rxrpc_tx_window_has_space(call)) if (!rxrpc_tx_window_has_space(call))
...@@ -292,16 +332,15 @@ static void rxrpc_decant_prepared_tx(struct rxrpc_call *call) ...@@ -292,16 +332,15 @@ static void rxrpc_decant_prepared_tx(struct rxrpc_call *call)
static void rxrpc_transmit_some_data(struct rxrpc_call *call) static void rxrpc_transmit_some_data(struct rxrpc_call *call)
{ {
switch (call->state) { switch (__rxrpc_call_state(call)) {
case RXRPC_CALL_SERVER_ACK_REQUEST: case RXRPC_CALL_SERVER_ACK_REQUEST:
if (list_empty(&call->tx_sendmsg)) if (list_empty(&call->tx_sendmsg))
return; return;
rxrpc_begin_service_reply(call);
fallthrough; fallthrough;
case RXRPC_CALL_SERVER_SEND_REPLY: case RXRPC_CALL_SERVER_SEND_REPLY:
case RXRPC_CALL_SERVER_AWAIT_ACK:
case RXRPC_CALL_CLIENT_SEND_REQUEST: case RXRPC_CALL_CLIENT_SEND_REQUEST:
case RXRPC_CALL_CLIENT_AWAIT_REPLY:
if (!rxrpc_tx_window_has_space(call)) if (!rxrpc_tx_window_has_space(call))
return; return;
if (list_empty(&call->tx_sendmsg)) { if (list_empty(&call->tx_sendmsg)) {
...@@ -331,21 +370,31 @@ static void rxrpc_send_initial_ping(struct rxrpc_call *call) ...@@ -331,21 +370,31 @@ static void rxrpc_send_initial_ping(struct rxrpc_call *call)
/* /*
* Handle retransmission and deferred ACK/abort generation. * Handle retransmission and deferred ACK/abort generation.
*/ */
void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
{ {
unsigned long now, next, t; unsigned long now, next, t;
rxrpc_serial_t ackr_serial; rxrpc_serial_t ackr_serial;
bool resend = false, expired = false; bool resend = false, expired = false;
s32 abort_code;
rxrpc_see_call(call, rxrpc_call_see_input); rxrpc_see_call(call, rxrpc_call_see_input);
//printk("\n--------------------\n"); //printk("\n--------------------\n");
_enter("{%d,%s,%lx}", _enter("{%d,%s,%lx}",
call->debug_id, rxrpc_call_states[call->state], call->events); call->debug_id, rxrpc_call_states[__rxrpc_call_state(call)],
call->events);
if (call->state == RXRPC_CALL_COMPLETE) if (__rxrpc_call_is_complete(call))
goto out; goto out;
/* Handle abort request locklessly, vs rxrpc_propose_abort(). */
abort_code = smp_load_acquire(&call->send_abort);
if (abort_code) {
rxrpc_abort_call(call, 0, call->send_abort, call->send_abort_err,
call->send_abort_why);
goto out;
}
if (skb && skb->mark == RXRPC_SKB_MARK_ERROR) if (skb && skb->mark == RXRPC_SKB_MARK_ERROR)
goto out; goto out;
...@@ -358,7 +407,7 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -358,7 +407,7 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
} }
t = READ_ONCE(call->expect_req_by); t = READ_ONCE(call->expect_req_by);
if (call->state == RXRPC_CALL_SERVER_RECV_REQUEST && if (__rxrpc_call_state(call) == RXRPC_CALL_SERVER_RECV_REQUEST &&
time_after_eq(now, t)) { time_after_eq(now, t)) {
trace_rxrpc_timer(call, rxrpc_timer_exp_idle, now); trace_rxrpc_timer(call, rxrpc_timer_exp_idle, now);
expired = true; expired = true;
...@@ -429,11 +478,12 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -429,11 +478,12 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
if (test_bit(RXRPC_CALL_RX_HEARD, &call->flags) && if (test_bit(RXRPC_CALL_RX_HEARD, &call->flags) &&
(int)call->conn->hi_serial - (int)call->rx_serial > 0) { (int)call->conn->hi_serial - (int)call->rx_serial > 0) {
trace_rxrpc_call_reset(call); trace_rxrpc_call_reset(call);
rxrpc_abort_call("EXP", call, 0, RX_CALL_DEAD, -ECONNRESET); rxrpc_abort_call(call, 0, RX_CALL_DEAD, -ECONNRESET,
rxrpc_abort_call_reset);
} else { } else {
rxrpc_abort_call("EXP", call, 0, RX_CALL_TIMEOUT, -ETIME); rxrpc_abort_call(call, 0, RX_CALL_TIMEOUT, -ETIME,
rxrpc_abort_call_timeout);
} }
rxrpc_send_abort_packet(call);
goto out; goto out;
} }
...@@ -441,7 +491,7 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -441,7 +491,7 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
rxrpc_send_ACK(call, RXRPC_ACK_PING, 0, rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
rxrpc_propose_ack_ping_for_lost_ack); rxrpc_propose_ack_ping_for_lost_ack);
if (resend && call->state != RXRPC_CALL_CLIENT_RECV_REPLY) if (resend && __rxrpc_call_state(call) != RXRPC_CALL_CLIENT_RECV_REPLY)
rxrpc_resend(call, NULL); rxrpc_resend(call, NULL);
if (test_and_clear_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags)) if (test_and_clear_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags))
...@@ -453,7 +503,7 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -453,7 +503,7 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
rxrpc_propose_ack_input_data); rxrpc_propose_ack_input_data);
/* Make sure the timer is restarted */ /* Make sure the timer is restarted */
if (call->state != RXRPC_CALL_COMPLETE) { if (!__rxrpc_call_is_complete(call)) {
next = call->expect_rx_by; next = call->expect_rx_by;
#define set(T) { t = READ_ONCE(T); if (time_before(t, next)) next = t; } #define set(T) { t = READ_ONCE(T); if (time_before(t, next)) next = t; }
...@@ -474,9 +524,15 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -474,9 +524,15 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
} }
out: out:
if (call->state == RXRPC_CALL_COMPLETE) if (__rxrpc_call_is_complete(call)) {
del_timer_sync(&call->timer); del_timer_sync(&call->timer);
if (!test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
rxrpc_disconnect_call(call);
if (call->security)
call->security->free_call_crypto(call);
}
if (call->acks_hard_ack != call->tx_bottom) if (call->acks_hard_ack != call->tx_bottom)
rxrpc_shrink_call_tx_buffer(call); rxrpc_shrink_call_tx_buffer(call);
_leave(""); _leave("");
return true;
} }
...@@ -50,7 +50,7 @@ void rxrpc_poke_call(struct rxrpc_call *call, enum rxrpc_call_poke_trace what) ...@@ -50,7 +50,7 @@ void rxrpc_poke_call(struct rxrpc_call *call, enum rxrpc_call_poke_trace what)
struct rxrpc_local *local = call->local; struct rxrpc_local *local = call->local;
bool busy; bool busy;
if (call->state < RXRPC_CALL_COMPLETE) { if (!test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) {
spin_lock_bh(&local->lock); spin_lock_bh(&local->lock);
busy = !list_empty(&call->attend_link); busy = !list_empty(&call->attend_link);
trace_rxrpc_poke_call(call, busy, what); trace_rxrpc_poke_call(call, busy, what);
...@@ -69,7 +69,7 @@ static void rxrpc_call_timer_expired(struct timer_list *t) ...@@ -69,7 +69,7 @@ static void rxrpc_call_timer_expired(struct timer_list *t)
_enter("%d", call->debug_id); _enter("%d", call->debug_id);
if (call->state < RXRPC_CALL_COMPLETE) { if (!__rxrpc_call_is_complete(call)) {
trace_rxrpc_timer_expired(call, jiffies); trace_rxrpc_timer_expired(call, jiffies);
rxrpc_poke_call(call, rxrpc_call_poke_timer); rxrpc_poke_call(call, rxrpc_call_poke_timer);
} }
...@@ -150,7 +150,7 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp, ...@@ -150,7 +150,7 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,
timer_setup(&call->timer, rxrpc_call_timer_expired, 0); timer_setup(&call->timer, rxrpc_call_timer_expired, 0);
INIT_WORK(&call->destroyer, rxrpc_destroy_call); INIT_WORK(&call->destroyer, rxrpc_destroy_call);
INIT_LIST_HEAD(&call->link); INIT_LIST_HEAD(&call->link);
INIT_LIST_HEAD(&call->chan_wait_link); INIT_LIST_HEAD(&call->wait_link);
INIT_LIST_HEAD(&call->accept_link); INIT_LIST_HEAD(&call->accept_link);
INIT_LIST_HEAD(&call->recvmsg_link); INIT_LIST_HEAD(&call->recvmsg_link);
INIT_LIST_HEAD(&call->sock_link); INIT_LIST_HEAD(&call->sock_link);
...@@ -162,7 +162,6 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp, ...@@ -162,7 +162,6 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,
init_waitqueue_head(&call->waitq); init_waitqueue_head(&call->waitq);
spin_lock_init(&call->notify_lock); spin_lock_init(&call->notify_lock);
spin_lock_init(&call->tx_lock); spin_lock_init(&call->tx_lock);
rwlock_init(&call->state_lock);
refcount_set(&call->ref, 1); refcount_set(&call->ref, 1);
call->debug_id = debug_id; call->debug_id = debug_id;
call->tx_total_len = -1; call->tx_total_len = -1;
...@@ -211,7 +210,6 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, ...@@ -211,7 +210,6 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,
now = ktime_get_real(); now = ktime_get_real();
call->acks_latest_ts = now; call->acks_latest_ts = now;
call->cong_tstamp = now; call->cong_tstamp = now;
call->state = RXRPC_CALL_CLIENT_AWAIT_CONN;
call->dest_srx = *srx; call->dest_srx = *srx;
call->interruptibility = p->interruptibility; call->interruptibility = p->interruptibility;
call->tx_total_len = p->tx_total_len; call->tx_total_len = p->tx_total_len;
...@@ -227,11 +225,13 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, ...@@ -227,11 +225,13 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,
ret = rxrpc_init_client_call_security(call); ret = rxrpc_init_client_call_security(call);
if (ret < 0) { if (ret < 0) {
__rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, 0, ret); rxrpc_prefail_call(call, RXRPC_CALL_LOCAL_ERROR, ret);
rxrpc_put_call(call, rxrpc_call_put_discard_error); rxrpc_put_call(call, rxrpc_call_put_discard_error);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_CONN);
trace_rxrpc_call(call->debug_id, refcount_read(&call->ref), trace_rxrpc_call(call->debug_id, refcount_read(&call->ref),
p->user_call_ID, rxrpc_call_new_client); p->user_call_ID, rxrpc_call_new_client);
...@@ -242,7 +242,7 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, ...@@ -242,7 +242,7 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,
/* /*
* Initiate the call ack/resend/expiry timer. * Initiate the call ack/resend/expiry timer.
*/ */
static void rxrpc_start_call_timer(struct rxrpc_call *call) void rxrpc_start_call_timer(struct rxrpc_call *call)
{ {
unsigned long now = jiffies; unsigned long now = jiffies;
unsigned long j = now + MAX_JIFFY_OFFSET; unsigned long j = now + MAX_JIFFY_OFFSET;
...@@ -286,6 +286,39 @@ static void rxrpc_put_call_slot(struct rxrpc_call *call) ...@@ -286,6 +286,39 @@ static void rxrpc_put_call_slot(struct rxrpc_call *call)
up(limiter); up(limiter);
} }
/*
* Start the process of connecting a call. We obtain a peer and a connection
* bundle, but the actual association of a call with a connection is offloaded
* to the I/O thread to simplify locking.
*/
static int rxrpc_connect_call(struct rxrpc_call *call, gfp_t gfp)
{
struct rxrpc_local *local = call->local;
int ret = 0;
_enter("{%d,%lx},", call->debug_id, call->user_call_ID);
call->peer = rxrpc_lookup_peer(local, &call->dest_srx, gfp);
if (!call->peer)
goto error;
ret = rxrpc_look_up_bundle(call, gfp);
if (ret < 0)
goto error;
trace_rxrpc_client(NULL, -1, rxrpc_client_queue_new_call);
rxrpc_get_call(call, rxrpc_call_get_io_thread);
spin_lock(&local->client_call_lock);
list_add_tail(&call->wait_link, &local->new_client_calls);
spin_unlock(&local->client_call_lock);
rxrpc_wake_up_io_thread(local);
return 0;
error:
__set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
return ret;
}
/* /*
* Set up a call for the given parameters. * Set up a call for the given parameters.
* - Called with the socket lock held, which it must release. * - Called with the socket lock held, which it must release.
...@@ -365,14 +398,10 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, ...@@ -365,14 +398,10 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
/* Set up or get a connection record and set the protocol parameters, /* Set up or get a connection record and set the protocol parameters,
* including channel number and call ID. * including channel number and call ID.
*/ */
ret = rxrpc_connect_call(rx, call, cp, srx, gfp); ret = rxrpc_connect_call(call, gfp);
if (ret < 0) if (ret < 0)
goto error_attached_to_socket; goto error_attached_to_socket;
rxrpc_see_call(call, rxrpc_call_see_connected);
rxrpc_start_call_timer(call);
_leave(" = %p [new]", call); _leave(" = %p [new]", call);
return call; return call;
...@@ -384,27 +413,23 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, ...@@ -384,27 +413,23 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
error_dup_user_ID: error_dup_user_ID:
write_unlock(&rx->call_lock); write_unlock(&rx->call_lock);
release_sock(&rx->sk); release_sock(&rx->sk);
__rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, rxrpc_prefail_call(call, RXRPC_CALL_LOCAL_ERROR, -EEXIST);
RX_CALL_DEAD, -EEXIST);
trace_rxrpc_call(call->debug_id, refcount_read(&call->ref), 0, trace_rxrpc_call(call->debug_id, refcount_read(&call->ref), 0,
rxrpc_call_see_userid_exists); rxrpc_call_see_userid_exists);
rxrpc_release_call(rx, call);
mutex_unlock(&call->user_mutex); mutex_unlock(&call->user_mutex);
rxrpc_put_call(call, rxrpc_call_put_userid_exists); rxrpc_put_call(call, rxrpc_call_put_userid_exists);
_leave(" = -EEXIST"); _leave(" = -EEXIST");
return ERR_PTR(-EEXIST); return ERR_PTR(-EEXIST);
/* We got an error, but the call is attached to the socket and is in /* We got an error, but the call is attached to the socket and is in
* need of release. However, we might now race with recvmsg() when * need of release. However, we might now race with recvmsg() when it
* completing the call queues it. Return 0 from sys_sendmsg() and * completion notifies the socket. Return 0 from sys_sendmsg() and
* leave the error to recvmsg() to deal with. * leave the error to recvmsg() to deal with.
*/ */
error_attached_to_socket: error_attached_to_socket:
trace_rxrpc_call(call->debug_id, refcount_read(&call->ref), ret, trace_rxrpc_call(call->debug_id, refcount_read(&call->ref), ret,
rxrpc_call_see_connect_failed); rxrpc_call_see_connect_failed);
set_bit(RXRPC_CALL_DISCONNECTED, &call->flags); rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, 0, ret);
__rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR,
RX_CALL_DEAD, ret);
_leave(" = c=%08x [err]", call->debug_id); _leave(" = c=%08x [err]", call->debug_id);
return call; return call;
} }
...@@ -427,32 +452,32 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx, ...@@ -427,32 +452,32 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx,
call->call_id = sp->hdr.callNumber; call->call_id = sp->hdr.callNumber;
call->dest_srx.srx_service = sp->hdr.serviceId; call->dest_srx.srx_service = sp->hdr.serviceId;
call->cid = sp->hdr.cid; call->cid = sp->hdr.cid;
call->state = RXRPC_CALL_SERVER_SECURING;
call->cong_tstamp = skb->tstamp; call->cong_tstamp = skb->tstamp;
__set_bit(RXRPC_CALL_EXPOSED, &call->flags);
rxrpc_set_call_state(call, RXRPC_CALL_SERVER_SECURING);
spin_lock(&conn->state_lock); spin_lock(&conn->state_lock);
switch (conn->state) { switch (conn->state) {
case RXRPC_CONN_SERVICE_UNSECURED: case RXRPC_CONN_SERVICE_UNSECURED:
case RXRPC_CONN_SERVICE_CHALLENGING: case RXRPC_CONN_SERVICE_CHALLENGING:
call->state = RXRPC_CALL_SERVER_SECURING; rxrpc_set_call_state(call, RXRPC_CALL_SERVER_SECURING);
break; break;
case RXRPC_CONN_SERVICE: case RXRPC_CONN_SERVICE:
call->state = RXRPC_CALL_SERVER_RECV_REQUEST; rxrpc_set_call_state(call, RXRPC_CALL_SERVER_RECV_REQUEST);
break; break;
case RXRPC_CONN_REMOTELY_ABORTED: case RXRPC_CONN_ABORTED:
__rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED, rxrpc_set_call_completion(call, conn->completion,
conn->abort_code, conn->error); conn->abort_code, conn->error);
break;
case RXRPC_CONN_LOCALLY_ABORTED:
__rxrpc_abort_call("CON", call, 1,
conn->abort_code, conn->error);
break; break;
default: default:
BUG(); BUG();
} }
rxrpc_get_call(call, rxrpc_call_get_io_thread);
/* Set the channel for this call. We don't get channel_lock as we're /* Set the channel for this call. We don't get channel_lock as we're
* only defending against the data_ready handler (which we're called * only defending against the data_ready handler (which we're called
* from) and the RESPONSE packet parser (which is only really * from) and the RESPONSE packet parser (which is only really
...@@ -462,7 +487,7 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx, ...@@ -462,7 +487,7 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx,
chan = sp->hdr.cid & RXRPC_CHANNELMASK; chan = sp->hdr.cid & RXRPC_CHANNELMASK;
conn->channels[chan].call_counter = call->call_id; conn->channels[chan].call_counter = call->call_id;
conn->channels[chan].call_id = call->call_id; conn->channels[chan].call_id = call->call_id;
rcu_assign_pointer(conn->channels[chan].call, call); conn->channels[chan].call = call;
spin_unlock(&conn->state_lock); spin_unlock(&conn->state_lock);
spin_lock(&conn->peer->lock); spin_lock(&conn->peer->lock);
...@@ -522,20 +547,17 @@ static void rxrpc_cleanup_ring(struct rxrpc_call *call) ...@@ -522,20 +547,17 @@ static void rxrpc_cleanup_ring(struct rxrpc_call *call)
void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
{ {
struct rxrpc_connection *conn = call->conn; struct rxrpc_connection *conn = call->conn;
bool put = false; bool put = false, putu = false;
_enter("{%d,%d}", call->debug_id, refcount_read(&call->ref)); _enter("{%d,%d}", call->debug_id, refcount_read(&call->ref));
trace_rxrpc_call(call->debug_id, refcount_read(&call->ref), trace_rxrpc_call(call->debug_id, refcount_read(&call->ref),
call->flags, rxrpc_call_see_release); call->flags, rxrpc_call_see_release);
ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
if (test_and_set_bit(RXRPC_CALL_RELEASED, &call->flags)) if (test_and_set_bit(RXRPC_CALL_RELEASED, &call->flags))
BUG(); BUG();
rxrpc_put_call_slot(call); rxrpc_put_call_slot(call);
del_timer_sync(&call->timer);
/* Make sure we don't get any more notifications */ /* Make sure we don't get any more notifications */
write_lock(&rx->recvmsg_lock); write_lock(&rx->recvmsg_lock);
...@@ -560,7 +582,7 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) ...@@ -560,7 +582,7 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
if (test_and_clear_bit(RXRPC_CALL_HAS_USERID, &call->flags)) { if (test_and_clear_bit(RXRPC_CALL_HAS_USERID, &call->flags)) {
rb_erase(&call->sock_node, &rx->calls); rb_erase(&call->sock_node, &rx->calls);
memset(&call->sock_node, 0xdd, sizeof(call->sock_node)); memset(&call->sock_node, 0xdd, sizeof(call->sock_node));
rxrpc_put_call(call, rxrpc_call_put_userid_exists); putu = true;
} }
list_del(&call->sock_link); list_del(&call->sock_link);
...@@ -568,10 +590,9 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) ...@@ -568,10 +590,9 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
_debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, conn); _debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, conn);
if (conn && !test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) if (putu)
rxrpc_disconnect_call(call); rxrpc_put_call(call, rxrpc_call_put_userid);
if (call->security)
call->security->free_call_crypto(call);
_leave(""); _leave("");
} }
...@@ -588,7 +609,8 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx) ...@@ -588,7 +609,8 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
call = list_entry(rx->to_be_accepted.next, call = list_entry(rx->to_be_accepted.next,
struct rxrpc_call, accept_link); struct rxrpc_call, accept_link);
list_del(&call->accept_link); list_del(&call->accept_link);
rxrpc_abort_call("SKR", call, 0, RX_CALL_DEAD, -ECONNRESET); rxrpc_propose_abort(call, RX_CALL_DEAD, -ECONNRESET,
rxrpc_abort_call_sock_release_tba);
rxrpc_put_call(call, rxrpc_call_put_release_sock_tba); rxrpc_put_call(call, rxrpc_call_put_release_sock_tba);
} }
...@@ -596,8 +618,8 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx) ...@@ -596,8 +618,8 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
call = list_entry(rx->sock_calls.next, call = list_entry(rx->sock_calls.next,
struct rxrpc_call, sock_link); struct rxrpc_call, sock_link);
rxrpc_get_call(call, rxrpc_call_get_release_sock); rxrpc_get_call(call, rxrpc_call_get_release_sock);
rxrpc_abort_call("SKT", call, 0, RX_CALL_DEAD, -ECONNRESET); rxrpc_propose_abort(call, RX_CALL_DEAD, -ECONNRESET,
rxrpc_send_abort_packet(call); rxrpc_abort_call_sock_release);
rxrpc_release_call(rx, call); rxrpc_release_call(rx, call);
rxrpc_put_call(call, rxrpc_call_put_release_sock); rxrpc_put_call(call, rxrpc_call_put_release_sock);
} }
...@@ -620,7 +642,7 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace why) ...@@ -620,7 +642,7 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace why)
dead = __refcount_dec_and_test(&call->ref, &r); dead = __refcount_dec_and_test(&call->ref, &r);
trace_rxrpc_call(debug_id, r - 1, 0, why); trace_rxrpc_call(debug_id, r - 1, 0, why);
if (dead) { if (dead) {
ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); ASSERTCMP(__rxrpc_call_state(call), ==, RXRPC_CALL_COMPLETE);
if (!list_empty(&call->link)) { if (!list_empty(&call->link)) {
spin_lock(&rxnet->call_lock); spin_lock(&rxnet->call_lock);
...@@ -669,6 +691,8 @@ static void rxrpc_destroy_call(struct work_struct *work) ...@@ -669,6 +691,8 @@ static void rxrpc_destroy_call(struct work_struct *work)
rxrpc_put_txbuf(call->tx_pending, rxrpc_txbuf_put_cleaned); rxrpc_put_txbuf(call->tx_pending, rxrpc_txbuf_put_cleaned);
rxrpc_put_connection(call->conn, rxrpc_conn_put_call); rxrpc_put_connection(call->conn, rxrpc_conn_put_call);
rxrpc_deactivate_bundle(call->bundle);
rxrpc_put_bundle(call->bundle, rxrpc_bundle_put_call);
rxrpc_put_peer(call->peer, rxrpc_peer_put_call); rxrpc_put_peer(call->peer, rxrpc_peer_put_call);
rxrpc_put_local(call->local, rxrpc_local_put_call); rxrpc_put_local(call->local, rxrpc_local_put_call);
call_rcu(&call->rcu, rxrpc_rcu_free_call); call_rcu(&call->rcu, rxrpc_rcu_free_call);
...@@ -681,7 +705,7 @@ void rxrpc_cleanup_call(struct rxrpc_call *call) ...@@ -681,7 +705,7 @@ void rxrpc_cleanup_call(struct rxrpc_call *call)
{ {
memset(&call->sock_node, 0xcd, sizeof(call->sock_node)); memset(&call->sock_node, 0xcd, sizeof(call->sock_node));
ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); ASSERTCMP(__rxrpc_call_state(call), ==, RXRPC_CALL_COMPLETE);
ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags)); ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags));
del_timer(&call->timer); del_timer(&call->timer);
...@@ -719,7 +743,7 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet) ...@@ -719,7 +743,7 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n", pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n",
call, refcount_read(&call->ref), call, refcount_read(&call->ref),
rxrpc_call_states[call->state], rxrpc_call_states[__rxrpc_call_state(call)],
call->flags, call->events); call->flags, call->events);
spin_unlock(&rxnet->call_lock); spin_unlock(&rxnet->call_lock);
......
// SPDX-License-Identifier: GPL-2.0-or-later
/* Call state changing functions.
*
* Copyright (C) 2022 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*/
#include "ar-internal.h"
/*
* Transition a call to the complete state.
*/
bool rxrpc_set_call_completion(struct rxrpc_call *call,
enum rxrpc_call_completion compl,
u32 abort_code,
int error)
{
if (__rxrpc_call_state(call) == RXRPC_CALL_COMPLETE)
return false;
call->abort_code = abort_code;
call->error = error;
call->completion = compl;
/* Allow reader of completion state to operate locklessly */
rxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);
trace_rxrpc_call_complete(call);
wake_up(&call->waitq);
rxrpc_notify_socket(call);
return true;
}
/*
* Record that a call successfully completed.
*/
bool rxrpc_call_completed(struct rxrpc_call *call)
{
return rxrpc_set_call_completion(call, RXRPC_CALL_SUCCEEDED, 0, 0);
}
/*
* Record that a call is locally aborted.
*/
bool rxrpc_abort_call(struct rxrpc_call *call, rxrpc_seq_t seq,
u32 abort_code, int error, enum rxrpc_abort_reason why)
{
trace_rxrpc_abort(call->debug_id, why, call->cid, call->call_id, seq,
abort_code, error);
if (!rxrpc_set_call_completion(call, RXRPC_CALL_LOCALLY_ABORTED,
abort_code, error))
return false;
if (test_bit(RXRPC_CALL_EXPOSED, &call->flags))
rxrpc_send_abort_packet(call);
return true;
}
/*
* Record that a call errored out before even getting off the ground, thereby
* setting the state to allow it to be destroyed.
*/
void rxrpc_prefail_call(struct rxrpc_call *call, enum rxrpc_call_completion compl,
int error)
{
call->abort_code = RX_CALL_DEAD;
call->error = error;
call->completion = compl;
call->_state = RXRPC_CALL_COMPLETE;
trace_rxrpc_call_complete(call);
WARN_ON_ONCE(__test_and_set_bit(RXRPC_CALL_RELEASED, &call->flags));
}
此差异已折叠。
...@@ -16,12 +16,66 @@ ...@@ -16,12 +16,66 @@
#include <net/ip.h> #include <net/ip.h>
#include "ar-internal.h" #include "ar-internal.h"
/*
* Set the completion state on an aborted connection.
*/
static bool rxrpc_set_conn_aborted(struct rxrpc_connection *conn, struct sk_buff *skb,
s32 abort_code, int err,
enum rxrpc_call_completion compl)
{
bool aborted = false;
if (conn->state != RXRPC_CONN_ABORTED) {
spin_lock(&conn->state_lock);
if (conn->state != RXRPC_CONN_ABORTED) {
conn->abort_code = abort_code;
conn->error = err;
conn->completion = compl;
/* Order the abort info before the state change. */
smp_store_release(&conn->state, RXRPC_CONN_ABORTED);
set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
set_bit(RXRPC_CONN_EV_ABORT_CALLS, &conn->events);
aborted = true;
}
spin_unlock(&conn->state_lock);
}
return aborted;
}
/*
* Mark a socket buffer to indicate that the connection it's on should be aborted.
*/
int rxrpc_abort_conn(struct rxrpc_connection *conn, struct sk_buff *skb,
s32 abort_code, int err, enum rxrpc_abort_reason why)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
if (rxrpc_set_conn_aborted(conn, skb, abort_code, err,
RXRPC_CALL_LOCALLY_ABORTED)) {
trace_rxrpc_abort(0, why, sp->hdr.cid, sp->hdr.callNumber,
sp->hdr.seq, abort_code, err);
rxrpc_poke_conn(conn, rxrpc_conn_get_poke_abort);
}
return -EPROTO;
}
/*
* Mark a connection as being remotely aborted.
*/
static bool rxrpc_input_conn_abort(struct rxrpc_connection *conn,
struct sk_buff *skb)
{
return rxrpc_set_conn_aborted(conn, skb, skb->priority, -ECONNABORTED,
RXRPC_CALL_REMOTELY_ABORTED);
}
/* /*
* Retransmit terminal ACK or ABORT of the previous call. * Retransmit terminal ACK or ABORT of the previous call.
*/ */
static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
struct sk_buff *skb, struct sk_buff *skb,
unsigned int channel) unsigned int channel)
{ {
struct rxrpc_skb_priv *sp = skb ? rxrpc_skb(skb) : NULL; struct rxrpc_skb_priv *sp = skb ? rxrpc_skb(skb) : NULL;
struct rxrpc_channel *chan; struct rxrpc_channel *chan;
...@@ -46,9 +100,7 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, ...@@ -46,9 +100,7 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
/* If the last call got moved on whilst we were waiting to run, just /* If the last call got moved on whilst we were waiting to run, just
* ignore this packet. * ignore this packet.
*/ */
call_id = READ_ONCE(chan->last_call); call_id = chan->last_call;
/* Sync with __rxrpc_disconnect_call() */
smp_rmb();
if (skb && call_id != sp->hdr.callNumber) if (skb && call_id != sp->hdr.callNumber)
return; return;
...@@ -65,9 +117,12 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, ...@@ -65,9 +117,12 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
iov[2].iov_base = &ack_info; iov[2].iov_base = &ack_info;
iov[2].iov_len = sizeof(ack_info); iov[2].iov_len = sizeof(ack_info);
serial = atomic_inc_return(&conn->serial);
pkt.whdr.epoch = htonl(conn->proto.epoch); pkt.whdr.epoch = htonl(conn->proto.epoch);
pkt.whdr.cid = htonl(conn->proto.cid | channel); pkt.whdr.cid = htonl(conn->proto.cid | channel);
pkt.whdr.callNumber = htonl(call_id); pkt.whdr.callNumber = htonl(call_id);
pkt.whdr.serial = htonl(serial);
pkt.whdr.seq = 0; pkt.whdr.seq = 0;
pkt.whdr.type = chan->last_type; pkt.whdr.type = chan->last_type;
pkt.whdr.flags = conn->out_clientflag; pkt.whdr.flags = conn->out_clientflag;
...@@ -104,31 +159,15 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, ...@@ -104,31 +159,15 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
iov[0].iov_len += sizeof(pkt.ack); iov[0].iov_len += sizeof(pkt.ack);
len += sizeof(pkt.ack) + 3 + sizeof(ack_info); len += sizeof(pkt.ack) + 3 + sizeof(ack_info);
ioc = 3; ioc = 3;
break;
default:
return;
}
/* Resync with __rxrpc_disconnect_call() and check that the last call
* didn't get advanced whilst we were filling out the packets.
*/
smp_rmb();
if (READ_ONCE(chan->last_call) != call_id)
return;
serial = atomic_inc_return(&conn->serial);
pkt.whdr.serial = htonl(serial);
switch (chan->last_type) {
case RXRPC_PACKET_TYPE_ABORT:
break;
case RXRPC_PACKET_TYPE_ACK:
trace_rxrpc_tx_ack(chan->call_debug_id, serial, trace_rxrpc_tx_ack(chan->call_debug_id, serial,
ntohl(pkt.ack.firstPacket), ntohl(pkt.ack.firstPacket),
ntohl(pkt.ack.serial), ntohl(pkt.ack.serial),
pkt.ack.reason, 0); pkt.ack.reason, 0);
break; break;
default:
return;
} }
ret = kernel_sendmsg(conn->local->socket, &msg, iov, ioc, len); ret = kernel_sendmsg(conn->local->socket, &msg, iov, ioc, len);
...@@ -146,131 +185,34 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, ...@@ -146,131 +185,34 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
/* /*
* pass a connection-level abort onto all calls on that connection * pass a connection-level abort onto all calls on that connection
*/ */
static void rxrpc_abort_calls(struct rxrpc_connection *conn, static void rxrpc_abort_calls(struct rxrpc_connection *conn)
enum rxrpc_call_completion compl,
rxrpc_serial_t serial)
{ {
struct rxrpc_call *call; struct rxrpc_call *call;
int i; int i;
_enter("{%d},%x", conn->debug_id, conn->abort_code); _enter("{%d},%x", conn->debug_id, conn->abort_code);
spin_lock(&conn->bundle->channel_lock);
for (i = 0; i < RXRPC_MAXCALLS; i++) { for (i = 0; i < RXRPC_MAXCALLS; i++) {
call = rcu_dereference_protected( call = conn->channels[i].call;
conn->channels[i].call, if (call)
lockdep_is_held(&conn->bundle->channel_lock)); rxrpc_set_call_completion(call,
if (call) { conn->completion,
if (compl == RXRPC_CALL_LOCALLY_ABORTED)
trace_rxrpc_abort(call->debug_id,
"CON", call->cid,
call->call_id, 0,
conn->abort_code, conn->abort_code,
conn->error); conn->error);
else
trace_rxrpc_rx_abort(call, serial,
conn->abort_code);
rxrpc_set_call_completion(call, compl,
conn->abort_code,
conn->error);
}
} }
spin_unlock(&conn->bundle->channel_lock);
_leave(""); _leave("");
} }
/*
* generate a connection-level abort
*/
static int rxrpc_abort_connection(struct rxrpc_connection *conn,
int error, u32 abort_code)
{
struct rxrpc_wire_header whdr;
struct msghdr msg;
struct kvec iov[2];
__be32 word;
size_t len;
u32 serial;
int ret;
_enter("%d,,%u,%u", conn->debug_id, error, abort_code);
/* generate a connection-level abort */
spin_lock(&conn->state_lock);
if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
spin_unlock(&conn->state_lock);
_leave(" = 0 [already dead]");
return 0;
}
conn->error = error;
conn->abort_code = abort_code;
conn->state = RXRPC_CONN_LOCALLY_ABORTED;
set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
spin_unlock(&conn->state_lock);
msg.msg_name = &conn->peer->srx.transport;
msg.msg_namelen = conn->peer->srx.transport_len;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
whdr.epoch = htonl(conn->proto.epoch);
whdr.cid = htonl(conn->proto.cid);
whdr.callNumber = 0;
whdr.seq = 0;
whdr.type = RXRPC_PACKET_TYPE_ABORT;
whdr.flags = conn->out_clientflag;
whdr.userStatus = 0;
whdr.securityIndex = conn->security_ix;
whdr._rsvd = 0;
whdr.serviceId = htons(conn->service_id);
word = htonl(conn->abort_code);
iov[0].iov_base = &whdr;
iov[0].iov_len = sizeof(whdr);
iov[1].iov_base = &word;
iov[1].iov_len = sizeof(word);
len = iov[0].iov_len + iov[1].iov_len;
serial = atomic_inc_return(&conn->serial);
rxrpc_abort_calls(conn, RXRPC_CALL_LOCALLY_ABORTED, serial);
whdr.serial = htonl(serial);
ret = kernel_sendmsg(conn->local->socket, &msg, iov, 2, len);
if (ret < 0) {
trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
rxrpc_tx_point_conn_abort);
_debug("sendmsg failed: %d", ret);
return -EAGAIN;
}
trace_rxrpc_tx_packet(conn->debug_id, &whdr, rxrpc_tx_point_conn_abort);
conn->peer->last_tx_at = ktime_get_seconds();
_leave(" = 0");
return 0;
}
/* /*
* mark a call as being on a now-secured channel * mark a call as being on a now-secured channel
* - must be called with BH's disabled. * - must be called with BH's disabled.
*/ */
static void rxrpc_call_is_secure(struct rxrpc_call *call) static void rxrpc_call_is_secure(struct rxrpc_call *call)
{ {
_enter("%p", call); if (call && __rxrpc_call_state(call) == RXRPC_CALL_SERVER_SECURING) {
if (call) { rxrpc_set_call_state(call, RXRPC_CALL_SERVER_RECV_REQUEST);
write_lock(&call->state_lock); rxrpc_notify_socket(call);
if (call->state == RXRPC_CALL_SERVER_SECURING) {
call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
rxrpc_notify_socket(call);
}
write_unlock(&call->state_lock);
} }
} }
...@@ -278,44 +220,22 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call) ...@@ -278,44 +220,22 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
* connection-level Rx packet processor * connection-level Rx packet processor
*/ */
static int rxrpc_process_event(struct rxrpc_connection *conn, static int rxrpc_process_event(struct rxrpc_connection *conn,
struct sk_buff *skb, struct sk_buff *skb)
u32 *_abort_code)
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
int loop, ret; int ret;
if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) { if (conn->state == RXRPC_CONN_ABORTED)
_leave(" = -ECONNABORTED [%u]", conn->state);
return -ECONNABORTED; return -ECONNABORTED;
}
_enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial); _enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial);
switch (sp->hdr.type) { switch (sp->hdr.type) {
case RXRPC_PACKET_TYPE_DATA:
case RXRPC_PACKET_TYPE_ACK:
rxrpc_conn_retransmit_call(conn, skb,
sp->hdr.cid & RXRPC_CHANNELMASK);
return 0;
case RXRPC_PACKET_TYPE_BUSY:
/* Just ignore BUSY packets for now. */
return 0;
case RXRPC_PACKET_TYPE_ABORT:
conn->error = -ECONNABORTED;
conn->abort_code = skb->priority;
conn->state = RXRPC_CONN_REMOTELY_ABORTED;
set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED, sp->hdr.serial);
return -ECONNABORTED;
case RXRPC_PACKET_TYPE_CHALLENGE: case RXRPC_PACKET_TYPE_CHALLENGE:
return conn->security->respond_to_challenge(conn, skb, return conn->security->respond_to_challenge(conn, skb);
_abort_code);
case RXRPC_PACKET_TYPE_RESPONSE: case RXRPC_PACKET_TYPE_RESPONSE:
ret = conn->security->verify_response(conn, skb, _abort_code); ret = conn->security->verify_response(conn, skb);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -324,27 +244,25 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, ...@@ -324,27 +244,25 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
if (ret < 0) if (ret < 0)
return ret; return ret;
spin_lock(&conn->bundle->channel_lock);
spin_lock(&conn->state_lock); spin_lock(&conn->state_lock);
if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING)
if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
conn->state = RXRPC_CONN_SERVICE; conn->state = RXRPC_CONN_SERVICE;
spin_unlock(&conn->state_lock); spin_unlock(&conn->state_lock);
for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
rxrpc_call_is_secure(
rcu_dereference_protected(
conn->channels[loop].call,
lockdep_is_held(&conn->bundle->channel_lock)));
} else {
spin_unlock(&conn->state_lock);
}
spin_unlock(&conn->bundle->channel_lock); if (conn->state == RXRPC_CONN_SERVICE) {
/* Offload call state flipping to the I/O thread. As
* we've already received the packet, put it on the
* front of the queue.
*/
skb->mark = RXRPC_SKB_MARK_SERVICE_CONN_SECURED;
rxrpc_get_skb(skb, rxrpc_skb_get_conn_secured);
skb_queue_head(&conn->local->rx_queue, skb);
rxrpc_wake_up_io_thread(conn->local);
}
return 0; return 0;
default: default:
trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, WARN_ON_ONCE(1);
tracepoint_string("bad_conn_pkt"));
return -EPROTO; return -EPROTO;
} }
} }
...@@ -354,26 +272,9 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, ...@@ -354,26 +272,9 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
*/ */
static void rxrpc_secure_connection(struct rxrpc_connection *conn) static void rxrpc_secure_connection(struct rxrpc_connection *conn)
{ {
u32 abort_code; if (conn->security->issue_challenge(conn) < 0)
int ret; rxrpc_abort_conn(conn, NULL, RX_CALL_DEAD, -ENOMEM,
rxrpc_abort_nomem);
_enter("{%d}", conn->debug_id);
ASSERT(conn->security_ix != 0);
if (conn->security->issue_challenge(conn) < 0) {
abort_code = RX_CALL_DEAD;
ret = -ENOMEM;
goto abort;
}
_leave("");
return;
abort:
_debug("abort %d, %d", ret, abort_code);
rxrpc_abort_connection(conn, ret, abort_code);
_leave(" [aborted]");
} }
/* /*
...@@ -395,9 +296,7 @@ void rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn, bool force) ...@@ -395,9 +296,7 @@ void rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn, bool force)
if (!test_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags)) if (!test_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags))
continue; continue;
smp_rmb(); /* vs rxrpc_disconnect_client_call */ ack_at = chan->final_ack_at;
ack_at = READ_ONCE(chan->final_ack_at);
if (time_before(j, ack_at) && !force) { if (time_before(j, ack_at) && !force) {
if (time_before(ack_at, next_j)) { if (time_before(ack_at, next_j)) {
next_j = ack_at; next_j = ack_at;
...@@ -424,47 +323,27 @@ void rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn, bool force) ...@@ -424,47 +323,27 @@ void rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn, bool force)
static void rxrpc_do_process_connection(struct rxrpc_connection *conn) static void rxrpc_do_process_connection(struct rxrpc_connection *conn)
{ {
struct sk_buff *skb; struct sk_buff *skb;
u32 abort_code = RX_PROTOCOL_ERROR;
int ret; int ret;
if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events)) if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events))
rxrpc_secure_connection(conn); rxrpc_secure_connection(conn);
/* Process delayed ACKs whose time has come. */
if (conn->flags & RXRPC_CONN_FINAL_ACK_MASK)
rxrpc_process_delayed_final_acks(conn, false);
/* go through the conn-level event packets, releasing the ref on this /* go through the conn-level event packets, releasing the ref on this
* connection that each one has when we've finished with it */ * connection that each one has when we've finished with it */
while ((skb = skb_dequeue(&conn->rx_queue))) { while ((skb = skb_dequeue(&conn->rx_queue))) {
rxrpc_see_skb(skb, rxrpc_skb_see_conn_work); rxrpc_see_skb(skb, rxrpc_skb_see_conn_work);
ret = rxrpc_process_event(conn, skb, &abort_code); ret = rxrpc_process_event(conn, skb);
switch (ret) { switch (ret) {
case -EPROTO:
case -EKEYEXPIRED:
case -EKEYREJECTED:
goto protocol_error;
case -ENOMEM: case -ENOMEM:
case -EAGAIN: case -EAGAIN:
goto requeue_and_leave; skb_queue_head(&conn->rx_queue, skb);
case -ECONNABORTED: rxrpc_queue_conn(conn, rxrpc_conn_queue_retry_work);
break;
default: default:
rxrpc_free_skb(skb, rxrpc_skb_put_conn_work); rxrpc_free_skb(skb, rxrpc_skb_put_conn_work);
break; break;
} }
} }
return;
requeue_and_leave:
skb_queue_head(&conn->rx_queue, skb);
return;
protocol_error:
if (rxrpc_abort_connection(conn, ret, abort_code) < 0)
goto requeue_and_leave;
rxrpc_free_skb(skb, rxrpc_skb_put_conn_work);
return;
} }
void rxrpc_process_connection(struct work_struct *work) void rxrpc_process_connection(struct work_struct *work)
...@@ -498,44 +377,59 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn, ...@@ -498,44 +377,59 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
/* /*
* Input a connection-level packet. * Input a connection-level packet.
*/ */
int rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb) bool rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
_leave(" = -ECONNABORTED [%u]", conn->state);
return -ECONNABORTED;
}
_enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial);
switch (sp->hdr.type) { switch (sp->hdr.type) {
case RXRPC_PACKET_TYPE_DATA:
case RXRPC_PACKET_TYPE_ACK:
rxrpc_conn_retransmit_call(conn, skb,
sp->hdr.cid & RXRPC_CHANNELMASK);
return 0;
case RXRPC_PACKET_TYPE_BUSY: case RXRPC_PACKET_TYPE_BUSY:
/* Just ignore BUSY packets for now. */ /* Just ignore BUSY packets for now. */
return 0; return true;
case RXRPC_PACKET_TYPE_ABORT: case RXRPC_PACKET_TYPE_ABORT:
conn->error = -ECONNABORTED; if (rxrpc_is_conn_aborted(conn))
conn->abort_code = skb->priority; return true;
conn->state = RXRPC_CONN_REMOTELY_ABORTED; rxrpc_input_conn_abort(conn, skb);
set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags); rxrpc_abort_calls(conn);
rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED, sp->hdr.serial); return true;
return -ECONNABORTED;
case RXRPC_PACKET_TYPE_CHALLENGE: case RXRPC_PACKET_TYPE_CHALLENGE:
case RXRPC_PACKET_TYPE_RESPONSE: case RXRPC_PACKET_TYPE_RESPONSE:
if (rxrpc_is_conn_aborted(conn)) {
if (conn->completion == RXRPC_CALL_LOCALLY_ABORTED)
rxrpc_send_conn_abort(conn);
return true;
}
rxrpc_post_packet_to_conn(conn, skb); rxrpc_post_packet_to_conn(conn, skb);
return 0; return true;
default: default:
trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, WARN_ON_ONCE(1);
tracepoint_string("bad_conn_pkt")); return true;
return -EPROTO;
} }
} }
/*
* Input a connection event.
*/
void rxrpc_input_conn_event(struct rxrpc_connection *conn, struct sk_buff *skb)
{
unsigned int loop;
if (test_and_clear_bit(RXRPC_CONN_EV_ABORT_CALLS, &conn->events))
rxrpc_abort_calls(conn);
switch (skb->mark) {
case RXRPC_SKB_MARK_SERVICE_CONN_SECURED:
if (conn->state != RXRPC_CONN_SERVICE)
break;
for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
rxrpc_call_is_secure(conn->channels[loop].call);
break;
}
/* Process delayed ACKs whose time has come. */
if (conn->flags & RXRPC_CONN_FINAL_ACK_MASK)
rxrpc_process_delayed_final_acks(conn, false);
}
...@@ -23,12 +23,30 @@ static void rxrpc_clean_up_connection(struct work_struct *work); ...@@ -23,12 +23,30 @@ static void rxrpc_clean_up_connection(struct work_struct *work);
static void rxrpc_set_service_reap_timer(struct rxrpc_net *rxnet, static void rxrpc_set_service_reap_timer(struct rxrpc_net *rxnet,
unsigned long reap_at); unsigned long reap_at);
void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
{
struct rxrpc_local *local = conn->local;
bool busy;
if (WARN_ON_ONCE(!local))
return;
spin_lock_bh(&local->lock);
busy = !list_empty(&conn->attend_link);
if (!busy) {
rxrpc_get_connection(conn, why);
list_add_tail(&conn->attend_link, &local->conn_attend_q);
}
spin_unlock_bh(&local->lock);
rxrpc_wake_up_io_thread(local);
}
static void rxrpc_connection_timer(struct timer_list *timer) static void rxrpc_connection_timer(struct timer_list *timer)
{ {
struct rxrpc_connection *conn = struct rxrpc_connection *conn =
container_of(timer, struct rxrpc_connection, timer); container_of(timer, struct rxrpc_connection, timer);
rxrpc_queue_conn(conn, rxrpc_conn_queue_timer); rxrpc_poke_conn(conn, rxrpc_conn_get_poke_timer);
} }
/* /*
...@@ -49,6 +67,7 @@ struct rxrpc_connection *rxrpc_alloc_connection(struct rxrpc_net *rxnet, ...@@ -49,6 +67,7 @@ struct rxrpc_connection *rxrpc_alloc_connection(struct rxrpc_net *rxnet,
INIT_WORK(&conn->destructor, rxrpc_clean_up_connection); INIT_WORK(&conn->destructor, rxrpc_clean_up_connection);
INIT_LIST_HEAD(&conn->proc_link); INIT_LIST_HEAD(&conn->proc_link);
INIT_LIST_HEAD(&conn->link); INIT_LIST_HEAD(&conn->link);
mutex_init(&conn->security_lock);
skb_queue_head_init(&conn->rx_queue); skb_queue_head_init(&conn->rx_queue);
conn->rxnet = rxnet; conn->rxnet = rxnet;
conn->security = &rxrpc_no_security; conn->security = &rxrpc_no_security;
...@@ -82,10 +101,10 @@ struct rxrpc_connection *rxrpc_find_client_connection_rcu(struct rxrpc_local *lo ...@@ -82,10 +101,10 @@ struct rxrpc_connection *rxrpc_find_client_connection_rcu(struct rxrpc_local *lo
_enter(",%x", sp->hdr.cid & RXRPC_CIDMASK); _enter(",%x", sp->hdr.cid & RXRPC_CIDMASK);
/* Look up client connections by connection ID alone as their IDs are /* Look up client connections by connection ID alone as their
* unique for this machine. * IDs are unique for this machine.
*/ */
conn = idr_find(&rxrpc_client_conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT); conn = idr_find(&local->conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT);
if (!conn || refcount_read(&conn->ref) == 0) { if (!conn || refcount_read(&conn->ref) == 0) {
_debug("no conn"); _debug("no conn");
goto not_found; goto not_found;
...@@ -139,7 +158,7 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn, ...@@ -139,7 +158,7 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn,
_enter("%d,%x", conn->debug_id, call->cid); _enter("%d,%x", conn->debug_id, call->cid);
if (rcu_access_pointer(chan->call) == call) { if (chan->call == call) {
/* Save the result of the call so that we can repeat it if necessary /* Save the result of the call so that we can repeat it if necessary
* through the channel, whilst disposing of the actual call record. * through the channel, whilst disposing of the actual call record.
*/ */
...@@ -159,12 +178,9 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn, ...@@ -159,12 +178,9 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn,
break; break;
} }
/* Sync with rxrpc_conn_retransmit(). */
smp_wmb();
chan->last_call = chan->call_id; chan->last_call = chan->call_id;
chan->call_id = chan->call_counter; chan->call_id = chan->call_counter;
chan->call = NULL;
rcu_assign_pointer(chan->call, NULL);
} }
_leave(""); _leave("");
...@@ -178,6 +194,9 @@ void rxrpc_disconnect_call(struct rxrpc_call *call) ...@@ -178,6 +194,9 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
{ {
struct rxrpc_connection *conn = call->conn; struct rxrpc_connection *conn = call->conn;
set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
rxrpc_see_call(call, rxrpc_call_see_disconnected);
call->peer->cong_ssthresh = call->cong_ssthresh; call->peer->cong_ssthresh = call->cong_ssthresh;
if (!hlist_unhashed(&call->error_link)) { if (!hlist_unhashed(&call->error_link)) {
...@@ -186,18 +205,17 @@ void rxrpc_disconnect_call(struct rxrpc_call *call) ...@@ -186,18 +205,17 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
spin_unlock(&call->peer->lock); spin_unlock(&call->peer->lock);
} }
if (rxrpc_is_client_call(call)) if (rxrpc_is_client_call(call)) {
return rxrpc_disconnect_client_call(conn->bundle, call); rxrpc_disconnect_client_call(call->bundle, call);
} else {
spin_lock(&conn->bundle->channel_lock); __rxrpc_disconnect_call(conn, call);
__rxrpc_disconnect_call(conn, call); conn->idle_timestamp = jiffies;
spin_unlock(&conn->bundle->channel_lock); if (atomic_dec_and_test(&conn->active))
rxrpc_set_service_reap_timer(conn->rxnet,
jiffies + rxrpc_connection_expiry);
}
set_bit(RXRPC_CALL_DISCONNECTED, &call->flags); rxrpc_put_call(call, rxrpc_call_put_io_thread);
conn->idle_timestamp = jiffies;
if (atomic_dec_and_test(&conn->active))
rxrpc_set_service_reap_timer(conn->rxnet,
jiffies + rxrpc_connection_expiry);
} }
/* /*
...@@ -293,10 +311,10 @@ static void rxrpc_clean_up_connection(struct work_struct *work) ...@@ -293,10 +311,10 @@ static void rxrpc_clean_up_connection(struct work_struct *work)
container_of(work, struct rxrpc_connection, destructor); container_of(work, struct rxrpc_connection, destructor);
struct rxrpc_net *rxnet = conn->rxnet; struct rxrpc_net *rxnet = conn->rxnet;
ASSERT(!rcu_access_pointer(conn->channels[0].call) && ASSERT(!conn->channels[0].call &&
!rcu_access_pointer(conn->channels[1].call) && !conn->channels[1].call &&
!rcu_access_pointer(conn->channels[2].call) && !conn->channels[2].call &&
!rcu_access_pointer(conn->channels[3].call)); !conn->channels[3].call);
ASSERT(list_empty(&conn->cache_link)); ASSERT(list_empty(&conn->cache_link));
del_timer_sync(&conn->timer); del_timer_sync(&conn->timer);
...@@ -447,7 +465,6 @@ void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet) ...@@ -447,7 +465,6 @@ void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet)
_enter(""); _enter("");
atomic_dec(&rxnet->nr_conns); atomic_dec(&rxnet->nr_conns);
rxrpc_destroy_all_client_connections(rxnet);
del_timer_sync(&rxnet->service_conn_reap_timer); del_timer_sync(&rxnet->service_conn_reap_timer);
rxrpc_queue_work(&rxnet->service_conn_reaper); rxrpc_queue_work(&rxnet->service_conn_reaper);
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
static struct rxrpc_bundle rxrpc_service_dummy_bundle = { static struct rxrpc_bundle rxrpc_service_dummy_bundle = {
.ref = REFCOUNT_INIT(1), .ref = REFCOUNT_INIT(1),
.debug_id = UINT_MAX, .debug_id = UINT_MAX,
.channel_lock = __SPIN_LOCK_UNLOCKED(&rxrpc_service_dummy_bundle.channel_lock),
}; };
/* /*
......
...@@ -9,11 +9,10 @@ ...@@ -9,11 +9,10 @@
#include "ar-internal.h" #include "ar-internal.h"
static void rxrpc_proto_abort(const char *why, static void rxrpc_proto_abort(struct rxrpc_call *call, rxrpc_seq_t seq,
struct rxrpc_call *call, rxrpc_seq_t seq) enum rxrpc_abort_reason why)
{ {
if (rxrpc_abort_call(why, call, seq, RX_PROTOCOL_ERROR, -EBADMSG)) rxrpc_abort_call(call, seq, RX_PROTOCOL_ERROR, -EBADMSG, why);
rxrpc_send_abort_packet(call);
} }
/* /*
...@@ -185,7 +184,7 @@ void rxrpc_congestion_degrade(struct rxrpc_call *call) ...@@ -185,7 +184,7 @@ void rxrpc_congestion_degrade(struct rxrpc_call *call)
if (call->cong_mode != RXRPC_CALL_SLOW_START && if (call->cong_mode != RXRPC_CALL_SLOW_START &&
call->cong_mode != RXRPC_CALL_CONGEST_AVOIDANCE) call->cong_mode != RXRPC_CALL_CONGEST_AVOIDANCE)
return; return;
if (call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY) if (__rxrpc_call_state(call) == RXRPC_CALL_CLIENT_AWAIT_REPLY)
return; return;
rtt = ns_to_ktime(call->peer->srtt_us * (1000 / 8)); rtt = ns_to_ktime(call->peer->srtt_us * (1000 / 8));
...@@ -250,47 +249,34 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to, ...@@ -250,47 +249,34 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to,
* This occurs when we get an ACKALL packet, the first DATA packet of a reply, * This occurs when we get an ACKALL packet, the first DATA packet of a reply,
* or a final ACK packet. * or a final ACK packet.
*/ */
static bool rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun, static void rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun,
const char *abort_why) enum rxrpc_abort_reason abort_why)
{ {
unsigned int state;
ASSERT(test_bit(RXRPC_CALL_TX_LAST, &call->flags)); ASSERT(test_bit(RXRPC_CALL_TX_LAST, &call->flags));
write_lock(&call->state_lock); switch (__rxrpc_call_state(call)) {
state = call->state;
switch (state) {
case RXRPC_CALL_CLIENT_SEND_REQUEST: case RXRPC_CALL_CLIENT_SEND_REQUEST:
case RXRPC_CALL_CLIENT_AWAIT_REPLY: case RXRPC_CALL_CLIENT_AWAIT_REPLY:
if (reply_begun) if (reply_begun) {
call->state = state = RXRPC_CALL_CLIENT_RECV_REPLY; rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_RECV_REPLY);
else trace_rxrpc_txqueue(call, rxrpc_txqueue_end);
call->state = state = RXRPC_CALL_CLIENT_AWAIT_REPLY; break;
}
rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_REPLY);
trace_rxrpc_txqueue(call, rxrpc_txqueue_await_reply);
break; break;
case RXRPC_CALL_SERVER_AWAIT_ACK: case RXRPC_CALL_SERVER_AWAIT_ACK:
__rxrpc_call_completed(call); rxrpc_call_completed(call);
state = call->state; trace_rxrpc_txqueue(call, rxrpc_txqueue_end);
break; break;
default: default:
goto bad_state; kdebug("end_tx %s", rxrpc_call_states[__rxrpc_call_state(call)]);
rxrpc_proto_abort(call, call->tx_top, abort_why);
break;
} }
write_unlock(&call->state_lock);
if (state == RXRPC_CALL_CLIENT_AWAIT_REPLY)
trace_rxrpc_txqueue(call, rxrpc_txqueue_await_reply);
else
trace_rxrpc_txqueue(call, rxrpc_txqueue_end);
_leave(" = ok");
return true;
bad_state:
write_unlock(&call->state_lock);
kdebug("end_tx %s", rxrpc_call_states[call->state]);
rxrpc_proto_abort(abort_why, call, call->tx_top);
return false;
} }
/* /*
...@@ -305,18 +291,48 @@ static bool rxrpc_receiving_reply(struct rxrpc_call *call) ...@@ -305,18 +291,48 @@ static bool rxrpc_receiving_reply(struct rxrpc_call *call)
if (call->ackr_reason) { if (call->ackr_reason) {
now = jiffies; now = jiffies;
timo = now + MAX_JIFFY_OFFSET; timo = now + MAX_JIFFY_OFFSET;
WRITE_ONCE(call->resend_at, timo);
WRITE_ONCE(call->delay_ack_at, timo); WRITE_ONCE(call->delay_ack_at, timo);
trace_rxrpc_timer(call, rxrpc_timer_init_for_reply, now); trace_rxrpc_timer(call, rxrpc_timer_init_for_reply, now);
} }
if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags)) { if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags)) {
if (!rxrpc_rotate_tx_window(call, top, &summary)) { if (!rxrpc_rotate_tx_window(call, top, &summary)) {
rxrpc_proto_abort("TXL", call, top); rxrpc_proto_abort(call, top, rxrpc_eproto_early_reply);
return false; return false;
} }
} }
return rxrpc_end_tx_phase(call, true, "ETD");
rxrpc_end_tx_phase(call, true, rxrpc_eproto_unexpected_reply);
return true;
}
/*
* End the packet reception phase.
*/
static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
{
rxrpc_seq_t whigh = READ_ONCE(call->rx_highest_seq);
_enter("%d,%s", call->debug_id, rxrpc_call_states[__rxrpc_call_state(call)]);
trace_rxrpc_receive(call, rxrpc_receive_end, 0, whigh);
switch (__rxrpc_call_state(call)) {
case RXRPC_CALL_CLIENT_RECV_REPLY:
rxrpc_propose_delay_ACK(call, serial, rxrpc_propose_ack_terminal_ack);
rxrpc_call_completed(call);
break;
case RXRPC_CALL_SERVER_RECV_REQUEST:
rxrpc_set_call_state(call, RXRPC_CALL_SERVER_ACK_REQUEST);
call->expect_req_by = jiffies + MAX_JIFFY_OFFSET;
rxrpc_propose_delay_ACK(call, serial, rxrpc_propose_ack_processing_op);
break;
default:
break;
}
} }
static void rxrpc_input_update_ack_window(struct rxrpc_call *call, static void rxrpc_input_update_ack_window(struct rxrpc_call *call,
...@@ -337,8 +353,9 @@ static void rxrpc_input_queue_data(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -337,8 +353,9 @@ static void rxrpc_input_queue_data(struct rxrpc_call *call, struct sk_buff *skb,
__skb_queue_tail(&call->recvmsg_queue, skb); __skb_queue_tail(&call->recvmsg_queue, skb);
rxrpc_input_update_ack_window(call, window, wtop); rxrpc_input_update_ack_window(call, window, wtop);
trace_rxrpc_receive(call, last ? why + 1 : why, sp->hdr.serial, sp->hdr.seq); trace_rxrpc_receive(call, last ? why + 1 : why, sp->hdr.serial, sp->hdr.seq);
if (last)
rxrpc_end_rx_phase(call, sp->hdr.serial);
} }
/* /*
...@@ -366,17 +383,14 @@ static void rxrpc_input_data_one(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -366,17 +383,14 @@ static void rxrpc_input_data_one(struct rxrpc_call *call, struct sk_buff *skb,
if (last) { if (last) {
if (test_and_set_bit(RXRPC_CALL_RX_LAST, &call->flags) && if (test_and_set_bit(RXRPC_CALL_RX_LAST, &call->flags) &&
seq + 1 != wtop) { seq + 1 != wtop)
rxrpc_proto_abort("LSN", call, seq); return rxrpc_proto_abort(call, seq, rxrpc_eproto_different_last);
return;
}
} else { } else {
if (test_bit(RXRPC_CALL_RX_LAST, &call->flags) && if (test_bit(RXRPC_CALL_RX_LAST, &call->flags) &&
after_eq(seq, wtop)) { after_eq(seq, wtop)) {
pr_warn("Packet beyond last: c=%x q=%x window=%x-%x wlimit=%x\n", pr_warn("Packet beyond last: c=%x q=%x window=%x-%x wlimit=%x\n",
call->debug_id, seq, window, wtop, wlimit); call->debug_id, seq, window, wtop, wlimit);
rxrpc_proto_abort("LSA", call, seq); return rxrpc_proto_abort(call, seq, rxrpc_eproto_data_after_last);
return;
} }
} }
...@@ -550,7 +564,6 @@ static bool rxrpc_input_split_jumbo(struct rxrpc_call *call, struct sk_buff *skb ...@@ -550,7 +564,6 @@ static bool rxrpc_input_split_jumbo(struct rxrpc_call *call, struct sk_buff *skb
static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
enum rxrpc_call_state state;
rxrpc_serial_t serial = sp->hdr.serial; rxrpc_serial_t serial = sp->hdr.serial;
rxrpc_seq_t seq0 = sp->hdr.seq; rxrpc_seq_t seq0 = sp->hdr.seq;
...@@ -558,11 +571,20 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -558,11 +571,20 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
atomic64_read(&call->ackr_window), call->rx_highest_seq, atomic64_read(&call->ackr_window), call->rx_highest_seq,
skb->len, seq0); skb->len, seq0);
state = READ_ONCE(call->state); if (__rxrpc_call_is_complete(call))
if (state >= RXRPC_CALL_COMPLETE)
return; return;
if (state == RXRPC_CALL_SERVER_RECV_REQUEST) { switch (__rxrpc_call_state(call)) {
case RXRPC_CALL_CLIENT_SEND_REQUEST:
case RXRPC_CALL_CLIENT_AWAIT_REPLY:
/* Received data implicitly ACKs all of the request
* packets we sent when we're acting as a client.
*/
if (!rxrpc_receiving_reply(call))
goto out_notify;
break;
case RXRPC_CALL_SERVER_RECV_REQUEST: {
unsigned long timo = READ_ONCE(call->next_req_timo); unsigned long timo = READ_ONCE(call->next_req_timo);
unsigned long now, expect_req_by; unsigned long now, expect_req_by;
...@@ -573,18 +595,15 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -573,18 +595,15 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
rxrpc_reduce_call_timer(call, expect_req_by, now, rxrpc_reduce_call_timer(call, expect_req_by, now,
rxrpc_timer_set_for_idle); rxrpc_timer_set_for_idle);
} }
break;
} }
/* Received data implicitly ACKs all of the request packets we sent default:
* when we're acting as a client. break;
*/ }
if ((state == RXRPC_CALL_CLIENT_SEND_REQUEST ||
state == RXRPC_CALL_CLIENT_AWAIT_REPLY) &&
!rxrpc_receiving_reply(call))
goto out_notify;
if (!rxrpc_input_split_jumbo(call, skb)) { if (!rxrpc_input_split_jumbo(call, skb)) {
rxrpc_proto_abort("VLD", call, sp->hdr.seq); rxrpc_proto_abort(call, sp->hdr.seq, rxrpc_badmsg_bad_jumbo);
goto out_notify; goto out_notify;
} }
skb = NULL; skb = NULL;
...@@ -765,7 +784,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -765,7 +784,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
offset = sizeof(struct rxrpc_wire_header); offset = sizeof(struct rxrpc_wire_header);
if (skb_copy_bits(skb, offset, &ack, sizeof(ack)) < 0) if (skb_copy_bits(skb, offset, &ack, sizeof(ack)) < 0)
return rxrpc_proto_abort("XAK", call, 0); return rxrpc_proto_abort(call, 0, rxrpc_badmsg_short_ack);
offset += sizeof(ack); offset += sizeof(ack);
ack_serial = sp->hdr.serial; ack_serial = sp->hdr.serial;
...@@ -845,7 +864,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -845,7 +864,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
ioffset = offset + nr_acks + 3; ioffset = offset + nr_acks + 3;
if (skb->len >= ioffset + sizeof(info) && if (skb->len >= ioffset + sizeof(info) &&
skb_copy_bits(skb, ioffset, &info, sizeof(info)) < 0) skb_copy_bits(skb, ioffset, &info, sizeof(info)) < 0)
return rxrpc_proto_abort("XAI", call, 0); return rxrpc_proto_abort(call, 0, rxrpc_badmsg_short_ack_info);
if (nr_acks > 0) if (nr_acks > 0)
skb_condense(skb); skb_condense(skb);
...@@ -868,10 +887,10 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -868,10 +887,10 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
rxrpc_input_ackinfo(call, skb, &info); rxrpc_input_ackinfo(call, skb, &info);
if (first_soft_ack == 0) if (first_soft_ack == 0)
return rxrpc_proto_abort("AK0", call, 0); return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_zero);
/* Ignore ACKs unless we are or have just been transmitting. */ /* Ignore ACKs unless we are or have just been transmitting. */
switch (READ_ONCE(call->state)) { switch (__rxrpc_call_state(call)) {
case RXRPC_CALL_CLIENT_SEND_REQUEST: case RXRPC_CALL_CLIENT_SEND_REQUEST:
case RXRPC_CALL_CLIENT_AWAIT_REPLY: case RXRPC_CALL_CLIENT_AWAIT_REPLY:
case RXRPC_CALL_SERVER_SEND_REPLY: case RXRPC_CALL_SERVER_SEND_REPLY:
...@@ -883,20 +902,20 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -883,20 +902,20 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
if (before(hard_ack, call->acks_hard_ack) || if (before(hard_ack, call->acks_hard_ack) ||
after(hard_ack, call->tx_top)) after(hard_ack, call->tx_top))
return rxrpc_proto_abort("AKW", call, 0); return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_outside_window);
if (nr_acks > call->tx_top - hard_ack) if (nr_acks > call->tx_top - hard_ack)
return rxrpc_proto_abort("AKN", call, 0); return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_sack_overflow);
if (after(hard_ack, call->acks_hard_ack)) { if (after(hard_ack, call->acks_hard_ack)) {
if (rxrpc_rotate_tx_window(call, hard_ack, &summary)) { if (rxrpc_rotate_tx_window(call, hard_ack, &summary)) {
rxrpc_end_tx_phase(call, false, "ETA"); rxrpc_end_tx_phase(call, false, rxrpc_eproto_unexpected_ack);
return; return;
} }
} }
if (nr_acks > 0) { if (nr_acks > 0) {
if (offset > (int)skb->len - nr_acks) if (offset > (int)skb->len - nr_acks)
return rxrpc_proto_abort("XSA", call, 0); return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_short_sack);
rxrpc_input_soft_acks(call, skb->data + offset, first_soft_ack, rxrpc_input_soft_acks(call, skb->data + offset, first_soft_ack,
nr_acks, &summary); nr_acks, &summary);
} }
...@@ -918,7 +937,7 @@ static void rxrpc_input_ackall(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -918,7 +937,7 @@ static void rxrpc_input_ackall(struct rxrpc_call *call, struct sk_buff *skb)
struct rxrpc_ack_summary summary = { 0 }; struct rxrpc_ack_summary summary = { 0 };
if (rxrpc_rotate_tx_window(call, call->tx_top, &summary)) if (rxrpc_rotate_tx_window(call, call->tx_top, &summary))
rxrpc_end_tx_phase(call, false, "ETL"); rxrpc_end_tx_phase(call, false, rxrpc_eproto_unexpected_ackall);
} }
/* /*
...@@ -963,27 +982,23 @@ void rxrpc_input_call_packet(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -963,27 +982,23 @@ void rxrpc_input_call_packet(struct rxrpc_call *call, struct sk_buff *skb)
switch (sp->hdr.type) { switch (sp->hdr.type) {
case RXRPC_PACKET_TYPE_DATA: case RXRPC_PACKET_TYPE_DATA:
rxrpc_input_data(call, skb); return rxrpc_input_data(call, skb);
break;
case RXRPC_PACKET_TYPE_ACK: case RXRPC_PACKET_TYPE_ACK:
rxrpc_input_ack(call, skb); return rxrpc_input_ack(call, skb);
break;
case RXRPC_PACKET_TYPE_BUSY: case RXRPC_PACKET_TYPE_BUSY:
/* Just ignore BUSY packets from the server; the retry and /* Just ignore BUSY packets from the server; the retry and
* lifespan timers will take care of business. BUSY packets * lifespan timers will take care of business. BUSY packets
* from the client don't make sense. * from the client don't make sense.
*/ */
break; return;
case RXRPC_PACKET_TYPE_ABORT: case RXRPC_PACKET_TYPE_ABORT:
rxrpc_input_abort(call, skb); return rxrpc_input_abort(call, skb);
break;
case RXRPC_PACKET_TYPE_ACKALL: case RXRPC_PACKET_TYPE_ACKALL:
rxrpc_input_ackall(call, skb); return rxrpc_input_ackall(call, skb);
break;
default: default:
break; break;
...@@ -998,24 +1013,18 @@ void rxrpc_input_call_packet(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -998,24 +1013,18 @@ void rxrpc_input_call_packet(struct rxrpc_call *call, struct sk_buff *skb)
*/ */
void rxrpc_implicit_end_call(struct rxrpc_call *call, struct sk_buff *skb) void rxrpc_implicit_end_call(struct rxrpc_call *call, struct sk_buff *skb)
{ {
struct rxrpc_connection *conn = call->conn; switch (__rxrpc_call_state(call)) {
switch (READ_ONCE(call->state)) {
case RXRPC_CALL_SERVER_AWAIT_ACK: case RXRPC_CALL_SERVER_AWAIT_ACK:
rxrpc_call_completed(call); rxrpc_call_completed(call);
fallthrough; fallthrough;
case RXRPC_CALL_COMPLETE: case RXRPC_CALL_COMPLETE:
break; break;
default: default:
if (rxrpc_abort_call("IMP", call, 0, RX_CALL_DEAD, -ESHUTDOWN)) rxrpc_abort_call(call, 0, RX_CALL_DEAD, -ESHUTDOWN,
rxrpc_send_abort_packet(call); rxrpc_eproto_improper_term);
trace_rxrpc_improper_term(call); trace_rxrpc_improper_term(call);
break; break;
} }
rxrpc_input_call_event(call, skb); rxrpc_input_call_event(call, skb);
spin_lock(&conn->bundle->channel_lock);
__rxrpc_disconnect_call(conn, call);
spin_unlock(&conn->bundle->channel_lock);
} }
...@@ -43,25 +43,17 @@ static void none_free_call_crypto(struct rxrpc_call *call) ...@@ -43,25 +43,17 @@ static void none_free_call_crypto(struct rxrpc_call *call)
} }
static int none_respond_to_challenge(struct rxrpc_connection *conn, static int none_respond_to_challenge(struct rxrpc_connection *conn,
struct sk_buff *skb, struct sk_buff *skb)
u32 *_abort_code)
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); return rxrpc_abort_conn(conn, skb, RX_PROTOCOL_ERROR, -EPROTO,
rxrpc_eproto_rxnull_challenge);
trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
tracepoint_string("chall_none"));
return -EPROTO;
} }
static int none_verify_response(struct rxrpc_connection *conn, static int none_verify_response(struct rxrpc_connection *conn,
struct sk_buff *skb, struct sk_buff *skb)
u32 *_abort_code)
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); return rxrpc_abort_conn(conn, skb, RX_PROTOCOL_ERROR, -EPROTO,
rxrpc_eproto_rxnull_response);
trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
tracepoint_string("resp_none"));
return -EPROTO;
} }
static void none_clear(struct rxrpc_connection *conn) static void none_clear(struct rxrpc_connection *conn)
......
...@@ -66,10 +66,32 @@ void rxrpc_error_report(struct sock *sk) ...@@ -66,10 +66,32 @@ void rxrpc_error_report(struct sock *sk)
rcu_read_unlock(); rcu_read_unlock();
} }
/*
* Directly produce an abort from a packet.
*/
bool rxrpc_direct_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
s32 abort_code, int err)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
trace_rxrpc_abort(0, why, sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
abort_code, err);
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
skb->priority = abort_code;
return false;
}
static bool rxrpc_bad_message(struct sk_buff *skb, enum rxrpc_abort_reason why)
{
return rxrpc_direct_abort(skb, why, RX_PROTOCOL_ERROR, -EBADMSG);
}
#define just_discard true
/* /*
* Process event packets targeted at a local endpoint. * Process event packets targeted at a local endpoint.
*/ */
static void rxrpc_input_version(struct rxrpc_local *local, struct sk_buff *skb) static bool rxrpc_input_version(struct rxrpc_local *local, struct sk_buff *skb)
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
char v; char v;
...@@ -81,22 +103,21 @@ static void rxrpc_input_version(struct rxrpc_local *local, struct sk_buff *skb) ...@@ -81,22 +103,21 @@ static void rxrpc_input_version(struct rxrpc_local *local, struct sk_buff *skb)
if (v == 0) if (v == 0)
rxrpc_send_version_request(local, &sp->hdr, skb); rxrpc_send_version_request(local, &sp->hdr, skb);
} }
return true;
} }
/* /*
* Extract the wire header from a packet and translate the byte order. * Extract the wire header from a packet and translate the byte order.
*/ */
static noinline static bool rxrpc_extract_header(struct rxrpc_skb_priv *sp,
int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb) struct sk_buff *skb)
{ {
struct rxrpc_wire_header whdr; struct rxrpc_wire_header whdr;
/* dig out the RxRPC connection details */ /* dig out the RxRPC connection details */
if (skb_copy_bits(skb, 0, &whdr, sizeof(whdr)) < 0) { if (skb_copy_bits(skb, 0, &whdr, sizeof(whdr)) < 0)
trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, return rxrpc_bad_message(skb, rxrpc_badmsg_short_hdr);
tracepoint_string("bad_hdr"));
return -EBADMSG;
}
memset(sp, 0, sizeof(*sp)); memset(sp, 0, sizeof(*sp));
sp->hdr.epoch = ntohl(whdr.epoch); sp->hdr.epoch = ntohl(whdr.epoch);
...@@ -110,7 +131,7 @@ int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb) ...@@ -110,7 +131,7 @@ int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb)
sp->hdr.securityIndex = whdr.securityIndex; sp->hdr.securityIndex = whdr.securityIndex;
sp->hdr._rsvd = ntohs(whdr._rsvd); sp->hdr._rsvd = ntohs(whdr._rsvd);
sp->hdr.serviceId = ntohs(whdr.serviceId); sp->hdr.serviceId = ntohs(whdr.serviceId);
return 0; return true;
} }
/* /*
...@@ -130,28 +151,28 @@ static bool rxrpc_extract_abort(struct sk_buff *skb) ...@@ -130,28 +151,28 @@ static bool rxrpc_extract_abort(struct sk_buff *skb)
/* /*
* Process packets received on the local endpoint * Process packets received on the local endpoint
*/ */
static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
{ {
struct rxrpc_connection *conn; struct rxrpc_connection *conn;
struct sockaddr_rxrpc peer_srx; struct sockaddr_rxrpc peer_srx;
struct rxrpc_skb_priv *sp; struct rxrpc_skb_priv *sp;
struct rxrpc_peer *peer = NULL; struct rxrpc_peer *peer = NULL;
struct sk_buff *skb = *_skb; struct sk_buff *skb = *_skb;
int ret = 0; bool ret = false;
skb_pull(skb, sizeof(struct udphdr)); skb_pull(skb, sizeof(struct udphdr));
sp = rxrpc_skb(skb); sp = rxrpc_skb(skb);
/* dig out the RxRPC connection details */ /* dig out the RxRPC connection details */
if (rxrpc_extract_header(sp, skb) < 0) if (!rxrpc_extract_header(sp, skb))
goto bad_message; return just_discard;
if (IS_ENABLED(CONFIG_AF_RXRPC_INJECT_LOSS)) { if (IS_ENABLED(CONFIG_AF_RXRPC_INJECT_LOSS)) {
static int lose; static int lose;
if ((lose++ & 7) == 7) { if ((lose++ & 7) == 7) {
trace_rxrpc_rx_lose(sp); trace_rxrpc_rx_lose(sp);
return 0; return just_discard;
} }
} }
...@@ -160,28 +181,28 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) ...@@ -160,28 +181,28 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
switch (sp->hdr.type) { switch (sp->hdr.type) {
case RXRPC_PACKET_TYPE_VERSION: case RXRPC_PACKET_TYPE_VERSION:
if (rxrpc_to_client(sp)) if (rxrpc_to_client(sp))
return 0; return just_discard;
rxrpc_input_version(local, skb); return rxrpc_input_version(local, skb);
return 0;
case RXRPC_PACKET_TYPE_BUSY: case RXRPC_PACKET_TYPE_BUSY:
if (rxrpc_to_server(sp)) if (rxrpc_to_server(sp))
return 0; return just_discard;
fallthrough; fallthrough;
case RXRPC_PACKET_TYPE_ACK: case RXRPC_PACKET_TYPE_ACK:
case RXRPC_PACKET_TYPE_ACKALL: case RXRPC_PACKET_TYPE_ACKALL:
if (sp->hdr.callNumber == 0) if (sp->hdr.callNumber == 0)
goto bad_message; return rxrpc_bad_message(skb, rxrpc_badmsg_zero_call);
break; break;
case RXRPC_PACKET_TYPE_ABORT: case RXRPC_PACKET_TYPE_ABORT:
if (!rxrpc_extract_abort(skb)) if (!rxrpc_extract_abort(skb))
return 0; /* Just discard if malformed */ return just_discard; /* Just discard if malformed */
break; break;
case RXRPC_PACKET_TYPE_DATA: case RXRPC_PACKET_TYPE_DATA:
if (sp->hdr.callNumber == 0 || if (sp->hdr.callNumber == 0)
sp->hdr.seq == 0) return rxrpc_bad_message(skb, rxrpc_badmsg_zero_call);
goto bad_message; if (sp->hdr.seq == 0)
return rxrpc_bad_message(skb, rxrpc_badmsg_zero_seq);
/* Unshare the packet so that it can be modified for in-place /* Unshare the packet so that it can be modified for in-place
* decryption. * decryption.
...@@ -191,7 +212,7 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) ...@@ -191,7 +212,7 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
if (!skb) { if (!skb) {
rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem); rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem);
*_skb = NULL; *_skb = NULL;
return 0; return just_discard;
} }
if (skb != *_skb) { if (skb != *_skb) {
...@@ -205,28 +226,28 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) ...@@ -205,28 +226,28 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
case RXRPC_PACKET_TYPE_CHALLENGE: case RXRPC_PACKET_TYPE_CHALLENGE:
if (rxrpc_to_server(sp)) if (rxrpc_to_server(sp))
return 0; return just_discard;
break; break;
case RXRPC_PACKET_TYPE_RESPONSE: case RXRPC_PACKET_TYPE_RESPONSE:
if (rxrpc_to_client(sp)) if (rxrpc_to_client(sp))
return 0; return just_discard;
break; break;
/* Packet types 9-11 should just be ignored. */ /* Packet types 9-11 should just be ignored. */
case RXRPC_PACKET_TYPE_PARAMS: case RXRPC_PACKET_TYPE_PARAMS:
case RXRPC_PACKET_TYPE_10: case RXRPC_PACKET_TYPE_10:
case RXRPC_PACKET_TYPE_11: case RXRPC_PACKET_TYPE_11:
return 0; return just_discard;
default: default:
goto bad_message; return rxrpc_bad_message(skb, rxrpc_badmsg_unsupported_packet);
} }
if (sp->hdr.serviceId == 0) if (sp->hdr.serviceId == 0)
goto bad_message; return rxrpc_bad_message(skb, rxrpc_badmsg_zero_service);
if (WARN_ON_ONCE(rxrpc_extract_addr_from_skb(&peer_srx, skb) < 0)) if (WARN_ON_ONCE(rxrpc_extract_addr_from_skb(&peer_srx, skb) < 0))
return true; /* Unsupported address type - discard. */ return just_discard; /* Unsupported address type. */
if (peer_srx.transport.family != local->srx.transport.family && if (peer_srx.transport.family != local->srx.transport.family &&
(peer_srx.transport.family == AF_INET && (peer_srx.transport.family == AF_INET &&
...@@ -234,7 +255,7 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) ...@@ -234,7 +255,7 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n", pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n",
peer_srx.transport.family, peer_srx.transport.family,
local->srx.transport.family); local->srx.transport.family);
return true; /* Wrong address type - discard. */ return just_discard; /* Wrong address type. */
} }
if (rxrpc_to_client(sp)) { if (rxrpc_to_client(sp)) {
...@@ -242,12 +263,8 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) ...@@ -242,12 +263,8 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
conn = rxrpc_find_client_connection_rcu(local, &peer_srx, skb); conn = rxrpc_find_client_connection_rcu(local, &peer_srx, skb);
conn = rxrpc_get_connection_maybe(conn, rxrpc_conn_get_call_input); conn = rxrpc_get_connection_maybe(conn, rxrpc_conn_get_call_input);
rcu_read_unlock(); rcu_read_unlock();
if (!conn) { if (!conn)
trace_rxrpc_abort(0, "NCC", sp->hdr.cid, return rxrpc_protocol_error(skb, rxrpc_eproto_no_client_conn);
sp->hdr.callNumber, sp->hdr.seq,
RXKADINCONSISTENCY, EBADMSG);
goto protocol_error;
}
ret = rxrpc_input_packet_on_conn(conn, &peer_srx, skb); ret = rxrpc_input_packet_on_conn(conn, &peer_srx, skb);
rxrpc_put_connection(conn, rxrpc_conn_put_call_input); rxrpc_put_connection(conn, rxrpc_conn_put_call_input);
...@@ -280,19 +297,7 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) ...@@ -280,19 +297,7 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
ret = rxrpc_new_incoming_call(local, peer, NULL, &peer_srx, skb); ret = rxrpc_new_incoming_call(local, peer, NULL, &peer_srx, skb);
rxrpc_put_peer(peer, rxrpc_peer_put_input); rxrpc_put_peer(peer, rxrpc_peer_put_input);
if (ret < 0) return ret;
goto reject_packet;
return 0;
bad_message:
trace_rxrpc_abort(0, "BAD", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
RX_PROTOCOL_ERROR, EBADMSG);
protocol_error:
skb->priority = RX_PROTOCOL_ERROR;
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
reject_packet:
rxrpc_reject_packet(local, skb);
return 0;
} }
/* /*
...@@ -306,21 +311,23 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn, ...@@ -306,21 +311,23 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
struct rxrpc_channel *chan; struct rxrpc_channel *chan;
struct rxrpc_call *call = NULL; struct rxrpc_call *call = NULL;
unsigned int channel; unsigned int channel;
bool ret;
if (sp->hdr.securityIndex != conn->security_ix) if (sp->hdr.securityIndex != conn->security_ix)
goto wrong_security; return rxrpc_direct_abort(skb, rxrpc_eproto_wrong_security,
RXKADINCONSISTENCY, -EBADMSG);
if (sp->hdr.serviceId != conn->service_id) { if (sp->hdr.serviceId != conn->service_id) {
int old_id; int old_id;
if (!test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags)) if (!test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags))
goto reupgrade; return rxrpc_protocol_error(skb, rxrpc_eproto_reupgrade);
old_id = cmpxchg(&conn->service_id, conn->orig_service_id, old_id = cmpxchg(&conn->service_id, conn->orig_service_id,
sp->hdr.serviceId); sp->hdr.serviceId);
if (old_id != conn->orig_service_id && if (old_id != conn->orig_service_id &&
old_id != sp->hdr.serviceId) old_id != sp->hdr.serviceId)
goto reupgrade; return rxrpc_protocol_error(skb, rxrpc_eproto_bad_upgrade);
} }
if (after(sp->hdr.serial, conn->hi_serial)) if (after(sp->hdr.serial, conn->hi_serial))
...@@ -336,19 +343,19 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn, ...@@ -336,19 +343,19 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
/* Ignore really old calls */ /* Ignore really old calls */
if (sp->hdr.callNumber < chan->last_call) if (sp->hdr.callNumber < chan->last_call)
return 0; return just_discard;
if (sp->hdr.callNumber == chan->last_call) { if (sp->hdr.callNumber == chan->last_call) {
if (chan->call || if (chan->call ||
sp->hdr.type == RXRPC_PACKET_TYPE_ABORT) sp->hdr.type == RXRPC_PACKET_TYPE_ABORT)
return 0; return just_discard;
/* For the previous service call, if completed successfully, we /* For the previous service call, if completed successfully, we
* discard all further packets. * discard all further packets.
*/ */
if (rxrpc_conn_is_service(conn) && if (rxrpc_conn_is_service(conn) &&
chan->last_type == RXRPC_PACKET_TYPE_ACK) chan->last_type == RXRPC_PACKET_TYPE_ACK)
return 0; return just_discard;
/* But otherwise we need to retransmit the final packet from /* But otherwise we need to retransmit the final packet from
* data cached in the connection record. * data cached in the connection record.
...@@ -358,19 +365,17 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn, ...@@ -358,19 +365,17 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
sp->hdr.seq, sp->hdr.seq,
sp->hdr.serial, sp->hdr.serial,
sp->hdr.flags); sp->hdr.flags);
rxrpc_input_conn_packet(conn, skb); rxrpc_conn_retransmit_call(conn, skb, channel);
return 0; return just_discard;
} }
rcu_read_lock(); call = rxrpc_try_get_call(chan->call, rxrpc_call_get_input);
call = rxrpc_try_get_call(rcu_dereference(chan->call),
rxrpc_call_get_input);
rcu_read_unlock();
if (sp->hdr.callNumber > chan->call_id) { if (sp->hdr.callNumber > chan->call_id) {
if (rxrpc_to_client(sp)) { if (rxrpc_to_client(sp)) {
rxrpc_put_call(call, rxrpc_call_put_input); rxrpc_put_call(call, rxrpc_call_put_input);
goto reject_packet; return rxrpc_protocol_error(skb,
rxrpc_eproto_unexpected_implicit_end);
} }
if (call) { if (call) {
...@@ -382,38 +387,14 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn, ...@@ -382,38 +387,14 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
if (!call) { if (!call) {
if (rxrpc_to_client(sp)) if (rxrpc_to_client(sp))
goto bad_message; return rxrpc_protocol_error(skb, rxrpc_eproto_no_client_call);
if (rxrpc_new_incoming_call(conn->local, conn->peer, conn, return rxrpc_new_incoming_call(conn->local, conn->peer, conn,
peer_srx, skb) == 0) peer_srx, skb);
return 0;
goto reject_packet;
} }
rxrpc_input_call_event(call, skb); ret = rxrpc_input_call_event(call, skb);
rxrpc_put_call(call, rxrpc_call_put_input); rxrpc_put_call(call, rxrpc_call_put_input);
return 0; return ret;
wrong_security:
trace_rxrpc_abort(0, "SEC", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
RXKADINCONSISTENCY, EBADMSG);
skb->priority = RXKADINCONSISTENCY;
goto post_abort;
reupgrade:
trace_rxrpc_abort(0, "UPG", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
RX_PROTOCOL_ERROR, EBADMSG);
goto protocol_error;
bad_message:
trace_rxrpc_abort(0, "BAD", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
RX_PROTOCOL_ERROR, EBADMSG);
protocol_error:
skb->priority = RX_PROTOCOL_ERROR;
post_abort:
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
reject_packet:
rxrpc_reject_packet(conn->local, skb);
return 0;
} }
/* /*
...@@ -421,6 +402,7 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn, ...@@ -421,6 +402,7 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
*/ */
int rxrpc_io_thread(void *data) int rxrpc_io_thread(void *data)
{ {
struct rxrpc_connection *conn;
struct sk_buff_head rx_queue; struct sk_buff_head rx_queue;
struct rxrpc_local *local = data; struct rxrpc_local *local = data;
struct rxrpc_call *call; struct rxrpc_call *call;
...@@ -436,6 +418,24 @@ int rxrpc_io_thread(void *data) ...@@ -436,6 +418,24 @@ int rxrpc_io_thread(void *data)
for (;;) { for (;;) {
rxrpc_inc_stat(local->rxnet, stat_io_loop); rxrpc_inc_stat(local->rxnet, stat_io_loop);
/* Deal with connections that want immediate attention. */
conn = list_first_entry_or_null(&local->conn_attend_q,
struct rxrpc_connection,
attend_link);
if (conn) {
spin_lock_bh(&local->lock);
list_del_init(&conn->attend_link);
spin_unlock_bh(&local->lock);
rxrpc_input_conn_event(conn, NULL);
rxrpc_put_connection(conn, rxrpc_conn_put_poke);
continue;
}
if (test_and_clear_bit(RXRPC_CLIENT_CONN_REAP_TIMER,
&local->client_conn_flags))
rxrpc_discard_expired_client_conns(local);
/* Deal with calls that want immediate attention. */ /* Deal with calls that want immediate attention. */
if ((call = list_first_entry_or_null(&local->call_attend_q, if ((call = list_first_entry_or_null(&local->call_attend_q,
struct rxrpc_call, struct rxrpc_call,
...@@ -450,12 +450,17 @@ int rxrpc_io_thread(void *data) ...@@ -450,12 +450,17 @@ int rxrpc_io_thread(void *data)
continue; continue;
} }
if (!list_empty(&local->new_client_calls))
rxrpc_connect_client_calls(local);
/* Process received packets and errors. */ /* Process received packets and errors. */
if ((skb = __skb_dequeue(&rx_queue))) { if ((skb = __skb_dequeue(&rx_queue))) {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
switch (skb->mark) { switch (skb->mark) {
case RXRPC_SKB_MARK_PACKET: case RXRPC_SKB_MARK_PACKET:
skb->priority = 0; skb->priority = 0;
rxrpc_input_packet(local, &skb); if (!rxrpc_input_packet(local, &skb))
rxrpc_reject_packet(local, skb);
trace_rxrpc_rx_done(skb->mark, skb->priority); trace_rxrpc_rx_done(skb->mark, skb->priority);
rxrpc_free_skb(skb, rxrpc_skb_put_input); rxrpc_free_skb(skb, rxrpc_skb_put_input);
break; break;
...@@ -463,6 +468,11 @@ int rxrpc_io_thread(void *data) ...@@ -463,6 +468,11 @@ int rxrpc_io_thread(void *data)
rxrpc_input_error(local, skb); rxrpc_input_error(local, skb);
rxrpc_free_skb(skb, rxrpc_skb_put_error_report); rxrpc_free_skb(skb, rxrpc_skb_put_error_report);
break; break;
case RXRPC_SKB_MARK_SERVICE_CONN_SECURED:
rxrpc_input_conn_event(sp->conn, skb);
rxrpc_put_connection(sp->conn, rxrpc_conn_put_poke);
rxrpc_free_skb(skb, rxrpc_skb_put_conn_secured);
break;
default: default:
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
rxrpc_free_skb(skb, rxrpc_skb_put_unknown); rxrpc_free_skb(skb, rxrpc_skb_put_unknown);
...@@ -481,7 +491,11 @@ int rxrpc_io_thread(void *data) ...@@ -481,7 +491,11 @@ int rxrpc_io_thread(void *data)
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
should_stop = kthread_should_stop(); should_stop = kthread_should_stop();
if (!skb_queue_empty(&local->rx_queue) || if (!skb_queue_empty(&local->rx_queue) ||
!list_empty(&local->call_attend_q)) { !list_empty(&local->call_attend_q) ||
!list_empty(&local->conn_attend_q) ||
!list_empty(&local->new_client_calls) ||
test_bit(RXRPC_CLIENT_CONN_REAP_TIMER,
&local->client_conn_flags)) {
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
continue; continue;
} }
......
...@@ -82,31 +82,59 @@ static long rxrpc_local_cmp_key(const struct rxrpc_local *local, ...@@ -82,31 +82,59 @@ static long rxrpc_local_cmp_key(const struct rxrpc_local *local,
} }
} }
static void rxrpc_client_conn_reap_timeout(struct timer_list *timer)
{
struct rxrpc_local *local =
container_of(timer, struct rxrpc_local, client_conn_reap_timer);
if (local->kill_all_client_conns &&
test_and_set_bit(RXRPC_CLIENT_CONN_REAP_TIMER, &local->client_conn_flags))
rxrpc_wake_up_io_thread(local);
}
/* /*
* Allocate a new local endpoint. * Allocate a new local endpoint.
*/ */
static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet, static struct rxrpc_local *rxrpc_alloc_local(struct net *net,
const struct sockaddr_rxrpc *srx) const struct sockaddr_rxrpc *srx)
{ {
struct rxrpc_local *local; struct rxrpc_local *local;
u32 tmp;
local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL); local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL);
if (local) { if (local) {
refcount_set(&local->ref, 1); refcount_set(&local->ref, 1);
atomic_set(&local->active_users, 1); atomic_set(&local->active_users, 1);
local->rxnet = rxnet; local->net = net;
local->rxnet = rxrpc_net(net);
INIT_HLIST_NODE(&local->link); INIT_HLIST_NODE(&local->link);
init_rwsem(&local->defrag_sem); init_rwsem(&local->defrag_sem);
init_completion(&local->io_thread_ready); init_completion(&local->io_thread_ready);
skb_queue_head_init(&local->rx_queue); skb_queue_head_init(&local->rx_queue);
INIT_LIST_HEAD(&local->conn_attend_q);
INIT_LIST_HEAD(&local->call_attend_q); INIT_LIST_HEAD(&local->call_attend_q);
local->client_bundles = RB_ROOT; local->client_bundles = RB_ROOT;
spin_lock_init(&local->client_bundles_lock); spin_lock_init(&local->client_bundles_lock);
local->kill_all_client_conns = false;
INIT_LIST_HEAD(&local->idle_client_conns);
timer_setup(&local->client_conn_reap_timer,
rxrpc_client_conn_reap_timeout, 0);
spin_lock_init(&local->lock); spin_lock_init(&local->lock);
rwlock_init(&local->services_lock); rwlock_init(&local->services_lock);
local->debug_id = atomic_inc_return(&rxrpc_debug_id); local->debug_id = atomic_inc_return(&rxrpc_debug_id);
memcpy(&local->srx, srx, sizeof(*srx)); memcpy(&local->srx, srx, sizeof(*srx));
local->srx.srx_service = 0; local->srx.srx_service = 0;
idr_init(&local->conn_ids);
get_random_bytes(&tmp, sizeof(tmp));
tmp &= 0x3fffffff;
if (tmp == 0)
tmp = 1;
idr_set_cursor(&local->conn_ids, tmp);
INIT_LIST_HEAD(&local->new_client_calls);
spin_lock_init(&local->client_call_lock);
trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, 1); trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, 1);
} }
...@@ -248,7 +276,7 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net, ...@@ -248,7 +276,7 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
goto found; goto found;
} }
local = rxrpc_alloc_local(rxnet, srx); local = rxrpc_alloc_local(net, srx);
if (!local) if (!local)
goto nomem; goto nomem;
...@@ -407,6 +435,7 @@ void rxrpc_destroy_local(struct rxrpc_local *local) ...@@ -407,6 +435,7 @@ void rxrpc_destroy_local(struct rxrpc_local *local)
* local endpoint. * local endpoint.
*/ */
rxrpc_purge_queue(&local->rx_queue); rxrpc_purge_queue(&local->rx_queue);
rxrpc_purge_client_connections(local);
} }
/* /*
......
...@@ -10,15 +10,6 @@ ...@@ -10,15 +10,6 @@
unsigned int rxrpc_net_id; unsigned int rxrpc_net_id;
static void rxrpc_client_conn_reap_timeout(struct timer_list *timer)
{
struct rxrpc_net *rxnet =
container_of(timer, struct rxrpc_net, client_conn_reap_timer);
if (rxnet->live)
rxrpc_queue_work(&rxnet->client_conn_reaper);
}
static void rxrpc_service_conn_reap_timeout(struct timer_list *timer) static void rxrpc_service_conn_reap_timeout(struct timer_list *timer)
{ {
struct rxrpc_net *rxnet = struct rxrpc_net *rxnet =
...@@ -63,14 +54,6 @@ static __net_init int rxrpc_init_net(struct net *net) ...@@ -63,14 +54,6 @@ static __net_init int rxrpc_init_net(struct net *net)
rxrpc_service_conn_reap_timeout, 0); rxrpc_service_conn_reap_timeout, 0);
atomic_set(&rxnet->nr_client_conns, 0); atomic_set(&rxnet->nr_client_conns, 0);
rxnet->kill_all_client_conns = false;
spin_lock_init(&rxnet->client_conn_cache_lock);
mutex_init(&rxnet->client_conn_discard_lock);
INIT_LIST_HEAD(&rxnet->idle_client_conns);
INIT_WORK(&rxnet->client_conn_reaper,
rxrpc_discard_expired_client_conns);
timer_setup(&rxnet->client_conn_reap_timer,
rxrpc_client_conn_reap_timeout, 0);
INIT_HLIST_HEAD(&rxnet->local_endpoints); INIT_HLIST_HEAD(&rxnet->local_endpoints);
mutex_init(&rxnet->local_mutex); mutex_init(&rxnet->local_mutex);
......
...@@ -261,7 +261,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) ...@@ -261,7 +261,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
rxrpc_tx_point_call_ack); rxrpc_tx_point_call_ack);
rxrpc_tx_backoff(call, ret); rxrpc_tx_backoff(call, ret);
if (call->state < RXRPC_CALL_COMPLETE) { if (!__rxrpc_call_is_complete(call)) {
if (ret < 0) if (ret < 0)
rxrpc_cancel_rtt_probe(call, serial, rtt_slot); rxrpc_cancel_rtt_probe(call, serial, rtt_slot);
rxrpc_set_keepalive(call); rxrpc_set_keepalive(call);
...@@ -544,6 +544,62 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb) ...@@ -544,6 +544,62 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
goto done; goto done;
} }
/*
* Transmit a connection-level abort.
*/
void rxrpc_send_conn_abort(struct rxrpc_connection *conn)
{
struct rxrpc_wire_header whdr;
struct msghdr msg;
struct kvec iov[2];
__be32 word;
size_t len;
u32 serial;
int ret;
msg.msg_name = &conn->peer->srx.transport;
msg.msg_namelen = conn->peer->srx.transport_len;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
whdr.epoch = htonl(conn->proto.epoch);
whdr.cid = htonl(conn->proto.cid);
whdr.callNumber = 0;
whdr.seq = 0;
whdr.type = RXRPC_PACKET_TYPE_ABORT;
whdr.flags = conn->out_clientflag;
whdr.userStatus = 0;
whdr.securityIndex = conn->security_ix;
whdr._rsvd = 0;
whdr.serviceId = htons(conn->service_id);
word = htonl(conn->abort_code);
iov[0].iov_base = &whdr;
iov[0].iov_len = sizeof(whdr);
iov[1].iov_base = &word;
iov[1].iov_len = sizeof(word);
len = iov[0].iov_len + iov[1].iov_len;
serial = atomic_inc_return(&conn->serial);
whdr.serial = htonl(serial);
iov_iter_kvec(&msg.msg_iter, WRITE, iov, 2, len);
ret = do_udp_sendmsg(conn->local->socket, &msg, len);
if (ret < 0) {
trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
rxrpc_tx_point_conn_abort);
_debug("sendmsg failed: %d", ret);
return;
}
trace_rxrpc_tx_packet(conn->debug_id, &whdr, rxrpc_tx_point_conn_abort);
conn->peer->last_tx_at = ktime_get_seconds();
}
/* /*
* Reject a packet through the local endpoint. * Reject a packet through the local endpoint.
*/ */
...@@ -667,7 +723,7 @@ void rxrpc_send_keepalive(struct rxrpc_peer *peer) ...@@ -667,7 +723,7 @@ void rxrpc_send_keepalive(struct rxrpc_peer *peer)
static inline void rxrpc_instant_resend(struct rxrpc_call *call, static inline void rxrpc_instant_resend(struct rxrpc_call *call,
struct rxrpc_txbuf *txb) struct rxrpc_txbuf *txb)
{ {
if (call->state < RXRPC_CALL_COMPLETE) if (!__rxrpc_call_is_complete(call))
kdebug("resend"); kdebug("resend");
} }
......
...@@ -147,10 +147,10 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local, ...@@ -147,10 +147,10 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local,
* assess the MTU size for the network interface through which this peer is * assess the MTU size for the network interface through which this peer is
* reached * reached
*/ */
static void rxrpc_assess_MTU_size(struct rxrpc_sock *rx, static void rxrpc_assess_MTU_size(struct rxrpc_local *local,
struct rxrpc_peer *peer) struct rxrpc_peer *peer)
{ {
struct net *net = sock_net(&rx->sk); struct net *net = local->net;
struct dst_entry *dst; struct dst_entry *dst;
struct rtable *rt; struct rtable *rt;
struct flowi fl; struct flowi fl;
...@@ -236,11 +236,11 @@ struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp, ...@@ -236,11 +236,11 @@ struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp,
/* /*
* Initialise peer record. * Initialise peer record.
*/ */
static void rxrpc_init_peer(struct rxrpc_sock *rx, struct rxrpc_peer *peer, static void rxrpc_init_peer(struct rxrpc_local *local, struct rxrpc_peer *peer,
unsigned long hash_key) unsigned long hash_key)
{ {
peer->hash_key = hash_key; peer->hash_key = hash_key;
rxrpc_assess_MTU_size(rx, peer); rxrpc_assess_MTU_size(local, peer);
peer->mtu = peer->if_mtu; peer->mtu = peer->if_mtu;
peer->rtt_last_req = ktime_get_real(); peer->rtt_last_req = ktime_get_real();
...@@ -272,8 +272,7 @@ static void rxrpc_init_peer(struct rxrpc_sock *rx, struct rxrpc_peer *peer, ...@@ -272,8 +272,7 @@ static void rxrpc_init_peer(struct rxrpc_sock *rx, struct rxrpc_peer *peer,
/* /*
* Set up a new peer. * Set up a new peer.
*/ */
static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_sock *rx, static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local,
struct rxrpc_local *local,
struct sockaddr_rxrpc *srx, struct sockaddr_rxrpc *srx,
unsigned long hash_key, unsigned long hash_key,
gfp_t gfp) gfp_t gfp)
...@@ -285,7 +284,7 @@ static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_sock *rx, ...@@ -285,7 +284,7 @@ static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_sock *rx,
peer = rxrpc_alloc_peer(local, gfp, rxrpc_peer_new_client); peer = rxrpc_alloc_peer(local, gfp, rxrpc_peer_new_client);
if (peer) { if (peer) {
memcpy(&peer->srx, srx, sizeof(*srx)); memcpy(&peer->srx, srx, sizeof(*srx));
rxrpc_init_peer(rx, peer, hash_key); rxrpc_init_peer(local, peer, hash_key);
} }
_leave(" = %p", peer); _leave(" = %p", peer);
...@@ -304,14 +303,13 @@ static void rxrpc_free_peer(struct rxrpc_peer *peer) ...@@ -304,14 +303,13 @@ static void rxrpc_free_peer(struct rxrpc_peer *peer)
* since we've already done a search in the list from the non-reentrant context * since we've already done a search in the list from the non-reentrant context
* (the data_ready handler) that is the only place we can add new peers. * (the data_ready handler) that is the only place we can add new peers.
*/ */
void rxrpc_new_incoming_peer(struct rxrpc_sock *rx, struct rxrpc_local *local, void rxrpc_new_incoming_peer(struct rxrpc_local *local, struct rxrpc_peer *peer)
struct rxrpc_peer *peer)
{ {
struct rxrpc_net *rxnet = local->rxnet; struct rxrpc_net *rxnet = local->rxnet;
unsigned long hash_key; unsigned long hash_key;
hash_key = rxrpc_peer_hash_key(local, &peer->srx); hash_key = rxrpc_peer_hash_key(local, &peer->srx);
rxrpc_init_peer(rx, peer, hash_key); rxrpc_init_peer(local, peer, hash_key);
spin_lock(&rxnet->peer_hash_lock); spin_lock(&rxnet->peer_hash_lock);
hash_add_rcu(rxnet->peer_hash, &peer->hash_link, hash_key); hash_add_rcu(rxnet->peer_hash, &peer->hash_link, hash_key);
...@@ -322,8 +320,7 @@ void rxrpc_new_incoming_peer(struct rxrpc_sock *rx, struct rxrpc_local *local, ...@@ -322,8 +320,7 @@ void rxrpc_new_incoming_peer(struct rxrpc_sock *rx, struct rxrpc_local *local,
/* /*
* obtain a remote transport endpoint for the specified address * obtain a remote transport endpoint for the specified address
*/ */
struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_sock *rx, struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
struct rxrpc_local *local,
struct sockaddr_rxrpc *srx, gfp_t gfp) struct sockaddr_rxrpc *srx, gfp_t gfp)
{ {
struct rxrpc_peer *peer, *candidate; struct rxrpc_peer *peer, *candidate;
...@@ -343,7 +340,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_sock *rx, ...@@ -343,7 +340,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_sock *rx,
/* The peer is not yet present in hash - create a candidate /* The peer is not yet present in hash - create a candidate
* for a new record and then redo the search. * for a new record and then redo the search.
*/ */
candidate = rxrpc_create_peer(rx, local, srx, hash_key, gfp); candidate = rxrpc_create_peer(local, srx, hash_key, gfp);
if (!candidate) { if (!candidate) {
_leave(" = NULL [nomem]"); _leave(" = NULL [nomem]");
return NULL; return NULL;
......
...@@ -12,13 +12,13 @@ ...@@ -12,13 +12,13 @@
static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = { static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
[RXRPC_CONN_UNUSED] = "Unused ", [RXRPC_CONN_UNUSED] = "Unused ",
[RXRPC_CONN_CLIENT_UNSECURED] = "ClUnsec ",
[RXRPC_CONN_CLIENT] = "Client ", [RXRPC_CONN_CLIENT] = "Client ",
[RXRPC_CONN_SERVICE_PREALLOC] = "SvPrealc", [RXRPC_CONN_SERVICE_PREALLOC] = "SvPrealc",
[RXRPC_CONN_SERVICE_UNSECURED] = "SvUnsec ", [RXRPC_CONN_SERVICE_UNSECURED] = "SvUnsec ",
[RXRPC_CONN_SERVICE_CHALLENGING] = "SvChall ", [RXRPC_CONN_SERVICE_CHALLENGING] = "SvChall ",
[RXRPC_CONN_SERVICE] = "SvSecure", [RXRPC_CONN_SERVICE] = "SvSecure",
[RXRPC_CONN_REMOTELY_ABORTED] = "RmtAbort", [RXRPC_CONN_ABORTED] = "Aborted ",
[RXRPC_CONN_LOCALLY_ABORTED] = "LocAbort",
}; };
/* /*
...@@ -51,6 +51,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v) ...@@ -51,6 +51,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
struct rxrpc_local *local; struct rxrpc_local *local;
struct rxrpc_call *call; struct rxrpc_call *call;
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq)); struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
enum rxrpc_call_state state;
unsigned long timeout = 0; unsigned long timeout = 0;
rxrpc_seq_t acks_hard_ack; rxrpc_seq_t acks_hard_ack;
char lbuff[50], rbuff[50]; char lbuff[50], rbuff[50];
...@@ -75,7 +76,8 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v) ...@@ -75,7 +76,8 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
sprintf(rbuff, "%pISpc", &call->dest_srx.transport); sprintf(rbuff, "%pISpc", &call->dest_srx.transport);
if (call->state != RXRPC_CALL_SERVER_PREALLOC) { state = rxrpc_call_state(call);
if (state != RXRPC_CALL_SERVER_PREALLOC) {
timeout = READ_ONCE(call->expect_rx_by); timeout = READ_ONCE(call->expect_rx_by);
timeout -= jiffies; timeout -= jiffies;
} }
...@@ -92,7 +94,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v) ...@@ -92,7 +94,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
call->call_id, call->call_id,
rxrpc_is_service_call(call) ? "Svc" : "Clt", rxrpc_is_service_call(call) ? "Svc" : "Clt",
refcount_read(&call->ref), refcount_read(&call->ref),
rxrpc_call_states[call->state], rxrpc_call_states[state],
call->abort_code, call->abort_code,
call->debug_id, call->debug_id,
acks_hard_ack, READ_ONCE(call->tx_top) - acks_hard_ack, acks_hard_ack, READ_ONCE(call->tx_top) - acks_hard_ack,
...@@ -143,6 +145,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v) ...@@ -143,6 +145,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
{ {
struct rxrpc_connection *conn; struct rxrpc_connection *conn;
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq)); struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
const char *state;
char lbuff[50], rbuff[50]; char lbuff[50], rbuff[50];
if (v == &rxnet->conn_proc_list) { if (v == &rxnet->conn_proc_list) {
...@@ -163,9 +166,11 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v) ...@@ -163,9 +166,11 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
} }
sprintf(lbuff, "%pISpc", &conn->local->srx.transport); sprintf(lbuff, "%pISpc", &conn->local->srx.transport);
sprintf(rbuff, "%pISpc", &conn->peer->srx.transport); sprintf(rbuff, "%pISpc", &conn->peer->srx.transport);
print: print:
state = rxrpc_is_conn_aborted(conn) ?
rxrpc_call_completions[conn->completion] :
rxrpc_conn_states[conn->state];
seq_printf(seq, seq_printf(seq,
"UDP %-47.47s %-47.47s %4x %08x %s %3u %3d" "UDP %-47.47s %-47.47s %4x %08x %s %3u %3d"
" %s %08x %08x %08x %08x %08x %08x %08x\n", " %s %08x %08x %08x %08x %08x %08x %08x\n",
...@@ -176,7 +181,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v) ...@@ -176,7 +181,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
rxrpc_conn_is_service(conn) ? "Svc" : "Clt", rxrpc_conn_is_service(conn) ? "Svc" : "Clt",
refcount_read(&conn->ref), refcount_read(&conn->ref),
atomic_read(&conn->active), atomic_read(&conn->active),
rxrpc_conn_states[conn->state], state,
key_serial(conn->key), key_serial(conn->key),
atomic_read(&conn->serial), atomic_read(&conn->serial),
conn->hi_serial, conn->hi_serial,
......
...@@ -58,85 +58,6 @@ void rxrpc_notify_socket(struct rxrpc_call *call) ...@@ -58,85 +58,6 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
_leave(""); _leave("");
} }
/*
* Transition a call to the complete state.
*/
bool __rxrpc_set_call_completion(struct rxrpc_call *call,
enum rxrpc_call_completion compl,
u32 abort_code,
int error)
{
if (call->state < RXRPC_CALL_COMPLETE) {
call->abort_code = abort_code;
call->error = error;
call->completion = compl;
call->state = RXRPC_CALL_COMPLETE;
trace_rxrpc_call_complete(call);
wake_up(&call->waitq);
rxrpc_notify_socket(call);
return true;
}
return false;
}
bool rxrpc_set_call_completion(struct rxrpc_call *call,
enum rxrpc_call_completion compl,
u32 abort_code,
int error)
{
bool ret = false;
if (call->state < RXRPC_CALL_COMPLETE) {
write_lock(&call->state_lock);
ret = __rxrpc_set_call_completion(call, compl, abort_code, error);
write_unlock(&call->state_lock);
}
return ret;
}
/*
* Record that a call successfully completed.
*/
bool __rxrpc_call_completed(struct rxrpc_call *call)
{
return __rxrpc_set_call_completion(call, RXRPC_CALL_SUCCEEDED, 0, 0);
}
bool rxrpc_call_completed(struct rxrpc_call *call)
{
bool ret = false;
if (call->state < RXRPC_CALL_COMPLETE) {
write_lock(&call->state_lock);
ret = __rxrpc_call_completed(call);
write_unlock(&call->state_lock);
}
return ret;
}
/*
* Record that a call is locally aborted.
*/
bool __rxrpc_abort_call(const char *why, struct rxrpc_call *call,
rxrpc_seq_t seq, u32 abort_code, int error)
{
trace_rxrpc_abort(call->debug_id, why, call->cid, call->call_id, seq,
abort_code, error);
return __rxrpc_set_call_completion(call, RXRPC_CALL_LOCALLY_ABORTED,
abort_code, error);
}
bool rxrpc_abort_call(const char *why, struct rxrpc_call *call,
rxrpc_seq_t seq, u32 abort_code, int error)
{
bool ret;
write_lock(&call->state_lock);
ret = __rxrpc_abort_call(why, call, seq, abort_code, error);
write_unlock(&call->state_lock);
return ret;
}
/* /*
* Pass a call terminating message to userspace. * Pass a call terminating message to userspace.
*/ */
...@@ -168,7 +89,7 @@ static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg) ...@@ -168,7 +89,7 @@ static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg)
ret = put_cmsg(msg, SOL_RXRPC, RXRPC_LOCAL_ERROR, 4, &tmp); ret = put_cmsg(msg, SOL_RXRPC, RXRPC_LOCAL_ERROR, 4, &tmp);
break; break;
default: default:
pr_err("Invalid terminal call state %u\n", call->state); pr_err("Invalid terminal call state %u\n", call->completion);
BUG(); BUG();
break; break;
} }
...@@ -179,41 +100,6 @@ static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg) ...@@ -179,41 +100,6 @@ static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg)
return ret; return ret;
} }
/*
* End the packet reception phase.
*/
static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
{
rxrpc_seq_t whigh = READ_ONCE(call->rx_highest_seq);
_enter("%d,%s", call->debug_id, rxrpc_call_states[call->state]);
trace_rxrpc_receive(call, rxrpc_receive_end, 0, whigh);
if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY)
rxrpc_propose_delay_ACK(call, serial, rxrpc_propose_ack_terminal_ack);
write_lock(&call->state_lock);
switch (call->state) {
case RXRPC_CALL_CLIENT_RECV_REPLY:
__rxrpc_call_completed(call);
write_unlock(&call->state_lock);
break;
case RXRPC_CALL_SERVER_RECV_REQUEST:
call->state = RXRPC_CALL_SERVER_ACK_REQUEST;
call->expect_req_by = jiffies + MAX_JIFFY_OFFSET;
write_unlock(&call->state_lock);
rxrpc_propose_delay_ACK(call, serial,
rxrpc_propose_ack_processing_op);
break;
default:
write_unlock(&call->state_lock);
break;
}
}
/* /*
* Discard a packet we've used up and advance the Rx window by one. * Discard a packet we've used up and advance the Rx window by one.
*/ */
...@@ -244,10 +130,9 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call) ...@@ -244,10 +130,9 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
trace_rxrpc_receive(call, last ? rxrpc_receive_rotate_last : rxrpc_receive_rotate, trace_rxrpc_receive(call, last ? rxrpc_receive_rotate_last : rxrpc_receive_rotate,
serial, call->rx_consumed); serial, call->rx_consumed);
if (last) {
rxrpc_end_rx_phase(call, serial); if (last)
return; set_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags);
}
/* Check to see if there's an ACK that needs sending. */ /* Check to see if there's an ACK that needs sending. */
acked = atomic_add_return(call->rx_consumed - old_consumed, acked = atomic_add_return(call->rx_consumed - old_consumed,
...@@ -272,7 +157,8 @@ static int rxrpc_verify_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -272,7 +157,8 @@ static int rxrpc_verify_data(struct rxrpc_call *call, struct sk_buff *skb)
/* /*
* Deliver messages to a call. This keeps processing packets until the buffer * Deliver messages to a call. This keeps processing packets until the buffer
* is filled and we find either more DATA (returns 0) or the end of the DATA * is filled and we find either more DATA (returns 0) or the end of the DATA
* (returns 1). If more packets are required, it returns -EAGAIN. * (returns 1). If more packets are required, it returns -EAGAIN and if the
* call has failed it returns -EIO.
*/ */
static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
struct msghdr *msg, struct iov_iter *iter, struct msghdr *msg, struct iov_iter *iter,
...@@ -288,7 +174,13 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, ...@@ -288,7 +174,13 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
rx_pkt_offset = call->rx_pkt_offset; rx_pkt_offset = call->rx_pkt_offset;
rx_pkt_len = call->rx_pkt_len; rx_pkt_len = call->rx_pkt_len;
if (call->state >= RXRPC_CALL_SERVER_ACK_REQUEST) { if (rxrpc_call_has_failed(call)) {
seq = lower_32_bits(atomic64_read(&call->ackr_window)) - 1;
ret = -EIO;
goto done;
}
if (test_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags)) {
seq = lower_32_bits(atomic64_read(&call->ackr_window)) - 1; seq = lower_32_bits(atomic64_read(&call->ackr_window)) - 1;
ret = 1; ret = 1;
goto done; goto done;
...@@ -312,14 +204,15 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, ...@@ -312,14 +204,15 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
if (rx_pkt_offset == 0) { if (rx_pkt_offset == 0) {
ret2 = rxrpc_verify_data(call, skb); ret2 = rxrpc_verify_data(call, skb);
rx_pkt_offset = sp->offset;
rx_pkt_len = sp->len;
trace_rxrpc_recvdata(call, rxrpc_recvmsg_next, seq, trace_rxrpc_recvdata(call, rxrpc_recvmsg_next, seq,
rx_pkt_offset, rx_pkt_len, ret2); sp->offset, sp->len, ret2);
if (ret2 < 0) { if (ret2 < 0) {
kdebug("verify = %d", ret2);
ret = ret2; ret = ret2;
goto out; goto out;
} }
rx_pkt_offset = sp->offset;
rx_pkt_len = sp->len;
} else { } else {
trace_rxrpc_recvdata(call, rxrpc_recvmsg_cont, seq, trace_rxrpc_recvdata(call, rxrpc_recvmsg_cont, seq,
rx_pkt_offset, rx_pkt_len, 0); rx_pkt_offset, rx_pkt_len, 0);
...@@ -494,36 +387,36 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, ...@@ -494,36 +387,36 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
msg->msg_namelen = len; msg->msg_namelen = len;
} }
switch (READ_ONCE(call->state)) { ret = rxrpc_recvmsg_data(sock, call, msg, &msg->msg_iter, len,
case RXRPC_CALL_CLIENT_RECV_REPLY: flags, &copied);
case RXRPC_CALL_SERVER_RECV_REQUEST: if (ret == -EAGAIN)
case RXRPC_CALL_SERVER_ACK_REQUEST:
ret = rxrpc_recvmsg_data(sock, call, msg, &msg->msg_iter, len,
flags, &copied);
if (ret == -EAGAIN)
ret = 0;
if (!skb_queue_empty(&call->recvmsg_queue))
rxrpc_notify_socket(call);
break;
default:
ret = 0; ret = 0;
break; if (ret == -EIO)
} goto call_failed;
if (ret < 0) if (ret < 0)
goto error_unlock_call; goto error_unlock_call;
if (call->state == RXRPC_CALL_COMPLETE) { if (rxrpc_call_is_complete(call) &&
ret = rxrpc_recvmsg_term(call, msg); skb_queue_empty(&call->recvmsg_queue))
if (ret < 0) goto call_complete;
goto error_unlock_call; if (rxrpc_call_has_failed(call))
if (!(flags & MSG_PEEK)) goto call_failed;
rxrpc_release_call(rx, call);
msg->msg_flags |= MSG_EOR;
ret = 1;
}
rxrpc_notify_socket(call);
goto not_yet_complete;
call_failed:
rxrpc_purge_queue(&call->recvmsg_queue);
call_complete:
ret = rxrpc_recvmsg_term(call, msg);
if (ret < 0)
goto error_unlock_call;
if (!(flags & MSG_PEEK))
rxrpc_release_call(rx, call);
msg->msg_flags |= MSG_EOR;
ret = 1;
not_yet_complete:
if (ret == 0) if (ret == 0)
msg->msg_flags |= MSG_MORE; msg->msg_flags |= MSG_MORE;
else else
...@@ -586,49 +479,34 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, ...@@ -586,49 +479,34 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
size_t offset = 0; size_t offset = 0;
int ret; int ret;
_enter("{%d,%s},%zu,%d", _enter("{%d},%zu,%d", call->debug_id, *_len, want_more);
call->debug_id, rxrpc_call_states[call->state],
*_len, want_more);
ASSERTCMP(call->state, !=, RXRPC_CALL_SERVER_SECURING);
mutex_lock(&call->user_mutex); mutex_lock(&call->user_mutex);
switch (READ_ONCE(call->state)) { ret = rxrpc_recvmsg_data(sock, call, NULL, iter, *_len, 0, &offset);
case RXRPC_CALL_CLIENT_RECV_REPLY: *_len -= offset;
case RXRPC_CALL_SERVER_RECV_REQUEST: if (ret == -EIO)
case RXRPC_CALL_SERVER_ACK_REQUEST: goto call_failed;
ret = rxrpc_recvmsg_data(sock, call, NULL, iter, if (ret < 0)
*_len, 0, &offset);
*_len -= offset;
if (ret < 0)
goto out;
/* We can only reach here with a partially full buffer if we
* have reached the end of the data. We must otherwise have a
* full buffer or have been given -EAGAIN.
*/
if (ret == 1) {
if (iov_iter_count(iter) > 0)
goto short_data;
if (!want_more)
goto read_phase_complete;
ret = 0;
goto out;
}
if (!want_more)
goto excess_data;
goto out; goto out;
case RXRPC_CALL_COMPLETE: /* We can only reach here with a partially full buffer if we have
goto call_complete; * reached the end of the data. We must otherwise have a full buffer
* or have been given -EAGAIN.
default: */
ret = -EINPROGRESS; if (ret == 1) {
if (iov_iter_count(iter) > 0)
goto short_data;
if (!want_more)
goto read_phase_complete;
ret = 0;
goto out; goto out;
} }
if (!want_more)
goto excess_data;
goto out;
read_phase_complete: read_phase_complete:
ret = 1; ret = 1;
out: out:
...@@ -639,14 +517,18 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, ...@@ -639,14 +517,18 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
return ret; return ret;
short_data: short_data:
trace_rxrpc_rx_eproto(call, 0, tracepoint_string("short_data")); trace_rxrpc_abort(call->debug_id, rxrpc_recvmsg_short_data,
call->cid, call->call_id, call->rx_consumed,
0, -EBADMSG);
ret = -EBADMSG; ret = -EBADMSG;
goto out; goto out;
excess_data: excess_data:
trace_rxrpc_rx_eproto(call, 0, tracepoint_string("excess_data")); trace_rxrpc_abort(call->debug_id, rxrpc_recvmsg_excess_data,
call->cid, call->call_id, call->rx_consumed,
0, -EMSGSIZE);
ret = -EMSGSIZE; ret = -EMSGSIZE;
goto out; goto out;
call_complete: call_failed:
*_abort = call->abort_code; *_abort = call->abort_code;
ret = call->error; ret = call->error;
if (call->completion == RXRPC_CALL_SUCCEEDED) { if (call->completion == RXRPC_CALL_SUCCEEDED) {
......
此差异已折叠。
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/af_rxrpc.h> #include <net/af_rxrpc.h>
#define RXRPC_TRACE_ONLY_DEFINE_ENUMS
#include <trace/events/rxrpc.h>
MODULE_DESCRIPTION("rxperf test server (afs)"); MODULE_DESCRIPTION("rxperf test server (afs)");
MODULE_AUTHOR("Red Hat, Inc."); MODULE_AUTHOR("Red Hat, Inc.");
...@@ -307,12 +309,14 @@ static void rxperf_deliver_to_call(struct work_struct *work) ...@@ -307,12 +309,14 @@ static void rxperf_deliver_to_call(struct work_struct *work)
case -EOPNOTSUPP: case -EOPNOTSUPP:
abort_code = RXGEN_OPCODE; abort_code = RXGEN_OPCODE;
rxrpc_kernel_abort_call(rxperf_socket, call->rxcall, rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
abort_code, ret, "GOP"); abort_code, ret,
rxperf_abort_op_not_supported);
goto call_complete; goto call_complete;
case -ENOTSUPP: case -ENOTSUPP:
abort_code = RX_USER_ABORT; abort_code = RX_USER_ABORT;
rxrpc_kernel_abort_call(rxperf_socket, call->rxcall, rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
abort_code, ret, "GUA"); abort_code, ret,
rxperf_abort_op_not_supported);
goto call_complete; goto call_complete;
case -EIO: case -EIO:
pr_err("Call %u in bad state %u\n", pr_err("Call %u in bad state %u\n",
...@@ -324,11 +328,13 @@ static void rxperf_deliver_to_call(struct work_struct *work) ...@@ -324,11 +328,13 @@ static void rxperf_deliver_to_call(struct work_struct *work)
case -ENOMEM: case -ENOMEM:
case -EFAULT: case -EFAULT:
rxrpc_kernel_abort_call(rxperf_socket, call->rxcall, rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
RXGEN_SS_UNMARSHAL, ret, "GUM"); RXGEN_SS_UNMARSHAL, ret,
rxperf_abort_unmarshal_error);
goto call_complete; goto call_complete;
default: default:
rxrpc_kernel_abort_call(rxperf_socket, call->rxcall, rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
RX_CALL_DEAD, ret, "GER"); RX_CALL_DEAD, ret,
rxperf_abort_general_error);
goto call_complete; goto call_complete;
} }
} }
...@@ -523,7 +529,8 @@ static int rxperf_process_call(struct rxperf_call *call) ...@@ -523,7 +529,8 @@ static int rxperf_process_call(struct rxperf_call *call)
if (n == -ENOMEM) if (n == -ENOMEM)
rxrpc_kernel_abort_call(rxperf_socket, call->rxcall, rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
RXGEN_SS_MARSHAL, -ENOMEM, "GOM"); RXGEN_SS_MARSHAL, -ENOMEM,
rxperf_abort_oom);
return n; return n;
} }
......
...@@ -97,38 +97,31 @@ int rxrpc_init_client_call_security(struct rxrpc_call *call) ...@@ -97,38 +97,31 @@ int rxrpc_init_client_call_security(struct rxrpc_call *call)
*/ */
int rxrpc_init_client_conn_security(struct rxrpc_connection *conn) int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
{ {
const struct rxrpc_security *sec;
struct rxrpc_key_token *token; struct rxrpc_key_token *token;
struct key *key = conn->key; struct key *key = conn->key;
int ret; int ret = 0;
_enter("{%d},{%x}", conn->debug_id, key_serial(key)); _enter("{%d},{%x}", conn->debug_id, key_serial(key));
if (!key)
return 0;
ret = key_validate(key);
if (ret < 0)
return ret;
for (token = key->payload.data[0]; token; token = token->next) { for (token = key->payload.data[0]; token; token = token->next) {
sec = rxrpc_security_lookup(token->security_index); if (token->security_index == conn->security->security_index)
if (sec)
goto found; goto found;
} }
return -EKEYREJECTED; return -EKEYREJECTED;
found: found:
conn->security = sec; mutex_lock(&conn->security_lock);
if (conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
ret = conn->security->init_connection_security(conn, token); ret = conn->security->init_connection_security(conn, token);
if (ret < 0) { if (ret == 0) {
conn->security = &rxrpc_no_security; spin_lock(&conn->state_lock);
return ret; if (conn->state == RXRPC_CONN_CLIENT_UNSECURED)
conn->state = RXRPC_CONN_CLIENT;
spin_unlock(&conn->state_lock);
}
} }
mutex_unlock(&conn->security_lock);
_leave(" = 0"); return ret;
return 0;
} }
/* /*
...@@ -144,21 +137,15 @@ const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *rx, ...@@ -144,21 +137,15 @@ const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *rx,
sec = rxrpc_security_lookup(sp->hdr.securityIndex); sec = rxrpc_security_lookup(sp->hdr.securityIndex);
if (!sec) { if (!sec) {
trace_rxrpc_abort(0, "SVS", rxrpc_direct_abort(skb, rxrpc_abort_unsupported_security,
sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, RX_INVALID_OPERATION, -EKEYREJECTED);
RX_INVALID_OPERATION, EKEYREJECTED);
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
skb->priority = RX_INVALID_OPERATION;
return NULL; return NULL;
} }
if (sp->hdr.securityIndex != RXRPC_SECURITY_NONE && if (sp->hdr.securityIndex != RXRPC_SECURITY_NONE &&
!rx->securities) { !rx->securities) {
trace_rxrpc_abort(0, "SVR", rxrpc_direct_abort(skb, rxrpc_abort_no_service_key,
sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, sec->no_key_abort, -EKEYREJECTED);
RX_INVALID_OPERATION, EKEYREJECTED);
skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
skb->priority = sec->no_key_abort;
return NULL; return NULL;
} }
...@@ -191,9 +178,9 @@ struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn, ...@@ -191,9 +178,9 @@ struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn,
sprintf(kdesc, "%u:%u", sprintf(kdesc, "%u:%u",
sp->hdr.serviceId, sp->hdr.securityIndex); sp->hdr.serviceId, sp->hdr.securityIndex);
rcu_read_lock(); read_lock(&conn->local->services_lock);
rx = rcu_dereference(conn->local->service); rx = conn->local->service;
if (!rx) if (!rx)
goto out; goto out;
...@@ -215,6 +202,6 @@ struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn, ...@@ -215,6 +202,6 @@ struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn,
} }
out: out:
rcu_read_unlock(); read_unlock(&conn->local->services_lock);
return key; return key;
} }
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册