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