AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/11 16:41 flow patch-triage
1m Args:
null

Results:
{
  "EnableConfigs": [
    "AF_RXRPC",
    "RXGK",
    "AFS_FS"
  ],
  "FocusSymbols": [
    "afs_create_server_appdata",
    "afs_create_yfs_rxgk_cm_appdata",
    "rxgk_respond_to_challenge",
    "rxrpc_sendmsg_cmsg",
    "put_user_key_payload"
  ],
  "Reasoning": "The patch series refactors out-of-band message handling in rxrpc, replacing it with a key-based approach for passing application data in RxGK responses. It also modifies AFS to use this new mechanism by creating a key containing the app data and passing it to rxrpc_kernel_begin_call. These are functional changes to core rxrpc and AFS logic that should be fuzzed to ensure the new key-based app data handling and challenge-response mechanisms work correctly.",
  "WorthFuzzing": true
}

1/1 2026/07/11 16:41 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit e670920210e13fe875f0ff4ecd3e4a5223bc1f0e\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Jul 11 16:41:14 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/fs/afs/cm_security.c b/fs/afs/cm_security.c\nindex 103168c70dd4df..f0fec3a7652288 100644\n--- a/fs/afs/cm_security.c\n+++ b/fs/afs/cm_security.c\n@@ -6,7 +6,9 @@\n  */\n \n #include \u003clinux/slab.h\u003e\n+#include \u003clinux/key-type.h\u003e\n #include \u003ccrypto/krb5.h\u003e\n+#include \u003ckeys/user-type.h\u003e\n #include \"internal.h\"\n #include \"afs_cm.h\"\n #include \"afs_fs.h\"\n@@ -19,195 +21,39 @@\n #define xdr_len_object(x) (4 + round_up((x), sizeof(__be32)))\n \n #ifdef CONFIG_RXGK\n-static int afs_create_yfs_cm_token(struct sk_buff *challenge,\n-\t\t\t\t   struct afs_server *server);\n-#endif\n-\n /*\n- * Respond to an RxGK challenge, adding appdata.\n+ * As the YFS RxGK appdata to be passed in the YFS.FS-service RESPONSE packet,\n+ * create a GSS token to use as a ticket to the specified fileserver.\n  */\n-static int afs_respond_to_challenge(struct sk_buff *challenge)\n-{\n-#ifdef CONFIG_RXGK\n-\tstruct krb5_buffer appdata = {};\n-\tstruct afs_server *server;\n-#endif\n-\tstruct rxrpc_peer *peer;\n-\tunsigned long peer_data;\n-\tu16 service_id;\n-\tu8 security_index;\n-\n-\trxrpc_kernel_query_challenge(challenge, \u0026peer, \u0026peer_data,\n-\t\t\t\t     \u0026service_id, \u0026security_index);\n-\n-\t_enter(\"%u,%u\", service_id, security_index);\n-\n-\tswitch (service_id) {\n-\t\t/* We don't send CM_SERVICE RPCs, so don't expect a challenge\n-\t\t * therefrom.\n-\t\t */\n-\tcase FS_SERVICE:\n-\tcase VL_SERVICE:\n-\tcase YFS_FS_SERVICE:\n-\tcase YFS_VL_SERVICE:\n-\t\tbreak;\n-\tdefault:\n-\t\tpr_warn(\"Can't respond to unknown challenge %u:%u\",\n-\t\t\tservice_id, security_index);\n-\t\treturn rxrpc_kernel_reject_challenge(challenge, RX_USER_ABORT, -EPROTO,\n-\t\t\t\t\t\t     afs_abort_unsupported_sec_class);\n-\t}\n-\n-\tswitch (security_index) {\n-#ifdef CONFIG_RXKAD\n-\tcase RXRPC_SECURITY_RXKAD:\n-\t\treturn rxkad_kernel_respond_to_challenge(challenge);\n-#endif\n-\n-#ifdef CONFIG_RXGK\n-\tcase RXRPC_SECURITY_RXGK:\n-\t\treturn rxgk_kernel_respond_to_challenge(challenge, \u0026appdata);\n-\n-\tcase RXRPC_SECURITY_YFS_RXGK:\n-\t\tswitch (service_id) {\n-\t\tcase FS_SERVICE:\n-\t\tcase YFS_FS_SERVICE:\n-\t\t\tserver = (struct afs_server *)peer_data;\n-\t\t\tif (!server-\u003ecm_rxgk_appdata.data) {\n-\t\t\t\tmutex_lock(\u0026server-\u003ecm_token_lock);\n-\t\t\t\tif (!server-\u003ecm_rxgk_appdata.data)\n-\t\t\t\t\tafs_create_yfs_cm_token(challenge, server);\n-\t\t\t\tmutex_unlock(\u0026server-\u003ecm_token_lock);\n-\t\t\t}\n-\t\t\tif (server-\u003ecm_rxgk_appdata.data)\n-\t\t\t\tappdata = server-\u003ecm_rxgk_appdata;\n-\t\t\tbreak;\n-\t\t}\n-\t\treturn rxgk_kernel_respond_to_challenge(challenge, \u0026appdata);\n-#endif\n-\n-\tdefault:\n-\t\treturn rxrpc_kernel_reject_challenge(challenge, RX_USER_ABORT, -EPROTO,\n-\t\t\t\t\t\t     afs_abort_unsupported_sec_class);\n-\t}\n-}\n-\n-/*\n- * Process the OOB message queue, processing challenge packets.\n- */\n-void afs_process_oob_queue(struct work_struct *work)\n-{\n-\tstruct afs_net *net = container_of(work, struct afs_net, rx_oob_work);\n-\tstruct sk_buff *oob;\n-\tenum rxrpc_oob_type type;\n-\n-\twhile (READ_ONCE(net-\u003elive) \u0026\u0026\n-\t       (oob = rxrpc_kernel_dequeue_oob(net-\u003esocket, \u0026type))) {\n-\t\tswitch (type) {\n-\t\tcase RXRPC_OOB_CHALLENGE:\n-\t\t\tafs_respond_to_challenge(oob);\n-\t\t\tbreak;\n-\t\t}\n-\t\trxrpc_kernel_free_oob(oob);\n-\t}\n-}\n-\n-#ifdef CONFIG_RXGK\n-/*\n- * Create a securities keyring for the cache manager and attach a key to it for\n- * the RxGK tokens we want to use to secure the callback connection back from\n- * the fileserver.\n- */\n-int afs_create_token_key(struct afs_net *net, struct socket *socket)\n-{\n-\tconst struct krb5_enctype *krb5;\n-\tstruct key *ring;\n-\tkey_ref_t key;\n-\tchar K0[32], *desc;\n-\tint ret;\n-\n-\tring = keyring_alloc(\"kafs\",\n-\t\t\t     GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),\n-\t\t\t     KEY_POS_SEARCH | KEY_POS_WRITE |\n-\t\t\t     KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH,\n-\t\t\t     KEY_ALLOC_NOT_IN_QUOTA,\n-\t\t\t     NULL, NULL);\n-\tif (IS_ERR(ring))\n-\t\treturn PTR_ERR(ring);\n-\n-\tret = rxrpc_sock_set_security_keyring(socket-\u003esk, ring);\n-\tif (ret \u003c 0)\n-\t\tgoto out;\n-\n-\tret = -ENOPKG;\n-\tkrb5 = crypto_krb5_find_enctype(KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96);\n-\tif (!krb5)\n-\t\tgoto out;\n-\n-\tif (WARN_ON_ONCE(krb5-\u003ekey_len \u003e sizeof(K0)))\n-\t\tgoto out;\n-\n-\tret = -ENOMEM;\n-\tdesc = kasprintf(GFP_KERNEL, \"%u:%u:%u:%u\",\n-\t\t\t YFS_CM_SERVICE, RXRPC_SECURITY_YFS_RXGK, 1, krb5-\u003eetype);\n-\tif (!desc)\n-\t\tgoto out;\n-\n-\twait_for_random_bytes();\n-\tget_random_bytes(K0, krb5-\u003ekey_len);\n-\n-\tkey = key_create(make_key_ref(ring, true),\n-\t\t\t \"rxrpc_s\", desc,\n-\t\t\t K0, krb5-\u003ekey_len,\n-\t\t\t KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_USR_VIEW,\n-\t\t\t KEY_ALLOC_NOT_IN_QUOTA);\n-\tkfree(desc);\n-\tif (IS_ERR(key)) {\n-\t\tret = PTR_ERR(key);\n-\t\tgoto out;\n-\t}\n-\n-\tnet-\u003efs_cm_token_key = key_ref_to_ptr(key);\n-\tret = 0;\n-out:\n-\tkey_put(ring);\n-\treturn ret;\n-}\n-\n-/*\n- * Create an YFS RxGK GSS token to use as a ticket to the specified fileserver.\n- */\n-static int afs_create_yfs_cm_token(struct sk_buff *challenge,\n-\t\t\t\t   struct afs_server *server)\n+static int afs_create_yfs_rxgk_cm_appdata(struct afs_server *server, u32 enctype)\n {\n \tconst struct krb5_enctype *conn_krb5, *token_krb5;\n \tconst struct krb5_buffer *token_key;\n \tstruct crypto_aead *aead;\n \tstruct scatterlist sg;\n \tstruct afs_net *net = server-\u003ecell-\u003enet;\n-\tconst struct key *key = net-\u003efs_cm_token_key;\n-\tsize_t keysize, uuidsize, authsize, toksize, encsize, contsize, adatasize, offset;\n+\tconst struct key *cm_key = net-\u003efs_cm_token_key;\n+\tstruct key *appdata_key = NULL;\n+\tsize_t keysize, uuidsize, authsize, toksize, encsize, contsize;\n+\tsize_t adatasize, offset;\n \t__be32 caps[1] = {\n \t\t[0] = htonl(AFS_CAP_ERROR_TRANSLATION),\n \t};\n \t__be32 *xdr;\n \tvoid *appdata, *K0, *encbase;\n-\tu32 enctype;\n \tint ret;\n \n-\tif (!key)\n+\tif (!cm_key)\n \t\treturn -ENOKEY;\n \n \t/* Assume that the fileserver is happy to use the same encoding type as\n \t * we were told to use by the token obtained by the user.\n \t */\n-\tenctype = rxgk_kernel_query_challenge(challenge);\n-\n \tconn_krb5 = crypto_krb5_find_enctype(enctype);\n \tif (!conn_krb5)\n \t\treturn -ENOPKG;\n-\ttoken_krb5 = key-\u003epayload.data[0];\n-\ttoken_key = (const struct krb5_buffer *)\u0026key-\u003epayload.data[2];\n+\ttoken_krb5 = cm_key-\u003epayload.data[0];\n+\ttoken_key = (const struct krb5_buffer *)\u0026cm_key-\u003epayload.data[2];\n \n \t/* struct rxgk_key {\n \t *\tafs_uint32\tenctype;\n@@ -327,9 +173,23 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,\n \tif (ret \u003c 0)\n \t\tgoto out_aead;\n \n-\tserver-\u003ecm_rxgk_appdata.len  = adatasize;\n-\tserver-\u003ecm_rxgk_appdata.data = appdata;\n-\tappdata = NULL;\n+\tappdata_key = key_alloc(\u0026key_type_user, \"rxrpc: afs rxgk appdata\",\n+\t\t\t\tGLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),\n+\t\t\t\tKEY_POS_VIEW | KEY_POS_SEARCH | KEY_USR_VIEW,\n+\t\t\t\tKEY_ALLOC_NOT_IN_QUOTA, NULL);\n+\tif (IS_ERR(appdata_key)) {\n+\t\tret = PTR_ERR(appdata_key);\n+\t\tgoto out_aead;\n+\t}\n+\n+\tret = key_instantiate_and_link(appdata_key, appdata, adatasize, NULL, NULL);\n+\tif (ret \u003c 0) {\n+\t\tkey_put(appdata_key);\n+\t\tgoto out_aead;\n+\t}\n+\n+\t/* Store the appdata before the key pointer */\n+\tsmp_store_release(\u0026server-\u003eyfs_rxgk_appdata, appdata_key);\n \n out_aead:\n \tcrypto_free_aead(aead);\n@@ -339,3 +199,116 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,\n \treturn ret;\n }\n #endif /* CONFIG_RXGK */\n+\n+/*\n+ * Create the application data to go in a RESPONSE packet a server's CHALLENGE\n+ * from the parameters contained in a key.  The key specifies the security\n+ * index and other appropriate parameters such as the encoding type for RxGK.\n+ */\n+int afs_create_server_appdata(struct afs_server *server, struct key *key)\n+{\n+\tu32 krb5_enctype;\n+\tint ret;\n+\tu8 security_index;\n+\n+\tif (!key)\n+\t\treturn 0;\n+\n+\trxrpc_kernel_query_key(key, \u0026security_index, \u0026krb5_enctype);\n+\n+\t_enter(\"%u,%u\", security_index, krb5_enctype);\n+\n+\tswitch (security_index) {\n+#ifdef CONFIG_RXGK\n+\tcase RXRPC_SECURITY_YFS_RXGK:\n+\t\t/* Read the key pointer before the appdata */\n+\t\tif (smp_load_acquire(\u0026server-\u003eyfs_rxgk_appdata))\n+\t\t\treturn 0;\n+\t\tbreak;\n+#endif\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+\n+\tret = 0;\n+\tmutex_lock(\u0026server-\u003ecm_token_lock);\n+\n+\tswitch (security_index) {\n+#ifdef CONFIG_RXGK\n+\tcase RXRPC_SECURITY_YFS_RXGK:\n+\t\t/* Read the key pointer before the appdata */\n+\t\tif (smp_load_acquire(\u0026server-\u003eyfs_rxgk_appdata))\n+\t\t\tbreak;\n+\t\tret = afs_create_yfs_rxgk_cm_appdata(server, krb5_enctype);\n+\t\tbreak;\n+#endif\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tmutex_unlock(\u0026server-\u003ecm_token_lock);\n+\treturn ret;\n+}\n+\n+#ifdef CONFIG_RXGK\n+/*\n+ * Create a securities keyring for the cache manager and attach a key to it for\n+ * the RxGK tokens we want to use to secure the callback connection back from\n+ * the fileserver.\n+ */\n+int afs_create_token_key(struct afs_net *net, struct socket *socket)\n+{\n+\tconst struct krb5_enctype *krb5;\n+\tstruct key *ring;\n+\tkey_ref_t key;\n+\tchar K0[32], *desc;\n+\tint ret;\n+\n+\tring = keyring_alloc(\"kafs\",\n+\t\t\t     GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),\n+\t\t\t     KEY_POS_SEARCH | KEY_POS_WRITE |\n+\t\t\t     KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH,\n+\t\t\t     KEY_ALLOC_NOT_IN_QUOTA,\n+\t\t\t     NULL, NULL);\n+\tif (IS_ERR(ring))\n+\t\treturn PTR_ERR(ring);\n+\n+\tret = rxrpc_sock_set_security_keyring(socket-\u003esk, ring);\n+\tif (ret \u003c 0)\n+\t\tgoto out;\n+\n+\tret = -ENOPKG;\n+\tkrb5 = crypto_krb5_find_enctype(KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96);\n+\tif (!krb5)\n+\t\tgoto out;\n+\n+\tif (WARN_ON_ONCE(krb5-\u003ekey_len \u003e sizeof(K0)))\n+\t\tgoto out;\n+\n+\tret = -ENOMEM;\n+\tdesc = kasprintf(GFP_KERNEL, \"%u:%u:%u:%u\",\n+\t\t\t YFS_CM_SERVICE, RXRPC_SECURITY_YFS_RXGK, 1, krb5-\u003eetype);\n+\tif (!desc)\n+\t\tgoto out;\n+\n+\twait_for_random_bytes();\n+\tget_random_bytes(K0, krb5-\u003ekey_len);\n+\n+\tkey = key_create(make_key_ref(ring, true),\n+\t\t\t \"rxrpc_s\", desc,\n+\t\t\t K0, krb5-\u003ekey_len,\n+\t\t\t KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_USR_VIEW,\n+\t\t\t KEY_ALLOC_NOT_IN_QUOTA);\n+\tkfree(desc);\n+\tif (IS_ERR(key)) {\n+\t\tret = PTR_ERR(key);\n+\t\tgoto out;\n+\t}\n+\n+\tnet-\u003efs_cm_token_key = key_ref_to_ptr(key);\n+\tret = 0;\n+out:\n+\tkey_put(ring);\n+\treturn ret;\n+}\n+#endif /* CONFIG_RXGK */\ndiff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c\nindex 5540ae1cad599a..f92bddd4f1e9af 100644\n--- a/fs/afs/cmservice.c\n+++ b/fs/afs/cmservice.c\n@@ -23,11 +23,11 @@ static int afs_deliver_cb_callback(struct afs_call *);\n static int afs_deliver_cb_probe_uuid(struct afs_call *);\n static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *);\n static void afs_cm_destructor(struct afs_call *);\n-static void SRXAFSCB_CallBack(struct work_struct *);\n-static void SRXAFSCB_InitCallBackState(struct work_struct *);\n-static void SRXAFSCB_Probe(struct work_struct *);\n-static void SRXAFSCB_ProbeUuid(struct work_struct *);\n-static void SRXAFSCB_TellMeAboutYourself(struct work_struct *);\n+static void SRXAFSCB_CallBack(struct afs_call *call);\n+static void SRXAFSCB_InitCallBackState(struct afs_call *call);\n+static void SRXAFSCB_Probe(struct afs_call *call);\n+static void SRXAFSCB_ProbeUuid(struct afs_call *call);\n+static void SRXAFSCB_TellMeAboutYourself(struct afs_call *call);\n \n static int afs_deliver_yfs_cb_callback(struct afs_call *);\n \n@@ -161,10 +161,8 @@ static void afs_abort_service_call(struct afs_call *call, u32 abort_code, int er\n /*\n  * The server supplied a list of callbacks that it wanted to break.\n  */\n-static void SRXAFSCB_CallBack(struct work_struct *work)\n+static void SRXAFSCB_CallBack(struct afs_call *call)\n {\n-\tstruct afs_call *call = container_of(work, struct afs_call, work);\n-\n \t_enter(\"\");\n \n \t/* We need to break the callbacks before sending the reply as the\n@@ -180,7 +178,6 @@ static void SRXAFSCB_CallBack(struct work_struct *work)\n \t}\n \n \tafs_send_empty_reply(call);\n-\tafs_put_call(call);\n \t_leave(\"\");\n }\n \n@@ -284,16 +281,13 @@ static int afs_deliver_cb_callback(struct afs_call *call)\n /*\n  * allow the fileserver to request callback state (re-)initialisation\n  */\n-static void SRXAFSCB_InitCallBackState(struct work_struct *work)\n+static void SRXAFSCB_InitCallBackState(struct afs_call *call)\n {\n-\tstruct afs_call *call = container_of(work, struct afs_call, work);\n-\n \t_enter(\"{%p}\", call-\u003eserver);\n \n \tif (call-\u003eserver)\n \t\tafs_init_callback_state(call-\u003eserver);\n \tafs_send_empty_reply(call);\n-\tafs_put_call(call);\n \t_leave(\"\");\n }\n \n@@ -332,11 +326,8 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)\n \tcase 1:\n \t\t_debug(\"extract UUID\");\n \t\tret = afs_extract_data(call, false);\n-\t\tswitch (ret) {\n-\t\tcase 0:\t\tbreak;\n-\t\tcase -EAGAIN:\treturn 0;\n-\t\tdefault:\treturn ret;\n-\t\t}\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n \n \t\t_debug(\"unmarshall UUID\");\n \t\tcall-\u003erequest = kmalloc_obj(struct afs_uuid);\n@@ -364,7 +355,8 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)\n \tif (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))\n \t\treturn afs_io_error(call, afs_io_error_cm_reply);\n \n-\tif (memcmp(call-\u003erequest, \u0026call-\u003eserver-\u003e_uuid, sizeof(call-\u003eserver-\u003e_uuid)) != 0) {\n+\tif (call-\u003eserver \u0026\u0026\n+\t    memcmp(call-\u003erequest, \u0026call-\u003eserver-\u003e_uuid, sizeof(call-\u003eserver-\u003e_uuid)) != 0) {\n \t\tpr_notice(\"Callback UUID does not match fileserver UUID\\n\");\n \t\ttrace_afs_cm_no_server_u(call, call-\u003erequest);\n \t\treturn 0;\n@@ -376,13 +368,10 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)\n /*\n  * allow the fileserver to see if the cache manager is still alive\n  */\n-static void SRXAFSCB_Probe(struct work_struct *work)\n+static void SRXAFSCB_Probe(struct afs_call *call)\n {\n-\tstruct afs_call *call = container_of(work, struct afs_call, work);\n-\n \t_enter(\"\");\n \tafs_send_empty_reply(call);\n-\tafs_put_call(call);\n \t_leave(\"\");\n }\n \n@@ -409,9 +398,8 @@ static int afs_deliver_cb_probe(struct afs_call *call)\n  * Allow the fileserver to quickly find out if the cache manager has been\n  * rebooted.\n  */\n-static void SRXAFSCB_ProbeUuid(struct work_struct *work)\n+static void SRXAFSCB_ProbeUuid(struct afs_call *call)\n {\n-\tstruct afs_call *call = container_of(work, struct afs_call, work);\n \tstruct afs_uuid *r = call-\u003erequest;\n \n \t_enter(\"\");\n@@ -421,7 +409,6 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work)\n \telse\n \t\tafs_abort_service_call(call, 1, 1, afs_abort_probeuuid_negative);\n \n-\tafs_put_call(call);\n \t_leave(\"\");\n }\n \n@@ -449,11 +436,8 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)\n \tcase 1:\n \t\t_debug(\"extract UUID\");\n \t\tret = afs_extract_data(call, false);\n-\t\tswitch (ret) {\n-\t\tcase 0:\t\tbreak;\n-\t\tcase -EAGAIN:\treturn 0;\n-\t\tdefault:\treturn ret;\n-\t\t}\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n \n \t\t_debug(\"unmarshall UUID\");\n \t\tcall-\u003erequest = kmalloc_obj(struct afs_uuid);\n@@ -486,9 +470,8 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)\n /*\n  * allow the fileserver to ask about the cache manager's capabilities\n  */\n-static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)\n+static void SRXAFSCB_TellMeAboutYourself(struct afs_call *call)\n {\n-\tstruct afs_call *call = container_of(work, struct afs_call, work);\n \tint loop;\n \n \tstruct {\n@@ -520,7 +503,6 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)\n \treply.cap.capcount = htonl(1);\n \treply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);\n \tafs_send_simple_reply(call, \u0026reply, sizeof(reply));\n-\tafs_put_call(call);\n \t_leave(\"\");\n }\n \ndiff --git a/fs/afs/file.c b/fs/afs/file.c\nindex 0467742bfeee34..625dc67f79f366 100644\n--- a/fs/afs/file.c\n+++ b/fs/afs/file.c\n@@ -298,7 +298,7 @@ static void afs_read_receive(struct afs_call *call)\n \top-\u003ecall_responded\t= call-\u003eresponded;\n \top-\u003ecall\t\t= NULL;\n \tcall-\u003eop\t\t= NULL;\n-\tafs_put_call(call);\n+\tafs_put_call(call, afs_call_trace_put_read_op);\n \n \t/* If the call failed, then we need to crank the server rotation\n \t * handle and try the next.\n@@ -316,15 +316,17 @@ void afs_fetch_data_async_rx(struct work_struct *work)\n \tstruct afs_call *call = container_of(work, struct afs_call, async_work);\n \n \tafs_read_receive(call);\n-\tafs_put_call(call);\n+\n+\tif (call-\u003estate == AFS_CALL_COMPLETE) {\n+\t\tcancel_work(\u0026call-\u003easync_work);\n+\t\tafs_put_call(call, afs_call_trace_put_read_complete);\n+\t}\n }\n \n void afs_fetch_data_immediate_cancel(struct afs_call *call)\n {\n \tif (call-\u003easync) {\n-\t\tafs_get_call(call, afs_call_trace_wake);\n-\t\tif (!queue_work(afs_async_calls, \u0026call-\u003easync_work))\n-\t\t\tafs_deferred_put_call(call);\n+\t\tqueue_work(afs_async_calls, \u0026call-\u003easync_work);\n \t\tflush_work(\u0026call-\u003easync_work);\n \t}\n }\ndiff --git a/fs/afs/fs_operation.c b/fs/afs/fs_operation.c\nindex c0dbbc6d3716e0..9ea9db256a41ab 100644\n--- a/fs/afs/fs_operation.c\n+++ b/fs/afs/fs_operation.c\n@@ -296,7 +296,7 @@ void afs_wait_for_operation(struct afs_operation *op)\n \t\t\top-\u003ecall_abort_code = op-\u003ecall-\u003eabort_code;\n \t\t\top-\u003ecall_error = op-\u003ecall-\u003eerror;\n \t\t\top-\u003ecall_responded = op-\u003ecall-\u003eresponded;\n-\t\t\tafs_put_call(op-\u003ecall);\n+\t\t\tafs_put_call(op-\u003ecall, afs_call_trace_put_wait_op);\n \t\t}\n \t}\n \ndiff --git a/fs/afs/fs_probe.c b/fs/afs/fs_probe.c\nindex a91ad1938d0788..e26f7f1e30a23a 100644\n--- a/fs/afs/fs_probe.c\n+++ b/fs/afs/fs_probe.c\n@@ -241,9 +241,14 @@ int afs_fs_probe_fileserver(struct afs_net *net, struct afs_server *server,\n \tstruct afs_endpoint_state *estate, *old;\n \tstruct afs_addr_list *old_alist = NULL, *alist;\n \tunsigned long unprobed;\n+\tint ret;\n \n \t_enter(\"%pU\", \u0026server-\u003euuid);\n \n+\tret = afs_create_server_appdata(server, key);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n \testate = kzalloc_obj(*estate);\n \tif (!estate)\n \t\treturn -ENOMEM;\ndiff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c\nindex a2ffd60889f89d..9acad5017fbab3 100644\n--- a/fs/afs/fsclient.c\n+++ b/fs/afs/fsclient.c\n@@ -477,6 +477,9 @@ void afs_fs_fetch_data(struct afs_operation *op)\n \tif (!call)\n \t\treturn afs_op_nomem(op);\n \n+\tif (op-\u003eflags \u0026 AFS_OPERATION_ASYNC)\n+\t\tcall-\u003easync = true;\n+\n \t/* marshall the parameters */\n \tbp = call-\u003erequest;\n \tbp[0] = htonl(FSFETCHDATA);\n@@ -1659,7 +1662,7 @@ int afs_fs_give_up_all_callbacks(struct afs_net *net, struct afs_server *server,\n \tret = call-\u003eerror;\n \tif (call-\u003eresponded)\n \t\tset_bit(AFS_SERVER_FL_RESPONDING, \u0026server-\u003eflags);\n-\tafs_put_call(call);\n+\tafs_put_call(call, afs_call_trace_put_giveupcallbacks);\n \treturn ret;\n }\n \n@@ -1775,7 +1778,7 @@ bool afs_fs_get_capabilities(struct afs_net *net, struct afs_server *server,\n \n \ttrace_afs_make_fs_call(call, NULL);\n \tafs_make_call(call, GFP_NOFS);\n-\tafs_put_call(call);\n+\tafs_put_call(call, afs_call_trace_put_get_capabilities);\n \treturn true;\n }\n \ndiff --git a/fs/afs/internal.h b/fs/afs/internal.h\nindex 0b72a856629992..3d0193ea255b62 100644\n--- a/fs/afs/internal.h\n+++ b/fs/afs/internal.h\n@@ -129,7 +129,7 @@ struct afs_call {\n \tconst struct afs_call_type *type;\t/* type of call */\n \twait_queue_head_t\twaitq;\t\t/* processes awaiting completion */\n \tstruct work_struct\tasync_work;\t/* async I/O processor */\n-\tstruct work_struct\twork;\t\t/* actual work processor */\n+\tvoid (*work)(struct afs_call *call);\t/* Worker function */\n \tstruct work_struct\tfree_work;\t/* Deferred free processor */\n \tstruct rxrpc_call\t*rxcall;\t/* RxRPC call handle */\n \tstruct rxrpc_peer\t*peer;\t\t/* Remote endpoint */\n@@ -169,7 +169,6 @@ struct afs_call {\n \tunsigned\t\treply_max;\t/* maximum size of reply */\n \tunsigned\t\tcount2;\t\t/* count used in unmarshalling */\n \tunsigned char\t\tunmarshall;\t/* unmarshalling phase */\n-\tbool\t\t\tdrop_ref;\t/* T if need to drop ref for incoming call */\n \tbool\t\t\tneed_attention;\t/* T if RxRPC poked us */\n \tbool\t\t\tasync;\t\t/* T if asynchronous */\n \tbool\t\t\tupgrade;\t/* T to request service upgrade */\n@@ -208,7 +207,7 @@ struct afs_call_type {\n \tvoid (*async_rx)(struct work_struct *work);\n \n \t/* Work function */\n-\tvoid (*work)(struct work_struct *work);\n+\tvoid (*work)(struct afs_call *call);\n \n \t/* Call done function (gets called immediately on success or failure) */\n \tvoid (*done)(struct afs_call *call);\n@@ -283,7 +282,6 @@ struct afs_net {\n \tstruct socket\t\t*socket;\n \tstruct afs_call\t\t*spare_incoming_call;\n \tstruct work_struct\tcharge_preallocation_work;\n-\tstruct work_struct\trx_oob_work;\n \tstruct mutex\t\tsocket_mutex;\n \tatomic_t\t\tnr_outstanding_calls;\n \tatomic_t\t\tnr_superblocks;\n@@ -547,7 +545,7 @@ struct afs_server {\n \tstruct work_struct\tdestroyer;\t/* Work item to try and destroy a server */\n \tstruct timer_list\ttimer;\t\t/* Management timer */\n \tstruct mutex\t\tcm_token_lock;\t/* Lock governing creation of appdata */\n-\tstruct krb5_buffer\tcm_rxgk_appdata; /* Appdata to be included in RESPONSE packet */\n+\tstruct key\t\t*yfs_rxgk_appdata; /* Appdata to be included in RESPONSE packet */\n \ttime64_t\t\tunuse_time;\t/* Time at which last unused */\n \tunsigned long\t\tflags;\n #define AFS_SERVER_FL_RESPONDING 0\t\t/* The server is responding */\n@@ -1090,7 +1088,7 @@ extern bool afs_cm_incoming_call(struct afs_call *);\n /*\n  * cm_security.c\n  */\n-void afs_process_oob_queue(struct work_struct *work);\n+int afs_create_server_appdata(struct afs_server *server, struct key *key);\n #ifdef CONFIG_RXGK\n int afs_create_token_key(struct afs_net *net, struct socket *socket);\n #else\n@@ -1381,8 +1379,7 @@ extern struct workqueue_struct *afs_async_calls;\n extern int __net_init afs_open_socket(struct afs_net *);\n extern void __net_exit afs_close_socket(struct afs_net *);\n extern void afs_charge_preallocation(struct work_struct *);\n-extern void afs_put_call(struct afs_call *);\n-void afs_deferred_put_call(struct afs_call *call);\n+void afs_put_call(struct afs_call *call, enum afs_call_trace trace);\n void afs_make_call(struct afs_call *call, gfp_t gfp);\n void afs_deliver_to_call(struct afs_call *call);\n void afs_wait_for_call_to_complete(struct afs_call *call);\n@@ -1403,8 +1400,7 @@ static inline struct afs_call *afs_get_call(struct afs_call *call,\n \t__refcount_inc(\u0026call-\u003eref, \u0026r);\n \n \ttrace_afs_call(call-\u003edebug_id, why, r + 1,\n-\t\t       atomic_read(\u0026call-\u003enet-\u003enr_outstanding_calls),\n-\t\t       __builtin_return_address(0));\n+\t\t       atomic_read(\u0026call-\u003enet-\u003enr_outstanding_calls));\n \treturn call;\n }\n \n@@ -1413,23 +1409,7 @@ static inline void afs_see_call(struct afs_call *call, enum afs_call_trace why)\n \tint r = refcount_read(\u0026call-\u003eref);\n \n \ttrace_afs_call(call-\u003edebug_id, why, r,\n-\t\t       atomic_read(\u0026call-\u003enet-\u003enr_outstanding_calls),\n-\t\t       __builtin_return_address(0));\n-}\n-\n-static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,\n-\t\t\t\t    gfp_t gfp)\n-{\n-\tstruct afs_addr_list *alist = op-\u003eestate-\u003eaddresses;\n-\n-\top-\u003ecall\t= call;\n-\top-\u003etype\t= call-\u003etype;\n-\tcall-\u003eop\t= op;\n-\tcall-\u003ekey\t= op-\u003ekey;\n-\tcall-\u003eintr\t= !(op-\u003eflags \u0026 AFS_OPERATION_UNINTR);\n-\tcall-\u003epeer\t= rxrpc_kernel_get_peer(alist-\u003eaddrs[op-\u003eaddr_index].peer);\n-\tcall-\u003eservice_id = op-\u003eserver-\u003eservice_id;\n-\tafs_make_call(call, gfp);\n+\t\t       atomic_read(\u0026call-\u003enet-\u003enr_outstanding_calls));\n }\n \n static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)\n@@ -1495,7 +1475,6 @@ static inline void afs_set_call_complete(struct afs_call *call,\n \t\t\t\t\t int error, u32 remote_abort)\n {\n \tenum afs_call_state state;\n-\tbool ok = false;\n \n \tspin_lock_bh(\u0026call-\u003estate_lock);\n \tstate = call-\u003estate;\n@@ -1505,19 +1484,8 @@ static inline void afs_set_call_complete(struct afs_call *call,\n \t\tcall-\u003estate = AFS_CALL_COMPLETE;\n \t\ttrace_afs_call_state(call, state, AFS_CALL_COMPLETE,\n \t\t\t\t     error, remote_abort);\n-\t\tok = true;\n \t}\n \tspin_unlock_bh(\u0026call-\u003estate_lock);\n-\tif (ok) {\n-\t\ttrace_afs_call_done(call);\n-\n-\t\t/* Asynchronous calls have two refs to release - one from the alloc and\n-\t\t * one queued with the work item - and we can't just deallocate the\n-\t\t * call because the work item may be queued again.\n-\t\t */\n-\t\tif (call-\u003edrop_ref)\n-\t\t\tafs_put_call(call);\n-\t}\n }\n \n /*\n@@ -1763,6 +1731,23 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)\n \treturn \u0026vnode-\u003enetfs.inode;\n }\n \n+static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,\n+\t\t\t\t    gfp_t gfp)\n+{\n+\tstruct afs_addr_list *alist = op-\u003eestate-\u003eaddresses;\n+\n+\top-\u003ecall\t= afs_get_call(call, afs_call_trace_get_op_call);\n+\top-\u003etype\t= call-\u003etype;\n+\tcall-\u003eop\t= op;\n+\tcall-\u003eserver\t= afs_use_server(op-\u003eserver, false, afs_server_trace_use_call);\n+\tcall-\u003ekey\t= op-\u003ekey;\n+\tcall-\u003eintr\t= !(op-\u003eflags \u0026 AFS_OPERATION_UNINTR);\n+\tcall-\u003epeer\t= rxrpc_kernel_get_peer(alist-\u003eaddrs[op-\u003eaddr_index].peer);\n+\tcall-\u003eservice_id = op-\u003eserver-\u003eservice_id;\n+\tafs_make_call(call, gfp);\n+\tafs_put_call(call, afs_call_trace_put_made_call);\n+}\n+\n /*\n  * Note that a dentry got changed.  We need to set d_fsdata to the data version\n  * number derived from the result of the operation.  It doesn't matter if\ndiff --git a/fs/afs/main.c b/fs/afs/main.c\nindex 7a883c59976ff2..6353feaa5fb4b5 100644\n--- a/fs/afs/main.c\n+++ b/fs/afs/main.c\n@@ -73,7 +73,6 @@ static int __net_init afs_net_init(struct net *net_ns)\n \tgenerate_random_uuid((unsigned char *)\u0026net-\u003euuid);\n \n \tINIT_WORK(\u0026net-\u003echarge_preallocation_work, afs_charge_preallocation);\n-\tINIT_WORK(\u0026net-\u003erx_oob_work, afs_process_oob_queue);\n \tmutex_init(\u0026net-\u003esocket_mutex);\n \n \tnet-\u003ecells = RB_ROOT;\ndiff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c\nindex d82916657a3ddf..4f6d699b5d226a 100644\n--- a/fs/afs/rxrpc.c\n+++ b/fs/afs/rxrpc.c\n@@ -25,14 +25,12 @@ static void afs_process_async_call(struct work_struct *);\n static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long);\n static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long);\n static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID);\n-static void afs_rx_notify_oob(struct sock *sk, struct sk_buff *oob);\n static int afs_deliver_cm_op_id(struct afs_call *);\n \n static const struct rxrpc_kernel_ops afs_rxrpc_callback_ops = {\n \t.notify_new_call\t= afs_rx_new_call,\n \t.discard_new_call\t= afs_rx_discard_new_call,\n \t.user_attach_call\t= afs_rx_attach,\n-\t.notify_oob\t\t= afs_rx_notify_oob,\n };\n \n /* asynchronous incoming call initial processing */\n@@ -74,10 +72,6 @@ int afs_open_socket(struct afs_net *net)\n \tif (ret \u003c 0)\n \t\tgoto error_2;\n \n-\tret = rxrpc_sock_set_manage_response(socket-\u003esk, true);\n-\tif (ret \u003c 0)\n-\t\tgoto error_2;\n-\n \tret = afs_create_token_key(net, socket);\n \tif (ret \u003c 0)\n \t\tpr_err(\"Couldn't create RxGK CM key: %d\\n\", ret);\n@@ -128,7 +122,6 @@ void afs_close_socket(struct afs_net *net)\n \t_enter(\"\");\n \n \tcancel_work_sync(\u0026net-\u003echarge_preallocation_work);\n-\tcancel_work_sync(\u0026net-\u003erx_oob_work);\n \t/* Future work items should now see -\u003elive is false. */\n \n \tkernel_listen(net-\u003esocket, 0);\n@@ -138,7 +131,7 @@ void afs_close_socket(struct afs_net *net)\n \tcancel_work_sync(\u0026net-\u003echarge_preallocation_work);\n \n \tif (net-\u003espare_incoming_call) {\n-\t\tafs_put_call(net-\u003espare_incoming_call);\n+\t\tafs_put_call(net-\u003espare_incoming_call, afs_call_trace_put_spare_svc);\n \t\tnet-\u003espare_incoming_call = NULL;\n \t}\n \n@@ -149,7 +142,6 @@ void afs_close_socket(struct afs_net *net)\n \n \tkernel_sock_shutdown(net-\u003esocket, SHUT_RDWR);\n \tflush_workqueue(afs_async_calls);\n-\tcancel_work_sync(\u0026net-\u003erx_oob_work);\n \tnet-\u003esocket-\u003esk-\u003esk_user_data = NULL;\n \tsock_release(net-\u003esocket);\n \tkey_put(net-\u003efs_cm_token_key);\n@@ -177,21 +169,20 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,\n \tcall-\u003edebug_id = atomic_inc_return(\u0026rxrpc_debug_id);\n \trefcount_set(\u0026call-\u003eref, 1);\n \tINIT_WORK(\u0026call-\u003easync_work, type-\u003easync_rx ?: afs_process_async_call);\n-\tINIT_WORK(\u0026call-\u003ework, call-\u003etype-\u003ework);\n \tINIT_WORK(\u0026call-\u003efree_work, afs_deferred_free_worker);\n \tinit_waitqueue_head(\u0026call-\u003ewaitq);\n \tspin_lock_init(\u0026call-\u003estate_lock);\n \tcall-\u003eiter = \u0026call-\u003edef_iter;\n \n \to = atomic_inc_return(\u0026net-\u003enr_outstanding_calls);\n-\ttrace_afs_call(call-\u003edebug_id, afs_call_trace_alloc, 1, o,\n-\t\t       __builtin_return_address(0));\n+\ttrace_afs_call(call-\u003edebug_id, afs_call_trace_alloc, 1, o);\n \treturn call;\n }\n \n static void afs_free_call(struct afs_call *call)\n {\n \tstruct afs_net *net = call-\u003enet;\n+\tunsigned int debug_id = call-\u003edebug_id;\n \tint o;\n \n \tASSERT(!work_pending(\u0026call-\u003easync_work));\n@@ -208,13 +199,10 @@ static void afs_free_call(struct afs_call *call)\n \n \tafs_unuse_server_notime(call-\u003enet, call-\u003eserver, afs_server_trace_unuse_call);\n \tkfree(call-\u003erequest);\n-\n-\to = atomic_read(\u0026net-\u003enr_outstanding_calls);\n-\ttrace_afs_call(call-\u003edebug_id, afs_call_trace_free, 0, o,\n-\t\t       __builtin_return_address(0));\n \tkfree(call);\n \n \to = atomic_dec_return(\u0026net-\u003enr_outstanding_calls);\n+\ttrace_afs_call(debug_id, afs_call_trace_free, 0, o);\n \tif (o == 0)\n \t\twake_up_var(\u0026net-\u003enr_outstanding_calls);\n }\n@@ -222,7 +210,7 @@ static void afs_free_call(struct afs_call *call)\n /*\n  * Dispose of a reference on a call.\n  */\n-void afs_put_call(struct afs_call *call)\n+void afs_put_call(struct afs_call *call, enum afs_call_trace trace)\n {\n \tstruct afs_net *net = call-\u003enet;\n \tunsigned int debug_id = call-\u003edebug_id;\n@@ -231,8 +219,7 @@ void afs_put_call(struct afs_call *call)\n \n \tzero = __refcount_dec_and_test(\u0026call-\u003eref, \u0026r);\n \to = atomic_read(\u0026net-\u003enr_outstanding_calls);\n-\ttrace_afs_call(debug_id, afs_call_trace_put, r - 1, o,\n-\t\t       __builtin_return_address(0));\n+\ttrace_afs_call(debug_id, trace, r - 1, o);\n \tif (zero)\n \t\tafs_free_call(call);\n }\n@@ -244,37 +231,6 @@ static void afs_deferred_free_worker(struct work_struct *work)\n \tafs_free_call(call);\n }\n \n-/*\n- * Dispose of a reference on a call, deferring the cleanup to a workqueue\n- * to avoid lock recursion.\n- */\n-void afs_deferred_put_call(struct afs_call *call)\n-{\n-\tstruct afs_net *net = call-\u003enet;\n-\tunsigned int debug_id = call-\u003edebug_id;\n-\tbool zero;\n-\tint r, o;\n-\n-\tzero = __refcount_dec_and_test(\u0026call-\u003eref, \u0026r);\n-\to = atomic_read(\u0026net-\u003enr_outstanding_calls);\n-\ttrace_afs_call(debug_id, afs_call_trace_put, r - 1, o,\n-\t\t       __builtin_return_address(0));\n-\tif (zero)\n-\t\tschedule_work(\u0026call-\u003efree_work);\n-}\n-\n-/*\n- * Queue the call for actual work.\n- */\n-static void afs_queue_call_work(struct afs_call *call)\n-{\n-\tif (call-\u003etype-\u003ework) {\n-\t\tafs_get_call(call, afs_call_trace_work);\n-\t\tif (!queue_work(afs_wq, \u0026call-\u003ework))\n-\t\t\tafs_put_call(call);\n-\t}\n-}\n-\n /*\n  * allocate a call with flat request and reply buffers\n  */\n@@ -308,7 +264,7 @@ struct afs_call *afs_alloc_flat_call(struct afs_net *net,\n \treturn call;\n \n nomem_free:\n-\tafs_put_call(call);\n+\tafs_put_call(call, afs_call_trace_put_oom);\n nomem_call:\n \treturn NULL;\n }\n@@ -347,7 +303,10 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \tstruct rxrpc_call *rxcall;\n \tstruct msghdr msg;\n \tstruct kvec iov[1];\n+\tunsigned int debug_id = call-\u003edebug_id;\n+\tstruct key *app_data = NULL;\n \tsize_t len;\n+\tbool write_iter = call-\u003ewrite_iter;\n \ts64 tx_total_len;\n \tint ret;\n \n@@ -373,13 +332,29 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \t/* If the call is going to be asynchronous, we need an extra ref for\n \t * the call to hold itself so the caller need not hang on to its ref.\n \t */\n-\tif (call-\u003easync) {\n-\t\tafs_get_call(call, afs_call_trace_get);\n-\t\tcall-\u003edrop_ref = true;\n+\tif (call-\u003easync)\n+\t\tafs_get_call(call, afs_call_trace_get_make_async_call);\n+\n+\tif (call-\u003ekey \u0026\u0026 call-\u003eserver) {\n+\t\tu32 krb5_enctype = 0;\n+\t\tu8 security_index = 0;\n+\n+\t\trxrpc_kernel_query_key(call-\u003ekey, \u0026security_index, \u0026krb5_enctype);\n+\t\tswitch (security_index) {\n+#ifdef CONFIG_RXGK\n+\t\tcase RXRPC_SECURITY_YFS_RXGK:\n+\t\t\t/* Read the key pointer before the appdata */\n+\t\t\tapp_data = smp_load_acquire(\u0026call-\u003eserver-\u003eyfs_rxgk_appdata);\n+\t\t\tbreak;\n+#endif\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n \t}\n \n \t/* create a call */\n-\trxcall = rxrpc_kernel_begin_call(call-\u003enet-\u003esocket, call-\u003epeer, call-\u003ekey,\n+\trxcall = rxrpc_kernel_begin_call(call-\u003enet-\u003esocket, call-\u003epeer,\n+\t\t\t\t\t call-\u003ekey, app_data,\n \t\t\t\t\t (unsigned long)call,\n \t\t\t\t\t tx_total_len,\n \t\t\t\t\t call-\u003emax_lifespan,\n@@ -410,7 +385,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \tiov_iter_kvec(\u0026msg.msg_iter, ITER_SOURCE, iov, 1, call-\u003erequest_size);\n \tmsg.msg_control\t\t= NULL;\n \tmsg.msg_controllen\t= 0;\n-\tmsg.msg_flags\t\t= MSG_WAITALL | (call-\u003ewrite_iter ? MSG_MORE : 0);\n+\tmsg.msg_flags\t\t= MSG_WAITALL | (write_iter ? MSG_MORE : 0);\n \n \tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket, rxcall,\n \t\t\t\t     \u0026msg, call-\u003erequest_size,\n@@ -418,7 +393,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \tif (ret \u003c 0)\n \t\tgoto error_do_abort;\n \n-\tif (call-\u003ewrite_iter) {\n+\tif (write_iter) {\n \t\tmsg.msg_iter = *call-\u003ewrite_iter;\n \t\tmsg.msg_flags \u0026= ~MSG_MORE;\n \t\ttrace_afs_send_data(call, \u0026msg);\n@@ -427,9 +402,8 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \t\t\t\t\t     call-\u003erxcall, \u0026msg,\n \t\t\t\t\t     iov_iter_count(\u0026msg.msg_iter),\n \t\t\t\t\t     afs_notify_end_request_tx);\n-\t\t*call-\u003ewrite_iter = msg.msg_iter;\n \n-\t\ttrace_afs_sent_data(call, \u0026msg, ret);\n+\t\ttrace_afs_sent_data(debug_id, \u0026msg, ret);\n \t\tif (ret \u003c 0)\n \t\t\tgoto error_do_abort;\n \t}\n@@ -448,7 +422,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \t\t\t\t\tRX_USER_ABORT, ret,\n \t\t\t\t\tafs_abort_send_data_error);\n \tif (call-\u003easync) {\n-\t\tafs_see_call(call, afs_call_trace_async_abort);\n+\t\tafs_see_call(call, afs_call_trace_see_async_abort);\n \t\treturn;\n \t}\n \n@@ -464,7 +438,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \ttrace_afs_call_done(call);\n error_kill_call:\n \tif (call-\u003easync)\n-\t\tafs_see_call(call, afs_call_trace_async_kill);\n+\t\tafs_see_call(call, afs_call_trace_see_async_kill);\n \tif (call-\u003etype-\u003eimmediate_cancel)\n \t\tcall-\u003etype-\u003eimmediate_cancel(call);\n \n@@ -475,8 +449,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \tif (call-\u003erxcall)\n \t\trxrpc_kernel_shutdown_call(call-\u003enet-\u003esocket, call-\u003erxcall);\n \tif (call-\u003easync) {\n-\t\tif (cancel_work_sync(\u0026call-\u003easync_work))\n-\t\t\tafs_put_call(call);\n+\t\tcancel_work_sync(\u0026call-\u003easync_work);\n \t\tafs_set_call_complete(call, ret, 0);\n \t}\n \n@@ -562,7 +535,8 @@ void afs_deliver_to_call(struct afs_call *call)\n \t\tswitch (ret) {\n \t\tcase 0:\n \t\t\tcall-\u003eresponded = true;\n-\t\t\tafs_queue_call_work(call);\n+\t\t\tif (call-\u003ework)\n+\t\t\t\tcall-\u003ework(call);\n \t\t\tif (state == AFS_CALL_CL_PROC_REPLY) {\n \t\t\t\tif (call-\u003eop)\n \t\t\t\t\tset_bit(AFS_SERVER_FL_MAY_HAVE_CB,\n@@ -612,6 +586,7 @@ void afs_deliver_to_call(struct afs_call *call)\n \t}\n \n done:\n+\ttrace_afs_call_done(call);\n \tif (call-\u003etype-\u003edone)\n \t\tcall-\u003etype-\u003edone(call);\n out:\n@@ -700,19 +675,12 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,\n \t\t\t\t   unsigned long call_user_ID)\n {\n \tstruct afs_call *call = (struct afs_call *)call_user_ID;\n-\tint r;\n \n \ttrace_afs_notify_call(rxcall, call);\n \tcall-\u003eneed_attention = true;\n \n-\tif (__refcount_inc_not_zero(\u0026call-\u003eref, \u0026r)) {\n-\t\ttrace_afs_call(call-\u003edebug_id, afs_call_trace_wake, r + 1,\n-\t\t\t       atomic_read(\u0026call-\u003enet-\u003enr_outstanding_calls),\n-\t\t\t       __builtin_return_address(0));\n-\n-\t\tif (!queue_work(afs_async_calls, \u0026call-\u003easync_work))\n-\t\t\tafs_deferred_put_call(call);\n-\t}\n+\tafs_see_call(call, afs_call_trace_see_async_wake);\n+\tqueue_work(afs_async_calls, \u0026call-\u003easync_work);\n }\n \n /*\n@@ -725,12 +693,17 @@ static void afs_process_async_call(struct work_struct *work)\n \n \t_enter(\"\");\n \n+\tafs_see_call(call, afs_call_trace_see_async_process);\n+\n \tif (call-\u003estate \u003c AFS_CALL_COMPLETE \u0026\u0026 call-\u003eneed_attention) {\n \t\tcall-\u003eneed_attention = false;\n \t\tafs_deliver_to_call(call);\n \t}\n \n-\tafs_put_call(call);\n+\tif (call-\u003estate == AFS_CALL_COMPLETE) {\n+\t\tcancel_work(\u0026call-\u003easync_work);\n+\t\tafs_put_call(call, afs_call_trace_put_async_complete);\n+\t}\n \t_leave(\"\");\n }\n \n@@ -756,7 +729,6 @@ void afs_charge_preallocation(struct work_struct *work)\n \t\t\tif (!call)\n \t\t\t\tbreak;\n \n-\t\t\tcall-\u003edrop_ref = true;\n \t\t\tcall-\u003easync = true;\n \t\t\tcall-\u003estate = AFS_CALL_SV_AWAIT_OP_ID;\n \t\t\tinit_waitqueue_head(\u0026call-\u003ewaitq);\n@@ -783,7 +755,7 @@ static void afs_rx_discard_new_call(struct rxrpc_call *rxcall,\n \tstruct afs_call *call = (struct afs_call *)user_call_ID;\n \n \tcall-\u003erxcall = NULL;\n-\tafs_put_call(call);\n+\tafs_put_call(call, afs_call_trace_put_discard_prealloc);\n }\n \n /*\n@@ -832,7 +804,7 @@ static int afs_deliver_cm_op_id(struct afs_call *call)\n \t\t\t\t\t\t\t     \u0026call-\u003eenctype);\n \n \ttrace_afs_cb_call(call);\n-\tcall-\u003ework.func = call-\u003etype-\u003ework;\n+\tcall-\u003ework = call-\u003etype-\u003ework;\n \n \t/* pass responsibility for the remainder of this message off to the\n \t * cache manager op */\n@@ -983,14 +955,3 @@ noinline int afs_protocol_error(struct afs_call *call,\n \t\tcall-\u003eunmarshalling_error = true;\n \treturn -EBADMSG;\n }\n-\n-/*\n- * Wake up OOB notification processing.\n- */\n-static void afs_rx_notify_oob(struct sock *sk, struct sk_buff *oob)\n-{\n-\tstruct afs_net *net = sk-\u003esk_user_data;\n-\n-\tif (READ_ONCE(net-\u003elive))\n-\t\tqueue_work(afs_wq, \u0026net-\u003erx_oob_work);\n-}\ndiff --git a/fs/afs/server.c b/fs/afs/server.c\nindex 0fe162ea2a36db..4c3a7bd0f7d866 100644\n--- a/fs/afs/server.c\n+++ b/fs/afs/server.c\n@@ -398,7 +398,7 @@ static void afs_server_rcu(struct rcu_head *rcu)\n \tafs_put_endpoint_state(rcu_access_pointer(server-\u003eendpoint_state),\n \t\t\t       afs_estate_trace_put_server);\n \tafs_put_cell(server-\u003ecell, afs_cell_trace_put_server);\n-\tkfree(server-\u003ecm_rxgk_appdata.data);\n+\tkey_put(server-\u003eyfs_rxgk_appdata);\n \tkfree(server);\n }\n \ndiff --git a/fs/afs/vl_probe.c b/fs/afs/vl_probe.c\nindex 3d2e0c925460f9..1d70887c9f318b 100644\n--- a/fs/afs/vl_probe.c\n+++ b/fs/afs/vl_probe.c\n@@ -186,7 +186,7 @@ static bool afs_do_probe_vlserver(struct afs_net *net,\n \t\t\t\t\t       server_index);\n \t\tif (!IS_ERR(call)) {\n \t\t\tafs_prioritise_error(_e, call-\u003eerror, call-\u003eabort_code);\n-\t\t\tafs_put_call(call);\n+\t\t\tafs_put_call(call, afs_call_trace_put_vl_get_caps);\n \t\t\tin_progress = true;\n \t\t} else {\n \t\t\tafs_prioritise_error(_e, PTR_ERR(call), 0);\ndiff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c\nindex a40b43464cfa9e..8a4c8c9a1e3996 100644\n--- a/fs/afs/vlclient.c\n+++ b/fs/afs/vlclient.c\n@@ -153,7 +153,7 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,\n \tvc-\u003ecall_abort_code\t= call-\u003eabort_code;\n \tvc-\u003ecall_error\t\t= call-\u003eerror;\n \tvc-\u003ecall_responded\t= call-\u003eresponded;\n-\tafs_put_call(call);\n+\tafs_put_call(call, afs_call_trace_put_vl_call);\n \tif (vc-\u003ecall_error) {\n \t\tkfree(entry);\n \t\treturn ERR_PTR(vc-\u003ecall_error);\n@@ -303,7 +303,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,\n \tvc-\u003ecall_error\t\t= call-\u003eerror;\n \tvc-\u003ecall_responded\t= call-\u003eresponded;\n \talist\t\t\t= call-\u003eret_alist;\n-\tafs_put_call(call);\n+\tafs_put_call(call, afs_call_trace_put_vl_call);\n \tif (vc-\u003ecall_error) {\n \t\tafs_put_addrlist(alist, afs_alist_trace_put_getaddru);\n \t\treturn ERR_PTR(vc-\u003ecall_error);\n@@ -666,7 +666,7 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,\n \tvc-\u003ecall_error\t\t= call-\u003eerror;\n \tvc-\u003ecall_responded\t= call-\u003eresponded;\n \talist\t\t\t= call-\u003eret_alist;\n-\tafs_put_call(call);\n+\tafs_put_call(call, afs_call_trace_put_vl_call);\n \tif (vc-\u003ecall_error) {\n \t\tafs_put_addrlist(alist, afs_alist_trace_put_getaddru);\n \t\treturn ERR_PTR(vc-\u003ecall_error);\n@@ -784,7 +784,7 @@ char *afs_yfsvl_get_cell_name(struct afs_vl_cursor *vc)\n \tvc-\u003ecall_error\t\t= call-\u003eerror;\n \tvc-\u003ecall_responded\t= call-\u003eresponded;\n \tcellname\t\t= call-\u003eret_str;\n-\tafs_put_call(call);\n+\tafs_put_call(call, afs_call_trace_put_vl_call);\n \tif (vc-\u003ecall_error) {\n \t\tkfree(cellname);\n \t\treturn ERR_PTR(vc-\u003ecall_error);\ndiff --git a/include/keys/user-type.h b/include/keys/user-type.h\nindex 386c3143278995..7002a993a47228 100644\n--- a/include/keys/user-type.h\n+++ b/include/keys/user-type.h\n@@ -26,6 +26,7 @@\n  */\n struct user_key_payload {\n \tstruct rcu_head\trcu;\t\t/* RCU destructor */\n+\trefcount_t\tref;\n \tunsigned short\tdatalen;\t/* length of this data */\n \tchar\t\tdata[] __aligned(__alignof__(u64)); /* actual data */\n };\n@@ -37,6 +38,7 @@ struct key_preparsed_payload;\n \n extern int user_preparse(struct key_preparsed_payload *prep);\n extern void user_free_preparse(struct key_preparsed_payload *prep);\n+void put_user_key_payload(struct user_key_payload *payload);\n extern int user_update(struct key *key, struct key_preparsed_payload *prep);\n extern void user_revoke(struct key *key);\n extern void user_destroy(struct key *key);\ndiff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h\nindex 0fb4c41c9bbf55..a9b8e1ba67ef8d 100644\n--- a/include/net/af_rxrpc.h\n+++ b/include/net/af_rxrpc.h\n@@ -55,6 +55,7 @@ void rxrpc_kernel_set_notifications(struct socket *sock,\n struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,\n \t\t\t\t\t   struct rxrpc_peer *peer,\n \t\t\t\t\t   struct key *key,\n+\t\t\t\t\t   struct key *app_data,\n \t\t\t\t\t   unsigned long user_call_ID,\n \t\t\t\t\t   s64 tx_total_len,\n \t\t\t\t\t   u32 hard_timeout,\n@@ -91,24 +92,8 @@ bool rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *);\n \n int rxrpc_sock_set_min_security_level(struct sock *sk, unsigned int val);\n int rxrpc_sock_set_security_keyring(struct sock *, struct key *);\n-int rxrpc_sock_set_manage_response(struct sock *sk, bool set);\n-\n-enum rxrpc_oob_type rxrpc_kernel_query_oob(struct sk_buff *oob,\n-\t\t\t\t\t   struct rxrpc_peer **_peer,\n-\t\t\t\t\t   unsigned long *_peer_appdata);\n-struct sk_buff *rxrpc_kernel_dequeue_oob(struct socket *sock,\n-\t\t\t\t\t enum rxrpc_oob_type *_type);\n-void rxrpc_kernel_free_oob(struct sk_buff *oob);\n-void rxrpc_kernel_query_challenge(struct sk_buff *challenge,\n-\t\t\t\t  struct rxrpc_peer **_peer,\n-\t\t\t\t  unsigned long *_peer_appdata,\n-\t\t\t\t  u16 *_service_id, u8 *_security_index);\n-int rxrpc_kernel_reject_challenge(struct sk_buff *challenge, u32 abort_code,\n-\t\t\t\t  int error, enum rxrpc_abort_reason why);\n-int rxkad_kernel_respond_to_challenge(struct sk_buff *challenge);\n-u32 rxgk_kernel_query_challenge(struct sk_buff *challenge);\n-int rxgk_kernel_respond_to_challenge(struct sk_buff *challenge,\n-\t\t\t\t     struct krb5_buffer *appdata);\n+void rxrpc_kernel_query_key(const struct key *key, u8 *_security_index,\n+\t\t\t    u32 *_krb5_enctype);\n u8 rxrpc_kernel_query_call_security(struct rxrpc_call *call,\n \t\t\t\t    u16 *_service_id, u32 *_enctype);\n \ndiff --git a/include/trace/events/afs.h b/include/trace/events/afs.h\nindex 1b3c48b5591dfd..a4f57414d527fb 100644\n--- a/include/trace/events/afs.h\n+++ b/include/trace/events/afs.h\n@@ -120,14 +120,26 @@ enum yfs_cm_operation {\n  * Declare tracing information enums and their string mappings for display.\n  */\n #define afs_call_traces \\\n-\tEM(afs_call_trace_alloc,\t\t\"ALLOC\") \\\n-\tEM(afs_call_trace_async_abort,\t\t\"ASYAB\") \\\n-\tEM(afs_call_trace_async_kill,\t\t\"ASYKL\") \\\n-\tEM(afs_call_trace_free,\t\t\t\"FREE \") \\\n-\tEM(afs_call_trace_get,\t\t\t\"GET  \") \\\n-\tEM(afs_call_trace_put,\t\t\t\"PUT  \") \\\n-\tEM(afs_call_trace_wake,\t\t\t\"WAKE \") \\\n-\tE_(afs_call_trace_work,\t\t\t\"QUEUE\")\n+\tEM(afs_call_trace_alloc,\t\t\"ALLOC      \") \\\n+\tEM(afs_call_trace_free,\t\t\t\"FREE       \") \\\n+\tEM(afs_call_trace_get_op_call,\t\t\"GET op     \") \\\n+\tEM(afs_call_trace_get_make_async_call,\t\"GET a-make \") \\\n+\tEM(afs_call_trace_put_async_complete,\t\"PUT a-cmpl \") \\\n+\tEM(afs_call_trace_put_made_call,\t\"PUT made   \") \\\n+\tEM(afs_call_trace_put_discard_prealloc,\t\"PUT dis-pre\") \\\n+\tEM(afs_call_trace_put_get_capabilities,\t\"PUT get-cap\") \\\n+\tEM(afs_call_trace_put_giveupcallbacks,\t\"PUT gvup-cb\") \\\n+\tEM(afs_call_trace_put_oom,\t\t\"PUT oom    \") \\\n+\tEM(afs_call_trace_put_read_complete,\t\"PUT rd-cpl \") \\\n+\tEM(afs_call_trace_put_read_op,\t\t\"PUT rd-op  \") \\\n+\tEM(afs_call_trace_put_spare_svc,\t\"PUT spare-s\") \\\n+\tEM(afs_call_trace_put_vl_call,\t\t\"PUT vl-call\") \\\n+\tEM(afs_call_trace_put_vl_get_caps,\t\"PUT vl-gcap\") \\\n+\tEM(afs_call_trace_put_wait_op,\t\t\"PUT wt-op  \") \\\n+\tEM(afs_call_trace_see_async_abort,\t\"SEE a-abort\") \\\n+\tEM(afs_call_trace_see_async_kill,\t\"SEE a-kill \") \\\n+\tEM(afs_call_trace_see_async_process,\t\"SEE a-proc \") \\\n+\tE_(afs_call_trace_see_async_wake,\t\"SEE a-wake \")\n \n #define afs_server_traces \\\n \tEM(afs_server_trace_callback,\t\t\"CALLBACK \") \\\n@@ -148,6 +160,7 @@ enum yfs_cm_operation {\n \tEM(afs_server_trace_unuse_slist_isort,\t\"UNU isort\") \\\n \tEM(afs_server_trace_update,\t\t\"UPDATE   \") \\\n \tEM(afs_server_trace_use_by_uuid,\t\"USE uuid \") \\\n+\tEM(afs_server_trace_use_call,\t\t\"USE call \") \\\n \tEM(afs_server_trace_use_cm_call,\t\"USE cm-cl\") \\\n \tEM(afs_server_trace_use_get_caps,\t\"USE gcaps\") \\\n \tEM(afs_server_trace_use_give_up_cb,\t\"USE gvupc\") \\\n@@ -693,16 +706,15 @@ TRACE_EVENT(afs_cb_call,\n \n TRACE_EVENT(afs_call,\n \t    TP_PROTO(unsigned int call_debug_id, enum afs_call_trace op,\n-\t\t     int ref, int outstanding, const void *where),\n+\t\t     int ref, int outstanding),\n \n-\t    TP_ARGS(call_debug_id, op, ref, outstanding, where),\n+\t    TP_ARGS(call_debug_id, op, ref, outstanding),\n \n \t    TP_STRUCT__entry(\n \t\t    __field(unsigned int,\t\tcall)\n \t\t    __field(int,\t\t\top)\n \t\t    __field(int,\t\t\tref)\n \t\t    __field(int,\t\t\toutstanding)\n-\t\t    __field(const void *,\t\twhere)\n \t\t\t     ),\n \n \t    TP_fast_assign(\n@@ -710,15 +722,13 @@ TRACE_EVENT(afs_call,\n \t\t    __entry-\u003eop = op;\n \t\t    __entry-\u003eref = ref;\n \t\t    __entry-\u003eoutstanding = outstanding;\n-\t\t    __entry-\u003ewhere = where;\n \t\t\t   ),\n \n-\t    TP_printk(\"c=%08x %s r=%d o=%d sp=%pSR\",\n+\t    TP_printk(\"c=%08x %s r=%d o=%d\",\n \t\t      __entry-\u003ecall,\n \t\t      __print_symbolic(__entry-\u003eop, afs_call_traces),\n \t\t      __entry-\u003eref,\n-\t\t      __entry-\u003eoutstanding,\n-\t\t      __entry-\u003ewhere)\n+\t\t      __entry-\u003eoutstanding)\n \t    );\n \n TRACE_EVENT(afs_make_fs_call,\n@@ -937,9 +947,9 @@ TRACE_EVENT(afs_send_data,\n \t    );\n \n TRACE_EVENT(afs_sent_data,\n-\t    TP_PROTO(struct afs_call *call, struct msghdr *msg, int ret),\n+\t    TP_PROTO(unsigned int call_debug_id, struct msghdr *msg, int ret),\n \n-\t    TP_ARGS(call, msg, ret),\n+\t    TP_ARGS(call_debug_id, msg, ret),\n \n \t    TP_STRUCT__entry(\n \t\t    __field(unsigned int,\t\tcall)\n@@ -949,7 +959,7 @@ TRACE_EVENT(afs_sent_data,\n \t\t\t     ),\n \n \t    TP_fast_assign(\n-\t\t    __entry-\u003ecall = call-\u003edebug_id;\n+\t\t    __entry-\u003ecall = call_debug_id;\n \t\t    __entry-\u003eret = ret;\n \t\t    __entry-\u003eoffset = msg-\u003emsg_iter.xarray_start + msg-\u003emsg_iter.iov_offset;\n \t\t    __entry-\u003ecount = iov_iter_count(\u0026msg-\u003emsg_iter);\ndiff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h\nindex 704a10de667004..45e4550a18ed81 100644\n--- a/include/trace/events/rxrpc.h\n+++ b/include/trace/events/rxrpc.h\n@@ -148,6 +148,7 @@\n \tEM(rxrpc_eproto_wrong_security,\t\t\"wrong-sec\")\t\t\\\n \tEM(rxrpc_recvmsg_excess_data,\t\t\"recvmsg-excess\")\t\\\n \tEM(rxrpc_recvmsg_short_data,\t\t\"recvmsg-short\")\t\\\n+\tEM(rxrpc_sendmsg_tx_error,\t\t\"tx-error\")\t\t\\\n \tE_(rxrpc_sendmsg_late_send,\t\t\"sendmsg-late\")\n \n #define rxrpc_call_poke_traces \\\n@@ -262,7 +263,6 @@\n \tEM(rxrpc_conn_free,\t\t\t\"FREE        \") \\\n \tEM(rxrpc_conn_get_activate_call,\t\"GET act-call\") \\\n \tEM(rxrpc_conn_get_call_input,\t\t\"GET inp-call\") \\\n-\tEM(rxrpc_conn_get_challenge_input,\t\"GET inp-chal\") \\\n \tEM(rxrpc_conn_get_conn_input,\t\t\"GET inp-conn\") \\\n \tEM(rxrpc_conn_get_idle,\t\t\t\"GET idle    \") \\\n \tEM(rxrpc_conn_get_poke_abort,\t\t\"GET pk-abort\") \\\n@@ -274,7 +274,6 @@\n \tEM(rxrpc_conn_new_service,\t\t\"NEW service \") \\\n \tEM(rxrpc_conn_put_call,\t\t\t\"PUT call    \") \\\n \tEM(rxrpc_conn_put_call_input,\t\t\"PUT inp-call\") \\\n-\tEM(rxrpc_conn_put_challenge_input,\t\"PUT inp-chal\") \\\n \tEM(rxrpc_conn_put_conn_input,\t\t\"PUT inp-conn\") \\\n \tEM(rxrpc_conn_put_discard_idle,\t\t\"PUT disc-idl\") \\\n \tEM(rxrpc_conn_put_local_dead,\t\t\"PUT loc-dead\") \\\n@@ -342,6 +341,7 @@\n \tEM(rxrpc_call_see_distribute_error,\t\"SEE dist-err\") \\\n \tEM(rxrpc_call_see_input,\t\t\"SEE input   \") \\\n \tEM(rxrpc_call_see_notify_released,\t\"SEE nfy-rlsd\") \\\n+\tEM(rxrpc_call_see_notify_skipped,\t\"SEE nfy-skip\") \\\n \tEM(rxrpc_call_see_recvmsg,\t\t\"SEE recvmsg \") \\\n \tEM(rxrpc_call_see_recvmsg_requeue,\t\"SEE recv-rqu\") \\\n \tEM(rxrpc_call_see_recvmsg_requeue_first, \"SEE recv-rqF\") \\\ndiff --git a/include/uapi/linux/rxrpc.h b/include/uapi/linux/rxrpc.h\nindex d9735abd4c7910..7d6a5015193112 100644\n--- a/include/uapi/linux/rxrpc.h\n+++ b/include/uapi/linux/rxrpc.h\n@@ -58,11 +58,7 @@ enum rxrpc_cmsg_type {\n \tRXRPC_TX_LENGTH\t\t= 12,\t/* -s-: Total length of Tx data */\n \tRXRPC_SET_CALL_TIMEOUT\t= 13,\t/* -s-: Set one or more call timeouts */\n \tRXRPC_CHARGE_ACCEPT\t= 14,\t/* Ss-: Charge the accept pool with a user call ID */\n-\tRXRPC_OOB_ID\t\t= 15,\t/* -sr: OOB message ID */\n-\tRXRPC_CHALLENGED\t= 16,\t/* C-r: Info on a received CHALLENGE */\n-\tRXRPC_RESPOND\t\t= 17,\t/* Cs-: Respond to a challenge */\n-\tRXRPC_RESPONDED\t\t= 18,\t/* S-r: Data received in RESPONSE */\n-\tRXRPC_RESP_RXGK_APPDATA\t= 19,\t/* Cs-: RESPONSE: RxGK app data to include */\n+\tRXRPC_RESPONSE_APPDATA\t= 20,\t/* Cs-: User key holding app data for RESPONSE */\n \tRXRPC__SUPPORTED\n };\n \ndiff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c\nindex c3c8c3240ef946..aa3c058f409559 100644\n--- a/net/dns_resolver/dns_key.c\n+++ b/net/dns_resolver/dns_key.c\n@@ -208,6 +208,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)\n \t\tkleave(\" = -ENOMEM\");\n \t\treturn -ENOMEM;\n \t}\n+\trefcount_set(\u0026upayload-\u003eref, 1);\n \n \tupayload-\u003edatalen = result_len;\n \tmemcpy(upayload-\u003edata, data, result_len);\ndiff --git a/net/rxrpc/Makefile b/net/rxrpc/Makefile\nindex f994f9f30a29d4..f7a5e0a592ee13 100644\n--- a/net/rxrpc/Makefile\n+++ b/net/rxrpc/Makefile\n@@ -24,7 +24,6 @@ rxrpc-y := \\\n \tlocal_object.o \\\n \tmisc.o \\\n \tnet_ns.o \\\n-\toob.o \\\n \toutput.o \\\n \tpeer_event.o \\\n \tpeer_object.o \\\ndiff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c\nindex 9ab0f22c881ec5..9d5ce1c7ad0d22 100644\n--- a/net/rxrpc/af_rxrpc.c\n+++ b/net/rxrpc/af_rxrpc.c\n@@ -318,6 +318,7 @@ EXPORT_SYMBOL(rxrpc_kernel_put_peer);\n  * @sock: The socket on which to make the call\n  * @peer: The peer to contact\n  * @key: The security context to use (defaults to socket setting)\n+ * @app_data: The security response application data (or NULL)\n  * @user_call_ID: The ID to use\n  * @tx_total_len: Total length of data to transmit during the call (or -1)\n  * @hard_timeout: The maximum lifespan of the call in sec\n@@ -340,6 +341,7 @@ EXPORT_SYMBOL(rxrpc_kernel_put_peer);\n struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,\n \t\t\t\t\t   struct rxrpc_peer *peer,\n \t\t\t\t\t   struct key *key,\n+\t\t\t\t\t   struct key *app_data,\n \t\t\t\t\t   unsigned long user_call_ID,\n \t\t\t\t\t   s64 tx_total_len,\n \t\t\t\t\t   u32 hard_timeout,\n@@ -368,6 +370,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,\n \t\tkey = NULL; /* a no-security key */\n \n \tmemset(\u0026p, 0, sizeof(p));\n+\tp.app_data\t\t= app_data;\n \tp.user_call_ID\t\t= user_call_ID;\n \tp.tx_total_len\t\t= tx_total_len;\n \tp.interruptibility\t= interruptibility;\n@@ -595,10 +598,7 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)\n \t\tfallthrough;\n \tcase RXRPC_SERVER_BOUND:\n \tcase RXRPC_SERVER_LISTENING:\n-\t\tif (m-\u003emsg_flags \u0026 MSG_OOB)\n-\t\t\tret = rxrpc_sendmsg_oob(rx, m, len);\n-\t\telse\n-\t\t\tret = rxrpc_do_sendmsg(rx, m, len);\n+\t\tret = rxrpc_do_sendmsg(rx, m, len);\n \t\t/* The socket has been unlocked */\n \t\tgoto out;\n \tdefault:\n@@ -633,7 +633,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,\n \t\t\t    sockptr_t optval, unsigned int optlen)\n {\n \tstruct rxrpc_sock *rx = rxrpc_sk(sock-\u003esk);\n-\tunsigned int min_sec_level, val;\n+\tunsigned int min_sec_level;\n \tu16 service_upgrade[2];\n \tint ret;\n \n@@ -710,23 +710,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,\n \n \t\tcase RXRPC_MANAGE_RESPONSE:\n \t\t\tret = -EINVAL;\n-\t\t\tif (optlen != sizeof(unsigned int))\n-\t\t\t\tgoto error;\n-\t\t\tret = -EISCONN;\n-\t\t\tif (rx-\u003esk.sk_state != RXRPC_UNBOUND)\n-\t\t\t\tgoto error;\n-\t\t\tret = copy_safe_from_sockptr(\u0026val, sizeof(val),\n-\t\t\t\t\t\t     optval, optlen);\n-\t\t\tif (ret)\n-\t\t\t\tgoto error;\n-\t\t\tret = -EINVAL;\n-\t\t\tif (val \u003e 1)\n-\t\t\t\tgoto error;\n-\t\t\tif (val)\n-\t\t\t\tset_bit(RXRPC_SOCK_MANAGE_RESPONSE, \u0026rx-\u003eflags);\n-\t\t\telse\n-\t\t\t\tclear_bit(RXRPC_SOCK_MANAGE_RESPONSE, \u0026rx-\u003eflags);\n-\t\t\tgoto success;\n+\t\t\tgoto error;\n \n \t\tdefault:\n \t\t\tbreak;\n@@ -835,8 +819,6 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,\n \trx-\u003ecalls = RB_ROOT;\n \n \tspin_lock_init(\u0026rx-\u003eincoming_lock);\n-\tskb_queue_head_init(\u0026rx-\u003erecvmsg_oobq);\n-\trx-\u003epending_oobq = RB_ROOT;\n \tINIT_LIST_HEAD(\u0026rx-\u003esock_calls);\n \tINIT_LIST_HEAD(\u0026rx-\u003eto_be_accepted);\n \tINIT_LIST_HEAD(\u0026rx-\u003erecvmsg_q);\n@@ -884,23 +866,6 @@ static int rxrpc_shutdown(struct socket *sock, int flags)\n \treturn ret;\n }\n \n-/*\n- * Purge the out-of-band queue.\n- */\n-static void rxrpc_purge_oob_queue(struct sock *sk)\n-{\n-\tstruct rxrpc_sock *rx = rxrpc_sk(sk);\n-\tstruct sk_buff *skb;\n-\n-\twhile ((skb = skb_dequeue(\u0026rx-\u003erecvmsg_oobq)))\n-\t\trxrpc_kernel_free_oob(skb);\n-\twhile (!RB_EMPTY_ROOT(\u0026rx-\u003epending_oobq)) {\n-\t\tskb = rb_entry(rx-\u003epending_oobq.rb_node, struct sk_buff, rbnode);\n-\t\trb_erase(\u0026skb-\u003erbnode, \u0026rx-\u003epending_oobq);\n-\t\trxrpc_kernel_free_oob(skb);\n-\t}\n-}\n-\n /*\n  * RxRPC socket destructor\n  */\n@@ -908,7 +873,6 @@ static void rxrpc_sock_destructor(struct sock *sk)\n {\n \t_enter(\"%p\", sk);\n \n-\trxrpc_purge_oob_queue(sk);\n \trxrpc_purge_queue(\u0026sk-\u003esk_receive_queue);\n \n \tWARN_ON(refcount_read(\u0026sk-\u003esk_wmem_alloc));\n@@ -961,7 +925,6 @@ static int rxrpc_release_sock(struct sock *sk)\n \trxrpc_discard_prealloc(rx);\n \trxrpc_release_calls_on_socket(rx);\n \tflush_workqueue(rxrpc_workqueue);\n-\trxrpc_purge_oob_queue(sk);\n \trxrpc_purge_queue(\u0026sk-\u003esk_receive_queue);\n \n \trxrpc_unuse_local(rx-\u003elocal, rxrpc_local_unuse_release_sock);\ndiff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h\nindex ce946b0a03e2b3..1c6f4a279034f3 100644\n--- a/net/rxrpc/ar-internal.h\n+++ b/net/rxrpc/ar-internal.h\n@@ -171,9 +171,6 @@ struct rxrpc_sock {\n \tconst struct rxrpc_kernel_ops *app_ops;\t/* Table of kernel app notification funcs */\n \tstruct rxrpc_local\t*local;\t\t/* local endpoint */\n \tstruct rxrpc_backlog\t*backlog;\t/* Preallocation for services */\n-\tstruct sk_buff_head\trecvmsg_oobq;\t/* OOB messages for recvmsg to pick up */\n-\tstruct rb_root\t\tpending_oobq;\t/* OOB messages awaiting userspace to respond to */\n-\tu64\t\t\toob_id_counter;\t/* OOB message ID counter */\n \tspinlock_t\t\tincoming_lock;\t/* Incoming call vs service shutdown lock */\n \tstruct list_head\tsock_calls;\t/* List of calls owned by this socket */\n \tstruct list_head\tto_be_accepted;\t/* calls awaiting acceptance */\n@@ -184,7 +181,6 @@ struct rxrpc_sock {\n \tstruct rb_root\t\tcalls;\t\t/* User ID -\u003e call mapping */\n \tunsigned long\t\tflags;\n #define RXRPC_SOCK_CONNECTED\t\t0\t/* connect_srx is set */\n-#define RXRPC_SOCK_MANAGE_RESPONSE\t1\t/* User wants to manage RESPONSE packets */\n \trwlock_t\t\tcall_lock;\t/* lock for calls */\n \tu32\t\t\tmin_sec_level;\t/* minimum security level */\n #define RXRPC_SECURITY_MAX\tRXRPC_SECURITY_ENCRYPT\n@@ -241,7 +237,6 @@ struct rxrpc_skb_priv {\n \t\t\tu8\t\treason;\t\t/* Reason for ack */\n \t\t} ack;\n \t\tstruct {\n-\t\t\tstruct rxrpc_connection *conn;\t/* Connection referred to */\n \t\t\tunion {\n \t\t\t\tu32 rxkad_nonce;\n \t\t\t};\n@@ -310,13 +305,6 @@ struct rxrpc_security {\n \tbool (*validate_challenge)(struct rxrpc_connection *conn,\n \t\t\t\t   struct sk_buff *skb);\n \n-\t/* Fill out the cmsg for recvmsg() to pass on a challenge to userspace.\n-\t * The security class gets to add additional information.\n-\t */\n-\tint (*challenge_to_recvmsg)(struct rxrpc_connection *conn,\n-\t\t\t\t    struct sk_buff *challenge,\n-\t\t\t\t    struct msghdr *msg);\n-\n \t/* Parse sendmsg() control message and respond to challenge. */\n \tint (*sendmsg_respond_to_challenge)(struct sk_buff *challenge,\n \t\t\t\t\t    struct msghdr *msg);\n@@ -516,6 +504,7 @@ struct rxrpc_bundle {\n \tstruct rxrpc_local\t*local;\t\t/* Representation of local endpoint */\n \tstruct rxrpc_peer\t*peer;\t\t/* Remote endpoint */\n \tstruct key\t\t*key;\t\t/* Security details */\n+\tstruct key\t\t*app_data;\t/* Security response app data */\n \tstruct list_head\tproc_link;\t/* Link in net-\u003ebundle_proc_list */\n \tconst struct rxrpc_security *security;\t/* applied security module */\n \trefcount_t\t\tref;\n@@ -642,6 +631,7 @@ enum rxrpc_call_flag {\n \tRXRPC_CALL_TX_LAST,\t\t/* Last packet in Tx buffer (at rxtx_top) */\n \tRXRPC_CALL_TX_ALL_ACKED,\t/* Last packet has been hard-acked */\n \tRXRPC_CALL_TX_NO_MORE,\t\t/* No more data to transmit (MSG_MORE deasserted) */\n+\tRXRPC_CALL_TX_ERROR,\t\t/* Terminal error; call needs abort */\n \tRXRPC_CALL_SEND_PING,\t\t/* A ping will need to be sent */\n \tRXRPC_CALL_RETRANS_TIMEOUT,\t/* Retransmission due to timeout occurred */\n \tRXRPC_CALL_BEGAN_RX_TIMER,\t/* We began the expect_rx_by timer */\n@@ -719,6 +709,7 @@ struct rxrpc_call {\n \tstruct rxrpc_sock __rcu\t*socket;\t/* socket responsible */\n \tstruct rxrpc_net\t*rxnet;\t\t/* Network namespace to which call belongs */\n \tstruct key\t\t*key;\t\t/* Security details */\n+\tstruct key\t\t*app_data;\t/* Security response app data */\n \tconst struct rxrpc_security *security;\t/* applied security module */\n \tstruct mutex\t\tuser_mutex;\t/* User access mutex */\n \tstruct sockaddr_rxrpc\tdest_srx;\t/* Destination address */\n@@ -913,6 +904,7 @@ enum rxrpc_command {\n };\n \n struct rxrpc_call_params {\n+\tstruct key\t\t*app_data;\t/* Security response app data */\n \ts64\t\t\ttx_total_len;\t/* Total Tx data length (if send data) */\n \tunsigned long\t\tuser_call_ID;\t/* User's call ID */\n \tstruct {\n@@ -1375,13 +1367,6 @@ static inline struct rxrpc_net *rxrpc_net(struct net *net)\n \treturn net_generic(net, rxrpc_net_id);\n }\n \n-/*\n- * oob.c\n- */\n-bool rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb);\n-void rxrpc_add_pending_oob(struct rxrpc_sock *rx, struct sk_buff *skb);\n-int rxrpc_sendmsg_oob(struct rxrpc_sock *rx, struct msghdr *msg, size_t len);\n-\n /*\n  * output.c\n  */\ndiff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c\nindex 817ed9acb91e61..9f6130d90c4ca8 100644\n--- a/net/rxrpc/call_object.c\n+++ b/net/rxrpc/call_object.c\n@@ -211,6 +211,7 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,\n \tcall-\u003einterruptibility\t= p-\u003einterruptibility;\n \tcall-\u003etx_total_len\t= p-\u003etx_total_len;\n \tcall-\u003ekey\t\t= key_get(cp-\u003ekey);\n+\tcall-\u003eapp_data\t\t= key_get(p-\u003eapp_data);\n \tcall-\u003epeer\t\t= rxrpc_get_peer(cp-\u003epeer, rxrpc_peer_get_call);\n \tcall-\u003elocal\t\t= rxrpc_get_local(cp-\u003elocal, rxrpc_local_get_call);\n \tcall-\u003esecurity_level\t= cp-\u003esecurity_level;\n@@ -697,6 +698,7 @@ static void rxrpc_destroy_call(struct work_struct *work)\n \trxrpc_put_peer(call-\u003epeer, rxrpc_peer_put_call);\n \trxrpc_put_local(call-\u003elocal, rxrpc_local_put_call);\n \tkey_put(call-\u003ekey);\n+\tkey_put(call-\u003eapp_data);\n \tcall_rcu(\u0026call-\u003ercu, rxrpc_rcu_free_call);\n }\n \ndiff --git a/net/rxrpc/call_state.c b/net/rxrpc/call_state.c\nindex 6afb54373ebbf9..6e402312e145c0 100644\n--- a/net/rxrpc/call_state.c\n+++ b/net/rxrpc/call_state.c\n@@ -7,6 +7,61 @@\n \n #include \"ar-internal.h\"\n \n+/*\n+ * Post a call for attention by the socket or kernel service.  Further\n+ * notifications are suppressed by putting recvmsg_link on a dummy queue.\n+ */\n+static void __rxrpc_notify_socket(struct rxrpc_call *call)\n+{\n+\tstruct rxrpc_sock *rx;\n+\tstruct sock *sk;\n+\n+\tif (test_bit(RXRPC_CALL_RELEASED, \u0026call-\u003eflags)) {\n+\t\trxrpc_see_call(call, rxrpc_call_see_notify_released);\n+\t\treturn;\n+\t}\n+\n+\trcu_read_lock();\n+\n+\trx = rcu_dereference(call-\u003esocket);\n+\tsk = \u0026rx-\u003esk;\n+\tif (rx \u0026\u0026 sk-\u003esk_state \u003c RXRPC_CLOSE) {\n+\t\tif (call-\u003enotify_rx) {\n+\t\t\tspin_lock_irq(\u0026call-\u003enotify_lock);\n+\t\t\tcall-\u003enotify_rx(sk, call, call-\u003euser_call_ID);\n+\t\t\tspin_unlock_irq(\u0026call-\u003enotify_lock);\n+\t\t} else {\n+\t\t\tspin_lock_irq(\u0026rx-\u003erecvmsg_lock);\n+\t\t\tif (list_empty(\u0026call-\u003erecvmsg_link)) {\n+\t\t\t\trxrpc_get_call(call, rxrpc_call_get_notify_socket);\n+\t\t\t\tlist_add_tail(\u0026call-\u003erecvmsg_link, \u0026rx-\u003erecvmsg_q);\n+\t\t\t}\n+\t\t\tspin_unlock_irq(\u0026rx-\u003erecvmsg_lock);\n+\n+\t\t\tif (!sock_flag(sk, SOCK_DEAD)) {\n+\t\t\t\t_debug(\"call %ps\", sk-\u003esk_data_ready);\n+\t\t\t\tsk-\u003esk_data_ready(sk);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\trcu_read_unlock();\n+}\n+\n+/*\n+ * Post a call for attention by the socket or kernel service.  Further\n+ * notifications are suppressed by putting recvmsg_link on a dummy queue.\n+ */\n+void rxrpc_notify_socket(struct rxrpc_call *call)\n+{\n+\tif (rxrpc_call_is_complete(call)) {\n+\t\trxrpc_see_call(call, rxrpc_call_see_notify_skipped);\n+\t\treturn;\n+\t}\n+\n+\t__rxrpc_notify_socket(call);\n+}\n+\n /*\n  * Transition a call to the complete state.\n  */\n@@ -25,7 +80,7 @@ bool rxrpc_set_call_completion(struct rxrpc_call *call,\n \trxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);\n \ttrace_rxrpc_call_complete(call);\n \twake_up(\u0026call-\u003ewaitq);\n-\trxrpc_notify_socket(call);\n+\t__rxrpc_notify_socket(call);\n \treturn true;\n }\n \ndiff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c\nindex 48519f0de18539..5cbfa7b223e011 100644\n--- a/net/rxrpc/conn_client.c\n+++ b/net/rxrpc/conn_client.c\n@@ -81,6 +81,7 @@ static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_call *call,\n \t\tbundle-\u003elocal\t\t= call-\u003elocal;\n \t\tbundle-\u003epeer\t\t= rxrpc_get_peer(call-\u003epeer, rxrpc_peer_get_bundle);\n \t\tbundle-\u003ekey\t\t= key_get(call-\u003ekey);\n+\t\tbundle-\u003eapp_data\t= key_get(call-\u003eapp_data);\n \t\tbundle-\u003esecurity\t= call-\u003esecurity;\n \t\tbundle-\u003eexclusive\t= test_bit(RXRPC_CALL_EXCLUSIVE, \u0026call-\u003eflags);\n \t\tbundle-\u003eupgrade\t\t= test_bit(RXRPC_CALL_UPGRADE, \u0026call-\u003eflags);\n@@ -118,6 +119,7 @@ static void rxrpc_free_bundle(struct rxrpc_bundle *bundle)\n \twrite_unlock(\u0026bundle-\u003elocal-\u003erxnet-\u003econn_lock);\n \trxrpc_put_peer(bundle-\u003epeer, rxrpc_peer_put_bundle);\n \tkey_put(bundle-\u003ekey);\n+\tkey_put(bundle-\u003eapp_data);\n \tkfree(bundle);\n }\n \ndiff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c\nindex 611c790bc6d0ce..9146b9d4c2ac50 100644\n--- a/net/rxrpc/conn_event.c\n+++ b/net/rxrpc/conn_event.c\n@@ -279,10 +279,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,\n \n \tswitch (sp-\u003ehdr.type) {\n \tcase RXRPC_PACKET_TYPE_CHALLENGE:\n-\t\tret = conn-\u003esecurity-\u003erespond_to_challenge(conn, skb);\n-\t\tsp-\u003echall.conn = NULL;\n-\t\trxrpc_put_connection(conn, rxrpc_conn_put_challenge_input);\n-\t\treturn ret;\n+\t\treturn conn-\u003esecurity-\u003erespond_to_challenge(conn, skb);\n \n \tcase RXRPC_PACKET_TYPE_RESPONSE:\n \t\tspin_lock_irq(\u0026conn-\u003estate_lock);\n@@ -425,66 +422,6 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,\n \trxrpc_queue_conn(conn, rxrpc_conn_queue_rx_work);\n }\n \n-/*\n- * Post a CHALLENGE packet to the socket of one of a connection's calls so that\n- * it can get application data to include in the packet, possibly querying\n- * userspace.\n- */\n-static bool rxrpc_post_challenge(struct rxrpc_connection *conn,\n-\t\t\t\t struct sk_buff *skb)\n-{\n-\tstruct rxrpc_skb_priv *sp = rxrpc_skb(skb);\n-\tstruct rxrpc_call *call = NULL;\n-\tstruct rxrpc_sock *rx;\n-\tbool respond = false, queued = false;\n-\n-\tsp-\u003echall.conn =\n-\t\trxrpc_get_connection(conn, rxrpc_conn_get_challenge_input);\n-\n-\tif (!conn-\u003esecurity-\u003echallenge_to_recvmsg) {\n-\t\trxrpc_post_packet_to_conn(conn, skb);\n-\t\treturn true;\n-\t}\n-\n-\trcu_read_lock();\n-\n-\tfor (int i = 0; i \u003c ARRAY_SIZE(conn-\u003echannels); i++) {\n-\t\tif (conn-\u003echannels[i].call) {\n-\t\t\tcall = conn-\u003echannels[i].call;\n-\t\t\trx = rcu_dereference(call-\u003esocket);\n-\t\t\tif (!rx) {\n-\t\t\t\tcall = NULL;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\n-\t\t\trespond = true;\n-\t\t\tif (test_bit(RXRPC_SOCK_MANAGE_RESPONSE, \u0026rx-\u003eflags))\n-\t\t\t\tbreak;\n-\t\t\tcall = NULL;\n-\t\t}\n-\t}\n-\n-\tif (!respond) {\n-\t\trcu_read_unlock();\n-\t\trxrpc_put_connection(conn, rxrpc_conn_put_challenge_input);\n-\t\tsp-\u003echall.conn = NULL;\n-\t\treturn false;\n-\t}\n-\n-\tif (call)\n-\t\tqueued = rxrpc_notify_socket_oob(call, skb);\n-\trcu_read_unlock();\n-\tif (call \u0026\u0026 !queued) {\n-\t\trxrpc_put_connection(conn, rxrpc_conn_put_challenge_input);\n-\t\tsp-\u003echall.conn = NULL;\n-\t\treturn false;\n-\t}\n-\n-\tif (!call)\n-\t\trxrpc_post_packet_to_conn(conn, skb);\n-\treturn true;\n-}\n-\n /*\n  * Input a connection-level packet.\n  */\n@@ -513,7 +450,8 @@ bool rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb)\n \t\t}\n \t\tif (!conn-\u003esecurity-\u003evalidate_challenge(conn, skb))\n \t\t\treturn false;\n-\t\treturn rxrpc_post_challenge(conn, skb);\n+\t\trxrpc_post_packet_to_conn(conn, skb);\n+\t\treturn true;\n \n \tcase RXRPC_PACKET_TYPE_RESPONSE:\n \t\tif (rxrpc_is_conn_aborted(conn)) {\ndiff --git a/net/rxrpc/key.c b/net/rxrpc/key.c\nindex a0aa78d892897f..16bab72e6f0777 100644\n--- a/net/rxrpc/key.c\n+++ b/net/rxrpc/key.c\n@@ -893,3 +893,40 @@ static long rxrpc_read(const struct key *key,\n \t_leave(\" = %zu\", size);\n \treturn size;\n }\n+\n+/**\n+ * rxrpc_kernel_query_key - Query parameters from an rxrpc key\n+ * @key: The key to query\n+ * @_security_index: Where to return the security index\n+ * @_krb5_enctype: Where to return the krb5 encryption type if applicable\n+ *\n+ * Query an rxrpc authentication key, extracting the security index from the\n+ * first token therein.\n+ */\n+void rxrpc_kernel_query_key(const struct key *key, u8 *_security_index,\n+\t\t\t    u32 *_krb5_enctype)\n+{\n+\tconst struct rxrpc_key_token *token;\n+\n+\ttoken = key-\u003epayload.data[0];\n+\tif (!token) {\n+\t\t*_security_index = 0;\n+\t\t*_krb5_enctype = 0;\n+\t\treturn;\n+\t}\n+\n+\t*_security_index = token-\u003esecurity_index;\n+\tswitch (token-\u003esecurity_index) {\n+\tcase RXRPC_SECURITY_RXKAD:\n+\t\t*_krb5_enctype = 0;\n+\t\tbreak;\n+\tcase RXRPC_SECURITY_YFS_RXGK:\n+\t\t*_krb5_enctype = token-\u003erxgk-\u003eenctype;\n+\t\tbreak;\n+\tdefault:\n+\t\tWARN_ON_ONCE(1);\n+\t\t*_krb5_enctype = 0;\n+\t\tbreak;\n+\t}\n+}\n+EXPORT_SYMBOL(rxrpc_kernel_query_key);\ndiff --git a/net/rxrpc/oob.c b/net/rxrpc/oob.c\ndeleted file mode 100644\nindex c80ee2487d0941..00000000000000\n--- a/net/rxrpc/oob.c\n+++ /dev/null\n@@ -1,387 +0,0 @@\n-// SPDX-License-Identifier: GPL-2.0-or-later\n-/* Out of band message handling (e.g. challenge-response)\n- *\n- * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.\n- * Written by David Howells (dhowells@redhat.com)\n- */\n-\n-#define pr_fmt(fmt) KBUILD_MODNAME \": \" fmt\n-\n-#include \u003clinux/net.h\u003e\n-#include \u003clinux/gfp.h\u003e\n-#include \u003clinux/skbuff.h\u003e\n-#include \u003clinux/export.h\u003e\n-#include \u003clinux/sched/signal.h\u003e\n-#include \u003cnet/sock.h\u003e\n-#include \u003cnet/af_rxrpc.h\u003e\n-#include \"ar-internal.h\"\n-\n-enum rxrpc_oob_command {\n-\tRXRPC_OOB_CMD_UNSET,\n-\tRXRPC_OOB_CMD_RESPOND,\n-} __mode(byte);\n-\n-struct rxrpc_oob_params {\n-\tu64\t\t\toob_id;\t\t/* ID number of message if reply */\n-\ts32\t\t\tabort_code;\n-\tenum rxrpc_oob_command\tcommand;\n-\tbool\t\t\thave_oob_id:1;\n-};\n-\n-/*\n- * Post an out-of-band message for attention by the socket or kernel service\n- * associated with a reference call.\n- */\n-bool rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb)\n-{\n-\tstruct rxrpc_skb_priv *sp = rxrpc_skb(skb);\n-\tstruct rxrpc_sock *rx;\n-\tstruct sock *sk;\n-\tbool queued = false;\n-\n-\trcu_read_lock();\n-\n-\trx = rcu_dereference(call-\u003esocket);\n-\tif (rx) {\n-\t\tsk = \u0026rx-\u003esk;\n-\t\tspin_lock_irq(\u0026rx-\u003erecvmsg_lock);\n-\n-\t\tif (sk-\u003esk_state \u003c RXRPC_CLOSE) {\n-\t\t\tskb-\u003eskb_mstamp_ns = rx-\u003eoob_id_counter++;\n-\t\t\trxrpc_get_skb(skb, rxrpc_skb_get_post_oob);\n-\t\t\tskb_queue_tail(\u0026rx-\u003erecvmsg_oobq, skb);\n-\t\t\tqueued = true;\n-\n-\t\t\ttrace_rxrpc_notify_socket(call-\u003edebug_id, sp-\u003ehdr.serial);\n-\t\t\tif (rx-\u003eapp_ops)\n-\t\t\t\trx-\u003eapp_ops-\u003enotify_oob(sk, skb);\n-\t\t}\n-\n-\t\tspin_unlock_irq(\u0026rx-\u003erecvmsg_lock);\n-\t\tif (queued \u0026\u0026 !rx-\u003eapp_ops \u0026\u0026 !sock_flag(sk, SOCK_DEAD))\n-\t\t\tsk-\u003esk_data_ready(sk);\n-\t}\n-\n-\trcu_read_unlock();\n-\treturn queued;\n-}\n-\n-/*\n- * Locate the OOB message to respond to by its ID.\n- */\n-static struct sk_buff *rxrpc_find_pending_oob(struct rxrpc_sock *rx, u64 oob_id)\n-{\n-\tstruct rb_node *p;\n-\tstruct sk_buff *skb;\n-\n-\tp = rx-\u003epending_oobq.rb_node;\n-\twhile (p) {\n-\t\tskb = rb_entry(p, struct sk_buff, rbnode);\n-\n-\t\tif (oob_id \u003c skb-\u003eskb_mstamp_ns)\n-\t\t\tp = p-\u003erb_left;\n-\t\telse if (oob_id \u003e skb-\u003eskb_mstamp_ns)\n-\t\t\tp = p-\u003erb_right;\n-\t\telse\n-\t\t\treturn skb;\n-\t}\n-\n-\treturn NULL;\n-}\n-\n-/*\n- * Add an OOB message into the pending-response set.  We always assign the next\n- * value from a 64-bit counter to the oob_id, so just assume we're always going\n- * to be on the right-hand edge of the tree and that the counter won't wrap.\n- * The tree is also given a ref to the message.\n- */\n-void rxrpc_add_pending_oob(struct rxrpc_sock *rx, struct sk_buff *skb)\n-{\n-\tstruct rb_node **pp = \u0026rx-\u003epending_oobq.rb_node, *p = NULL;\n-\n-\twhile (*pp) {\n-\t\tp = *pp;\n-\t\tpp = \u0026(*pp)-\u003erb_right;\n-\t}\n-\n-\trb_link_node(\u0026skb-\u003erbnode, p, pp);\n-\trb_insert_color(\u0026skb-\u003erbnode, \u0026rx-\u003epending_oobq);\n-}\n-\n-/*\n- * Extract control messages from the sendmsg() control buffer.\n- */\n-static int rxrpc_sendmsg_oob_cmsg(struct msghdr *msg, struct rxrpc_oob_params *p)\n-{\n-\tstruct cmsghdr *cmsg;\n-\tint len;\n-\n-\tif (msg-\u003emsg_controllen == 0)\n-\t\treturn -EINVAL;\n-\n-\tfor_each_cmsghdr(cmsg, msg) {\n-\t\tif (!CMSG_OK(msg, cmsg))\n-\t\t\treturn -EINVAL;\n-\n-\t\tlen = cmsg-\u003ecmsg_len - sizeof(struct cmsghdr);\n-\t\t_debug(\"CMSG %d, %d, %d\",\n-\t\t       cmsg-\u003ecmsg_level, cmsg-\u003ecmsg_type, len);\n-\n-\t\tif (cmsg-\u003ecmsg_level != SOL_RXRPC)\n-\t\t\tcontinue;\n-\n-\t\tswitch (cmsg-\u003ecmsg_type) {\n-\t\tcase RXRPC_OOB_ID:\n-\t\t\tif (len != sizeof(p-\u003eoob_id) || p-\u003ehave_oob_id)\n-\t\t\t\treturn -EINVAL;\n-\t\t\tmemcpy(\u0026p-\u003eoob_id, CMSG_DATA(cmsg), sizeof(p-\u003eoob_id));\n-\t\t\tp-\u003ehave_oob_id = true;\n-\t\t\tbreak;\n-\t\tcase RXRPC_RESPOND:\n-\t\t\tif (p-\u003ecommand != RXRPC_OOB_CMD_UNSET)\n-\t\t\t\treturn -EINVAL;\n-\t\t\tp-\u003ecommand = RXRPC_OOB_CMD_RESPOND;\n-\t\t\tbreak;\n-\t\tcase RXRPC_ABORT:\n-\t\t\tif (len != sizeof(p-\u003eabort_code) || p-\u003eabort_code)\n-\t\t\t\treturn -EINVAL;\n-\t\t\tmemcpy(\u0026p-\u003eabort_code, CMSG_DATA(cmsg), sizeof(p-\u003eabort_code));\n-\t\t\tif (p-\u003eabort_code == 0)\n-\t\t\t\treturn -EINVAL;\n-\t\t\tbreak;\n-\t\tcase RXRPC_RESP_RXGK_APPDATA:\n-\t\t\tif (p-\u003ecommand != RXRPC_OOB_CMD_RESPOND)\n-\t\t\t\treturn -EINVAL;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\treturn -EINVAL;\n-\t\t}\n-\t}\n-\n-\tswitch (p-\u003ecommand) {\n-\tcase RXRPC_OOB_CMD_RESPOND:\n-\t\tif (!p-\u003ehave_oob_id)\n-\t\t\treturn -EBADSLT;\n-\t\tbreak;\n-\tdefault:\n-\t\treturn -EINVAL;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-/*\n- * Allow userspace to respond to an OOB using sendmsg().\n- */\n-static int rxrpc_respond_to_oob(struct rxrpc_sock *rx,\n-\t\t\t\tstruct rxrpc_oob_params *p,\n-\t\t\t\tstruct msghdr *msg)\n-{\n-\tstruct rxrpc_connection *conn;\n-\tstruct rxrpc_skb_priv *sp;\n-\tstruct sk_buff *skb;\n-\tint ret;\n-\n-\tskb = rxrpc_find_pending_oob(rx, p-\u003eoob_id);\n-\tif (skb)\n-\t\trb_erase(\u0026skb-\u003erbnode, \u0026rx-\u003epending_oobq);\n-\trelease_sock(\u0026rx-\u003esk);\n-\tif (!skb)\n-\t\treturn -EBADSLT;\n-\n-\tsp = rxrpc_skb(skb);\n-\n-\tswitch (p-\u003ecommand) {\n-\tcase RXRPC_OOB_CMD_RESPOND:\n-\t\tret = -EPROTO;\n-\t\tif (skb-\u003emark != RXRPC_OOB_CHALLENGE)\n-\t\t\tbreak;\n-\t\tconn = sp-\u003echall.conn;\n-\t\tret = -EOPNOTSUPP;\n-\t\tif (!conn-\u003esecurity-\u003esendmsg_respond_to_challenge)\n-\t\t\tbreak;\n-\t\tif (p-\u003eabort_code) {\n-\t\t\trxrpc_abort_conn(conn, NULL, p-\u003eabort_code, -ECONNABORTED,\n-\t\t\t\t\t rxrpc_abort_response_sendmsg);\n-\t\t\tret = 0;\n-\t\t} else {\n-\t\t\tret = conn-\u003esecurity-\u003esendmsg_respond_to_challenge(skb, msg);\n-\t\t}\n-\t\tbreak;\n-\tdefault:\n-\t\tret = -EINVAL;\n-\t\tbreak;\n-\t}\n-\n-\tswitch (skb-\u003emark) {\n-\tcase RXRPC_OOB_CHALLENGE:\n-\t\trxrpc_put_connection(sp-\u003echall.conn, rxrpc_conn_put_oob);\n-\t\tbreak;\n-\t}\n-\trxrpc_free_skb(skb, rxrpc_skb_put_oob);\n-\treturn ret;\n-}\n-\n-/*\n- * Send an out-of-band message or respond to a received out-of-band message.\n- * - caller gives us the socket lock\n- * - the socket may be either a client socket or a server socket\n- */\n-int rxrpc_sendmsg_oob(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n-{\n-\tstruct rxrpc_oob_params p = {};\n-\tint ret;\n-\n-\t_enter(\"\");\n-\n-\tret = rxrpc_sendmsg_oob_cmsg(msg, \u0026p);\n-\tif (ret \u003c 0)\n-\t\tgoto error_release_sock;\n-\n-\tif (p.have_oob_id)\n-\t\treturn rxrpc_respond_to_oob(rx, \u0026p, msg);\n-\n-\trelease_sock(\u0026rx-\u003esk);\n-\n-\tswitch (p.command) {\n-\tdefault:\n-\t\tret = -EINVAL;\n-\t\tbreak;\n-\t}\n-\n-\t_leave(\" = %d\", ret);\n-\treturn ret;\n-\n-error_release_sock:\n-\trelease_sock(\u0026rx-\u003esk);\n-\treturn ret;\n-}\n-\n-/**\n- * rxrpc_kernel_query_oob - Query the parameters of an out-of-band message\n- * @oob: The message to query\n- * @_peer: Where to return the peer record\n- * @_peer_appdata: The application data attached to a peer record\n- *\n- * Extract useful parameters from an out-of-band message.  The source peer\n- * parameters are returned through the argument list and the message type is\n- * returned.\n- *\n- * Return:\n- * * %RXRPC_OOB_CHALLENGE - Challenge wanting a response.\n- */\n-enum rxrpc_oob_type rxrpc_kernel_query_oob(struct sk_buff *oob,\n-\t\t\t\t\t   struct rxrpc_peer **_peer,\n-\t\t\t\t\t   unsigned long *_peer_appdata)\n-{\n-\tstruct rxrpc_skb_priv *sp = rxrpc_skb(oob);\n-\tenum rxrpc_oob_type type = oob-\u003emark;\n-\n-\tswitch (type) {\n-\tcase RXRPC_OOB_CHALLENGE:\n-\t\t*_peer\t\t= sp-\u003echall.conn-\u003epeer;\n-\t\t*_peer_appdata\t= sp-\u003echall.conn-\u003epeer-\u003eapp_data;\n-\t\tbreak;\n-\tdefault:\n-\t\tWARN_ON_ONCE(1);\n-\t\t*_peer\t\t= NULL;\n-\t\t*_peer_appdata\t= 0;\n-\t\tbreak;\n-\t}\n-\n-\treturn type;\n-}\n-EXPORT_SYMBOL(rxrpc_kernel_query_oob);\n-\n-/**\n- * rxrpc_kernel_dequeue_oob - Dequeue and return the front OOB message\n- * @sock: The socket to query\n- * @_type: Where to return the message type\n- *\n- * Dequeue the front OOB message, if there is one, and return it and\n- * its type.\n- *\n- * Return: The sk_buff representing the OOB message or %NULL if the queue was\n- * empty.\n- */\n-struct sk_buff *rxrpc_kernel_dequeue_oob(struct socket *sock,\n-\t\t\t\t\t enum rxrpc_oob_type *_type)\n-{\n-\tstruct rxrpc_sock *rx = rxrpc_sk(sock-\u003esk);\n-\tstruct sk_buff *oob;\n-\n-\toob = skb_dequeue(\u0026rx-\u003erecvmsg_oobq);\n-\tif (oob)\n-\t\t*_type = oob-\u003emark;\n-\treturn oob;\n-}\n-EXPORT_SYMBOL(rxrpc_kernel_dequeue_oob);\n-\n-/**\n- * rxrpc_kernel_free_oob - Free an out-of-band message\n- * @oob: The OOB message to free\n- *\n- * Free an OOB message along with any resources it holds.\n- */\n-void rxrpc_kernel_free_oob(struct sk_buff *oob)\n-{\n-\tstruct rxrpc_skb_priv *sp = rxrpc_skb(oob);\n-\n-\tswitch (oob-\u003emark) {\n-\tcase RXRPC_OOB_CHALLENGE:\n-\t\trxrpc_put_connection(sp-\u003echall.conn, rxrpc_conn_put_oob);\n-\t\tbreak;\n-\t}\n-\n-\trxrpc_free_skb(oob, rxrpc_skb_put_purge_oob);\n-}\n-EXPORT_SYMBOL(rxrpc_kernel_free_oob);\n-\n-/**\n- * rxrpc_kernel_query_challenge - Query the parameters of a challenge\n- * @challenge: The challenge to query\n- * @_peer: Where to return the peer record\n- * @_peer_appdata: The application data attached to a peer record\n- * @_service_id: Where to return the connection service ID\n- * @_security_index: Where to return the connection security index\n- *\n- * Extract useful parameters from a CHALLENGE message.\n- */\n-void rxrpc_kernel_query_challenge(struct sk_buff *challenge,\n-\t\t\t\t  struct rxrpc_peer **_peer,\n-\t\t\t\t  unsigned long *_peer_appdata,\n-\t\t\t\t  u16 *_service_id, u8 *_security_index)\n-{\n-\tstruct rxrpc_skb_priv *sp = rxrpc_skb(challenge);\n-\n-\t*_peer\t\t= sp-\u003echall.conn-\u003epeer;\n-\t*_peer_appdata\t= sp-\u003echall.conn-\u003epeer-\u003eapp_data;\n-\t*_service_id\t= sp-\u003ehdr.serviceId;\n-\t*_security_index = sp-\u003ehdr.securityIndex;\n-}\n-EXPORT_SYMBOL(rxrpc_kernel_query_challenge);\n-\n-/**\n- * rxrpc_kernel_reject_challenge - Allow a kernel service to reject a challenge\n- * @challenge: The challenge to be rejected\n- * @abort_code: The abort code to stick into the ABORT packet\n- * @error: Local error value\n- * @why: Indication as to why.\n- *\n- * Allow a kernel service to reject a challenge by aborting the connection if\n- * it's still in an abortable state.  The error is returned so this function\n- * can be used with a return statement.\n- *\n- * Return: The %error parameter.\n- */\n-int rxrpc_kernel_reject_challenge(struct sk_buff *challenge, u32 abort_code,\n-\t\t\t\t  int error, enum rxrpc_abort_reason why)\n-{\n-\tstruct rxrpc_skb_priv *sp = rxrpc_skb(challenge);\n-\n-\t_enter(\"{%x},%d,%d,%u\", sp-\u003ehdr.serial, abort_code, error, why);\n-\n-\trxrpc_abort_conn(sp-\u003echall.conn, NULL, abort_code, error, why);\n-\treturn error;\n-}\n-EXPORT_SYMBOL(rxrpc_kernel_reject_challenge);\ndiff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c\nindex efcba4b2e74f0c..5b8c7f573b7f5a 100644\n--- a/net/rxrpc/recvmsg.c\n+++ b/net/rxrpc/recvmsg.c\n@@ -17,13 +17,12 @@\n #include \"ar-internal.h\"\n \n /*\n- * Post a call for attention by the socket or kernel service.  Further\n- * notifications are suppressed by putting recvmsg_link on a dummy queue.\n+ * Requeue a call for recvmsg() to pick up.\n  */\n-void rxrpc_notify_socket(struct rxrpc_call *call)\n+static void rxrpc_requeue_call(struct socket *sock, struct rxrpc_call *call)\n {\n-\tstruct rxrpc_sock *rx;\n-\tstruct sock *sk;\n+\tstruct rxrpc_sock *rx = rxrpc_sk(sock-\u003esk);\n+\tstruct sock *sk = \u0026rx-\u003esk;\n \n \t_enter(\"%d\", call-\u003edebug_id);\n \n@@ -32,31 +31,18 @@ void rxrpc_notify_socket(struct rxrpc_call *call)\n \t\treturn;\n \t}\n \n-\trcu_read_lock();\n-\n-\trx = rcu_dereference(call-\u003esocket);\n-\tsk = \u0026rx-\u003esk;\n-\tif (rx \u0026\u0026 sk-\u003esk_state \u003c RXRPC_CLOSE) {\n-\t\tif (call-\u003enotify_rx) {\n-\t\t\tspin_lock_irq(\u0026call-\u003enotify_lock);\n-\t\t\tcall-\u003enotify_rx(sk, call, call-\u003euser_call_ID);\n-\t\t\tspin_unlock_irq(\u0026call-\u003enotify_lock);\n-\t\t} else {\n-\t\t\tspin_lock_irq(\u0026rx-\u003erecvmsg_lock);\n-\t\t\tif (list_empty(\u0026call-\u003erecvmsg_link)) {\n-\t\t\t\trxrpc_get_call(call, rxrpc_call_get_notify_socket);\n-\t\t\t\tlist_add_tail(\u0026call-\u003erecvmsg_link, \u0026rx-\u003erecvmsg_q);\n-\t\t\t}\n-\t\t\tspin_unlock_irq(\u0026rx-\u003erecvmsg_lock);\n+\tspin_lock_irq(\u0026rx-\u003erecvmsg_lock);\n+\tif (list_empty(\u0026call-\u003erecvmsg_link)) {\n+\t\trxrpc_get_call(call, rxrpc_call_get_notify_socket);\n+\t\tlist_add_tail(\u0026call-\u003erecvmsg_link, \u0026rx-\u003erecvmsg_q);\n+\t}\n+\tspin_unlock_irq(\u0026rx-\u003erecvmsg_lock);\n \n-\t\t\tif (!sock_flag(sk, SOCK_DEAD)) {\n-\t\t\t\t_debug(\"call %ps\", sk-\u003esk_data_ready);\n-\t\t\t\tsk-\u003esk_data_ready(sk);\n-\t\t\t}\n-\t\t}\n+\tif (!sock_flag(sk, SOCK_DEAD)) {\n+\t\t_debug(\"call %ps\", sk-\u003esk_data_ready);\n+\t\tsk-\u003esk_data_ready(sk);\n \t}\n \n-\trcu_read_unlock();\n \t_leave(\"\");\n }\n \n@@ -215,61 +201,6 @@ static int rxrpc_recvmsg_user_id(struct rxrpc_call *call, struct msghdr *msg,\n \t}\n }\n \n-/*\n- * Deal with a CHALLENGE packet.\n- */\n-static int rxrpc_recvmsg_challenge(struct socket *sock, struct msghdr *msg,\n-\t\t\t\t   struct sk_buff *challenge, unsigned int flags)\n-{\n-\tstruct rxrpc_skb_priv *sp = rxrpc_skb(challenge);\n-\tstruct rxrpc_connection *conn = sp-\u003echall.conn;\n-\n-\treturn conn-\u003esecurity-\u003echallenge_to_recvmsg(conn, challenge, msg);\n-}\n-\n-/*\n- * Process OOB packets.  Called with the socket locked.\n- */\n-static int rxrpc_recvmsg_oob(struct socket *sock, struct msghdr *msg,\n-\t\t\t     unsigned int flags)\n-{\n-\tstruct rxrpc_sock *rx = rxrpc_sk(sock-\u003esk);\n-\tstruct sk_buff *skb;\n-\tbool need_response = false;\n-\tint ret;\n-\n-\tskb = skb_peek(\u0026rx-\u003erecvmsg_oobq);\n-\tif (!skb)\n-\t\treturn -EAGAIN;\n-\trxrpc_see_skb(skb, rxrpc_skb_see_recvmsg);\n-\n-\tret = put_cmsg(msg, SOL_RXRPC, RXRPC_OOB_ID, sizeof(u64),\n-\t\t       \u0026skb-\u003eskb_mstamp_ns);\n-\tif (ret \u003c 0)\n-\t\treturn ret;\n-\n-\tswitch ((enum rxrpc_oob_type)skb-\u003emark) {\n-\tcase RXRPC_OOB_CHALLENGE:\n-\t\tneed_response = true;\n-\t\tret = rxrpc_recvmsg_challenge(sock, msg, skb, flags);\n-\t\tbreak;\n-\tdefault:\n-\t\tWARN_ONCE(1, \"recvmsg() can't process unknown OOB type %u\\n\",\n-\t\t\t  skb-\u003emark);\n-\t\tret = -EIO;\n-\t\tbreak;\n-\t}\n-\n-\tif (!(flags \u0026 MSG_PEEK)) {\n-\t\tskb_unlink(skb, \u0026rx-\u003erecvmsg_oobq);\n-\t\tif (need_response)\n-\t\t\trxrpc_add_pending_oob(rx, skb);\n-\t\telse\n-\t\t\trxrpc_free_skb(skb, rxrpc_skb_put_oob);\n-\t}\n-\treturn ret;\n-}\n-\n /*\n  * Deliver messages to a call.  This keeps processing packets until the buffer\n  * is filled and we find either more DATA (returns 0) or the end of the DATA\n@@ -281,7 +212,6 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,\n \t\t\t      size_t len, int flags, size_t *_offset)\n {\n \tstruct rxrpc_skb_priv *sp;\n-\tstruct rxrpc_sock *rx = rxrpc_sk(sock-\u003esk);\n \tstruct sk_buff *skb;\n \trxrpc_seq_t seq = 0;\n \tsize_t remain;\n@@ -376,13 +306,6 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,\n \n \t\tif (!(flags \u0026 MSG_PEEK))\n \t\t\trxrpc_rotate_rx_window(call);\n-\n-\t\tif (!rx-\u003eapp_ops \u0026\u0026\n-\t\t    !skb_queue_empty_lockless(\u0026rx-\u003erecvmsg_oobq)) {\n-\t\t\ttrace_rxrpc_recvdata(call, rxrpc_recvmsg_oobq, seq,\n-\t\t\t\t\t     rx_pkt_offset, rx_pkt_len, ret);\n-\t\t\tbreak;\n-\t\t}\n \t}\n \n out:\n@@ -419,7 +342,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,\n \n \ttrace_rxrpc_recvmsg(0, rxrpc_recvmsg_enter, 0);\n \n-\tif (flags \u0026 (MSG_OOB | MSG_TRUNC))\n+\tif (flags \u0026 MSG_TRUNC)\n \t\treturn -EOPNOTSUPP;\n \n \ttimeo = sock_rcvtimeo(\u0026rx-\u003esk, flags \u0026 MSG_DONTWAIT);\n@@ -430,14 +353,12 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,\n \t/* Return immediately if a client socket has no outstanding calls */\n \tif (RB_EMPTY_ROOT(\u0026rx-\u003ecalls) \u0026\u0026\n \t    list_empty(\u0026rx-\u003erecvmsg_q) \u0026\u0026\n-\t    skb_queue_empty_lockless(\u0026rx-\u003erecvmsg_oobq) \u0026\u0026\n \t    rx-\u003esk.sk_state != RXRPC_SERVER_LISTENING) {\n \t\trelease_sock(\u0026rx-\u003esk);\n \t\treturn -EAGAIN;\n \t}\n \n-\tif (list_empty(\u0026rx-\u003erecvmsg_q) \u0026\u0026\n-\t    skb_queue_empty_lockless(\u0026rx-\u003erecvmsg_oobq)) {\n+\tif (list_empty(\u0026rx-\u003erecvmsg_q)) {\n \t\tret = -EWOULDBLOCK;\n \t\tif (timeo == 0) {\n \t\t\tcall = NULL;\n@@ -453,8 +374,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,\n \t\tif (ret)\n \t\t\tgoto wait_error;\n \n-\t\tif (list_empty(\u0026rx-\u003erecvmsg_q) \u0026\u0026\n-\t\t    skb_queue_empty_lockless(\u0026rx-\u003erecvmsg_oobq)) {\n+\t\tif (list_empty(\u0026rx-\u003erecvmsg_q)) {\n \t\t\tif (signal_pending(current))\n \t\t\t\tgoto wait_interrupted;\n \t\t\ttrace_rxrpc_recvmsg(0, rxrpc_recvmsg_wait, 0);\n@@ -464,15 +384,6 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,\n \t\tgoto try_again;\n \t}\n \n-\t/* Deal with OOB messages before we consider getting normal data. */\n-\tif (!skb_queue_empty_lockless(\u0026rx-\u003erecvmsg_oobq)) {\n-\t\tret = rxrpc_recvmsg_oob(sock, msg, flags);\n-\t\trelease_sock(\u0026rx-\u003esk);\n-\t\tif (ret == -EAGAIN)\n-\t\t\tgoto try_again;\n-\t\tgoto error_trace;\n-\t}\n-\n \t/* Find the next call and dequeue it if we're not just peeking.  If we\n \t * do dequeue it, that comes with a ref that we will need to release.\n \t * We also want to weed out calls that got requeued whilst we were\n@@ -483,8 +394,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,\n \tcall = list_entry(l, struct rxrpc_call, recvmsg_link);\n \n \tif (!rxrpc_call_is_complete(call) \u0026\u0026\n-\t    skb_queue_empty(\u0026call-\u003erecvmsg_queue) \u0026\u0026\n-\t    skb_queue_empty(\u0026rx-\u003erecvmsg_oobq)) {\n+\t    skb_queue_empty(\u0026call-\u003erecvmsg_queue)) {\n \t\tlist_del_init(\u0026call-\u003erecvmsg_link);\n \t\tspin_unlock_irq(\u0026rx-\u003erecvmsg_lock);\n \t\trelease_sock(\u0026rx-\u003esk);\n@@ -561,7 +471,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,\n \n \tif (!(flags \u0026 MSG_PEEK) \u0026\u0026\n \t    !skb_queue_empty(\u0026call-\u003erecvmsg_queue))\n-\t\trxrpc_notify_socket(call);\n+\t\trxrpc_requeue_call(sock, call);\n \tgoto not_yet_complete;\n \n call_failed:\ndiff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c\nindex 77a67ace1d2481..b9efeec145dd17 100644\n--- a/net/rxrpc/rxgk.c\n+++ b/net/rxrpc/rxgk.c\n@@ -11,6 +11,7 @@\n #include \u003clinux/skbuff.h\u003e\n #include \u003clinux/slab.h\u003e\n #include \u003clinux/key-type.h\u003e\n+#include \u003ckeys/user-type.h\u003e\n #include \"ar-internal.h\"\n #include \"rxgk_common.h\"\n \n@@ -734,37 +735,6 @@ static bool rxgk_validate_challenge(struct rxrpc_connection *conn,\n \treturn true;\n }\n \n-/**\n- * rxgk_kernel_query_challenge - Query RxGK-specific challenge parameters\n- * @challenge: The challenge packet to query\n- *\n- * Return: The Kerberos 5 encoding type for the challenged connection.\n- */\n-u32 rxgk_kernel_query_challenge(struct sk_buff *challenge)\n-{\n-\tstruct rxrpc_skb_priv *sp = rxrpc_skb(challenge);\n-\n-\treturn sp-\u003echall.conn-\u003erxgk.enctype;\n-}\n-EXPORT_SYMBOL(rxgk_kernel_query_challenge);\n-\n-/*\n- * Fill out the control message to pass to userspace to inform about the\n- * challenge.\n- */\n-static int rxgk_challenge_to_recvmsg(struct rxrpc_connection *conn,\n-\t\t\t\t     struct sk_buff *challenge,\n-\t\t\t\t     struct msghdr *msg)\n-{\n-\tstruct rxgk_challenge chall;\n-\n-\tchall.base.service_id\t\t= conn-\u003eservice_id;\n-\tchall.base.security_index\t= conn-\u003esecurity_ix;\n-\tchall.enctype\t\t\t= conn-\u003erxgk.enctype;\n-\n-\treturn put_cmsg(msg, SOL_RXRPC, RXRPC_CHALLENGED, sizeof(chall), \u0026chall);\n-}\n-\n /*\n  * Insert the requisite amount of XDR padding for the length given.\n  */\n@@ -837,7 +807,7 @@ static noinline ssize_t rxgk_insert_response_header(struct rxrpc_connection *con\n  */\n static ssize_t rxgk_construct_authenticator(struct rxrpc_connection *conn,\n \t\t\t\t\t    struct sk_buff *challenge,\n-\t\t\t\t\t    const struct krb5_buffer *appdata,\n+\t\t\t\t\t    const struct user_key_payload *appdata,\n \t\t\t\t\t    struct sk_buff *response,\n \t\t\t\t\t    size_t offset)\n {\n@@ -859,20 +829,20 @@ static ssize_t rxgk_construct_authenticator(struct rxrpc_connection *conn,\n \tif (ret \u003c 0)\n \t\treturn -EPROTO;\n \n-\ta.appdata_len = htonl(appdata-\u003elen);\n+\ta.appdata_len = htonl(appdata-\u003edatalen);\n \n \tret = skb_store_bits(response, offset, \u0026a, sizeof(a));\n \tif (ret \u003c 0)\n \t\treturn ret;\n \toffset += sizeof(a);\n \n-\tif (appdata-\u003elen) {\n-\t\tret = skb_store_bits(response, offset, appdata-\u003edata, appdata-\u003elen);\n+\tif (appdata-\u003edatalen) {\n+\t\tret = skb_store_bits(response, offset, appdata-\u003edata, appdata-\u003edatalen);\n \t\tif (ret \u003c 0)\n \t\t\treturn ret;\n-\t\toffset += appdata-\u003elen;\n+\t\toffset += appdata-\u003edatalen;\n \n-\t\tret = rxgk_pad_out(response, appdata-\u003elen, offset);\n+\t\tret = rxgk_pad_out(response, appdata-\u003edatalen, offset);\n \t\tif (ret \u003c 0)\n \t\t\treturn ret;\n \t\toffset += ret;\n@@ -890,7 +860,7 @@ static ssize_t rxgk_construct_authenticator(struct rxrpc_connection *conn,\n \tret = skb_store_bits(response, offset, \u0026b, sizeof(b));\n \tif (ret \u003c 0)\n \t\treturn ret;\n-\treturn sizeof(a) + xdr_round_up(appdata-\u003elen) + sizeof(b);\n+\treturn sizeof(a) + xdr_round_up(appdata-\u003edatalen) + sizeof(b);\n }\n \n static ssize_t rxgk_encrypt_authenticator(struct rxrpc_connection *conn,\n@@ -923,7 +893,7 @@ static ssize_t rxgk_encrypt_authenticator(struct rxrpc_connection *conn,\n  */\n static int rxgk_construct_response(struct rxrpc_connection *conn,\n \t\t\t\t   struct sk_buff *challenge,\n-\t\t\t\t   struct krb5_buffer *appdata)\n+\t\t\t\t   const struct user_key_payload *appdata)\n {\n \tstruct rxrpc_skb_priv *csp, *rsp;\n \tstruct rxgk_context *gk;\n@@ -936,7 +906,7 @@ static int rxgk_construct_response(struct rxrpc_connection *conn,\n \tif (IS_ERR(gk))\n \t\treturn PTR_ERR(gk);\n \n-\tauth_len = 20 + (4 + appdata-\u003elen) + 12 + (1 + 4) * 4;\n+\tauth_len = 20 + (4 + appdata-\u003edatalen) + 12 + (1 + 4) * 4;\n \tauthx_len = crypto_krb5_how_much_buffer(gk-\u003ekrb5, KRB5_ENCRYPT_MODE,\n \t\t\t\t\t\tauth_len, \u0026auth_offset);\n \tlen = sizeof(struct rxrpc_wire_header) +\n@@ -1011,66 +981,36 @@ static int rxgk_construct_response(struct rxrpc_connection *conn,\n  * Respond to a challenge packet.\n  */\n static int rxgk_respond_to_challenge(struct rxrpc_connection *conn,\n-\t\t\t\t     struct sk_buff *challenge,\n-\t\t\t\t     struct krb5_buffer *appdata)\n+\t\t\t\t     struct sk_buff *challenge)\n {\n-\t_enter(\"{%d,%x}\", conn-\u003edebug_id, key_serial(conn-\u003ekey));\n+\tstruct user_key_payload dummy = {}, *appdata = \u0026dummy;\n+\tint ret;\n+\n+\t_enter(\"{%d,%u,%x,%x}\",\n+\t       conn-\u003edebug_id, conn-\u003eservice_id,\n+\t       key_serial(conn-\u003ekey), key_serial(conn-\u003ebundle-\u003eapp_data));\n \n \tif (key_validate(conn-\u003ekey) \u003c 0)\n \t\treturn rxrpc_abort_conn(conn, NULL, RXGK_EXPIRED, -EPROTO,\n \t\t\t\t\trxgk_abort_chall_key_expired);\n \n-\treturn rxgk_construct_response(conn, challenge, appdata);\n-}\n-\n-static int rxgk_respond_to_challenge_no_appdata(struct rxrpc_connection *conn,\n-\t\t\t\t\t\tstruct sk_buff *challenge)\n-{\n-\tstruct krb5_buffer appdata = {};\n-\n-\treturn rxgk_respond_to_challenge(conn, challenge, \u0026appdata);\n-}\n-\n-/**\n- * rxgk_kernel_respond_to_challenge - Respond to a challenge with appdata\n- * @challenge: The challenge to respond to\n- * @appdata: The application data to include in the RESPONSE authenticator\n- *\n- * Allow a kernel application to respond to a CHALLENGE with application data\n- * to be included in the RxGK RESPONSE Authenticator.\n- *\n- * Return: %0 if successful and a negative error code otherwise.\n- */\n-int rxgk_kernel_respond_to_challenge(struct sk_buff *challenge,\n-\t\t\t\t     struct krb5_buffer *appdata)\n-{\n-\tstruct rxrpc_skb_priv *csp = rxrpc_skb(challenge);\n-\n-\treturn rxgk_respond_to_challenge(csp-\u003echall.conn, challenge, appdata);\n-}\n-EXPORT_SYMBOL(rxgk_kernel_respond_to_challenge);\n-\n-/*\n- * Parse sendmsg() control message and respond to challenge.  We need to see if\n- * there's an appdata to fish out.\n- */\n-static int rxgk_sendmsg_respond_to_challenge(struct sk_buff *challenge,\n-\t\t\t\t\t     struct msghdr *msg)\n-{\n-\tstruct krb5_buffer appdata = {};\n-\tstruct cmsghdr *cmsg;\n-\n-\tfor_each_cmsghdr(cmsg, msg) {\n-\t\tif (cmsg-\u003ecmsg_level != SOL_RXRPC ||\n-\t\t    cmsg-\u003ecmsg_type != RXRPC_RESP_RXGK_APPDATA)\n-\t\t\tcontinue;\n-\t\tif (appdata.data)\n-\t\t\treturn -EINVAL;\n-\t\tappdata.data = CMSG_DATA(cmsg);\n-\t\tappdata.len = cmsg-\u003ecmsg_len - sizeof(struct cmsghdr);\n+\tif (conn-\u003ebundle-\u003eapp_data) {\n+\t\trcu_read_lock();\n+\t\tappdata = (struct user_key_payload *)\n+\t\t\tuser_key_payload_rcu(conn-\u003ebundle-\u003eapp_data);\n+\t\tif (appdata \u0026\u0026 !refcount_inc_not_zero(\u0026appdata-\u003eref))\n+\t\t\tappdata = NULL;\n+\t\trcu_read_unlock();\n+\t\tif (!appdata)\n+\t\t\treturn rxrpc_abort_conn(conn, NULL, RXGK_EXPIRED, -EKEYREVOKED,\n+\t\t\t\t\t\trxgk_abort_chall_key_expired);\n \t}\n \n-\treturn rxgk_kernel_respond_to_challenge(challenge, \u0026appdata);\n+\tret = rxgk_construct_response(conn, challenge, appdata);\n+\n+\tif (appdata != \u0026dummy)\n+\t\tput_user_key_payload(appdata);\n+\treturn ret;\n }\n \n /*\n@@ -1346,9 +1286,7 @@ const struct rxrpc_security rxgk_yfs = {\n \t.free_call_crypto\t\t= rxgk_free_call_crypto,\n \t.issue_challenge\t\t= rxgk_issue_challenge,\n \t.validate_challenge\t\t= rxgk_validate_challenge,\n-\t.challenge_to_recvmsg\t\t= rxgk_challenge_to_recvmsg,\n-\t.sendmsg_respond_to_challenge\t= rxgk_sendmsg_respond_to_challenge,\n-\t.respond_to_challenge\t\t= rxgk_respond_to_challenge_no_appdata,\n+\t.respond_to_challenge\t\t= rxgk_respond_to_challenge,\n \t.verify_response\t\t= rxgk_verify_response,\n \t.clear\t\t\t\t= rxgk_clear,\n \t.default_decode_ticket\t\t= rxgk_yfs_decode_ticket,\ndiff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c\nindex ca9f0e82cb9ac7..e55bfca10e1a94 100644\n--- a/net/rxrpc/rxkad.c\n+++ b/net/rxrpc/rxkad.c\n@@ -748,32 +748,6 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,\n \treturn ret;\n }\n \n-/*\n- * RxKAD does automatic response only as there's nothing to manage that isn't\n- * already in the key.\n- */\n-static int rxkad_sendmsg_respond_to_challenge(struct sk_buff *challenge,\n-\t\t\t\t\t      struct msghdr *msg)\n-{\n-\treturn -EINVAL;\n-}\n-\n-/**\n- * rxkad_kernel_respond_to_challenge - Respond to a challenge with appdata\n- * @challenge: The challenge to respond to\n- *\n- * Allow a kernel application to respond to a CHALLENGE.\n- *\n- * Return: %0 if successful and a negative error code otherwise.\n- */\n-int rxkad_kernel_respond_to_challenge(struct sk_buff *challenge)\n-{\n-\tstruct rxrpc_skb_priv *csp = rxrpc_skb(challenge);\n-\n-\treturn rxkad_respond_to_challenge(csp-\u003echall.conn, challenge);\n-}\n-EXPORT_SYMBOL(rxkad_kernel_respond_to_challenge);\n-\n /* Decrypt data in-place using DES-PCBC.  @len must be a multiple of 8. */\n VISIBLE_IF_KUNIT void des_pcbc_decrypt_inplace(const struct des_ctx *key,\n \t\t\t\t\t       __le64 iv, u8 *data, size_t len)\n@@ -1134,7 +1108,6 @@ const struct rxrpc_security rxkad = {\n \t.free_call_crypto\t\t= rxkad_free_call_crypto,\n \t.issue_challenge\t\t= rxkad_issue_challenge,\n \t.validate_challenge\t\t= rxkad_validate_challenge,\n-\t.sendmsg_respond_to_challenge\t= rxkad_sendmsg_respond_to_challenge,\n \t.respond_to_challenge\t\t= rxkad_respond_to_challenge,\n \t.verify_response\t\t= rxkad_verify_response,\n \t.clear\t\t\t\t= rxkad_clear,\ndiff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c\nindex ed2c9a51005ade..cdf35440317d6d 100644\n--- a/net/rxrpc/sendmsg.c\n+++ b/net/rxrpc/sendmsg.c\n@@ -12,6 +12,7 @@\n #include \u003clinux/skbuff.h\u003e\n #include \u003clinux/export.h\u003e\n #include \u003clinux/sched/signal.h\u003e\n+#include \u003ckeys/user-type.h\u003e\n \n #include \u003cnet/sock.h\u003e\n #include \u003cnet/af_rxrpc.h\u003e\n@@ -320,8 +321,8 @@ static int rxrpc_alloc_txqueue(struct sock *sk, struct rxrpc_call *call)\n static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\t\t   struct rxrpc_call *call,\n \t\t\t   struct msghdr *msg, size_t len,\n-\t\t\t   rxrpc_notify_end_tx_t notify_end_tx,\n-\t\t\t   bool *_dropped_lock)\n+\t\t\t   rxrpc_notify_end_tx_t notify_end_tx)\n+\t__releases(\u0026call-\u003euser_mutex)\n {\n \tstruct rxrpc_txbuf *txb;\n \tstruct sock *sk = \u0026rx-\u003esk;\n@@ -330,23 +331,31 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \tbool more = msg-\u003emsg_flags \u0026 MSG_MORE;\n \tint ret, copied = 0;\n \n-\tif (test_bit(RXRPC_CALL_TX_NO_MORE, \u0026call-\u003eflags)) {\n+\tif (unlikely(test_bit(RXRPC_CALL_TX_NO_MORE, \u0026call-\u003eflags))) {\n \t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_sendmsg_late_send,\n \t\t\t\t  call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n \t\t\t\t  0, -EPROTO);\n-\t\treturn -EPROTO;\n+\t\tret = -EPROTO;\n+\t\tgoto out_unlock;\n+\t}\n+\tif (unlikely(test_bit(RXRPC_CALL_TX_ERROR, \u0026call-\u003eflags))) {\n+\t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_sendmsg_tx_error,\n+\t\t\t\t  call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n+\t\t\t\t  0, -EIO);\n+\t\tret = -EIO;\n+\t\tgoto out_unlock;\n \t}\n \n \ttimeo = sock_sndtimeo(sk, msg-\u003emsg_flags \u0026 MSG_DONTWAIT);\n \n \tret = rxrpc_wait_to_be_connected(call, \u0026timeo);\n \tif (ret \u003c 0)\n-\t\treturn ret;\n+\t\tgoto out_unlock;\n \n \tif (call-\u003econn-\u003estate == RXRPC_CONN_CLIENT_UNSECURED) {\n \t\tret = rxrpc_init_client_conn_security(call-\u003econn);\n \t\tif (ret \u003c 0)\n-\t\t\treturn ret;\n+\t\t\tgoto out_unlock;\n \t}\n \n \t/* this should be in poll */\n@@ -440,12 +449,21 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\t/* add the packet to the send queue if it's now full */\n \t\tif (!txb-\u003espace ||\n \t\t    (msg_data_left(msg) == 0 \u0026\u0026 !more)) {\n+\t\t\t/* Do any required crypto.  If this fails, it could\n+\t\t\t * have corrupted the txbuf content with a partial\n+\t\t\t * encrypt.  Assume that ENOMEM is retryable, but\n+\t\t\t * everything else is terminal.\n+\t\t\t */\n+\t\t\tret = call-\u003esecurity-\u003esecure_packet(call, txb);\n+\t\t\tif (ret \u003c 0) {\n+\t\t\t\tif (ret == -ENOMEM)\n+\t\t\t\t\tgoto maybe_error;\n+\t\t\t\tset_bit(RXRPC_CALL_TX_ERROR, \u0026call-\u003eflags);\n+\t\t\t\tgoto out_txb;\n+\t\t\t}\n+\n \t\t\tif (msg_data_left(msg) == 0 \u0026\u0026 !more)\n \t\t\t\ttxb-\u003eflags |= RXRPC_LAST_PACKET;\n-\n-\t\t\tret = call-\u003esecurity-\u003esecure_packet(call, txb);\n-\t\t\tif (ret \u003c 0)\n-\t\t\t\tgoto out;\n \t\t\trxrpc_queue_packet(rx, call, txb, notify_end_tx);\n \t\t\ttxb = NULL;\n \t\t}\n@@ -453,48 +471,58 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \n success:\n \tret = copied;\n-\tif (rxrpc_call_is_complete(call) \u0026\u0026\n-\t    call-\u003eerror \u003c 0)\n-\t\tret = call-\u003eerror;\n-out:\n+out_txb:\n \tcall-\u003etx_pending = txb;\n+out_unlock:\n+\tmutex_unlock(\u0026call-\u003euser_mutex);\n \t_leave(\" = %d\", ret);\n \treturn ret;\n \n call_terminated:\n \trxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);\n-\t_leave(\" = %d\", call-\u003eerror);\n-\treturn call-\u003eerror;\n+\tcall-\u003etx_pending = NULL;\n+\tret = call-\u003eerror;\n+\tgoto out_unlock;\n \n maybe_error:\n-\tif (copied)\n+\tif (copied) {\n+\t\tif (rxrpc_call_is_complete(call) \u0026\u0026\n+\t\t    call-\u003eerror \u003c 0) {\n+\t\t\tret = call-\u003eerror;\n+\t\t\tgoto out_unlock;\n+\t\t}\n \t\tgoto success;\n-\tgoto out;\n+\t}\n+\tgoto out_txb;\n \n efault:\n \tret = -EFAULT;\n-\tgoto out;\n+\tgoto out_txb;\n \n wait_for_space:\n \tret = -EAGAIN;\n \tif (msg-\u003emsg_flags \u0026 MSG_DONTWAIT)\n \t\tgoto maybe_error;\n+\tcall-\u003etx_pending = txb;\n+\ttxb = NULL;\n \tmutex_unlock(\u0026call-\u003euser_mutex);\n-\t*_dropped_lock = true;\n+\n \tret = rxrpc_wait_for_tx_window(rx, call, \u0026timeo,\n \t\t\t\t       msg-\u003emsg_flags \u0026 MSG_WAITALL);\n \tif (ret \u003c 0)\n-\t\tgoto maybe_error;\n+\t\tgoto out_nolock;\n \tif (call-\u003einterruptibility == RXRPC_INTERRUPTIBLE) {\n \t\tif (mutex_lock_interruptible(\u0026call-\u003euser_mutex) \u003c 0) {\n \t\t\tret = sock_intr_errno(timeo);\n-\t\t\tgoto maybe_error;\n+\t\t\tgoto out_nolock;\n \t\t}\n \t} else {\n \t\tmutex_lock(\u0026call-\u003euser_mutex);\n \t}\n-\t*_dropped_lock = false;\n \tgoto reload;\n+out_nolock:\n+\t_leave(\" = %d [intr]\", ret);\n+\treturn copied ?: ret;\n }\n \n /*\n@@ -503,6 +531,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p)\n {\n \tstruct cmsghdr *cmsg;\n+\tkey_serial_t key_id;\n+\tkey_ref_t key;\n \tbool got_user_ID = false;\n \tint len;\n \n@@ -587,6 +617,22 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p)\n \t\t\t\treturn -ERANGE;\n \t\t\tbreak;\n \n+\t\tcase RXRPC_RESPONSE_APPDATA:\n+\t\t\tif (len != sizeof(key_serial_t))\n+\t\t\t\treturn -EINVAL;\n+\t\t\tif (p-\u003ecall.app_data)\n+\t\t\t\treturn -EINVAL;\n+\t\t\tkey_id = *(key_serial_t *)CMSG_DATA(cmsg);\n+\t\t\tkey = lookup_user_key(key_id, 0, KEY_NEED_SEARCH);\n+\t\t\tif (IS_ERR(key))\n+\t\t\t\treturn PTR_ERR(key);\n+\t\t\tif (key_ref_to_ptr(key)-\u003etype == \u0026key_type_user) {\n+\t\t\t\tkey_ref_put(key);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\tp-\u003ecall.app_data = key_ref_to_ptr(key);\n+\t\t\tbreak;\n+\n \t\tdefault:\n \t\t\treturn -EINVAL;\n \t\t}\n@@ -695,8 +741,10 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n \t\t\tgoto error_release_sock;\n \t\tcall = rxrpc_new_client_call_for_sendmsg(rx, msg, \u0026p);\n \t\t/* The socket is now unlocked... */\n-\t\tif (IS_ERR(call))\n+\t\tif (IS_ERR(call)) {\n+\t\t\tkey_put(p.call.app_data);\n \t\t\treturn PTR_ERR(call);\n+\t\t}\n \t\t/* ... and we have the call lock. */\n \t\tp.call.nr_timeouts = 0;\n \t\tret = 0;\n@@ -769,8 +817,8 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n \t\tret = 0;\n \t\tbreak;\n \tcase RXRPC_CMD_SEND_DATA:\n-\t\tret = rxrpc_send_data(rx, call, msg, len, NULL, \u0026dropped_lock);\n-\t\tbreak;\n+\t\tret = rxrpc_send_data(rx, call, msg, len, NULL);\n+\t\tgoto error_put;\n \tdefault:\n \t\tret = -EINVAL;\n \t\tbreak;\n@@ -781,11 +829,13 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n \t\tmutex_unlock(\u0026call-\u003euser_mutex);\n error_put:\n \trxrpc_put_call(call, rxrpc_call_put_sendmsg);\n+\tkey_put(p.call.app_data);\n \t_leave(\" = %d\", ret);\n \treturn ret;\n \n error_release_sock:\n \trelease_sock(\u0026rx-\u003esk);\n+\tkey_put(p.call.app_data);\n \treturn ret;\n }\n \n@@ -808,7 +858,6 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,\n \t\t\t   struct msghdr *msg, size_t len,\n \t\t\t   rxrpc_notify_end_tx_t notify_end_tx)\n {\n-\tbool dropped_lock = false;\n \tint ret;\n \n \t_enter(\"{%d},\", call-\u003edebug_id);\n@@ -819,12 +868,10 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,\n \tmutex_lock(\u0026call-\u003euser_mutex);\n \n \tret = rxrpc_send_data(rxrpc_sk(sock-\u003esk), call, msg, len,\n-\t\t\t      notify_end_tx, \u0026dropped_lock);\n+\t\t\t      notify_end_tx);\n \tif (ret == -ESHUTDOWN)\n \t\tret = call-\u003eerror;\n \n-\tif (!dropped_lock)\n-\t\tmutex_unlock(\u0026call-\u003euser_mutex);\n \t_leave(\" = %d\", ret);\n \treturn ret;\n }\ndiff --git a/net/rxrpc/server_key.c b/net/rxrpc/server_key.c\nindex 3efe104b1930cb..fc6f478e1762a7 100644\n--- a/net/rxrpc/server_key.c\n+++ b/net/rxrpc/server_key.c\n@@ -173,43 +173,3 @@ int rxrpc_sock_set_security_keyring(struct sock *sk, struct key *keyring)\n \treturn ret;\n }\n EXPORT_SYMBOL(rxrpc_sock_set_security_keyring);\n-\n-/**\n- * rxrpc_sock_set_manage_response - Set the manage-response flag for a kernel service\n- * @sk: The socket to set the keyring on\n- * @set: True to set, false to clear the flag\n- *\n- * Set the flag on an rxrpc socket to say that the caller wants to manage the\n- * RESPONSE packet and the user-defined data it may contain.  Setting this\n- * means that recvmsg() will return messages with RXRPC_CHALLENGED in the\n- * control message buffer containing information about the challenge.\n- *\n- * The user should respond to the challenge by passing RXRPC_RESPOND or\n- * RXRPC_RESPOND_ABORT control messages with sendmsg() to the same call.\n- * Supplementary control messages, such as RXRPC_RESP_RXGK_APPDATA, may be\n- * included to indicate the parts the user wants to supply.\n- *\n- * The server will be passed the response data with a RXRPC_RESPONDED control\n- * message when it gets the first data from each call.\n- *\n- * Note that this is only honoured by security classes that need auxiliary data\n- * (e.g. RxGK).  Those that don't offer the facility (e.g. RxKAD) respond\n- * without consulting userspace.\n- *\n- * Return: The previous setting.\n- */\n-int rxrpc_sock_set_manage_response(struct sock *sk, bool set)\n-{\n-\tstruct rxrpc_sock *rx = rxrpc_sk(sk);\n-\tint ret;\n-\n-\tlock_sock(sk);\n-\tret = !!test_bit(RXRPC_SOCK_MANAGE_RESPONSE, \u0026rx-\u003eflags);\n-\tif (set)\n-\t\tset_bit(RXRPC_SOCK_MANAGE_RESPONSE, \u0026rx-\u003eflags);\n-\telse\n-\t\tclear_bit(RXRPC_SOCK_MANAGE_RESPONSE, \u0026rx-\u003eflags);\n-\trelease_sock(sk);\n-\treturn ret;\n-}\n-EXPORT_SYMBOL(rxrpc_sock_set_manage_response);\ndiff --git a/security/keys/user_defined.c b/security/keys/user_defined.c\nindex 6f88b507f92791..90c1bd5d7dfecf 100644\n--- a/security/keys/user_defined.c\n+++ b/security/keys/user_defined.c\n@@ -67,6 +67,7 @@ int user_preparse(struct key_preparsed_payload *prep)\n \tupayload = kmalloc_flex(*upayload, data, datalen);\n \tif (!upayload)\n \t\treturn -ENOMEM;\n+\trefcount_set(\u0026upayload-\u003eref, 1);\n \n \t/* attach the data */\n \tprep-\u003equotalen = datalen;\n@@ -88,12 +89,22 @@ EXPORT_SYMBOL_GPL(user_free_preparse);\n \n static void user_free_payload_rcu(struct rcu_head *head)\n {\n-\tstruct user_key_payload *payload;\n+\tstruct user_key_payload *payload =\n+\t\tcontainer_of(head, struct user_key_payload, rcu);\n \n-\tpayload = container_of(head, struct user_key_payload, rcu);\n \tkfree_sensitive(payload);\n }\n \n+/*\n+ * Free a user defined key payload.\n+ */\n+void put_user_key_payload(struct user_key_payload *payload)\n+{\n+\tif (payload \u0026\u0026 refcount_dec_and_test(\u0026payload-\u003eref))\n+\t\tcall_rcu(\u0026payload-\u003ercu, user_free_payload_rcu);\n+}\n+EXPORT_SYMBOL_GPL(put_user_key_payload);\n+\n /*\n  * update a user defined key\n  * - the key's semaphore is write-locked\n@@ -115,8 +126,7 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)\n \trcu_assign_keypointer(key, prep-\u003epayload.data[0]);\n \tprep-\u003epayload.data[0] = NULL;\n \n-\tif (zap)\n-\t\tcall_rcu(\u0026zap-\u003ercu, user_free_payload_rcu);\n+\tput_user_key_payload(zap);\n \treturn ret;\n }\n EXPORT_SYMBOL_GPL(user_update);\n@@ -134,7 +144,7 @@ void user_revoke(struct key *key)\n \n \tif (upayload) {\n \t\trcu_assign_keypointer(key, NULL);\n-\t\tcall_rcu(\u0026upayload-\u003ercu, user_free_payload_rcu);\n+\t\tput_user_key_payload(upayload);\n \t}\n }\n \n@@ -147,9 +157,8 @@ void user_destroy(struct key *key)\n {\n \tstruct user_key_payload *upayload = key-\u003epayload.data[0];\n \n-\tkfree_sensitive(upayload);\n+\tput_user_key_payload(upayload);\n }\n-\n EXPORT_SYMBOL_GPL(user_destroy);\n \n /*\n"
}

