1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2017 RackTop Systems. 14 */ 15 16 #include <sys/systm.h> 17 #include <sys/sdt.h> 18 #include <rpc/types.h> 19 #include <rpc/auth.h> 20 #include <rpc/auth_unix.h> 21 #include <rpc/auth_des.h> 22 #include <rpc/svc.h> 23 #include <rpc/xdr.h> 24 #include <nfs/nfs4.h> 25 #include <nfs/nfs_dispatch.h> 26 #include <sys/cmn_err.h> 27 #include <sys/modctl.h> 28 29 static void 30 rfs4_err_resp(COMPOUND4args *args, COMPOUND4res *resp, nfsstat4 err) 31 { 32 size_t sz; 33 34 resp->array_len = 1; 35 sz = resp->array_len * sizeof (nfs_resop4); 36 resp->array = kmem_zalloc(sz, KM_SLEEP); 37 38 resp->array[0].resop = args->array[0].argop; 39 resp->status = resp->array[0].nfs_resop4_u.opillegal.status = err; 40 } 41 42 /* 43 * The function checks if given compound operation is allowed 44 * to be the very fist operation in compound array. 45 */ 46 static bool_t 47 valid_first_compound_op(nfs_opnum4 op) 48 { 49 if (op == OP_BIND_CONN_TO_SESSION || 50 op == OP_SEQUENCE || 51 op == OP_EXCHANGE_ID || 52 op == OP_CREATE_SESSION || 53 op == OP_DESTROY_SESSION || 54 op == OP_DESTROY_CLIENTID || 55 op == OP_ILLEGAL) 56 return (TRUE); 57 58 return (FALSE); 59 } 60 61 /* 62 * The function verifies arguments passed to mds_op_compound. 63 * If agrguments are valid, NFS4_OK is returned, otherwise 64 * function returns correspoinding NFS4 error code. 65 */ 66 static nfsstat4 67 verify_compound_args(COMPOUND4args *args) 68 { 69 if (args->array_len == 0) 70 return (NFS4_OK); 71 72 if (!valid_first_compound_op(args->array[0].argop)) 73 return (NFS4ERR_OP_NOT_IN_SESSION); 74 75 if (args->array_len > 1 && args->array[0].argop != OP_SEQUENCE) { 76 /* 77 * Compound is outside the session. There must be 78 * only one operation in request. 79 */ 80 return (NFS4ERR_NOT_ONLY_OP); 81 } 82 83 return (NFS4_OK); 84 } 85 86 static void 87 rfs4x_dispatch_done(compound_state_t *cs) 88 { 89 if (cs->slot) 90 rfs4x_sequence_done(cs->cmpresp, cs); 91 else { 92 rfs4_compound_free(cs->cmpresp); 93 } 94 cs->cs_flags |= RFS4_DISPATCH_DONE; 95 } 96 97 static bool_t 98 xdr_compound_wrapper(XDR *xdrs, compound_state_t *cs) 99 { 100 COMPOUND4res *resp = cs->cmpresp; 101 bool_t res = FALSE; 102 bool_t isreal = (xdrs->x_handy != 0); /* real data encoding ? */ 103 104 if (!(cs->cs_flags & RFS4_DISPATCH_DONE)) { 105 res = xdr_COMPOUND4res_srv(xdrs, resp); 106 if (isreal) 107 rfs4x_dispatch_done(cs); 108 } 109 110 return (res); 111 } 112 113 int 114 rfs4x_dispatch(struct svc_req *req, SVCXPRT *xprt, char *ap) 115 { 116 struct compound_state cs; 117 COMPOUND4res res_buf; 118 COMPOUND4res *rbp; 119 COMPOUND4args *cap; 120 int rpcerr = 0; 121 nfsstat4 error; 122 123 bzero(&res_buf, sizeof (COMPOUND4res)); 124 rbp = &res_buf; 125 cap = (COMPOUND4args *)ap; 126 rfs4_init_compound_state(&cs); 127 128 cs.statusp = &error; 129 cs.cmpresp = rbp; 130 131 error = verify_compound_args(cap); 132 if (error != NFS4_OK) { 133 rfs4_err_resp(cap, rbp, error); 134 goto out_send; 135 } 136 137 error = rfs4x_sequence_prep(cap, rbp, &cs); 138 if (error != NFS4_OK) { 139 if (error != nfserr_replay_cache) 140 rfs4_err_resp(cap, rbp, error); 141 goto out_send; 142 } 143 144 /* Regular processing */ 145 curthread->t_flag |= T_DONTPEND; 146 rfs4_compound(cap, rbp, &cs, req, &rpcerr); 147 curthread->t_flag &= ~T_DONTPEND; 148 149 /* 150 * On RPC error, short sendreply 151 */ 152 if (rpcerr) { 153 goto out_free; 154 } 155 156 if (curthread->t_flag & T_WOULDBLOCK) { 157 curthread->t_flag &= ~T_WOULDBLOCK; 158 error = 1; 159 goto out_free; 160 } 161 162 out_send: 163 if (!svc_sendreply(xprt, xdr_compound_wrapper, (char *)&cs)) { 164 DTRACE_PROBE2(sendfail, SVCXPRT *, xprt, 165 compound_state_t *, &cs); 166 svcerr_systemerr(xprt); 167 rpcerr = 1; 168 } 169 170 out_free: 171 if (!(cs.cs_flags & RFS4_DISPATCH_DONE)) { 172 rfs4x_dispatch_done(&cs); 173 } 174 175 rfs4_fini_compound_state(&cs); 176 return ((error != NFS4_OK || rpcerr) ? 1 : 0); 177 } 178