2/1 2026/07/11 16:41 agent patch-evaluator
1m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "AF_RXRPC",
    "RXGK",
    "AFS_FS"
  ],
  "FocusSymbols": [
    "afs_create_server_appdata",
    "afs_create_yfs_rxgk_cm_appdata",
    "rxgk_respond_to_challenge",
    "rxrpc_sendmsg_cmsg",
    "put_user_key_payload"
  ],
  "Reasoning": "The patch series refactors out-of-band message handling in rxrpc, replacing it with a key-based approach for passing application data in RxGK responses. It also modifies AFS to use this new mechanism by creating a key containing the app data and passing it to rxrpc_kernel_begin_call. These are functional changes to core rxrpc and AFS logic that should be fuzzed to ensure the new key-based app data handling and challenge-response mechanisms work correctly.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit e670920210e13fe875f0ff4ecd3e4a5223bc1f0e
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Jul 11 16:41:14 2026 +0000

    syz-cluster: applied patch under review

diff --git a/fs/afs/cm_security.c b/fs/afs/cm_security.c
index 103168c70dd4df..f0fec3a7652288 100644
--- a/fs/afs/cm_security.c
+++ b/fs/afs/cm_security.c
@@ -6,7 +6,9 @@
  */
 
 #include <linux/slab.h>
+#include <linux/key-type.h>
 #include <crypto/krb5.h>
+#include <keys/user-type.h>
 #include "internal.h"
 #include "afs_cm.h"
 #include "afs_fs.h"
@@ -19,195 +21,39 @@
 #define xdr_len_object(x) (4 + round_up((x), sizeof(__be32)))
 
 #ifdef CONFIG_RXGK
-static int afs_create_yfs_cm_token(struct sk_buff *challenge,
-				   struct afs_server *server);
-#endif
-
 /*
- * Respond to an RxGK challenge, adding appdata.
+ * As the YFS RxGK appdata to be passed in the YFS.FS-service RESPONSE packet,
+ * create a GSS token to use as a ticket to the specified fileserver.
  */
-static int afs_respond_to_challenge(struct sk_buff *challenge)
-{
-#ifdef CONFIG_RXGK
-	struct krb5_buffer appdata = {};
-	struct afs_server *server;
-#endif
-	struct rxrpc_peer *peer;
-	unsigned long peer_data;
-	u16 service_id;
-	u8 security_index;
-
-	rxrpc_kernel_query_challenge(challenge, &peer, &peer_data,
-				     &service_id, &security_index);
-
-	_enter("%u,%u", service_id, security_index);
-
-	switch (service_id) {
-		/* We don't send CM_SERVICE RPCs, so don't expect a challenge
-		 * therefrom.
-		 */
-	case FS_SERVICE:
-	case VL_SERVICE:
-	case YFS_FS_SERVICE:
-	case YFS_VL_SERVICE:
-		break;
-	default:
-		pr_warn("Can't respond to unknown challenge %u:%u",
-			service_id, security_index);
-		return rxrpc_kernel_reject_challenge(challenge, RX_USER_ABORT, -EPROTO,
-						     afs_abort_unsupported_sec_class);
-	}
-
-	switch (security_index) {
-#ifdef CONFIG_RXKAD
-	case RXRPC_SECURITY_RXKAD:
-		return rxkad_kernel_respond_to_challenge(challenge);
-#endif
-
-#ifdef CONFIG_RXGK
-	case RXRPC_SECURITY_RXGK:
-		return rxgk_kernel_respond_to_challenge(challenge, &appdata);
-
-	case RXRPC_SECURITY_YFS_RXGK:
-		switch (service_id) {
-		case FS_SERVICE:
-		case YFS_FS_SERVICE:
-			server = (struct afs_server *)peer_data;
-			if (!server->cm_rxgk_appdata.data) {
-				mutex_lock(&server->cm_token_lock);
-				if (!server->cm_rxgk_appdata.data)
-					afs_create_yfs_cm_token(challenge, server);
-				mutex_unlock(&server->cm_token_lock);
-			}
-			if (server->cm_rxgk_appdata.data)
-				appdata = server->cm_rxgk_appdata;
-			break;
-		}
-		return rxgk_kernel_respond_to_challenge(challenge, &appdata);
-#endif
-
-	default:
-		return rxrpc_kernel_reject_challenge(challenge, RX_USER_ABORT, -EPROTO,
-						     afs_abort_unsupported_sec_class);
-	}
-}
-
-/*
- * Process the OOB message queue, processing challenge packets.
- */
-void afs_process_oob_queue(struct work_struct *work)
-{
-	struct afs_net *net = container_of(work, struct afs_net, rx_oob_work);
-	struct sk_buff *oob;
-	enum rxrpc_oob_type type;
-
-	while (READ_ONCE(net->live) &&
-	       (oob = rxrpc_kernel_dequeue_oob(net->socket, &type))) {
-		switch (type) {
-		case RXRPC_OOB_CHALLENGE:
-			afs_respond_to_challenge(oob);
-			break;
-		}
-		rxrpc_kernel_free_oob(oob);
-	}
-}
-
-#ifdef CONFIG_RXGK
-/*
- * Create a securities keyring for the cache manager and attach a key to it for
- * the RxGK tokens we want to use to secure the callback connection back from
- * the fileserver.
- */
-int afs_create_token_key(struct afs_net *net, struct socket *socket)
-{
-	const struct krb5_enctype *krb5;
-	struct key *ring;
-	key_ref_t key;
-	char K0[32], *desc;
-	int ret;
-
-	ring = keyring_alloc("kafs",
-			     GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
-			     KEY_POS_SEARCH | KEY_POS_WRITE |
-			     KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH,
-			     KEY_ALLOC_NOT_IN_QUOTA,
-			     NULL, NULL);
-	if (IS_ERR(ring))
-		return PTR_ERR(ring);
-
-	ret = rxrpc_sock_set_security_keyring(socket->sk, ring);
-	if (ret < 0)
-		goto out;
-
-	ret = -ENOPKG;
-	krb5 = crypto_krb5_find_enctype(KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96);
-	if (!krb5)
-		goto out;
-
-	if (WARN_ON_ONCE(krb5->key_len > sizeof(K0)))
-		goto out;
-
-	ret = -ENOMEM;
-	desc = kasprintf(GFP_KERNEL, "%u:%u:%u:%u",
-			 YFS_CM_SERVICE, RXRPC_SECURITY_YFS_RXGK, 1, krb5->etype);
-	if (!desc)
-		goto out;
-
-	wait_for_random_bytes();
-	get_random_bytes(K0, krb5->key_len);
-
-	key = key_create(make_key_ref(ring, true),
-			 "rxrpc_s", desc,
-			 K0, krb5->key_len,
-			 KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_USR_VIEW,
-			 KEY_ALLOC_NOT_IN_QUOTA);
-	kfree(desc);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
-		goto out;
-	}
-
-	net->fs_cm_token_key = key_ref_to_ptr(key);
-	ret = 0;
-out:
-	key_put(ring);
-	return ret;
-}
-
-/*
- * Create an YFS RxGK GSS token to use as a ticket to the specified fileserver.
- */
-static int afs_create_yfs_cm_token(struct sk_buff *challenge,
-				   struct afs_server *server)
+static int afs_create_yfs_rxgk_cm_appdata(struct afs_server *server, u32 enctype)
 {
 	const struct krb5_enctype *conn_krb5, *token_krb5;
 	const struct krb5_buffer *token_key;
 	struct crypto_aead *aead;
 	struct scatterlist sg;
 	struct afs_net *net = server->cell->net;
-	const struct key *key = net->fs_cm_token_key;
-	size_t keysize, uuidsize, authsize, toksize, encsize, contsize, adatasize, offset;
+	const struct key *cm_key = net->fs_cm_token_key;
+	struct key *appdata_key = NULL;
+	size_t keysize, uuidsize, authsize, toksize, encsize, contsize;
+	size_t adatasize, offset;
 	__be32 caps[1] = {
 		[0] = htonl(AFS_CAP_ERROR_TRANSLATION),
 	};
 	__be32 *xdr;
 	void *appdata, *K0, *encbase;
-	u32 enctype;
 	int ret;
 
-	if (!key)
+	if (!cm_key)
 		return -ENOKEY;
 
 	/* Assume that the fileserver is happy to use the same encoding type as
 	 * we were told to use by the token obtained by the user.
 	 */
-	enctype = rxgk_kernel_query_challenge(challenge);
-
 	conn_krb5 = crypto_krb5_find_enctype(enctype);
 	if (!conn_krb5)
 		return -ENOPKG;
-	token_krb5 = key->payload.data[0];
-	token_key = (const struct krb5_buffer *)&key->payload.data[2];
+	token_krb5 = cm_key->payload.data[0];
+	token_key = (const struct krb5_buffer *)&cm_key->payload.data[2];
 
 	/* struct rxgk_key {
 	 *	afs_uint32	enctype;
@@ -327,9 +173,23 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,
 	if (ret < 0)
 		goto out_aead;
 
-	server->cm_rxgk_appdata.len  = adatasize;
-	server->cm_rxgk_appdata.data = appdata;
-	appdata = NULL;
+	appdata_key = key_alloc(&key_type_user, "rxrpc: afs rxgk appdata",
+				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
+				KEY_POS_VIEW | KEY_POS_SEARCH | KEY_USR_VIEW,
+				KEY_ALLOC_NOT_IN_QUOTA, NULL);
+	if (IS_ERR(appdata_key)) {
+		ret = PTR_ERR(appdata_key);
+		goto out_aead;
+	}
+
+	ret = key_instantiate_and_link(appdata_key, appdata, adatasize, NULL, NULL);
+	if (ret < 0) {
+		key_put(appdata_key);
+		goto out_aead;
+	}
+
+	/* Store the appdata before the key pointer */
+	smp_store_release(&server->yfs_rxgk_appdata, appdata_key);
 
 out_aead:
 	crypto_free_aead(aead);
@@ -339,3 +199,116 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,
 	return ret;
 }
 #endif /* CONFIG_RXGK */
+
+/*
+ * Create the application data to go in a RESPONSE packet a server's CHALLENGE
+ * from the parameters contained in a key.  The key specifies the security
+ * index and other appropriate parameters such as the encoding type for RxGK.
+ */
+int afs_create_server_appdata(struct afs_server *server, struct key *key)
+{
+	u32 krb5_enctype;
+	int ret;
+	u8 security_index;
+
+	if (!key)
+		return 0;
+
+	rxrpc_kernel_query_key(key, &security_index, &krb5_enctype);
+
+	_enter("%u,%u", security_index, krb5_enctype);
+
+	switch (security_index) {
+#ifdef CONFIG_RXGK
+	case RXRPC_SECURITY_YFS_RXGK:
+		/* Read the key pointer before the appdata */
+		if (smp_load_acquire(&server->yfs_rxgk_appdata))
+			return 0;
+		break;
+#endif
+	default:
+		return 0;
+	}
+
+	ret = 0;
+	mutex_lock(&server->cm_token_lock);
+
+	switch (security_index) {
+#ifdef CONFIG_RXGK
+	case RXRPC_SECURITY_YFS_RXGK:
+		/* Read the key pointer before the appdata */
+		if (smp_load_acquire(&server->yfs_rxgk_appdata))
+			break;
+		ret = afs_create_yfs_rxgk_cm_appdata(server, krb5_enctype);
+		break;
+#endif
+	default:
+		break;
+	}
+
+	mutex_unlock(&server->cm_token_lock);
+	return ret;
+}
+
+#ifdef CONFIG_RXGK
+/*
+ * Create a securities keyring for the cache manager and attach a key to it for
+ * the RxGK tokens we want to use to secure the callback connection back from
+ * the fileserver.
+ */
+int afs_create_token_key(struct afs_net *net, struct socket *socket)
+{
+	const struct krb5_enctype *krb5;
+	struct key *ring;
+	key_ref_t key;
+	char K0[32], *desc;
+	int ret;
+
+	ring = keyring_alloc("kafs",
+			     GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
+			     KEY_POS_SEARCH | KEY_POS_WRITE |
+			     KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH,
+			     KEY_ALLOC_NOT_IN_QUOTA,
+			     NULL, NULL);
+	if (IS_ERR(ring))
+		return PTR_ERR(ring);
+
+	ret = rxrpc_sock_set_security_keyring(socket->sk, ring);
+	if (ret < 0)
+		goto out;
+
+	ret = -ENOPKG;
+	krb5 = crypto_krb5_find_enctype(KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96);
+	if (!krb5)
+		goto out;
+
+	if (WARN_ON_ONCE(krb5->key_len > sizeof(K0)))
+		goto out;
+
+	ret = -ENOMEM;
+	desc = kasprintf(GFP_KERNEL, "%u:%u:%u:%u",
+			 YFS_CM_SERVICE, RXRPC_SECURITY_YFS_RXGK, 1, krb5->etype);
+	if (!desc)
+		goto out;
+
+	wait_for_random_bytes();
+	get_random_bytes(K0, krb5->key_len);
+
+	key = key_create(make_key_ref(ring, true),
+			 "rxrpc_s", desc,
+			 K0, krb5->key_len,
+			 KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_USR_VIEW,
+			 KEY_ALLOC_NOT_IN_QUOTA);
+	kfree(desc);
+	if (IS_ERR(key)) {
+		ret = PTR_ERR(key);
+		goto out;
+	}
+
+	net->fs_cm_token_key = key_ref_to_ptr(key);
+	ret = 0;
+out:
+	key_put(ring);
+	return ret;
+}
+#endif /* CONFIG_RXGK */
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index 5540ae1cad599a..f92bddd4f1e9af 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -23,11 +23,11 @@ static int afs_deliver_cb_callback(struct afs_call *);
 static int afs_deliver_cb_probe_uuid(struct afs_call *);
 static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *);
 static void afs_cm_destructor(struct afs_call *);
-static void SRXAFSCB_CallBack(struct work_struct *);
-static void SRXAFSCB_InitCallBackState(struct work_struct *);
-static void SRXAFSCB_Probe(struct work_struct *);
-static void SRXAFSCB_ProbeUuid(struct work_struct *);
-static void SRXAFSCB_TellMeAboutYourself(struct work_struct *);
+static void SRXAFSCB_CallBack(struct afs_call *call);
+static void SRXAFSCB_InitCallBackState(struct afs_call *call);
+static void SRXAFSCB_Probe(struct afs_call *call);
+static void SRXAFSCB_ProbeUuid(struct afs_call *call);
+static void SRXAFSCB_TellMeAboutYourself(struct afs_call *call);
 
 static int afs_deliver_yfs_cb_callback(struct afs_call *);
 
@@ -161,10 +161,8 @@ static void afs_abort_service_call(struct afs_call *call, u32 abort_code, int er
 /*
  * The server supplied a list of callbacks that it wanted to break.
  */
-static void SRXAFSCB_CallBack(struct work_struct *work)
+static void SRXAFSCB_CallBack(struct afs_call *call)
 {
-	struct afs_call *call = container_of(work, struct afs_call, work);
-
 	_enter("");
 
 	/* We need to break the callbacks before sending the reply as the
@@ -180,7 +178,6 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
 	}
 
 	afs_send_empty_reply(call);
-	afs_put_call(call);
 	_leave("");
 }
 
@@ -284,16 +281,13 @@ static int afs_deliver_cb_callback(struct afs_call *call)
 /*
  * allow the fileserver to request callback state (re-)initialisation
  */
-static void SRXAFSCB_InitCallBackState(struct work_struct *work)
+static void SRXAFSCB_InitCallBackState(struct afs_call *call)
 {
-	struct afs_call *call = container_of(work, struct afs_call, work);
-
 	_enter("{%p}", call->server);
 
 	if (call->server)
 		afs_init_callback_state(call->server);
 	afs_send_empty_reply(call);
-	afs_put_call(call);
 	_leave("");
 }
 
@@ -332,11 +326,8 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
 	case 1:
 		_debug("extract UUID");
 		ret = afs_extract_data(call, false);
-		switch (ret) {
-		case 0:		break;
-		case -EAGAIN:	return 0;
-		default:	return ret;
-		}
+		if (ret < 0)
+			return ret;
 
 		_debug("unmarshall UUID");
 		call->request = kmalloc_obj(struct afs_uuid);
@@ -364,7 +355,8 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
 	if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
 		return afs_io_error(call, afs_io_error_cm_reply);
 
-	if (memcmp(call->request, &call->server->_uuid, sizeof(call->server->_uuid)) != 0) {
+	if (call->server &&
+	    memcmp(call->request, &call->server->_uuid, sizeof(call->server->_uuid)) != 0) {
 		pr_notice("Callback UUID does not match fileserver UUID\n");
 		trace_afs_cm_no_server_u(call, call->request);
 		return 0;
@@ -376,13 +368,10 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
 /*
  * allow the fileserver to see if the cache manager is still alive
  */
-static void SRXAFSCB_Probe(struct work_struct *work)
+static void SRXAFSCB_Probe(struct afs_call *call)
 {
-	struct afs_call *call = container_of(work, struct afs_call, work);
-
 	_enter("");
 	afs_send_empty_reply(call);
-	afs_put_call(call);
 	_leave("");
 }
 
@@ -409,9 +398,8 @@ static int afs_deliver_cb_probe(struct afs_call *call)
  * Allow the fileserver to quickly find out if the cache manager has been
  * rebooted.
  */
-static void SRXAFSCB_ProbeUuid(struct work_struct *work)
+static void SRXAFSCB_ProbeUuid(struct afs_call *call)
 {
-	struct afs_call *call = container_of(work, struct afs_call, work);
 	struct afs_uuid *r = call->request;
 
 	_enter("");
@@ -421,7 +409,6 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work)
 	else
 		afs_abort_service_call(call, 1, 1, afs_abort_probeuuid_negative);
 
-	afs_put_call(call);
 	_leave("");
 }
 
@@ -449,11 +436,8 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
 	case 1:
 		_debug("extract UUID");
 		ret = afs_extract_data(call, false);
-		switch (ret) {
-		case 0:		break;
-		case -EAGAIN:	return 0;
-		default:	return ret;
-		}
+		if (ret < 0)
+			return ret;
 
 		_debug("unmarshall UUID");
 		call->request = kmalloc_obj(struct afs_uuid);
@@ -486,9 +470,8 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
 /*
  * allow the fileserver to ask about the cache manager's capabilities
  */
-static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
+static void SRXAFSCB_TellMeAboutYourself(struct afs_call *call)
 {
-	struct afs_call *call = container_of(work, struct afs_call, work);
 	int loop;
 
 	struct {
@@ -520,7 +503,6 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
 	reply.cap.capcount = htonl(1);
 	reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
 	afs_send_simple_reply(call, &reply, sizeof(reply));
-	afs_put_call(call);
 	_leave("");
 }
 
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 0467742bfeee34..625dc67f79f366 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -298,7 +298,7 @@ static void afs_read_receive(struct afs_call *call)
 	op->call_responded	= call->responded;
 	op->call		= NULL;
 	call->op		= NULL;
-	afs_put_call(call);
+	afs_put_call(call, afs_call_trace_put_read_op);
 
 	/* If the call failed, then we need to crank the server rotation
 	 * handle and try the next.
@@ -316,15 +316,17 @@ void afs_fetch_data_async_rx(struct work_struct *work)
 	struct afs_call *call = container_of(work, struct afs_call, async_work);
 
 	afs_read_receive(call);
-	afs_put_call(call);
+
+	if (call->state == AFS_CALL_COMPLETE) {
+		cancel_work(&call->async_work);
+		afs_put_call(call, afs_call_trace_put_read_complete);
+	}
 }
 
 void afs_fetch_data_immediate_cancel(struct afs_call *call)
 {
 	if (call->async) {
-		afs_get_call(call, afs_call_trace_wake);
-		if (!queue_work(afs_async_calls, &call->async_work))
-			afs_deferred_put_call(call);
+		queue_work(afs_async_calls, &call->async_work);
 		flush_work(&call->async_work);
 	}
 }
diff --git a/fs/afs/fs_operation.c b/fs/afs/fs_operation.c
index c0dbbc6d3716e0..9ea9db256a41ab 100644
--- a/fs/afs/fs_operation.c
+++ b/fs/afs/fs_operation.c
@@ -296,7 +296,7 @@ void afs_wait_for_operation(struct afs_operation *op)
 			op->call_abort_code = op->call->abort_code;
 			op->call_error = op->call->error;
 			op->call_responded = op->call->responded;
-			afs_put_call(op->call);
+			afs_put_call(op->call, afs_call_trace_put_wait_op);
 		}
 	}
 
diff --git a/fs/afs/fs_probe.c b/fs/afs/fs_probe.c
index a91ad1938d0788..e26f7f1e30a23a 100644
--- a/fs/afs/fs_probe.c
+++ b/fs/afs/fs_probe.c
@@ -241,9 +241,14 @@ int afs_fs_probe_fileserver(struct afs_net *net, struct afs_server *server,
 	struct afs_endpoint_state *estate, *old;
 	struct afs_addr_list *old_alist = NULL, *alist;
 	unsigned long unprobed;
+	int ret;
 
 	_enter("%pU", &server->uuid);
 
+	ret = afs_create_server_appdata(server, key);
+	if (ret < 0)
+		return ret;
+
 	estate = kzalloc_obj(*estate);
 	if (!estate)
 		return -ENOMEM;
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index a2ffd60889f89d..9acad5017fbab3 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -477,6 +477,9 @@ void afs_fs_fetch_data(struct afs_operation *op)
 	if (!call)
 		return afs_op_nomem(op);
 
+	if (op->flags & AFS_OPERATION_ASYNC)
+		call->async = true;
+
 	/* marshall the parameters */
 	bp = call->request;
 	bp[0] = htonl(FSFETCHDATA);
@@ -1659,7 +1662,7 @@ int afs_fs_give_up_all_callbacks(struct afs_net *net, struct afs_server *server,
 	ret = call->error;
 	if (call->responded)
 		set_bit(AFS_SERVER_FL_RESPONDING, &server->flags);
-	afs_put_call(call);
+	afs_put_call(call, afs_call_trace_put_giveupcallbacks);
 	return ret;
 }
 
@@ -1775,7 +1778,7 @@ bool afs_fs_get_capabilities(struct afs_net *net, struct afs_server *server,
 
 	trace_afs_make_fs_call(call, NULL);
 	afs_make_call(call, GFP_NOFS);
-	afs_put_call(call);
+	afs_put_call(call, afs_call_trace_put_get_capabilities);
 	return true;
 }
 
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 0b72a856629992..3d0193ea255b62 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -129,7 +129,7 @@ struct afs_call {
 	const struct afs_call_type *type;	/* type of call */
 	wait_queue_head_t	waitq;		/* processes awaiting completion */
 	struct work_struct	async_work;	/* async I/O processor */
-	struct work_struct	work;		/* actual work processor */
+	void (*work)(struct afs_call *call);	/* Worker function */
 	struct work_struct	free_work;	/* Deferred free processor */
 	struct rxrpc_call	*rxcall;	/* RxRPC call handle */
 	struct rxrpc_peer	*peer;		/* Remote endpoint */
@@ -169,7 +169,6 @@ struct afs_call {
 	unsigned		reply_max;	/* maximum size of reply */
 	unsigned		count2;		/* count used in unmarshalling */
 	unsigned char		unmarshall;	/* unmarshalling phase */
-	bool			drop_ref;	/* T if need to drop ref for incoming call */
 	bool			need_attention;	/* T if RxRPC poked us */
 	bool			async;		/* T if asynchronous */
 	bool			upgrade;	/* T to request service upgrade */
@@ -208,7 +207,7 @@ struct afs_call_type {
 	void (*async_rx)(struct work_struct *work);
 
 	/* Work function */
-	void (*work)(struct work_struct *work);
+	void (*work)(struct afs_call *call);
 
 	/* Call done function (gets called immediately on success or failure) */
 	void (*done)(struct afs_call *call);
@@ -283,7 +282,6 @@ struct afs_net {
 	struct socket		*socket;
 	struct afs_call		*spare_incoming_call;
 	struct work_struct	charge_preallocation_work;
-	struct work_struct	rx_oob_work;
 	struct mutex		socket_mutex;
 	atomic_t		nr_outstanding_calls;
 	atomic_t		nr_superblocks;
@@ -547,7 +545,7 @@ struct afs_server {
 	struct work_struct	destroyer;	/* Work item to try and destroy a server */
 	struct timer_list	timer;		/* Management timer */
 	struct mutex		cm_token_lock;	/* Lock governing creation of appdata */
-	struct krb5_buffer	cm_rxgk_appdata; /* Appdata to be included in RESPONSE packet */
+	struct key		*yfs_rxgk_appdata; /* Appdata to be included in RESPONSE packet */
 	time64_t		unuse_time;	/* Time at which last unused */
 	unsigned long		flags;
 #define AFS_SERVER_FL_RESPONDING 0		/* The server is responding */
@@ -1090,7 +1088,7 @@ extern bool afs_cm_incoming_call(struct afs_call *);
 /*
  * cm_security.c
  */
-void afs_process_oob_queue(struct work_struct *work);
+int afs_create_server_appdata(struct afs_server *server, struct key *key);
 #ifdef CONFIG_RXGK
 int afs_create_token_key(struct afs_net *net, struct socket *socket);
 #else
@@ -1381,8 +1379,7 @@ extern struct workqueue_struct *afs_async_calls;
 extern int __net_init afs_open_socket(struct afs_net *);
 extern void __net_exit afs_close_socket(struct afs_net *);
 extern void afs_charge_preallocation(struct work_struct *);
-extern void afs_put_call(struct afs_call *);
-void afs_deferred_put_call(struct afs_call *call);
+void afs_put_call(struct afs_call *call, enum afs_call_trace trace);
 void afs_make_call(struct afs_call *call, gfp_t gfp);
 void afs_deliver_to_call(struct afs_call *call);
 void afs_wait_for_call_to_complete(struct afs_call *call);
@@ -1403,8 +1400,7 @@ static inline struct afs_call *afs_get_call(struct afs_call *call,
 	__refcount_inc(&call->ref, &r);
 
 	trace_afs_call(call->debug_id, why, r + 1,
-		       atomic_read(&call->net->nr_outstanding_calls),
-		       __builtin_return_address(0));
+		       atomic_read(&call->net->nr_outstanding_calls));
 	return call;
 }
 
@@ -1413,23 +1409,7 @@ static inline void afs_see_call(struct afs_call *call, enum afs_call_trace why)
 	int r = refcount_read(&call->ref);
 
 	trace_afs_call(call->debug_id, why, r,
-		       atomic_read(&call->net->nr_outstanding_calls),
-		       __builtin_return_address(0));
-}
-
-static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,
-				    gfp_t gfp)
-{
-	struct afs_addr_list *alist = op->estate->addresses;
-
-	op->call	= call;
-	op->type	= call->type;
-	call->op	= op;
-	call->key	= op->key;
-	call->intr	= !(op->flags & AFS_OPERATION_UNINTR);
-	call->peer	= rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
-	call->service_id = op->server->service_id;
-	afs_make_call(call, gfp);
+		       atomic_read(&call->net->nr_outstanding_calls));
 }
 
 static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
@@ -1495,7 +1475,6 @@ static inline void afs_set_call_complete(struct afs_call *call,
 					 int error, u32 remote_abort)
 {
 	enum afs_call_state state;
-	bool ok = false;
 
 	spin_lock_bh(&call->state_lock);
 	state = call->state;
@@ -1505,19 +1484,8 @@ static inline void afs_set_call_complete(struct afs_call *call,
 		call->state = AFS_CALL_COMPLETE;
 		trace_afs_call_state(call, state, AFS_CALL_COMPLETE,
 				     error, remote_abort);
-		ok = true;
 	}
 	spin_unlock_bh(&call->state_lock);
-	if (ok) {
-		trace_afs_call_done(call);
-
-		/* Asynchronous calls have two refs to release - one from the alloc and
-		 * one queued with the work item - and we can't just deallocate the
-		 * call because the work item may be queued again.
-		 */
-		if (call->drop_ref)
-			afs_put_call(call);
-	}
 }
 
 /*
@@ -1763,6 +1731,23 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)
 	return &vnode->netfs.inode;
 }
 
+static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,
+				    gfp_t gfp)
+{
+	struct afs_addr_list *alist = op->estate->addresses;
+
+	op->call	= afs_get_call(call, afs_call_trace_get_op_call);
+	op->type	= call->type;
+	call->op	= op;
+	call->server	= afs_use_server(op->server, false, afs_server_trace_use_call);
+	call->key	= op->key;
+	call->intr	= !(op->flags & AFS_OPERATION_UNINTR);
+	call->peer	= rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
+	call->service_id = op->server->service_id;
+	afs_make_call(call, gfp);
+	afs_put_call(call, afs_call_trace_put_made_call);
+}
+
 /*
  * Note that a dentry got changed.  We need to set d_fsdata to the data version
  * number derived from the result of the operation.  It doesn't matter if
diff --git a/fs/afs/main.c b/fs/afs/main.c
index 7a883c59976ff2..6353feaa5fb4b5 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -73,7 +73,6 @@ static int __net_init afs_net_init(struct net *net_ns)
 	generate_random_uuid((unsigned char *)&net->uuid);
 
 	INIT_WORK(&net->charge_preallocation_work, afs_charge_preallocation);
-	INIT_WORK(&net->rx_oob_work, afs_process_oob_queue);
 	mutex_init(&net->socket_mutex);
 
 	net->cells = RB_ROOT;
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index d82916657a3ddf..4f6d699b5d226a 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -25,14 +25,12 @@ static void afs_process_async_call(struct work_struct *);
 static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long);
 static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long);
 static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID);
-static void afs_rx_notify_oob(struct sock *sk, struct sk_buff *oob);
 static int afs_deliver_cm_op_id(struct afs_call *);
 
 static const struct rxrpc_kernel_ops afs_rxrpc_callback_ops = {
 	.notify_new_call	= afs_rx_new_call,
 	.discard_new_call	= afs_rx_discard_new_call,
 	.user_attach_call	= afs_rx_attach,
-	.notify_oob		= afs_rx_notify_oob,
 };
 
 /* asynchronous incoming call initial processing */
@@ -74,10 +72,6 @@ int afs_open_socket(struct afs_net *net)
 	if (ret < 0)
 		goto error_2;
 
-	ret = rxrpc_sock_set_manage_response(socket->sk, true);
-	if (ret < 0)
-		goto error_2;
-
 	ret = afs_create_token_key(net, socket);
 	if (ret < 0)
 		pr_err("Couldn't create RxGK CM key: %d\n", ret);
@@ -128,7 +122,6 @@ void afs_close_socket(struct afs_net *net)
 	_enter("");
 
 	cancel_work_sync(&net->charge_preallocation_work);
-	cancel_work_sync(&net->rx_oob_work);
 	/* Future work items should now see ->live is false. */
 
 	kernel_listen(net->socket, 0);
@@ -138,7 +131,7 @@ void afs_close_socket(struct afs_net *net)
 	cancel_work_sync(&net->charge_preallocation_work);
 
 	if (net->spare_incoming_call) {
-		afs_put_call(net->spare_incoming_call);
+		afs_put_call(net->spare_incoming_call, afs_call_trace_put_spare_svc);
 		net->spare_incoming_call = NULL;
 	}
 
@@ -149,7 +142,6 @@ void afs_close_socket(struct afs_net *net)
 
 	kernel_sock_shutdown(net->socket, SHUT_RDWR);
 	flush_workqueue(afs_async_calls);
-	cancel_work_sync(&net->rx_oob_work);
 	net->socket->sk->sk_user_data = NULL;
 	sock_release(net->socket);
 	key_put(net->fs_cm_token_key);
@@ -177,21 +169,20 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
 	call->debug_id = atomic_inc_return(&rxrpc_debug_id);
 	refcount_set(&call->ref, 1);
 	INIT_WORK(&call->async_work, type->async_rx ?: afs_process_async_call);
-	INIT_WORK(&call->work, call->type->work);
 	INIT_WORK(&call->free_work, afs_deferred_free_worker);
 	init_waitqueue_head(&call->waitq);
 	spin_lock_init(&call->state_lock);
 	call->iter = &call->def_iter;
 
 	o = atomic_inc_return(&net->nr_outstanding_calls);
-	trace_afs_call(call->debug_id, afs_call_trace_alloc, 1, o,
-		       __builtin_return_address(0));
+	trace_afs_call(call->debug_id, afs_call_trace_alloc, 1, o);
 	return call;
 }
 
 static void afs_free_call(struct afs_call *call)
 {
 	struct afs_net *net = call->net;
+	unsigned int debug_id = call->debug_id;
 	int o;
 
 	ASSERT(!work_pending(&call->async_work));
@@ -208,13 +199,10 @@ static void afs_free_call(struct afs_call *call)
 
 	afs_unuse_server_notime(call->net, call->server, afs_server_trace_unuse_call);
 	kfree(call->request);
-
-	o = atomic_read(&net->nr_outstanding_calls);
-	trace_afs_call(call->debug_id, afs_call_trace_free, 0, o,
-		       __builtin_return_address(0));
 	kfree(call);
 
 	o = atomic_dec_return(&net->nr_outstanding_calls);
+	trace_afs_call(debug_id, afs_call_trace_free, 0, o);
 	if (o == 0)
 		wake_up_var(&net->nr_outstanding_calls);
 }
@@ -222,7 +210,7 @@ static void afs_free_call(struct afs_call *call)
 /*
  * Dispose of a reference on a call.
  */
-void afs_put_call(struct afs_call *call)
+void afs_put_call(struct afs_call *call, enum afs_call_trace trace)
 {
 	struct afs_net *net = call->net;
 	unsigned int debug_id = call->debug_id;
@@ -231,8 +219,7 @@ void afs_put_call(struct afs_call *call)
 
 	zero = __refcount_dec_and_test(&call->ref, &r);
 	o = atomic_read(&net->nr_outstanding_calls);
-	trace_afs_call(debug_id, afs_call_trace_put, r - 1, o,
-		       __builtin_return_address(0));
+	trace_afs_call(debug_id, trace, r - 1, o);
 	if (zero)
 		afs_free_call(call);
 }
@@ -244,37 +231,6 @@ static void afs_deferred_free_worker(struct work_struct *work)
 	afs_free_call(call);
 }
 
-/*
- * Dispose of a reference on a call, deferring the cleanup to a workqueue
- * to avoid lock recursion.
- */
-void afs_deferred_put_call(struct afs_call *call)
-{
-	struct afs_net *net = call->net;
-	unsigned int debug_id = call->debug_id;
-	bool zero;
-	int r, o;
-
-	zero = __refcount_dec_and_test(&call->ref, &r);
-	o = atomic_read(&net->nr_outstanding_calls);
-	trace_afs_call(debug_id, afs_call_trace_put, r - 1, o,
-		       __builtin_return_address(0));
-	if (zero)
-		schedule_work(&call->free_work);
-}
-
-/*
- * Queue the call for actual work.
- */
-static void afs_queue_call_work(struct afs_call *call)
-{
-	if (call->type->work) {
-		afs_get_call(call, afs_call_trace_work);
-		if (!queue_work(afs_wq, &call->work))
-			afs_put_call(call);
-	}
-}
-
 /*
  * allocate a call with flat request and reply buffers
  */
@@ -308,7 +264,7 @@ struct afs_call *afs_alloc_flat_call(struct afs_net *net,
 	return call;
 
 nomem_free:
-	afs_put_call(call);
+	afs_put_call(call, afs_call_trace_put_oom);
 nomem_call:
 	return NULL;
 }
@@ -347,7 +303,10 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 	struct rxrpc_call *rxcall;
 	struct msghdr msg;
 	struct kvec iov[1];
+	unsigned int debug_id = call->debug_id;
+	struct key *app_data = NULL;
 	size_t len;
+	bool write_iter = call->write_iter;
 	s64 tx_total_len;
 	int ret;
 
@@ -373,13 +332,29 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 	/* If the call is going to be asynchronous, we need an extra ref for
 	 * the call to hold itself so the caller need not hang on to its ref.
 	 */
-	if (call->async) {
-		afs_get_call(call, afs_call_trace_get);
-		call->drop_ref = true;
+	if (call->async)
+		afs_get_call(call, afs_call_trace_get_make_async_call);
+
+	if (call->key && call->server) {
+		u32 krb5_enctype = 0;
+		u8 security_index = 0;
+
+		rxrpc_kernel_query_key(call->key, &security_index, &krb5_enctype);
+		switch (security_index) {
+#ifdef CONFIG_RXGK
+		case RXRPC_SECURITY_YFS_RXGK:
+			/* Read the key pointer before the appdata */
+			app_data = smp_load_acquire(&call->server->yfs_rxgk_appdata);
+			break;
+#endif
+		default:
+			break;
+		}
 	}
 
 	/* create a call */
-	rxcall = rxrpc_kernel_begin_call(call->net->socket, call->peer, call->key,
+	rxcall = rxrpc_kernel_begin_call(call->net->socket, call->peer,
+					 call->key, app_data,
 					 (unsigned long)call,
 					 tx_total_len,
 					 call->max_lifespan,
@@ -410,7 +385,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 	iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, call->request_size);
 	msg.msg_control		= NULL;
 	msg.msg_controllen	= 0;
-	msg.msg_flags		= MSG_WAITALL | (call->write_iter ? MSG_MORE : 0);
+	msg.msg_flags		= MSG_WAITALL | (write_iter ? MSG_MORE : 0);
 
 	ret = rxrpc_kernel_send_data(call->net->socket, rxcall,
 				     &msg, call->request_size,
@@ -418,7 +393,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 	if (ret < 0)
 		goto error_do_abort;
 
-	if (call->write_iter) {
+	if (write_iter) {
 		msg.msg_iter = *call->write_iter;
 		msg.msg_flags &= ~MSG_MORE;
 		trace_afs_send_data(call, &msg);
@@ -427,9 +402,8 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 					     call->rxcall, &msg,
 					     iov_iter_count(&msg.msg_iter),
 					     afs_notify_end_request_tx);
-		*call->write_iter = msg.msg_iter;
 
-		trace_afs_sent_data(call, &msg, ret);
+		trace_afs_sent_data(debug_id, &msg, ret);
 		if (ret < 0)
 			goto error_do_abort;
 	}
@@ -448,7 +422,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 					RX_USER_ABORT, ret,
 					afs_abort_send_data_error);
 	if (call->async) {
-		afs_see_call(call, afs_call_trace_async_abort);
+		afs_see_call(call, afs_call_trace_see_async_abort);
 		return;
 	}
 
@@ -464,7 +438,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 	trace_afs_call_done(call);
 error_kill_call:
 	if (call->async)
-		afs_see_call(call, afs_call_trace_async_kill);
+		afs_see_call(call, afs_call_trace_see_async_kill);
 	if (call->type->immediate_cancel)
 		call->type->immediate_cancel(call);
 
@@ -475,8 +449,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 	if (call->rxcall)
 		rxrpc_kernel_shutdown_call(call->net->socket, call->rxcall);
 	if (call->async) {
-		if (cancel_work_sync(&call->async_work))
-			afs_put_call(call);
+		cancel_work_sync(&call->async_work);
 		afs_set_call_complete(call, ret, 0);
 	}
 
@@ -562,7 +535,8 @@ void afs_deliver_to_call(struct afs_call *call)
 		switch (ret) {
 		case 0:
 			call->responded = true;
-			afs_queue_call_work(call);
+			if (call->work)
+				call->work(call);
 			if (state == AFS_CALL_CL_PROC_REPLY) {
 				if (call->op)
 					set_bit(AFS_SERVER_FL_MAY_HAVE_CB,
@@ -612,6 +586,7 @@ void afs_deliver_to_call(struct afs_call *call)
 	}
 
 done:
+	trace_afs_call_done(call);
 	if (call->type->done)
 		call->type->done(call);
 out:
@@ -700,19 +675,12 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,
 				   unsigned long call_user_ID)
 {
 	struct afs_call *call = (struct afs_call *)call_user_ID;
-	int r;
 
 	trace_afs_notify_call(rxcall, call);
 	call->need_attention = true;
 
-	if (__refcount_inc_not_zero(&call->ref, &r)) {
-		trace_afs_call(call->debug_id, afs_call_trace_wake, r + 1,
-			       atomic_read(&call->net->nr_outstanding_calls),
-			       __builtin_return_address(0));
-
-		if (!queue_work(afs_async_calls, &call->async_work))
-			afs_deferred_put_call(call);
-	}
+	afs_see_call(call, afs_call_trace_see_async_wake);
+	queue_work(afs_async_calls, &call->async_work);
 }
 
 /*
@@ -725,12 +693,17 @@ static void afs_process_async_call(struct work_struct *work)
 
 	_enter("");
 
+	afs_see_call(call, afs_call_trace_see_async_process);
+
 	if (call->state < AFS_CALL_COMPLETE && call->need_attention) {
 		call->need_attention = false;
 		afs_deliver_to_call(call);
 	}
 
-	afs_put_call(call);
+	if (call->state == AFS_CALL_COMPLETE) {
+		cancel_work(&call->async_work);
+		afs_put_call(call, afs_call_trace_put_async_complete);
+	}
 	_leave("");
 }
 
@@ -756,7 +729,6 @@ void afs_charge_preallocation(struct work_struct *work)
 			if (!call)
 				break;
 
-			call->drop_ref = true;
 			call->async = true;
 			call->state = AFS_CALL_SV_AWAIT_OP_ID;
 			init_waitqueue_head(&call->waitq);
@@ -783,7 +755,7 @@ static void afs_rx_discard_new_call(struct rxrpc_call *rxcall,
 	struct afs_call *call = (struct afs_call *)user_call_ID;
 
 	call->rxcall = NULL;
-	afs_put_call(call);
+	afs_put_call(call, afs_call_trace_put_discard_prealloc);
 }
 
 /*
@@ -832,7 +804,7 @@ static int afs_deliver_cm_op_id(struct afs_call *call)
 							     &call->enctype);
 
 	trace_afs_cb_call(call);
-	call->work.func = call->type->work;
+	call->work = call->type->work;
 
 	/* pass responsibility for the remainder of this message off to the
 	 * cache manager op */
@@ -983,14 +955,3 @@ noinline int afs_protocol_error(struct afs_call *call,
 		call->unmarshalling_error = true;
 	return -EBADMSG;
 }
-
-/*
- * Wake up OOB notification processing.
- */
-static void afs_rx_notify_oob(struct sock *sk, struct sk_buff *oob)
-{
-	struct afs_net *net = sk->sk_user_data;
-
-	if (READ_ONCE(net->live))
-		queue_work(afs_wq, &net->rx_oob_work);
-}
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 0fe162ea2a36db..4c3a7bd0f7d866 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -398,7 +398,7 @@ static void afs_server_rcu(struct rcu_head *rcu)
 	afs_put_endpoint_state(rcu_access_pointer(server->endpoint_state),
 			       afs_estate_trace_put_server);
 	afs_put_cell(server->cell, afs_cell_trace_put_server);
-	kfree(server->cm_rxgk_appdata.data);
+	key_put(server->yfs_rxgk_appdata);
 	kfree(server);
 }
 
diff --git a/fs/afs/vl_probe.c b/fs/afs/vl_probe.c
index 3d2e0c925460f9..1d70887c9f318b 100644
--- a/fs/afs/vl_probe.c
+++ b/fs/afs/vl_probe.c
@@ -186,7 +186,7 @@ static bool afs_do_probe_vlserver(struct afs_net *net,
 					       server_index);
 		if (!IS_ERR(call)) {
 			afs_prioritise_error(_e, call->error, call->abort_code);
-			afs_put_call(call);
+			afs_put_call(call, afs_call_trace_put_vl_get_caps);
 			in_progress = true;
 		} else {
 			afs_prioritise_error(_e, PTR_ERR(call), 0);
diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c
index a40b43464cfa9e..8a4c8c9a1e3996 100644
--- a/fs/afs/vlclient.c
+++ b/fs/afs/vlclient.c
@@ -153,7 +153,7 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,
 	vc->call_abort_code	= call->abort_code;
 	vc->call_error		= call->error;
 	vc->call_responded	= call->responded;
-	afs_put_call(call);
+	afs_put_call(call, afs_call_trace_put_vl_call);
 	if (vc->call_error) {
 		kfree(entry);
 		return ERR_PTR(vc->call_error);
@@ -303,7 +303,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
 	vc->call_error		= call->error;
 	vc->call_responded	= call->responded;
 	alist			= call->ret_alist;
-	afs_put_call(call);
+	afs_put_call(call, afs_call_trace_put_vl_call);
 	if (vc->call_error) {
 		afs_put_addrlist(alist, afs_alist_trace_put_getaddru);
 		return ERR_PTR(vc->call_error);
@@ -666,7 +666,7 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
 	vc->call_error		= call->error;
 	vc->call_responded	= call->responded;
 	alist			= call->ret_alist;
-	afs_put_call(call);
+	afs_put_call(call, afs_call_trace_put_vl_call);
 	if (vc->call_error) {
 		afs_put_addrlist(alist, afs_alist_trace_put_getaddru);
 		return ERR_PTR(vc->call_error);
@@ -784,7 +784,7 @@ char *afs_yfsvl_get_cell_name(struct afs_vl_cursor *vc)
 	vc->call_error		= call->error;
 	vc->call_responded	= call->responded;
 	cellname		= call->ret_str;
-	afs_put_call(call);
+	afs_put_call(call, afs_call_trace_put_vl_call);
 	if (vc->call_error) {
 		kfree(cellname);
 		return ERR_PTR(vc->call_error);
diff --git a/include/keys/user-type.h b/include/keys/user-type.h
index 386c3143278995..7002a993a47228 100644
--- a/include/keys/user-type.h
+++ b/include/keys/user-type.h
@@ -26,6 +26,7 @@
  */
 struct user_key_payload {
 	struct rcu_head	rcu;		/* RCU destructor */
+	refcount_t	ref;
 	unsigned short	datalen;	/* length of this data */
 	char		data[] __aligned(__alignof__(u64)); /* actual data */
 };
@@ -37,6 +38,7 @@ struct key_preparsed_payload;
 
 extern int user_preparse(struct key_preparsed_payload *prep);
 extern void user_free_preparse(struct key_preparsed_payload *prep);
+void put_user_key_payload(struct user_key_payload *payload);
 extern int user_update(struct key *key, struct key_preparsed_payload *prep);
 extern void user_revoke(struct key *key);
 extern void user_destroy(struct key *key);
diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h
index 0fb4c41c9bbf55..a9b8e1ba67ef8d 100644
--- a/include/net/af_rxrpc.h
+++ b/include/net/af_rxrpc.h
@@ -55,6 +55,7 @@ void rxrpc_kernel_set_notifications(struct socket *sock,
 struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
 					   struct rxrpc_peer *peer,
 					   struct key *key,
+					   struct key *app_data,
 					   unsigned long user_call_ID,
 					   s64 tx_total_len,
 					   u32 hard_timeout,
@@ -91,24 +92,8 @@ bool rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *);
 
 int rxrpc_sock_set_min_security_level(struct sock *sk, unsigned int val);
 int rxrpc_sock_set_security_keyring(struct sock *, struct key *);
-int rxrpc_sock_set_manage_response(struct sock *sk, bool set);
-
-enum rxrpc_oob_type rxrpc_kernel_query_oob(struct sk_buff *oob,
-					   struct rxrpc_peer **_peer,
-					   unsigned long *_peer_appdata);
-struct sk_buff *rxrpc_kernel_dequeue_oob(struct socket *sock,
-					 enum rxrpc_oob_type *_type);
-void rxrpc_kernel_free_oob(struct sk_buff *oob);
-void rxrpc_kernel_query_challenge(struct sk_buff *challenge,
-				  struct rxrpc_peer **_peer,
-				  unsigned long *_peer_appdata,
-				  u16 *_service_id, u8 *_security_index);
-int rxrpc_kernel_reject_challenge(struct sk_buff *challenge, u32 abort_code,
-				  int error, enum rxrpc_abort_reason why);
-int rxkad_kernel_respond_to_challenge(struct sk_buff *challenge);
-u32 rxgk_kernel_query_challenge(struct sk_buff *challenge);
-int rxgk_kernel_respond_to_challenge(struct sk_buff *challenge,
-				     struct krb5_buffer *appdata);
+void rxrpc_kernel_query_key(const struct key *key, u8 *_security_index,
+			    u32 *_krb5_enctype);
 u8 rxrpc_kernel_query_call_security(struct rxrpc_call *call,
 				    u16 *_service_id, u32 *_enctype);
 
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 1b3c48b5591dfd..a4f57414d527fb 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h
@@ -120,14 +120,26 @@ enum yfs_cm_operation {
  * Declare tracing information enums and their string mappings for display.
  */
 #define afs_call_traces \
-	EM(afs_call_trace_alloc,		"ALLOC") \
-	EM(afs_call_trace_async_abort,		"ASYAB") \
-	EM(afs_call_trace_async_kill,		"ASYKL") \
-	EM(afs_call_trace_free,			"FREE ") \
-	EM(afs_call_trace_get,			"GET  ") \
-	EM(afs_call_trace_put,			"PUT  ") \
-	EM(afs_call_trace_wake,			"WAKE ") \
-	E_(afs_call_trace_work,			"QUEUE")
+	EM(afs_call_trace_alloc,		"ALLOC      ") \
+	EM(afs_call_trace_free,			"FREE       ") \
+	EM(afs_call_trace_get_op_call,		"GET op     ") \
+	EM(afs_call_trace_get_make_async_call,	"GET a-make ") \
+	EM(afs_call_trace_put_async_complete,	"PUT a-cmpl ") \
+	EM(afs_call_trace_put_made_call,	"PUT made   ") \
+	EM(afs_call_trace_put_discard_prealloc,	"PUT dis-pre") \
+	EM(afs_call_trace_put_get_capabilities,	"PUT get-cap") \
+	EM(afs_call_trace_put_giveupcallbacks,	"PUT gvup-cb") \
+	EM(afs_call_trace_put_oom,		"PUT oom    ") \
+	EM(afs_call_trace_put_read_complete,	"PUT rd-cpl ") \
+	EM(afs_call_trace_put_read_op,		"PUT rd-op  ") \
+	EM(afs_call_trace_put_spare_svc,	"PUT spare-s") \
+	EM(afs_call_trace_put_vl_call,		"PUT vl-call") \
+	EM(afs_call_trace_put_vl_get_caps,	"PUT vl-gcap") \
+	EM(afs_call_trace_put_wait_op,		"PUT wt-op  ") \
+	EM(afs_call_trace_see_async_abort,	"SEE a-abort") \
+	EM(afs_call_trace_see_async_kill,	"SEE a-kill ") \
+	EM(afs_call_trace_see_async_process,	"SEE a-proc ") \
+	E_(afs_call_trace_see_async_wake,	"SEE a-wake ")
 
 #define afs_server_traces \
 	EM(afs_server_trace_callback,		"CALLBACK ") \
@@ -148,6 +160,7 @@ enum yfs_cm_operation {
 	EM(afs_server_trace_unuse_slist_isort,	"UNU isort") \
 	EM(afs_server_trace_update,		"UPDATE   ") \
 	EM(afs_server_trace_use_by_uuid,	"USE uuid ") \
+	EM(afs_server_trace_use_call,		"USE call ") \
 	EM(afs_server_trace_use_cm_call,	"USE cm-cl") \
 	EM(afs_server_trace_use_get_caps,	"USE gcaps") \
 	EM(afs_server_trace_use_give_up_cb,	"USE gvupc") \
@@ -693,16 +706,15 @@ TRACE_EVENT(afs_cb_call,
 
 TRACE_EVENT(afs_call,
 	    TP_PROTO(unsigned int call_debug_id, enum afs_call_trace op,
-		     int ref, int outstanding, const void *where),
+		     int ref, int outstanding),
 
-	    TP_ARGS(call_debug_id, op, ref, outstanding, where),
+	    TP_ARGS(call_debug_id, op, ref, outstanding),
 
 	    TP_STRUCT__entry(
 		    __field(unsigned int,		call)
 		    __field(int,			op)
 		    __field(int,			ref)
 		    __field(int,			outstanding)
-		    __field(const void *,		where)
 			     ),
 
 	    TP_fast_assign(
@@ -710,15 +722,13 @@ TRACE_EVENT(afs_call,
 		    __entry->op = op;
 		    __entry->ref = ref;
 		    __entry->outstanding = outstanding;
-		    __entry->where = where;
 			   ),
 
-	    TP_printk("c=%08x %s r=%d o=%d sp=%pSR",
+	    TP_printk("c=%08x %s r=%d o=%d",
 		      __entry->call,
 		      __print_symbolic(__entry->op, afs_call_traces),
 		      __entry->ref,
-		      __entry->outstanding,
-		      __entry->where)
+		      __entry->outstanding)
 	    );
 
 TRACE_EVENT(afs_make_fs_call,
@@ -937,9 +947,9 @@ TRACE_EVENT(afs_send_data,
 	    );
 
 TRACE_EVENT(afs_sent_data,
-	    TP_PROTO(struct afs_call *call, struct msghdr *msg, int ret),
+	    TP_PROTO(unsigned int call_debug_id, struct msghdr *msg, int ret),
 
-	    TP_ARGS(call, msg, ret),
+	    TP_ARGS(call_debug_id, msg, ret),
 
 	    TP_STRUCT__entry(
 		    __field(unsigned int,		call)
@@ -949,7 +959,7 @@ TRACE_EVENT(afs_sent_data,
 			     ),
 
 	    TP_fast_assign(
-		    __entry->call = call->debug_id;
+		    __entry->call = call_debug_id;
 		    __entry->ret = ret;
 		    __entry->offset = msg->msg_iter.xarray_start + msg->msg_iter.iov_offset;
 		    __entry->count = iov_iter_count(&msg->msg_iter);
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 704a10de667004..45e4550a18ed81 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -148,6 +148,7 @@
 	EM(rxrpc_eproto_wrong_security,		"wrong-sec")		\
 	EM(rxrpc_recvmsg_excess_data,		"recvmsg-excess")	\
 	EM(rxrpc_recvmsg_short_data,		"recvmsg-short")	\
+	EM(rxrpc_sendmsg_tx_error,		"tx-error")		\
 	E_(rxrpc_sendmsg_late_send,		"sendmsg-late")
 
 #define rxrpc_call_poke_traces \
@@ -262,7 +263,6 @@
 	EM(rxrpc_conn_free,			"FREE        ") \
 	EM(rxrpc_conn_get_activate_call,	"GET act-call") \
 	EM(rxrpc_conn_get_call_input,		"GET inp-call") \
-	EM(rxrpc_conn_get_challenge_input,	"GET inp-chal") \
 	EM(rxrpc_conn_get_conn_input,		"GET inp-conn") \
 	EM(rxrpc_conn_get_idle,			"GET idle    ") \
 	EM(rxrpc_conn_get_poke_abort,		"GET pk-abort") \
@@ -274,7 +274,6 @@
 	EM(rxrpc_conn_new_service,		"NEW service ") \
 	EM(rxrpc_conn_put_call,			"PUT call    ") \
 	EM(rxrpc_conn_put_call_input,		"PUT inp-call") \
-	EM(rxrpc_conn_put_challenge_input,	"PUT inp-chal") \
 	EM(rxrpc_conn_put_conn_input,		"PUT inp-conn") \
 	EM(rxrpc_conn_put_discard_idle,		"PUT disc-idl") \
 	EM(rxrpc_conn_put_local_dead,		"PUT loc-dead") \
@@ -342,6 +341,7 @@
 	EM(rxrpc_call_see_distribute_error,	"SEE dist-err") \
 	EM(rxrpc_call_see_input,		"SEE input   ") \
 	EM(rxrpc_call_see_notify_released,	"SEE nfy-rlsd") \
+	EM(rxrpc_call_see_notify_skipped,	"SEE nfy-skip") \
 	EM(rxrpc_call_see_recvmsg,		"SEE recvmsg ") \
 	EM(rxrpc_call_see_recvmsg_requeue,	"SEE recv-rqu") \
 	EM(rxrpc_call_see_recvmsg_requeue_first, "SEE recv-rqF") \
diff --git a/include/uapi/linux/rxrpc.h b/include/uapi/linux/rxrpc.h
index d9735abd4c7910..7d6a5015193112 100644
--- a/include/uapi/linux/rxrpc.h
+++ b/include/uapi/linux/rxrpc.h
@@ -58,11 +58,7 @@ enum rxrpc_cmsg_type {
 	RXRPC_TX_LENGTH		= 12,	/* -s-: Total length of Tx data */
 	RXRPC_SET_CALL_TIMEOUT	= 13,	/* -s-: Set one or more call timeouts */
 	RXRPC_CHARGE_ACCEPT	= 14,	/* Ss-: Charge the accept pool with a user call ID */
-	RXRPC_OOB_ID		= 15,	/* -sr: OOB message ID */
-	RXRPC_CHALLENGED	= 16,	/* C-r: Info on a received CHALLENGE */
-	RXRPC_RESPOND		= 17,	/* Cs-: Respond to a challenge */
-	RXRPC_RESPONDED		= 18,	/* S-r: Data received in RESPONSE */
-	RXRPC_RESP_RXGK_APPDATA	= 19,	/* Cs-: RESPONSE: RxGK app data to include */
+	RXRPC_RESPONSE_APPDATA	= 20,	/* Cs-: User key holding app data for RESPONSE */
 	RXRPC__SUPPORTED
 };
 
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
index c3c8c3240ef946..aa3c058f409559 100644
--- a/net/dns_resolver/dns_key.c
+++ b/net/dns_resolver/dns_key.c
@@ -208,6 +208,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
 		kleave(" = -ENOMEM");
 		return -ENOMEM;
 	}
+	refcount_set(&upayload->ref, 1);
 
 	upayload->datalen = result_len;
 	memcpy(upayload->data, data, result_len);
diff --git a/net/rxrpc/Makefile b/net/rxrpc/Makefile
index f994f9f30a29d4..f7a5e0a592ee13 100644
--- a/net/rxrpc/Makefile
+++ b/net/rxrpc/Makefile
@@ -24,7 +24,6 @@ rxrpc-y := \
 	local_object.o \
 	misc.o \
 	net_ns.o \
-	oob.o \
 	output.o \
 	peer_event.o \
 	peer_object.o \
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 9ab0f22c881ec5..9d5ce1c7ad0d22 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -318,6 +318,7 @@ EXPORT_SYMBOL(rxrpc_kernel_put_peer);
  * @sock: The socket on which to make the call
  * @peer: The peer to contact
  * @key: The security context to use (defaults to socket setting)
+ * @app_data: The security response application data (or NULL)
  * @user_call_ID: The ID to use
  * @tx_total_len: Total length of data to transmit during the call (or -1)
  * @hard_timeout: The maximum lifespan of the call in sec
@@ -340,6 +341,7 @@ EXPORT_SYMBOL(rxrpc_kernel_put_peer);
 struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
 					   struct rxrpc_peer *peer,
 					   struct key *key,
+					   struct key *app_data,
 					   unsigned long user_call_ID,
 					   s64 tx_total_len,
 					   u32 hard_timeout,
@@ -368,6 +370,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
 		key = NULL; /* a no-security key */
 
 	memset(&p, 0, sizeof(p));
+	p.app_data		= app_data;
 	p.user_call_ID		= user_call_ID;
 	p.tx_total_len		= tx_total_len;
 	p.interruptibility	= interruptibility;
@@ -595,10 +598,7 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
 		fallthrough;
 	case RXRPC_SERVER_BOUND:
 	case RXRPC_SERVER_LISTENING:
-		if (m->msg_flags & MSG_OOB)
-			ret = rxrpc_sendmsg_oob(rx, m, len);
-		else
-			ret = rxrpc_do_sendmsg(rx, m, len);
+		ret = rxrpc_do_sendmsg(rx, m, len);
 		/* The socket has been unlocked */
 		goto out;
 	default:
@@ -633,7 +633,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
 			    sockptr_t optval, unsigned int optlen)
 {
 	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
-	unsigned int min_sec_level, val;
+	unsigned int min_sec_level;
 	u16 service_upgrade[2];
 	int ret;
 
@@ -710,23 +710,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
 
 		case RXRPC_MANAGE_RESPONSE:
 			ret = -EINVAL;
-			if (optlen != sizeof(unsigned int))
-				goto error;
-			ret = -EISCONN;
-			if (rx->sk.sk_state != RXRPC_UNBOUND)
-				goto error;
-			ret = copy_safe_from_sockptr(&val, sizeof(val),
-						     optval, optlen);
-			if (ret)
-				goto error;
-			ret = -EINVAL;
-			if (val > 1)
-				goto error;
-			if (val)
-				set_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
-			else
-				clear_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
-			goto success;
+			goto error;
 
 		default:
 			break;
@@ -835,8 +819,6 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
 	rx->calls = RB_ROOT;
 
 	spin_lock_init(&rx->incoming_lock);
-	skb_queue_head_init(&rx->recvmsg_oobq);
-	rx->pending_oobq = RB_ROOT;
 	INIT_LIST_HEAD(&rx->sock_calls);
 	INIT_LIST_HEAD(&rx->to_be_accepted);
 	INIT_LIST_HEAD(&rx->recvmsg_q);
@@ -884,23 +866,6 @@ static int rxrpc_shutdown(struct socket *sock, int flags)
 	return ret;
 }
 
-/*
- * Purge the out-of-band queue.
- */
-static void rxrpc_purge_oob_queue(struct sock *sk)
-{
-	struct rxrpc_sock *rx = rxrpc_sk(sk);
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&rx->recvmsg_oobq)))
-		rxrpc_kernel_free_oob(skb);
-	while (!RB_EMPTY_ROOT(&rx->pending_oobq)) {
-		skb = rb_entry(rx->pending_oobq.rb_node, struct sk_buff, rbnode);
-		rb_erase(&skb->rbnode, &rx->pending_oobq);
-		rxrpc_kernel_free_oob(skb);
-	}
-}
-
 /*
  * RxRPC socket destructor
  */
@@ -908,7 +873,6 @@ static void rxrpc_sock_destructor(struct sock *sk)
 {
 	_enter("%p", sk);
 
-	rxrpc_purge_oob_queue(sk);
 	rxrpc_purge_queue(&sk->sk_receive_queue);
 
 	WARN_ON(refcount_read(&sk->sk_wmem_alloc));
@@ -961,7 +925,6 @@ static int rxrpc_release_sock(struct sock *sk)
 	rxrpc_discard_prealloc(rx);
 	rxrpc_release_calls_on_socket(rx);
 	flush_workqueue(rxrpc_workqueue);
-	rxrpc_purge_oob_queue(sk);
 	rxrpc_purge_queue(&sk->sk_receive_queue);
 
 	rxrpc_unuse_local(rx->local, rxrpc_local_unuse_release_sock);
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index ce946b0a03e2b3..1c6f4a279034f3 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -171,9 +171,6 @@ struct rxrpc_sock {
 	const struct rxrpc_kernel_ops *app_ops;	/* Table of kernel app notification funcs */
 	struct rxrpc_local	*local;		/* local endpoint */
 	struct rxrpc_backlog	*backlog;	/* Preallocation for services */
-	struct sk_buff_head	recvmsg_oobq;	/* OOB messages for recvmsg to pick up */
-	struct rb_root		pending_oobq;	/* OOB messages awaiting userspace to respond to */
-	u64			oob_id_counter;	/* OOB message ID counter */
 	spinlock_t		incoming_lock;	/* Incoming call vs service shutdown lock */
 	struct list_head	sock_calls;	/* List of calls owned by this socket */
 	struct list_head	to_be_accepted;	/* calls awaiting acceptance */
@@ -184,7 +181,6 @@ struct rxrpc_sock {
 	struct rb_root		calls;		/* User ID -> call mapping */
 	unsigned long		flags;
 #define RXRPC_SOCK_CONNECTED		0	/* connect_srx is set */
-#define RXRPC_SOCK_MANAGE_RESPONSE	1	/* User wants to manage RESPONSE packets */
 	rwlock_t		call_lock;	/* lock for calls */
 	u32			min_sec_level;	/* minimum security level */
 #define RXRPC_SECURITY_MAX	RXRPC_SECURITY_ENCRYPT
@@ -241,7 +237,6 @@ struct rxrpc_skb_priv {
 			u8		reason;		/* Reason for ack */
 		} ack;
 		struct {
-			struct rxrpc_connection *conn;	/* Connection referred to */
 			union {
 				u32 rxkad_nonce;
 			};
@@ -310,13 +305,6 @@ struct rxrpc_security {
 	bool (*validate_challenge)(struct rxrpc_connection *conn,
 				   struct sk_buff *skb);
 
-	/* Fill out the cmsg for recvmsg() to pass on a challenge to userspace.
-	 * The security class gets to add additional information.
-	 */
-	int (*challenge_to_recvmsg)(struct rxrpc_connection *conn,
-				    struct sk_buff *challenge,
-				    struct msghdr *msg);
-
 	/* Parse sendmsg() control message and respond to challenge. */
 	int (*sendmsg_respond_to_challenge)(struct sk_buff *challenge,
 					    struct msghdr *msg);
@@ -516,6 +504,7 @@ struct rxrpc_bundle {
 	struct rxrpc_local	*local;		/* Representation of local endpoint */
 	struct rxrpc_peer	*peer;		/* Remote endpoint */
 	struct key		*key;		/* Security details */
+	struct key		*app_data;	/* Security response app data */
 	struct list_head	proc_link;	/* Link in net->bundle_proc_list */
 	const struct rxrpc_security *security;	/* applied security module */
 	refcount_t		ref;
@@ -642,6 +631,7 @@ enum rxrpc_call_flag {
 	RXRPC_CALL_TX_LAST,		/* Last packet in Tx buffer (at rxtx_top) */
 	RXRPC_CALL_TX_ALL_ACKED,	/* Last packet has been hard-acked */
 	RXRPC_CALL_TX_NO_MORE,		/* No more data to transmit (MSG_MORE deasserted) */
+	RXRPC_CALL_TX_ERROR,		/* Terminal error; call needs abort */
 	RXRPC_CALL_SEND_PING,		/* A ping will need to be sent */
 	RXRPC_CALL_RETRANS_TIMEOUT,	/* Retransmission due to timeout occurred */
 	RXRPC_CALL_BEGAN_RX_TIMER,	/* We began the expect_rx_by timer */
@@ -719,6 +709,7 @@ struct rxrpc_call {
 	struct rxrpc_sock __rcu	*socket;	/* socket responsible */
 	struct rxrpc_net	*rxnet;		/* Network namespace to which call belongs */
 	struct key		*key;		/* Security details */
+	struct key		*app_data;	/* Security response app data */
 	const struct rxrpc_security *security;	/* applied security module */
 	struct mutex		user_mutex;	/* User access mutex */
 	struct sockaddr_rxrpc	dest_srx;	/* Destination address */
@@ -913,6 +904,7 @@ enum rxrpc_command {
 };
 
 struct rxrpc_call_params {
+	struct key		*app_data;	/* Security response app data */
 	s64			tx_total_len;	/* Total Tx data length (if send data) */
 	unsigned long		user_call_ID;	/* User's call ID */
 	struct {
@@ -1375,13 +1367,6 @@ static inline struct rxrpc_net *rxrpc_net(struct net *net)
 	return net_generic(net, rxrpc_net_id);
 }
 
-/*
- * oob.c
- */
-bool rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb);
-void rxrpc_add_pending_oob(struct rxrpc_sock *rx, struct sk_buff *skb);
-int rxrpc_sendmsg_oob(struct rxrpc_sock *rx, struct msghdr *msg, size_t len);
-
 /*
  * output.c
  */
diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
index 817ed9acb91e61..9f6130d90c4ca8 100644
--- a/net/rxrpc/call_object.c
+++ b/net/rxrpc/call_object.c
@@ -211,6 +211,7 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,
 	call->interruptibility	= p->interruptibility;
 	call->tx_total_len	= p->tx_total_len;
 	call->key		= key_get(cp->key);
+	call->app_data		= key_get(p->app_data);
 	call->peer		= rxrpc_get_peer(cp->peer, rxrpc_peer_get_call);
 	call->local		= rxrpc_get_local(cp->local, rxrpc_local_get_call);
 	call->security_level	= cp->security_level;
@@ -697,6 +698,7 @@ static void rxrpc_destroy_call(struct work_struct *work)
 	rxrpc_put_peer(call->peer, rxrpc_peer_put_call);
 	rxrpc_put_local(call->local, rxrpc_local_put_call);
 	key_put(call->key);
+	key_put(call->app_data);
 	call_rcu(&call->rcu, rxrpc_rcu_free_call);
 }
 
diff --git a/net/rxrpc/call_state.c b/net/rxrpc/call_state.c
index 6afb54373ebbf9..6e402312e145c0 100644
--- a/net/rxrpc/call_state.c
+++ b/net/rxrpc/call_state.c
@@ -7,6 +7,61 @@
 
 #include "ar-internal.h"
 
+/*
+ * Post a call for attention by the socket or kernel service.  Further
+ * notifications are suppressed by putting recvmsg_link on a dummy queue.
+ */
+static void __rxrpc_notify_socket(struct rxrpc_call *call)
+{
+	struct rxrpc_sock *rx;
+	struct sock *sk;
+
+	if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
+		rxrpc_see_call(call, rxrpc_call_see_notify_released);
+		return;
+	}
+
+	rcu_read_lock();
+
+	rx = rcu_dereference(call->socket);
+	sk = &rx->sk;
+	if (rx && sk->sk_state < RXRPC_CLOSE) {
+		if (call->notify_rx) {
+			spin_lock_irq(&call->notify_lock);
+			call->notify_rx(sk, call, call->user_call_ID);
+			spin_unlock_irq(&call->notify_lock);
+		} else {
+			spin_lock_irq(&rx->recvmsg_lock);
+			if (list_empty(&call->recvmsg_link)) {
+				rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+				list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+			}
+			spin_unlock_irq(&rx->recvmsg_lock);
+
+			if (!sock_flag(sk, SOCK_DEAD)) {
+				_debug("call %ps", sk->sk_data_ready);
+				sk->sk_data_ready(sk);
+			}
+		}
+	}
+
+	rcu_read_unlock();
+}
+
+/*
+ * Post a call for attention by the socket or kernel service.  Further
+ * notifications are suppressed by putting recvmsg_link on a dummy queue.
+ */
+void rxrpc_notify_socket(struct rxrpc_call *call)
+{
+	if (rxrpc_call_is_complete(call)) {
+		rxrpc_see_call(call, rxrpc_call_see_notify_skipped);
+		return;
+	}
+
+	__rxrpc_notify_socket(call);
+}
+
 /*
  * Transition a call to the complete state.
  */
@@ -25,7 +80,7 @@ bool rxrpc_set_call_completion(struct rxrpc_call *call,
 	rxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);
 	trace_rxrpc_call_complete(call);
 	wake_up(&call->waitq);
-	rxrpc_notify_socket(call);
+	__rxrpc_notify_socket(call);
 	return true;
 }
 
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
index 48519f0de18539..5cbfa7b223e011 100644
--- a/net/rxrpc/conn_client.c
+++ b/net/rxrpc/conn_client.c
@@ -81,6 +81,7 @@ static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_call *call,
 		bundle->local		= call->local;
 		bundle->peer		= rxrpc_get_peer(call->peer, rxrpc_peer_get_bundle);
 		bundle->key		= key_get(call->key);
+		bundle->app_data	= key_get(call->app_data);
 		bundle->security	= call->security;
 		bundle->exclusive	= test_bit(RXRPC_CALL_EXCLUSIVE, &call->flags);
 		bundle->upgrade		= test_bit(RXRPC_CALL_UPGRADE, &call->flags);
@@ -118,6 +119,7 @@ static void rxrpc_free_bundle(struct rxrpc_bundle *bundle)
 	write_unlock(&bundle->local->rxnet->conn_lock);
 	rxrpc_put_peer(bundle->peer, rxrpc_peer_put_bundle);
 	key_put(bundle->key);
+	key_put(bundle->app_data);
 	kfree(bundle);
 }
 
diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
index 611c790bc6d0ce..9146b9d4c2ac50 100644
--- a/net/rxrpc/conn_event.c
+++ b/net/rxrpc/conn_event.c
@@ -279,10 +279,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
 
 	switch (sp->hdr.type) {
 	case RXRPC_PACKET_TYPE_CHALLENGE:
-		ret = conn->security->respond_to_challenge(conn, skb);
-		sp->chall.conn = NULL;
-		rxrpc_put_connection(conn, rxrpc_conn_put_challenge_input);
-		return ret;
+		return conn->security->respond_to_challenge(conn, skb);
 
 	case RXRPC_PACKET_TYPE_RESPONSE:
 		spin_lock_irq(&conn->state_lock);
@@ -425,66 +422,6 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
 	rxrpc_queue_conn(conn, rxrpc_conn_queue_rx_work);
 }
 
-/*
- * Post a CHALLENGE packet to the socket of one of a connection's calls so that
- * it can get application data to include in the packet, possibly querying
- * userspace.
- */
-static bool rxrpc_post_challenge(struct rxrpc_connection *conn,
-				 struct sk_buff *skb)
-{
-	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-	struct rxrpc_call *call = NULL;
-	struct rxrpc_sock *rx;
-	bool respond = false, queued = false;
-
-	sp->chall.conn =
-		rxrpc_get_connection(conn, rxrpc_conn_get_challenge_input);
-
-	if (!conn->security->challenge_to_recvmsg) {
-		rxrpc_post_packet_to_conn(conn, skb);
-		return true;
-	}
-
-	rcu_read_lock();
-
-	for (int i = 0; i < ARRAY_SIZE(conn->channels); i++) {
-		if (conn->channels[i].call) {
-			call = conn->channels[i].call;
-			rx = rcu_dereference(call->socket);
-			if (!rx) {
-				call = NULL;
-				continue;
-			}
-
-			respond = true;
-			if (test_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags))
-				break;
-			call = NULL;
-		}
-	}
-
-	if (!respond) {
-		rcu_read_unlock();
-		rxrpc_put_connection(conn, rxrpc_conn_put_challenge_input);
-		sp->chall.conn = NULL;
-		return false;
-	}
-
-	if (call)
-		queued = rxrpc_notify_socket_oob(call, skb);
-	rcu_read_unlock();
-	if (call && !queued) {
-		rxrpc_put_connection(conn, rxrpc_conn_put_challenge_input);
-		sp->chall.conn = NULL;
-		return false;
-	}
-
-	if (!call)
-		rxrpc_post_packet_to_conn(conn, skb);
-	return true;
-}
-
 /*
  * Input a connection-level packet.
  */
@@ -513,7 +450,8 @@ bool rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
 		}
 		if (!conn->security->validate_challenge(conn, skb))
 			return false;
-		return rxrpc_post_challenge(conn, skb);
+		rxrpc_post_packet_to_conn(conn, skb);
+		return true;
 
 	case RXRPC_PACKET_TYPE_RESPONSE:
 		if (rxrpc_is_conn_aborted(conn)) {
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index a0aa78d892897f..16bab72e6f0777 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -893,3 +893,40 @@ static long rxrpc_read(const struct key *key,
 	_leave(" = %zu", size);
 	return size;
 }
+
+/**
+ * rxrpc_kernel_query_key - Query parameters from an rxrpc key
+ * @key: The key to query
+ * @_security_index: Where to return the security index
+ * @_krb5_enctype: Where to return the krb5 encryption type if applicable
+ *
+ * Query an rxrpc authentication key, extracting the security index from the
+ * first token therein.
+ */
+void rxrpc_kernel_query_key(const struct key *key, u8 *_security_index,
+			    u32 *_krb5_enctype)
+{
+	const struct rxrpc_key_token *token;
+
+	token = key->payload.data[0];
+	if (!token) {
+		*_security_index = 0;
+		*_krb5_enctype = 0;
+		return;
+	}
+
+	*_security_index = token->security_index;
+	switch (token->security_index) {
+	case RXRPC_SECURITY_RXKAD:
+		*_krb5_enctype = 0;
+		break;
+	case RXRPC_SECURITY_YFS_RXGK:
+		*_krb5_enctype = token->rxgk->enctype;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		*_krb5_enctype = 0;
+		break;
+	}
+}
+EXPORT_SYMBOL(rxrpc_kernel_query_key);
diff --git a/net/rxrpc/oob.c b/net/rxrpc/oob.c
deleted file mode 100644
index c80ee2487d0941..00000000000000
--- a/net/rxrpc/oob.c
+++ /dev/null
@@ -1,387 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* Out of band message handling (e.g. challenge-response)
- *
- * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/net.h>
-#include <linux/gfp.h>
-#include <linux/skbuff.h>
-#include <linux/export.h>
-#include <linux/sched/signal.h>
-#include <net/sock.h>
-#include <net/af_rxrpc.h>
-#include "ar-internal.h"
-
-enum rxrpc_oob_command {
-	RXRPC_OOB_CMD_UNSET,
-	RXRPC_OOB_CMD_RESPOND,
-} __mode(byte);
-
-struct rxrpc_oob_params {
-	u64			oob_id;		/* ID number of message if reply */
-	s32			abort_code;
-	enum rxrpc_oob_command	command;
-	bool			have_oob_id:1;
-};
-
-/*
- * Post an out-of-band message for attention by the socket or kernel service
- * associated with a reference call.
- */
-bool rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb)
-{
-	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-	struct rxrpc_sock *rx;
-	struct sock *sk;
-	bool queued = false;
-
-	rcu_read_lock();
-
-	rx = rcu_dereference(call->socket);
-	if (rx) {
-		sk = &rx->sk;
-		spin_lock_irq(&rx->recvmsg_lock);
-
-		if (sk->sk_state < RXRPC_CLOSE) {
-			skb->skb_mstamp_ns = rx->oob_id_counter++;
-			rxrpc_get_skb(skb, rxrpc_skb_get_post_oob);
-			skb_queue_tail(&rx->recvmsg_oobq, skb);
-			queued = true;
-
-			trace_rxrpc_notify_socket(call->debug_id, sp->hdr.serial);
-			if (rx->app_ops)
-				rx->app_ops->notify_oob(sk, skb);
-		}
-
-		spin_unlock_irq(&rx->recvmsg_lock);
-		if (queued && !rx->app_ops && !sock_flag(sk, SOCK_DEAD))
-			sk->sk_data_ready(sk);
-	}
-
-	rcu_read_unlock();
-	return queued;
-}
-
-/*
- * Locate the OOB message to respond to by its ID.
- */
-static struct sk_buff *rxrpc_find_pending_oob(struct rxrpc_sock *rx, u64 oob_id)
-{
-	struct rb_node *p;
-	struct sk_buff *skb;
-
-	p = rx->pending_oobq.rb_node;
-	while (p) {
-		skb = rb_entry(p, struct sk_buff, rbnode);
-
-		if (oob_id < skb->skb_mstamp_ns)
-			p = p->rb_left;
-		else if (oob_id > skb->skb_mstamp_ns)
-			p = p->rb_right;
-		else
-			return skb;
-	}
-
-	return NULL;
-}
-
-/*
- * Add an OOB message into the pending-response set.  We always assign the next
- * value from a 64-bit counter to the oob_id, so just assume we're always going
- * to be on the right-hand edge of the tree and that the counter won't wrap.
- * The tree is also given a ref to the message.
- */
-void rxrpc_add_pending_oob(struct rxrpc_sock *rx, struct sk_buff *skb)
-{
-	struct rb_node **pp = &rx->pending_oobq.rb_node, *p = NULL;
-
-	while (*pp) {
-		p = *pp;
-		pp = &(*pp)->rb_right;
-	}
-
-	rb_link_node(&skb->rbnode, p, pp);
-	rb_insert_color(&skb->rbnode, &rx->pending_oobq);
-}
-
-/*
- * Extract control messages from the sendmsg() control buffer.
- */
-static int rxrpc_sendmsg_oob_cmsg(struct msghdr *msg, struct rxrpc_oob_params *p)
-{
-	struct cmsghdr *cmsg;
-	int len;
-
-	if (msg->msg_controllen == 0)
-		return -EINVAL;
-
-	for_each_cmsghdr(cmsg, msg) {
-		if (!CMSG_OK(msg, cmsg))
-			return -EINVAL;
-
-		len = cmsg->cmsg_len - sizeof(struct cmsghdr);
-		_debug("CMSG %d, %d, %d",
-		       cmsg->cmsg_level, cmsg->cmsg_type, len);
-
-		if (cmsg->cmsg_level != SOL_RXRPC)
-			continue;
-
-		switch (cmsg->cmsg_type) {
-		case RXRPC_OOB_ID:
-			if (len != sizeof(p->oob_id) || p->have_oob_id)
-				return -EINVAL;
-			memcpy(&p->oob_id, CMSG_DATA(cmsg), sizeof(p->oob_id));
-			p->have_oob_id = true;
-			break;
-		case RXRPC_RESPOND:
-			if (p->command != RXRPC_OOB_CMD_UNSET)
-				return -EINVAL;
-			p->command = RXRPC_OOB_CMD_RESPOND;
-			break;
-		case RXRPC_ABORT:
-			if (len != sizeof(p->abort_code) || p->abort_code)
-				return -EINVAL;
-			memcpy(&p->abort_code, CMSG_DATA(cmsg), sizeof(p->abort_code));
-			if (p->abort_code == 0)
-				return -EINVAL;
-			break;
-		case RXRPC_RESP_RXGK_APPDATA:
-			if (p->command != RXRPC_OOB_CMD_RESPOND)
-				return -EINVAL;
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	switch (p->command) {
-	case RXRPC_OOB_CMD_RESPOND:
-		if (!p->have_oob_id)
-			return -EBADSLT;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/*
- * Allow userspace to respond to an OOB using sendmsg().
- */
-static int rxrpc_respond_to_oob(struct rxrpc_sock *rx,
-				struct rxrpc_oob_params *p,
-				struct msghdr *msg)
-{
-	struct rxrpc_connection *conn;
-	struct rxrpc_skb_priv *sp;
-	struct sk_buff *skb;
-	int ret;
-
-	skb = rxrpc_find_pending_oob(rx, p->oob_id);
-	if (skb)
-		rb_erase(&skb->rbnode, &rx->pending_oobq);
-	release_sock(&rx->sk);
-	if (!skb)
-		return -EBADSLT;
-
-	sp = rxrpc_skb(skb);
-
-	switch (p->command) {
-	case RXRPC_OOB_CMD_RESPOND:
-		ret = -EPROTO;
-		if (skb->mark != RXRPC_OOB_CHALLENGE)
-			break;
-		conn = sp->chall.conn;
-		ret = -EOPNOTSUPP;
-		if (!conn->security->sendmsg_respond_to_challenge)
-			break;
-		if (p->abort_code) {
-			rxrpc_abort_conn(conn, NULL, p->abort_code, -ECONNABORTED,
-					 rxrpc_abort_response_sendmsg);
-			ret = 0;
-		} else {
-			ret = conn->security->sendmsg_respond_to_challenge(skb, msg);
-		}
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	switch (skb->mark) {
-	case RXRPC_OOB_CHALLENGE:
-		rxrpc_put_connection(sp->chall.conn, rxrpc_conn_put_oob);
-		break;
-	}
-	rxrpc_free_skb(skb, rxrpc_skb_put_oob);
-	return ret;
-}
-
-/*
- * Send an out-of-band message or respond to a received out-of-band message.
- * - caller gives us the socket lock
- * - the socket may be either a client socket or a server socket
- */
-int rxrpc_sendmsg_oob(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
-{
-	struct rxrpc_oob_params p = {};
-	int ret;
-
-	_enter("");
-
-	ret = rxrpc_sendmsg_oob_cmsg(msg, &p);
-	if (ret < 0)
-		goto error_release_sock;
-
-	if (p.have_oob_id)
-		return rxrpc_respond_to_oob(rx, &p, msg);
-
-	release_sock(&rx->sk);
-
-	switch (p.command) {
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	_leave(" = %d", ret);
-	return ret;
-
-error_release_sock:
-	release_sock(&rx->sk);
-	return ret;
-}
-
-/**
- * rxrpc_kernel_query_oob - Query the parameters of an out-of-band message
- * @oob: The message to query
- * @_peer: Where to return the peer record
- * @_peer_appdata: The application data attached to a peer record
- *
- * Extract useful parameters from an out-of-band message.  The source peer
- * parameters are returned through the argument list and the message type is
- * returned.
- *
- * Return:
- * * %RXRPC_OOB_CHALLENGE - Challenge wanting a response.
- */
-enum rxrpc_oob_type rxrpc_kernel_query_oob(struct sk_buff *oob,
-					   struct rxrpc_peer **_peer,
-					   unsigned long *_peer_appdata)
-{
-	struct rxrpc_skb_priv *sp = rxrpc_skb(oob);
-	enum rxrpc_oob_type type = oob->mark;
-
-	switch (type) {
-	case RXRPC_OOB_CHALLENGE:
-		*_peer		= sp->chall.conn->peer;
-		*_peer_appdata	= sp->chall.conn->peer->app_data;
-		break;
-	default:
-		WARN_ON_ONCE(1);
-		*_peer		= NULL;
-		*_peer_appdata	= 0;
-		break;
-	}
-
-	return type;
-}
-EXPORT_SYMBOL(rxrpc_kernel_query_oob);
-
-/**
- * rxrpc_kernel_dequeue_oob - Dequeue and return the front OOB message
- * @sock: The socket to query
- * @_type: Where to return the message type
- *
- * Dequeue the front OOB message, if there is one, and return it and
- * its type.
- *
- * Return: The sk_buff representing the OOB message or %NULL if the queue was
- * empty.
- */
-struct sk_buff *rxrpc_kernel_dequeue_oob(struct socket *sock,
-					 enum rxrpc_oob_type *_type)
-{
-	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
-	struct sk_buff *oob;
-
-	oob = skb_dequeue(&rx->recvmsg_oobq);
-	if (oob)
-		*_type = oob->mark;
-	return oob;
-}
-EXPORT_SYMBOL(rxrpc_kernel_dequeue_oob);
-
-/**
- * rxrpc_kernel_free_oob - Free an out-of-band message
- * @oob: The OOB message to free
- *
- * Free an OOB message along with any resources it holds.
- */
-void rxrpc_kernel_free_oob(struct sk_buff *oob)
-{
-	struct rxrpc_skb_priv *sp = rxrpc_skb(oob);
-
-	switch (oob->mark) {
-	case RXRPC_OOB_CHALLENGE:
-		rxrpc_put_connection(sp->chall.conn, rxrpc_conn_put_oob);
-		break;
-	}
-
-	rxrpc_free_skb(oob, rxrpc_skb_put_purge_oob);
-}
-EXPORT_SYMBOL(rxrpc_kernel_free_oob);
-
-/**
- * rxrpc_kernel_query_challenge - Query the parameters of a challenge
- * @challenge: The challenge to query
- * @_peer: Where to return the peer record
- * @_peer_appdata: The application data attached to a peer record
- * @_service_id: Where to return the connection service ID
- * @_security_index: Where to return the connection security index
- *
- * Extract useful parameters from a CHALLENGE message.
- */
-void rxrpc_kernel_query_challenge(struct sk_buff *challenge,
-				  struct rxrpc_peer **_peer,
-				  unsigned long *_peer_appdata,
-				  u16 *_service_id, u8 *_security_index)
-{
-	struct rxrpc_skb_priv *sp = rxrpc_skb(challenge);
-
-	*_peer		= sp->chall.conn->peer;
-	*_peer_appdata	= sp->chall.conn->peer->app_data;
-	*_service_id	= sp->hdr.serviceId;
-	*_security_index = sp->hdr.securityIndex;
-}
-EXPORT_SYMBOL(rxrpc_kernel_query_challenge);
-
-/**
- * rxrpc_kernel_reject_challenge - Allow a kernel service to reject a challenge
- * @challenge: The challenge to be rejected
- * @abort_code: The abort code to stick into the ABORT packet
- * @error: Local error value
- * @why: Indication as to why.
- *
- * Allow a kernel service to reject a challenge by aborting the connection if
- * it's still in an abortable state.  The error is returned so this function
- * can be used with a return statement.
- *
- * Return: The %error parameter.
- */
-int rxrpc_kernel_reject_challenge(struct sk_buff *challenge, u32 abort_code,
-				  int error, enum rxrpc_abort_reason why)
-{
-	struct rxrpc_skb_priv *sp = rxrpc_skb(challenge);
-
-	_enter("{%x},%d,%d,%u", sp->hdr.serial, abort_code, error, why);
-
-	rxrpc_abort_conn(sp->chall.conn, NULL, abort_code, error, why);
-	return error;
-}
-EXPORT_SYMBOL(rxrpc_kernel_reject_challenge);
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index efcba4b2e74f0c..5b8c7f573b7f5a 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -17,13 +17,12 @@
 #include "ar-internal.h"
 
 /*
- * Post a call for attention by the socket or kernel service.  Further
- * notifications are suppressed by putting recvmsg_link on a dummy queue.
+ * Requeue a call for recvmsg() to pick up.
  */
-void rxrpc_notify_socket(struct rxrpc_call *call)
+static void rxrpc_requeue_call(struct socket *sock, struct rxrpc_call *call)
 {
-	struct rxrpc_sock *rx;
-	struct sock *sk;
+	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+	struct sock *sk = &rx->sk;
 
 	_enter("%d", call->debug_id);
 
@@ -32,31 +31,18 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
 		return;
 	}
 
-	rcu_read_lock();
-
-	rx = rcu_dereference(call->socket);
-	sk = &rx->sk;
-	if (rx && sk->sk_state < RXRPC_CLOSE) {
-		if (call->notify_rx) {
-			spin_lock_irq(&call->notify_lock);
-			call->notify_rx(sk, call, call->user_call_ID);
-			spin_unlock_irq(&call->notify_lock);
-		} else {
-			spin_lock_irq(&rx->recvmsg_lock);
-			if (list_empty(&call->recvmsg_link)) {
-				rxrpc_get_call(call, rxrpc_call_get_notify_socket);
-				list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
-			}
-			spin_unlock_irq(&rx->recvmsg_lock);
+	spin_lock_irq(&rx->recvmsg_lock);
+	if (list_empty(&call->recvmsg_link)) {
+		rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+		list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+	}
+	spin_unlock_irq(&rx->recvmsg_lock);
 
-			if (!sock_flag(sk, SOCK_DEAD)) {
-				_debug("call %ps", sk->sk_data_ready);
-				sk->sk_data_ready(sk);
-			}
-		}
+	if (!sock_flag(sk, SOCK_DEAD)) {
+		_debug("call %ps", sk->sk_data_ready);
+		sk->sk_data_ready(sk);
 	}
 
-	rcu_read_unlock();
 	_leave("");
 }
 
@@ -215,61 +201,6 @@ static int rxrpc_recvmsg_user_id(struct rxrpc_call *call, struct msghdr *msg,
 	}
 }
 
-/*
- * Deal with a CHALLENGE packet.
- */
-static int rxrpc_recvmsg_challenge(struct socket *sock, struct msghdr *msg,
-				   struct sk_buff *challenge, unsigned int flags)
-{
-	struct rxrpc_skb_priv *sp = rxrpc_skb(challenge);
-	struct rxrpc_connection *conn = sp->chall.conn;
-
-	return conn->security->challenge_to_recvmsg(conn, challenge, msg);
-}
-
-/*
- * Process OOB packets.  Called with the socket locked.
- */
-static int rxrpc_recvmsg_oob(struct socket *sock, struct msghdr *msg,
-			     unsigned int flags)
-{
-	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
-	struct sk_buff *skb;
-	bool need_response = false;
-	int ret;
-
-	skb = skb_peek(&rx->recvmsg_oobq);
-	if (!skb)
-		return -EAGAIN;
-	rxrpc_see_skb(skb, rxrpc_skb_see_recvmsg);
-
-	ret = put_cmsg(msg, SOL_RXRPC, RXRPC_OOB_ID, sizeof(u64),
-		       &skb->skb_mstamp_ns);
-	if (ret < 0)
-		return ret;
-
-	switch ((enum rxrpc_oob_type)skb->mark) {
-	case RXRPC_OOB_CHALLENGE:
-		need_response = true;
-		ret = rxrpc_recvmsg_challenge(sock, msg, skb, flags);
-		break;
-	default:
-		WARN_ONCE(1, "recvmsg() can't process unknown OOB type %u\n",
-			  skb->mark);
-		ret = -EIO;
-		break;
-	}
-
-	if (!(flags & MSG_PEEK)) {
-		skb_unlink(skb, &rx->recvmsg_oobq);
-		if (need_response)
-			rxrpc_add_pending_oob(rx, skb);
-		else
-			rxrpc_free_skb(skb, rxrpc_skb_put_oob);
-	}
-	return ret;
-}
-
 /*
  * 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
@@ -281,7 +212,6 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
 			      size_t len, int flags, size_t *_offset)
 {
 	struct rxrpc_skb_priv *sp;
-	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
 	struct sk_buff *skb;
 	rxrpc_seq_t seq = 0;
 	size_t remain;
@@ -376,13 +306,6 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
 
 		if (!(flags & MSG_PEEK))
 			rxrpc_rotate_rx_window(call);
-
-		if (!rx->app_ops &&
-		    !skb_queue_empty_lockless(&rx->recvmsg_oobq)) {
-			trace_rxrpc_recvdata(call, rxrpc_recvmsg_oobq, seq,
-					     rx_pkt_offset, rx_pkt_len, ret);
-			break;
-		}
 	}
 
 out:
@@ -419,7 +342,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 
 	trace_rxrpc_recvmsg(0, rxrpc_recvmsg_enter, 0);
 
-	if (flags & (MSG_OOB | MSG_TRUNC))
+	if (flags & MSG_TRUNC)
 		return -EOPNOTSUPP;
 
 	timeo = sock_rcvtimeo(&rx->sk, flags & MSG_DONTWAIT);
@@ -430,14 +353,12 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 	/* Return immediately if a client socket has no outstanding calls */
 	if (RB_EMPTY_ROOT(&rx->calls) &&
 	    list_empty(&rx->recvmsg_q) &&
-	    skb_queue_empty_lockless(&rx->recvmsg_oobq) &&
 	    rx->sk.sk_state != RXRPC_SERVER_LISTENING) {
 		release_sock(&rx->sk);
 		return -EAGAIN;
 	}
 
-	if (list_empty(&rx->recvmsg_q) &&
-	    skb_queue_empty_lockless(&rx->recvmsg_oobq)) {
+	if (list_empty(&rx->recvmsg_q)) {
 		ret = -EWOULDBLOCK;
 		if (timeo == 0) {
 			call = NULL;
@@ -453,8 +374,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 		if (ret)
 			goto wait_error;
 
-		if (list_empty(&rx->recvmsg_q) &&
-		    skb_queue_empty_lockless(&rx->recvmsg_oobq)) {
+		if (list_empty(&rx->recvmsg_q)) {
 			if (signal_pending(current))
 				goto wait_interrupted;
 			trace_rxrpc_recvmsg(0, rxrpc_recvmsg_wait, 0);
@@ -464,15 +384,6 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 		goto try_again;
 	}
 
-	/* Deal with OOB messages before we consider getting normal data. */
-	if (!skb_queue_empty_lockless(&rx->recvmsg_oobq)) {
-		ret = rxrpc_recvmsg_oob(sock, msg, flags);
-		release_sock(&rx->sk);
-		if (ret == -EAGAIN)
-			goto try_again;
-		goto error_trace;
-	}
-
 	/* Find the next call and dequeue it if we're not just peeking.  If we
 	 * do dequeue it, that comes with a ref that we will need to release.
 	 * We also want to weed out calls that got requeued whilst we were
@@ -483,8 +394,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 	call = list_entry(l, struct rxrpc_call, recvmsg_link);
 
 	if (!rxrpc_call_is_complete(call) &&
-	    skb_queue_empty(&call->recvmsg_queue) &&
-	    skb_queue_empty(&rx->recvmsg_oobq)) {
+	    skb_queue_empty(&call->recvmsg_queue)) {
 		list_del_init(&call->recvmsg_link);
 		spin_unlock_irq(&rx->recvmsg_lock);
 		release_sock(&rx->sk);
@@ -561,7 +471,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 
 	if (!(flags & MSG_PEEK) &&
 	    !skb_queue_empty(&call->recvmsg_queue))
-		rxrpc_notify_socket(call);
+		rxrpc_requeue_call(sock, call);
 	goto not_yet_complete;
 
 call_failed:
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
index 77a67ace1d2481..b9efeec145dd17 100644
--- a/net/rxrpc/rxgk.c
+++ b/net/rxrpc/rxgk.c
@@ -11,6 +11,7 @@
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <linux/key-type.h>
+#include <keys/user-type.h>
 #include "ar-internal.h"
 #include "rxgk_common.h"
 
@@ -734,37 +735,6 @@ static bool rxgk_validate_challenge(struct rxrpc_connection *conn,
 	return true;
 }
 
-/**
- * rxgk_kernel_query_challenge - Query RxGK-specific challenge parameters
- * @challenge: The challenge packet to query
- *
- * Return: The Kerberos 5 encoding type for the challenged connection.
- */
-u32 rxgk_kernel_query_challenge(struct sk_buff *challenge)
-{
-	struct rxrpc_skb_priv *sp = rxrpc_skb(challenge);
-
-	return sp->chall.conn->rxgk.enctype;
-}
-EXPORT_SYMBOL(rxgk_kernel_query_challenge);
-
-/*
- * Fill out the control message to pass to userspace to inform about the
- * challenge.
- */
-static int rxgk_challenge_to_recvmsg(struct rxrpc_connection *conn,
-				     struct sk_buff *challenge,
-				     struct msghdr *msg)
-{
-	struct rxgk_challenge chall;
-
-	chall.base.service_id		= conn->service_id;
-	chall.base.security_index	= conn->security_ix;
-	chall.enctype			= conn->rxgk.enctype;
-
-	return put_cmsg(msg, SOL_RXRPC, RXRPC_CHALLENGED, sizeof(chall), &chall);
-}
-
 /*
  * Insert the requisite amount of XDR padding for the length given.
  */
@@ -837,7 +807,7 @@ static noinline ssize_t rxgk_insert_response_header(struct rxrpc_connection *con
  */
 static ssize_t rxgk_construct_authenticator(struct rxrpc_connection *conn,
 					    struct sk_buff *challenge,
-					    const struct krb5_buffer *appdata,
+					    const struct user_key_payload *appdata,
 					    struct sk_buff *response,
 					    size_t offset)
 {
@@ -859,20 +829,20 @@ static ssize_t rxgk_construct_authenticator(struct rxrpc_connection *conn,
 	if (ret < 0)
 		return -EPROTO;
 
-	a.appdata_len = htonl(appdata->len);
+	a.appdata_len = htonl(appdata->datalen);
 
 	ret = skb_store_bits(response, offset, &a, sizeof(a));
 	if (ret < 0)
 		return ret;
 	offset += sizeof(a);
 
-	if (appdata->len) {
-		ret = skb_store_bits(response, offset, appdata->data, appdata->len);
+	if (appdata->datalen) {
+		ret = skb_store_bits(response, offset, appdata->data, appdata->datalen);
 		if (ret < 0)
 			return ret;
-		offset += appdata->len;
+		offset += appdata->datalen;
 
-		ret = rxgk_pad_out(response, appdata->len, offset);
+		ret = rxgk_pad_out(response, appdata->datalen, offset);
 		if (ret < 0)
 			return ret;
 		offset += ret;
@@ -890,7 +860,7 @@ static ssize_t rxgk_construct_authenticator(struct rxrpc_connection *conn,
 	ret = skb_store_bits(response, offset, &b, sizeof(b));
 	if (ret < 0)
 		return ret;
-	return sizeof(a) + xdr_round_up(appdata->len) + sizeof(b);
+	return sizeof(a) + xdr_round_up(appdata->datalen) + sizeof(b);
 }
 
 static ssize_t rxgk_encrypt_authenticator(struct rxrpc_connection *conn,
@@ -923,7 +893,7 @@ static ssize_t rxgk_encrypt_authenticator(struct rxrpc_connection *conn,
  */
 static int rxgk_construct_response(struct rxrpc_connection *conn,
 				   struct sk_buff *challenge,
-				   struct krb5_buffer *appdata)
+				   const struct user_key_payload *appdata)
 {
 	struct rxrpc_skb_priv *csp, *rsp;
 	struct rxgk_context *gk;
@@ -936,7 +906,7 @@ static int rxgk_construct_response(struct rxrpc_connection *conn,
 	if (IS_ERR(gk))
 		return PTR_ERR(gk);
 
-	auth_len = 20 + (4 + appdata->len) + 12 + (1 + 4) * 4;
+	auth_len = 20 + (4 + appdata->datalen) + 12 + (1 + 4) * 4;
 	authx_len = crypto_krb5_how_much_buffer(gk->krb5, KRB5_ENCRYPT_MODE,
 						auth_len, &auth_offset);
 	len = sizeof(struct rxrpc_wire_header) +
@@ -1011,66 +981,36 @@ static int rxgk_construct_response(struct rxrpc_connection *conn,
  * Respond to a challenge packet.
  */
 static int rxgk_respond_to_challenge(struct rxrpc_connection *conn,
-				     struct sk_buff *challenge,
-				     struct krb5_buffer *appdata)
+				     struct sk_buff *challenge)
 {
-	_enter("{%d,%x}", conn->debug_id, key_serial(conn->key));
+	struct user_key_payload dummy = {}, *appdata = &dummy;
+	int ret;
+
+	_enter("{%d,%u,%x,%x}",
+	       conn->debug_id, conn->service_id,
+	       key_serial(conn->key), key_serial(conn->bundle->app_data));
 
 	if (key_validate(conn->key) < 0)
 		return rxrpc_abort_conn(conn, NULL, RXGK_EXPIRED, -EPROTO,
 					rxgk_abort_chall_key_expired);
 
-	return rxgk_construct_response(conn, challenge, appdata);
-}
-
-static int rxgk_respond_to_challenge_no_appdata(struct rxrpc_connection *conn,
-						struct sk_buff *challenge)
-{
-	struct krb5_buffer appdata = {};
-
-	return rxgk_respond_to_challenge(conn, challenge, &appdata);
-}
-
-/**
- * rxgk_kernel_respond_to_challenge - Respond to a challenge with appdata
- * @challenge: The challenge to respond to
- * @appdata: The application data to include in the RESPONSE authenticator
- *
- * Allow a kernel application to respond to a CHALLENGE with application data
- * to be included in the RxGK RESPONSE Authenticator.
- *
- * Return: %0 if successful and a negative error code otherwise.
- */
-int rxgk_kernel_respond_to_challenge(struct sk_buff *challenge,
-				     struct krb5_buffer *appdata)
-{
-	struct rxrpc_skb_priv *csp = rxrpc_skb(challenge);
-
-	return rxgk_respond_to_challenge(csp->chall.conn, challenge, appdata);
-}
-EXPORT_SYMBOL(rxgk_kernel_respond_to_challenge);
-
-/*
- * Parse sendmsg() control message and respond to challenge.  We need to see if
- * there's an appdata to fish out.
- */
-static int rxgk_sendmsg_respond_to_challenge(struct sk_buff *challenge,
-					     struct msghdr *msg)
-{
-	struct krb5_buffer appdata = {};
-	struct cmsghdr *cmsg;
-
-	for_each_cmsghdr(cmsg, msg) {
-		if (cmsg->cmsg_level != SOL_RXRPC ||
-		    cmsg->cmsg_type != RXRPC_RESP_RXGK_APPDATA)
-			continue;
-		if (appdata.data)
-			return -EINVAL;
-		appdata.data = CMSG_DATA(cmsg);
-		appdata.len = cmsg->cmsg_len - sizeof(struct cmsghdr);
+	if (conn->bundle->app_data) {
+		rcu_read_lock();
+		appdata = (struct user_key_payload *)
+			user_key_payload_rcu(conn->bundle->app_data);
+		if (appdata && !refcount_inc_not_zero(&appdata->ref))
+			appdata = NULL;
+		rcu_read_unlock();
+		if (!appdata)
+			return rxrpc_abort_conn(conn, NULL, RXGK_EXPIRED, -EKEYREVOKED,
+						rxgk_abort_chall_key_expired);
 	}
 
-	return rxgk_kernel_respond_to_challenge(challenge, &appdata);
+	ret = rxgk_construct_response(conn, challenge, appdata);
+
+	if (appdata != &dummy)
+		put_user_key_payload(appdata);
+	return ret;
 }
 
 /*
@@ -1346,9 +1286,7 @@ const struct rxrpc_security rxgk_yfs = {
 	.free_call_crypto		= rxgk_free_call_crypto,
 	.issue_challenge		= rxgk_issue_challenge,
 	.validate_challenge		= rxgk_validate_challenge,
-	.challenge_to_recvmsg		= rxgk_challenge_to_recvmsg,
-	.sendmsg_respond_to_challenge	= rxgk_sendmsg_respond_to_challenge,
-	.respond_to_challenge		= rxgk_respond_to_challenge_no_appdata,
+	.respond_to_challenge		= rxgk_respond_to_challenge,
 	.verify_response		= rxgk_verify_response,
 	.clear				= rxgk_clear,
 	.default_decode_ticket		= rxgk_yfs_decode_ticket,
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index ca9f0e82cb9ac7..e55bfca10e1a94 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -748,32 +748,6 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
 	return ret;
 }
 
-/*
- * RxKAD does automatic response only as there's nothing to manage that isn't
- * already in the key.
- */
-static int rxkad_sendmsg_respond_to_challenge(struct sk_buff *challenge,
-					      struct msghdr *msg)
-{
-	return -EINVAL;
-}
-
-/**
- * rxkad_kernel_respond_to_challenge - Respond to a challenge with appdata
- * @challenge: The challenge to respond to
- *
- * Allow a kernel application to respond to a CHALLENGE.
- *
- * Return: %0 if successful and a negative error code otherwise.
- */
-int rxkad_kernel_respond_to_challenge(struct sk_buff *challenge)
-{
-	struct rxrpc_skb_priv *csp = rxrpc_skb(challenge);
-
-	return rxkad_respond_to_challenge(csp->chall.conn, challenge);
-}
-EXPORT_SYMBOL(rxkad_kernel_respond_to_challenge);
-
 /* Decrypt data in-place using DES-PCBC.  @len must be a multiple of 8. */
 VISIBLE_IF_KUNIT void des_pcbc_decrypt_inplace(const struct des_ctx *key,
 					       __le64 iv, u8 *data, size_t len)
@@ -1134,7 +1108,6 @@ const struct rxrpc_security rxkad = {
 	.free_call_crypto		= rxkad_free_call_crypto,
 	.issue_challenge		= rxkad_issue_challenge,
 	.validate_challenge		= rxkad_validate_challenge,
-	.sendmsg_respond_to_challenge	= rxkad_sendmsg_respond_to_challenge,
 	.respond_to_challenge		= rxkad_respond_to_challenge,
 	.verify_response		= rxkad_verify_response,
 	.clear				= rxkad_clear,
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index ed2c9a51005ade..cdf35440317d6d 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -12,6 +12,7 @@
 #include <linux/skbuff.h>
 #include <linux/export.h>
 #include <linux/sched/signal.h>
+#include <keys/user-type.h>
 
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
@@ -320,8 +321,8 @@ static int rxrpc_alloc_txqueue(struct sock *sk, struct rxrpc_call *call)
 static int rxrpc_send_data(struct rxrpc_sock *rx,
 			   struct rxrpc_call *call,
 			   struct msghdr *msg, size_t len,
-			   rxrpc_notify_end_tx_t notify_end_tx,
-			   bool *_dropped_lock)
+			   rxrpc_notify_end_tx_t notify_end_tx)
+	__releases(&call->user_mutex)
 {
 	struct rxrpc_txbuf *txb;
 	struct sock *sk = &rx->sk;
@@ -330,23 +331,31 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 	bool more = msg->msg_flags & MSG_MORE;
 	int ret, copied = 0;
 
-	if (test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags)) {
+	if (unlikely(test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags))) {
 		trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
 				  call->cid, call->call_id, call->rx_consumed,
 				  0, -EPROTO);
-		return -EPROTO;
+		ret = -EPROTO;
+		goto out_unlock;
+	}
+	if (unlikely(test_bit(RXRPC_CALL_TX_ERROR, &call->flags))) {
+		trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_tx_error,
+				  call->cid, call->call_id, call->rx_consumed,
+				  0, -EIO);
+		ret = -EIO;
+		goto out_unlock;
 	}
 
 	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
 
 	ret = rxrpc_wait_to_be_connected(call, &timeo);
 	if (ret < 0)
-		return ret;
+		goto out_unlock;
 
 	if (call->conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
 		ret = rxrpc_init_client_conn_security(call->conn);
 		if (ret < 0)
-			return ret;
+			goto out_unlock;
 	}
 
 	/* this should be in poll */
@@ -440,12 +449,21 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 		/* add the packet to the send queue if it's now full */
 		if (!txb->space ||
 		    (msg_data_left(msg) == 0 && !more)) {
+			/* Do any required crypto.  If this fails, it could
+			 * have corrupted the txbuf content with a partial
+			 * encrypt.  Assume that ENOMEM is retryable, but
+			 * everything else is terminal.
+			 */
+			ret = call->security->secure_packet(call, txb);
+			if (ret < 0) {
+				if (ret == -ENOMEM)
+					goto maybe_error;
+				set_bit(RXRPC_CALL_TX_ERROR, &call->flags);
+				goto out_txb;
+			}
+
 			if (msg_data_left(msg) == 0 && !more)
 				txb->flags |= RXRPC_LAST_PACKET;
-
-			ret = call->security->secure_packet(call, txb);
-			if (ret < 0)
-				goto out;
 			rxrpc_queue_packet(rx, call, txb, notify_end_tx);
 			txb = NULL;
 		}
@@ -453,48 +471,58 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 
 success:
 	ret = copied;
-	if (rxrpc_call_is_complete(call) &&
-	    call->error < 0)
-		ret = call->error;
-out:
+out_txb:
 	call->tx_pending = txb;
+out_unlock:
+	mutex_unlock(&call->user_mutex);
 	_leave(" = %d", ret);
 	return ret;
 
 call_terminated:
 	rxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);
-	_leave(" = %d", call->error);
-	return call->error;
+	call->tx_pending = NULL;
+	ret = call->error;
+	goto out_unlock;
 
 maybe_error:
-	if (copied)
+	if (copied) {
+		if (rxrpc_call_is_complete(call) &&
+		    call->error < 0) {
+			ret = call->error;
+			goto out_unlock;
+		}
 		goto success;
-	goto out;
+	}
+	goto out_txb;
 
 efault:
 	ret = -EFAULT;
-	goto out;
+	goto out_txb;
 
 wait_for_space:
 	ret = -EAGAIN;
 	if (msg->msg_flags & MSG_DONTWAIT)
 		goto maybe_error;
+	call->tx_pending = txb;
+	txb = NULL;
 	mutex_unlock(&call->user_mutex);
-	*_dropped_lock = true;
+
 	ret = rxrpc_wait_for_tx_window(rx, call, &timeo,
 				       msg->msg_flags & MSG_WAITALL);
 	if (ret < 0)
-		goto maybe_error;
+		goto out_nolock;
 	if (call->interruptibility == RXRPC_INTERRUPTIBLE) {
 		if (mutex_lock_interruptible(&call->user_mutex) < 0) {
 			ret = sock_intr_errno(timeo);
-			goto maybe_error;
+			goto out_nolock;
 		}
 	} else {
 		mutex_lock(&call->user_mutex);
 	}
-	*_dropped_lock = false;
 	goto reload;
+out_nolock:
+	_leave(" = %d [intr]", ret);
+	return copied ?: ret;
 }
 
 /*
@@ -503,6 +531,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p)
 {
 	struct cmsghdr *cmsg;
+	key_serial_t key_id;
+	key_ref_t key;
 	bool got_user_ID = false;
 	int len;
 
@@ -587,6 +617,22 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p)
 				return -ERANGE;
 			break;
 
+		case RXRPC_RESPONSE_APPDATA:
+			if (len != sizeof(key_serial_t))
+				return -EINVAL;
+			if (p->call.app_data)
+				return -EINVAL;
+			key_id = *(key_serial_t *)CMSG_DATA(cmsg);
+			key = lookup_user_key(key_id, 0, KEY_NEED_SEARCH);
+			if (IS_ERR(key))
+				return PTR_ERR(key);
+			if (key_ref_to_ptr(key)->type == &key_type_user) {
+				key_ref_put(key);
+				return -EINVAL;
+			}
+			p->call.app_data = key_ref_to_ptr(key);
+			break;
+
 		default:
 			return -EINVAL;
 		}
@@ -695,8 +741,10 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
 			goto error_release_sock;
 		call = rxrpc_new_client_call_for_sendmsg(rx, msg, &p);
 		/* The socket is now unlocked... */
-		if (IS_ERR(call))
+		if (IS_ERR(call)) {
+			key_put(p.call.app_data);
 			return PTR_ERR(call);
+		}
 		/* ... and we have the call lock. */
 		p.call.nr_timeouts = 0;
 		ret = 0;
@@ -769,8 +817,8 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
 		ret = 0;
 		break;
 	case RXRPC_CMD_SEND_DATA:
-		ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock);
-		break;
+		ret = rxrpc_send_data(rx, call, msg, len, NULL);
+		goto error_put;
 	default:
 		ret = -EINVAL;
 		break;
@@ -781,11 +829,13 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
 		mutex_unlock(&call->user_mutex);
 error_put:
 	rxrpc_put_call(call, rxrpc_call_put_sendmsg);
+	key_put(p.call.app_data);
 	_leave(" = %d", ret);
 	return ret;
 
 error_release_sock:
 	release_sock(&rx->sk);
+	key_put(p.call.app_data);
 	return ret;
 }
 
@@ -808,7 +858,6 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
 			   struct msghdr *msg, size_t len,
 			   rxrpc_notify_end_tx_t notify_end_tx)
 {
-	bool dropped_lock = false;
 	int ret;
 
 	_enter("{%d},", call->debug_id);
@@ -819,12 +868,10 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
 	mutex_lock(&call->user_mutex);
 
 	ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
-			      notify_end_tx, &dropped_lock);
+			      notify_end_tx);
 	if (ret == -ESHUTDOWN)
 		ret = call->error;
 
-	if (!dropped_lock)
-		mutex_unlock(&call->user_mutex);
 	_leave(" = %d", ret);
 	return ret;
 }
diff --git a/net/rxrpc/server_key.c b/net/rxrpc/server_key.c
index 3efe104b1930cb..fc6f478e1762a7 100644
--- a/net/rxrpc/server_key.c
+++ b/net/rxrpc/server_key.c
@@ -173,43 +173,3 @@ int rxrpc_sock_set_security_keyring(struct sock *sk, struct key *keyring)
 	return ret;
 }
 EXPORT_SYMBOL(rxrpc_sock_set_security_keyring);
-
-/**
- * rxrpc_sock_set_manage_response - Set the manage-response flag for a kernel service
- * @sk: The socket to set the keyring on
- * @set: True to set, false to clear the flag
- *
- * Set the flag on an rxrpc socket to say that the caller wants to manage the
- * RESPONSE packet and the user-defined data it may contain.  Setting this
- * means that recvmsg() will return messages with RXRPC_CHALLENGED in the
- * control message buffer containing information about the challenge.
- *
- * The user should respond to the challenge by passing RXRPC_RESPOND or
- * RXRPC_RESPOND_ABORT control messages with sendmsg() to the same call.
- * Supplementary control messages, such as RXRPC_RESP_RXGK_APPDATA, may be
- * included to indicate the parts the user wants to supply.
- *
- * The server will be passed the response data with a RXRPC_RESPONDED control
- * message when it gets the first data from each call.
- *
- * Note that this is only honoured by security classes that need auxiliary data
- * (e.g. RxGK).  Those that don't offer the facility (e.g. RxKAD) respond
- * without consulting userspace.
- *
- * Return: The previous setting.
- */
-int rxrpc_sock_set_manage_response(struct sock *sk, bool set)
-{
-	struct rxrpc_sock *rx = rxrpc_sk(sk);
-	int ret;
-
-	lock_sock(sk);
-	ret = !!test_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
-	if (set)
-		set_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
-	else
-		clear_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
-	release_sock(sk);
-	return ret;
-}
-EXPORT_SYMBOL(rxrpc_sock_set_manage_response);
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 6f88b507f92791..90c1bd5d7dfecf 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -67,6 +67,7 @@ int user_preparse(struct key_preparsed_payload *prep)
 	upayload = kmalloc_flex(*upayload, data, datalen);
 	if (!upayload)
 		return -ENOMEM;
+	refcount_set(&upayload->ref, 1);
 
 	/* attach the data */
 	prep->quotalen = datalen;
@@ -88,12 +89,22 @@ EXPORT_SYMBOL_GPL(user_free_preparse);
 
 static void user_free_payload_rcu(struct rcu_head *head)
 {
-	struct user_key_payload *payload;
+	struct user_key_payload *payload =
+		container_of(head, struct user_key_payload, rcu);
 
-	payload = container_of(head, struct user_key_payload, rcu);
 	kfree_sensitive(payload);
 }
 
+/*
+ * Free a user defined key payload.
+ */
+void put_user_key_payload(struct user_key_payload *payload)
+{
+	if (payload && refcount_dec_and_test(&payload->ref))
+		call_rcu(&payload->rcu, user_free_payload_rcu);
+}
+EXPORT_SYMBOL_GPL(put_user_key_payload);
+
 /*
  * update a user defined key
  * - the key's semaphore is write-locked
@@ -115,8 +126,7 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)
 	rcu_assign_keypointer(key, prep->payload.data[0]);
 	prep->payload.data[0] = NULL;
 
-	if (zap)
-		call_rcu(&zap->rcu, user_free_payload_rcu);
+	put_user_key_payload(zap);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(user_update);
@@ -134,7 +144,7 @@ void user_revoke(struct key *key)
 
 	if (upayload) {
 		rcu_assign_keypointer(key, NULL);
-		call_rcu(&upayload->rcu, user_free_payload_rcu);
+		put_user_key_payload(upayload);
 	}
 }
 
@@ -147,9 +157,8 @@ void user_destroy(struct key *key)
 {
 	struct user_key_payload *upayload = key->payload.data[0];
 
-	kfree_sensitive(upayload);
+	put_user_key_payload(upayload);
 }
-
 EXPORT_SYMBOL_GPL(user_destroy);
 
 /*

3/2 2026/07/11 16:41 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 43192
							output: 17
							thoughts: 236
						

Thoughts:
**Analyzing the RxRPC and AFS Patch Series**

Okay, so I'm looking at this patch series. It's making some pretty fundamental changes within the Linux kernel, specifically touching the `afs` and `rxrpc` subsystems. The gist of it is they're ditching the old `oob` message handling in `rxrpc`. Instead, they're using a key to neatly pass along application data within RxGK responses. This seems cleaner and probably more efficient.

The `afs` side of things is where the bulk of the changes are, as it uses `afs_create_server_appdata` and `afs_create_yfs_rxgk_cm_appdata` to create this crucial key that contains the app data. This key is then passed to `rxrpc_kernel_begin_call`. Essentially, `afs` is now building the key and handing it off to `rxrpc`. They're also removing `rxrpc_sock_set_manage_response`. Seems like some internal refactoring and simplification, which is always good to see. Plus, they've refactored `afs_put_call` to take a trace enum. This is likely for more granular debugging or logging capabilities, which is a sensible addition.

Now, my first thought is, is this actually doing what it's supposed to? And more importantly, does it *work*? The changes are definitely core to both `afs` and `rxrpc` so there is significant potential for disruption. I also need to make sure that whatever configuration dependencies are introduced are met. This will definitely involve `CONFIG_RXGK` and `CONFIG_AFS_FS`. So, I'm going to have to dive into the Kconfig files to see exactly what needs to be enabled for this patch to function correctly. This is important to ensure that if these configurations aren't turned on, the code does what's expected.



4/2 2026/07/11 16:41 tool grepper
0m Args:
{
  "Expression": "config RXGK"
}

Results:
{
  "Output": "net/rxrpc/Kconfig=58=config RXKAD\n--\nnet/rxrpc/Kconfig-65-\nnet/rxrpc/Kconfig:66:config RXGK\nnet/rxrpc/Kconfig-67-\tbool \"RxRPC GSSAPI security\"\n"
}

5/2 2026/07/11 16:41 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 43928
							output: 19
							thoughts: 9
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:

**Initial Assessment: AFS_FS Check**

Right, let's take a look at `AFS_FS`. It's a quick, internal check. Given my experience, I'm already formulating some likely scenarios in my head. This probably indicates a filesystem-related issue, possibly a performance bottleneck or something more critical. I'm immediately thinking about potential problems with quota usage, network connectivity if it's distributed, or even inconsistencies within the filesystem's metadata. My initial thought process is to understand *why* this needs to be checked. Is it part of a troubleshooting workflow, or a proactive monitoring step? That context will influence where I start to dig in.



6/2 2026/07/11 16:41 tool grepper
0m Args:
{
  "Expression": "config AFS_FS"
}

Results:
{
  "Output": "fs/afs/Kconfig-1-# SPDX-License-Identifier: GPL-2.0-only\nfs/afs/Kconfig:2:config AFS_FS\nfs/afs/Kconfig-3-\ttristate \"Andrew File System support (AFS)\"\n--\nfs/afs/Kconfig=17=config AFS_DEBUG\n--\nfs/afs/Kconfig-26-\nfs/afs/Kconfig:27:config AFS_FSCACHE\nfs/afs/Kconfig-28-\tbool \"Provide AFS client caching support\"\n"
}

7/2 2026/07/11 16:41 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 44263
							output: 30
							thoughts: 47
						

Thoughts:
**Analyzing Configuration Dependencies**

Okay, so I'm looking at this configuration and need to figure out how `RXGK` and `AFS_FS` relate. Right, `RXGK` is a simple boolean, that makes it easier to track. `AFS_FS` is a tristate, so it's a bit more nuanced.

First, let's just make sure `RXGK` is clear and doesn't get muddled later. No point chasing other variables until I'm absolutely clear. Now, let's see if this boolean depends on anything else. Gotta check its dependencies, see if there are any prerequisites or conditions that influence its setting. Need to figure out the impact of this particular config before I move any further!



8/2 2026/07/11 16:41 tool grepper
0m Args:
{
  "Expression": "config RXGK",
  "PathPrefix": "net/rxrpc/Kconfig"
}

Results:
{
  "Output": "net/rxrpc/Kconfig=58=config RXKAD\n--\nnet/rxrpc/Kconfig-65-\nnet/rxrpc/Kconfig:66:config RXGK\nnet/rxrpc/Kconfig-67-\tbool \"RxRPC GSSAPI security\"\n"
}

9/2 2026/07/11 16:41 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 44575
							output: 34
							thoughts: 19
						

Thoughts:
Here's my take on the thought process, as if I were the one thinking it:

**Diving into the net/rxrpc/Kconfig file**

Okay, time to dig into the `net/rxrpc/Kconfig` file. Specifically, I need to get my head around the configuration options related to the `config RXGK` setting. Understanding the configuration options here is crucial for understanding how to enable the RXRPC kernel module within the system. Let's see what knobs are available and how they're intended to work. I need to understand this configuration setting fully.



10/2 2026/07/11 16:41 tool read-file
0m Args:
{
  "File": "net/rxrpc/Kconfig",
  "FirstLine": 60,
  "LineCount": 20
}

Results:
{
  "Contents": "  60:\t\thelp\n  61:\t\t  Provide kerberos 4 and AFS kaserver security handling for AF_RXRPC\n  62:\t\t  through the use of the key retention service.\n  63:\t\n  64:\t\t  See Documentation/networking/rxrpc.rst.\n  65:\t\n  66:\tconfig RXGK\n  67:\t\tbool \"RxRPC GSSAPI security\"\n  68:\t\tselect CRYPTO_KRB5\n  69:\t\tselect CRYPTO_MANAGER\n  70:\t\tselect CRYPTO_KRB5ENC\n  71:\t\tselect CRYPTO_AUTHENC\n  72:\t\tselect CRYPTO_SKCIPHER\n  73:\t\tselect CRYPTO_HASH_INFO\n  74:\t\tselect CRYPTO_HMAC\n  75:\t\tselect CRYPTO_CMAC\n  76:\t\tselect CRYPTO_SHA1\n  77:\t\tselect CRYPTO_SHA256\n  78:\t\tselect CRYPTO_SHA512\n  79:\t\tselect CRYPTO_CBC\n"
}

11/2 2026/07/11 16:41 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 45016
							output: 20
							thoughts: 28
						

Thoughts:
Here's my take on those thoughts:

**Configuring the System: A Quick Review**

Okay, so I'm looking at these configurations. It seems like `RXGK` and `AFS_FS` are the primary ones I need to consider for this setup. But, hold on a second... I can't forget about `AF_RXRPC`. It's definitely in the mix too. I need to make sure that's accounted for. I’ll make a note to double-check that this is all in the same build.



12/2 2026/07/11 16:41 tool grepper
0m Args:
{
  "Expression": "config AF_RXRPC"
}

Results:
{
  "Output": "net/rxrpc/Kconfig-5-\nnet/rxrpc/Kconfig:6:config AF_RXRPC\nnet/rxrpc/Kconfig-7-\ttristate \"RxRPC session sockets\"\n--\nnet/rxrpc/Kconfig=25=if AF_RXRPC\nnet/rxrpc/Kconfig-26-\nnet/rxrpc/Kconfig:27:config AF_RXRPC_IPV6\nnet/rxrpc/Kconfig-28-\tbool \"IPv6 support for RxRPC\"\n--\nnet/rxrpc/Kconfig-33-\nnet/rxrpc/Kconfig:34:config AF_RXRPC_INJECT_LOSS\nnet/rxrpc/Kconfig-35-\tbool \"Inject packet loss into RxRPC packet stream\"\n--\nnet/rxrpc/Kconfig-39-\nnet/rxrpc/Kconfig:40:config AF_RXRPC_INJECT_RX_DELAY\nnet/rxrpc/Kconfig-41-\tbool \"Inject delay into packet reception\"\n--\nnet/rxrpc/Kconfig-49-\nnet/rxrpc/Kconfig:50:config AF_RXRPC_DEBUG\nnet/rxrpc/Kconfig-51-\tbool \"RxRPC dynamic debugging\"\n--\nnet/rxrpc/Kconfig=89=config RXPERF\n--\nnet/rxrpc/Kconfig-95-\nnet/rxrpc/Kconfig:96:config AF_RXRPC_KUNIT_TEST\nnet/rxrpc/Kconfig-97-\ttristate \"RxRPC crypto KUnit test\" if !KUNIT_ALL_TESTS\n"
}

13/2 2026/07/11 16:41 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 45580
							output: 22
							thoughts: 536
						

Thoughts:
**Analyzing Recent Changes and Hot Paths**

Okay, so I'm looking at these recent modifications, and it seems the core focus is on enhancing the interaction between AFS and RXRPC, specifically with the `AF_RXRPC`, `RXGK`, and `AFS_FS` configurations in mind. I've got a list of the modified or new functions: `afs_create_server_appdata`, `afs_create_yfs_rxgk_cm_appdata`, and several callback functions, along with RXRPC and RXGK related functions. 

The interesting bits here are the core changes, and I'm really trying to get a handle on the performance implications. I am trying to identify critical functions here.

Let's see, I've got a shortlist of functions that seem particularly relevant: `afs_create_server_appdata`, `afs_create_yfs_rxgk_cm_appdata`, `rxrpc_kernel_begin_call`, `rxrpc_kernel_query_key`, `rxrpc_sendmsg_cmsg`, `rxgk_construct_response`, `rxgk_respond_to_challenge`, and `put_user_key_payload`.

I'm thinking about hot paths. `rxrpc_kernel_begin_call` is involved in starting a call, so it's probably not the hottest path, although a good starting point. `rxrpc_sendmsg_cmsg`, on the other hand, is right in the message-sending process. That's a strong contender for a critical path. `rxgk_respond_to_challenge` is part of challenge response, so it could be hot depending on the load. `afs_create_server_appdata` is involved in server probing - that's definitely a point to look at. I need to focus on these functions to get a good read on any performance issues. I'll take a closer look at `afs_create_server_appdata`.



14/2 2026/07/11 16:41 tool grepper
0m Args:
{
  "Expression": "afs_create_server_appdata"
}

Results:
{
  "Output": "fs/afs/cm_security.c=28=static int afs_create_yfs_rxgk_cm_appdata(struct afs_server *server, u32 enctype)\n--\nfs/afs/cm_security.c-207- */\nfs/afs/cm_security.c:208:int afs_create_server_appdata(struct afs_server *server, struct key *key)\nfs/afs/cm_security.c-209-{\n--\nfs/afs/fs_probe.c=238=int afs_fs_probe_fileserver(struct afs_net *net, struct afs_server *server,\n--\nfs/afs/fs_probe.c-247-\nfs/afs/fs_probe.c:248:\tret = afs_create_server_appdata(server, key);\nfs/afs/fs_probe.c-249-\tif (ret \u003c 0)\n--\nfs/afs/internal.h=1086=extern bool afs_cm_incoming_call(struct afs_call *);\n--\nfs/afs/internal.h-1090- */\nfs/afs/internal.h:1091:int afs_create_server_appdata(struct afs_server *server, struct key *key);\nfs/afs/internal.h-1092-#ifdef CONFIG_RXGK\n"
}

15/2 2026/07/11 16:42 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 46916
							output: 23
							thoughts: 15
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:

**Analyzing the Call to Action: `rxgk_respond_to_challenge`**

Right, let's dissect this. "Check `rxgk_respond_to_challenge`." Seems pretty straightforward, but the implications are interesting. The naming convention, with that underscore, suggests it's a specific function or module within a larger system – likely one that's designed to interface with some form of external input, potentially asynchronous. The term "challenge" is critical here. It implies a situation where the system, or a component, is being tested, probed, or possibly even exploited. This could be anything from a simple validation check to a more complex security vulnerability scenario.

My immediate considerations are focused on its design. Is it properly sandboxed? Are there adequate input validation checks in place to prevent common attacks like injection or buffer overflows? What are the access control mechanisms around this function – who or what is allowed to trigger it, and under what circumstances? Does it exhibit any inherent vulnerability due to timing or resource exhaustion? The "respond" part suggests that it's going to actively do something, which ratchets up the potential consequences if something goes wrong. Understanding the context and the potential response options is key. I'll need to look at the function's architecture – its internal logic, any dependencies it has, and how it interacts with other modules to formulate an informed judgement.



16/2 2026/07/11 16:42 tool grepper
0m Args:
{
  "Expression": "rxgk_respond_to_challenge"
}

Results:
{
  "Output": "net/rxrpc/rxgk.c=894=static int rxgk_construct_response(struct rxrpc_connection *conn,\n--\nnet/rxrpc/rxgk.c-982- */\nnet/rxrpc/rxgk.c:983:static int rxgk_respond_to_challenge(struct rxrpc_connection *conn,\nnet/rxrpc/rxgk.c-984-\t\t\t\t     struct sk_buff *challenge)\n--\nnet/rxrpc/rxgk.c=1272=const struct rxrpc_security rxgk_yfs = {\n--\nnet/rxrpc/rxgk.c-1288-\t.validate_challenge\t\t= rxgk_validate_challenge,\nnet/rxrpc/rxgk.c:1289:\t.respond_to_challenge\t\t= rxgk_respond_to_challenge,\nnet/rxrpc/rxgk.c-1290-\t.verify_response\t\t= rxgk_verify_response,\n"
}

17/2 2026/07/11 16:42 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 47528
							output: 22
							thoughts: 14
						

Thoughts:
Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert:

**Diving into `rxrpc_sendmsg_cmsg`**

Alright, let's get right to it. The focus here is clearly on `rxrpc_sendmsg_cmsg`. I need to refresh my understanding of that function, probably related to the low-level details of sending messages with control messages in the RXRPC protocol. I'm going to need to figure out exactly how it handles the construction and transmission of those ancillary data buffers. Is it the main workhorse, or a helper function? What's the relationship with the underlying socket and network stack? What are the implications for performance, especially with larger control messages or fragmented payloads? This is where I'll need to go deep... let's see what's what.



18/2 2026/07/11 16:42 tool grepper
0m Args:
{
  "Expression": "rxrpc_sendmsg_cmsg"
}

Results:
{
  "Output": "net/rxrpc/sendmsg.c=321=static int rxrpc_send_data(struct rxrpc_sock *rx,\n--\nnet/rxrpc/sendmsg.c-530- */\nnet/rxrpc/sendmsg.c:531:static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p)\nnet/rxrpc/sendmsg.c-532-{\n--\nnet/rxrpc/sendmsg.c=706=int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n--\nnet/rxrpc/sendmsg.c-724-\nnet/rxrpc/sendmsg.c:725:\tret = rxrpc_sendmsg_cmsg(msg, \u0026p);\nnet/rxrpc/sendmsg.c-726-\tif (ret \u003c 0)\n"
}

19/2 2026/07/11 16:42 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 47985
							output: 21
							thoughts: 13
						

Thoughts:
Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert:

**Investigating `put_user_key_payload`**

Right, let's dive into this `put_user_key_payload` function. I need to understand its behavior, its inputs, and what it's ultimately doing with user keys. There's a subtle nuance here I should not overlook. It’s likely a critical component for key management and any vulnerability here is a significant risk. I wonder about the type-safety checks? Are there proper input validations, like sanitizing inputs and boundary conditions? I need to focus on potential weaknesses like buffer overflows or injection vulnerabilities. We should also check for proper error handling. What happens if the key already exists? What if the storage system is temporarily unavailable? And, is there any logging to track the operations?



20/2 2026/07/11 16:42 tool grepper
0m Args:
{
  "Expression": "put_user_key_payload"
}

Results:
{
  "Output": "include/keys/user-type.h=40=extern void user_free_preparse(struct key_preparsed_payload *prep);\ninclude/keys/user-type.h:41:void put_user_key_payload(struct user_key_payload *payload);\ninclude/keys/user-type.h-42-extern int user_update(struct key *key, struct key_preparsed_payload *prep);\n--\nnet/rxrpc/rxgk.c=983=static int rxgk_respond_to_challenge(struct rxrpc_connection *conn,\n--\nnet/rxrpc/rxgk.c-1011-\tif (appdata != \u0026dummy)\nnet/rxrpc/rxgk.c:1012:\t\tput_user_key_payload(appdata);\nnet/rxrpc/rxgk.c-1013-\treturn ret;\n--\nsecurity/keys/user_defined.c=90=static void user_free_payload_rcu(struct rcu_head *head)\n--\nsecurity/keys/user_defined.c-100- */\nsecurity/keys/user_defined.c:101:void put_user_key_payload(struct user_key_payload *payload)\nsecurity/keys/user_defined.c-102-{\n--\nsecurity/keys/user_defined.c-105-}\nsecurity/keys/user_defined.c:106:EXPORT_SYMBOL_GPL(put_user_key_payload);\nsecurity/keys/user_defined.c-107-\n--\nsecurity/keys/user_defined.c=112=int user_update(struct key *key, struct key_preparsed_payload *prep)\n--\nsecurity/keys/user_defined.c-128-\nsecurity/keys/user_defined.c:129:\tput_user_key_payload(zap);\nsecurity/keys/user_defined.c-130-\treturn ret;\n--\nsecurity/keys/user_defined.c=138=void user_revoke(struct key *key)\n--\nsecurity/keys/user_defined.c-146-\t\trcu_assign_keypointer(key, NULL);\nsecurity/keys/user_defined.c:147:\t\tput_user_key_payload(upayload);\nsecurity/keys/user_defined.c-148-\t}\n--\nsecurity/keys/user_defined.c=156=void user_destroy(struct key *key)\n--\nsecurity/keys/user_defined.c-159-\nsecurity/keys/user_defined.c:160:\tput_user_key_payload(upayload);\nsecurity/keys/user_defined.c-161-}\n"
}

21/2 2026/07/11 16:42 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 48884
							output: 210
							thoughts: 735
						

Thoughts:
**My Assessment of the Kernel Patch's Impact**

Okay, so this patch introduces some pretty significant functional changes to the kernel, specifically within the `afs` and `rxrpc` subsystems. That means this is definitely something that needs to be fuzzed thoroughly. We're looking at configurations like `AF_RXRPC`, `RXGK`, and `AFS_FS` being relevant here. I'll need to confirm that `AF_RXRPC` alone is sufficient or if `RXKAD` is also a dependency. Remember that `RXGK` selects `CRYPTO_KRB5` and other crypto options, and `AFS_FS` is tristate.

I've confirmed that `RXGK`, `AFS_FS`, and `AF_RXRPC` are all properly exposed in their respective Kconfig files (`net/rxrpc/Kconfig` and `fs/afs/Kconfig`). So, the configs are definitely `AF_RXRPC`, `RXGK`, and `AFS_FS`.

Now, let's drill down into the key symbols affected. I see that `rxrpc_kernel_begin_call` now takes an extra `struct key *app_data` argument, which confirms the key-based approach. We also have `rxrpc_kernel_query_key` added in `net/rxrpc/key.c`. The patch adds `afs_create_yfs_rxgk_cm_appdata` and `afs_create_server_appdata` in `fs/afs/cm_security.c`. I've also verified modifications to `rxgk_respond_to_challenge` in `net/rxrpc/rxgk.c` and `rxrpc_sendmsg_cmsg` in `net/rxrpc/sendmsg.c`, along with a new function `put_user_key_payload` added in `security/keys/user_defined.c`.

To summarize the focus symbols:

*   `afs_create_server_appdata`
*   `afs_create_yfs_rxgk_cm_appdata`
*   `rxgk_respond_to_challenge`
*   `rxrpc_sendmsg_cmsg`
*   `put_user_key_payload`

And the key configurations:

*   `AF_RXRPC`
*   `RXGK`
*   `AFS_FS`

Essentially, this patch is refactoring the out-of-band message handling in rxrpc, replacing it with a key-based system for passing application data, particularly in RxGK responses. AFS is modified to leverage this with key creation, and then it passes that key to `rxrpc_kernel_begin_call`. This is a big change to the core rxrpc and AFS logic, especially involving how they handle app data and challenge-response. Fuzzing this is going to be essential to validate the new key-based approach and ensure it works securely and correctly.



22/2 2026/07/11 16:42 tool set-results
0m Args:
{
  "EnableConfigs": [
    "AF_RXRPC",
    "RXGK",
    "AFS_FS"
  ],
  "FocusSymbols": [
    "afs_create_server_appdata",
    "afs_create_yfs_rxgk_cm_appdata",
    "rxgk_respond_to_challenge",
    "rxrpc_sendmsg_cmsg",
    "put_user_key_payload"
  ],
  "Reasoning": "The patch series refactors out-of-band message handling in rxrpc, replacing it with a key-based approach for passing application data in RxGK responses. It also modifies AFS to use this new mechanism by creating a key containing the app data and passing it to rxrpc_kernel_begin_call. These are functional changes to core rxrpc and AFS logic that should be fuzzed to ensure the new key-based app data handling and challenge-response mechanisms work correctly.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "AF_RXRPC",
    "RXGK",
    "AFS_FS"
  ],
  "FocusSymbols": [
    "afs_create_server_appdata",
    "afs_create_yfs_rxgk_cm_appdata",
    "rxgk_respond_to_challenge",
    "rxrpc_sendmsg_cmsg",
    "put_user_key_payload"
  ],
  "Reasoning": "The patch series refactors out-of-band message handling in rxrpc, replacing it with a key-based approach for passing application data in RxGK responses. It also modifies AFS to use this new mechanism by creating a key containing the app data and passing it to rxrpc_kernel_begin_call. These are functional changes to core rxrpc and AFS logic that should be fuzzed to ensure the new key-based app data handling and challenge-response mechanisms work correctly.",
  "WorthFuzzing": true
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)