1f44e1126SVitaliy Gusev /*
2f44e1126SVitaliy Gusev * CDDL HEADER START
3f44e1126SVitaliy Gusev *
4f44e1126SVitaliy Gusev * The contents of this file are subject to the terms of the
5f44e1126SVitaliy Gusev * Common Development and Distribution License (the "License").
6f44e1126SVitaliy Gusev * You may not use this file except in compliance with the License.
7f44e1126SVitaliy Gusev *
8f44e1126SVitaliy Gusev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f44e1126SVitaliy Gusev * or http://www.opensolaris.org/os/licensing.
10f44e1126SVitaliy Gusev * See the License for the specific language governing permissions
11f44e1126SVitaliy Gusev * and limitations under the License.
12f44e1126SVitaliy Gusev *
13f44e1126SVitaliy Gusev * When distributing Covered Code, include this CDDL HEADER in each
14f44e1126SVitaliy Gusev * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f44e1126SVitaliy Gusev * If applicable, add the following below this CDDL HEADER, with the
16f44e1126SVitaliy Gusev * fields enclosed by brackets "[]" replaced with your own identifying
17f44e1126SVitaliy Gusev * information: Portions Copyright [yyyy] [name of copyright owner]
18f44e1126SVitaliy Gusev *
19f44e1126SVitaliy Gusev * CDDL HEADER END
20f44e1126SVitaliy Gusev */
21f44e1126SVitaliy Gusev /*
22f44e1126SVitaliy Gusev * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23f44e1126SVitaliy Gusev * Use is subject to license terms.
24f44e1126SVitaliy Gusev *
25f44e1126SVitaliy Gusev * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26f44e1126SVitaliy Gusev * Copyright 2017 RackTop Systems.
27f44e1126SVitaliy Gusev */
28f44e1126SVitaliy Gusev
29f44e1126SVitaliy Gusev #include <rpc/types.h>
30f44e1126SVitaliy Gusev #include <rpc/auth.h>
31f44e1126SVitaliy Gusev #include <rpc/rpcsec_gss.h>
32f44e1126SVitaliy Gusev #include <sys/sdt.h>
33f44e1126SVitaliy Gusev #include <sys/disp.h>
34f44e1126SVitaliy Gusev #include <nfs/nfs.h>
35f44e1126SVitaliy Gusev #include <nfs/nfs4.h>
36f44e1126SVitaliy Gusev #include <sys/systeminfo.h>
37f44e1126SVitaliy Gusev
38f44e1126SVitaliy Gusev /* Helpers */
39f44e1126SVitaliy Gusev
40f44e1126SVitaliy Gusev /* Principal handling routines */
41f44e1126SVitaliy Gusev /* returns 0 if no match; or 1 for a match */
42f44e1126SVitaliy Gusev int
rfs4_cmp_cred_set(cred_set_t * p,struct compound_state * cs)43f44e1126SVitaliy Gusev rfs4_cmp_cred_set(cred_set_t *p, struct compound_state *cs)
44f44e1126SVitaliy Gusev {
45f44e1126SVitaliy Gusev int rc = 0;
46f44e1126SVitaliy Gusev rpc_gss_principal_t recp; /* cached clnt princ */
47f44e1126SVitaliy Gusev rpc_gss_principal_t ibrp; /* inbound req princ */
48f44e1126SVitaliy Gusev
49f44e1126SVitaliy Gusev
50f44e1126SVitaliy Gusev if (p->cp_cr == NULL)
51f44e1126SVitaliy Gusev return (rc); /* nothing to compare with */
52f44e1126SVitaliy Gusev
53f44e1126SVitaliy Gusev if (p->cp_aflavor != cs->req->rq_cred.oa_flavor)
54f44e1126SVitaliy Gusev return (rc);
55f44e1126SVitaliy Gusev
56f44e1126SVitaliy Gusev if (p->cp_secmod != cs->nfsflavor)
57f44e1126SVitaliy Gusev return (rc);
58f44e1126SVitaliy Gusev
59f44e1126SVitaliy Gusev if (crcmp(p->cp_cr, cs->basecr))
60f44e1126SVitaliy Gusev return (rc);
61f44e1126SVitaliy Gusev
62f44e1126SVitaliy Gusev switch (p->cp_aflavor) {
63f44e1126SVitaliy Gusev case AUTH_DES:
64f44e1126SVitaliy Gusev rc = (strcmp(p->cp_princ, cs->principal) == 0);
65f44e1126SVitaliy Gusev break;
66f44e1126SVitaliy Gusev
67f44e1126SVitaliy Gusev case RPCSEC_GSS:
68f44e1126SVitaliy Gusev recp = (rpc_gss_principal_t)p->cp_princ;
69f44e1126SVitaliy Gusev ibrp = (rpc_gss_principal_t)cs->principal;
70f44e1126SVitaliy Gusev
71f44e1126SVitaliy Gusev if (recp->len != ibrp->len)
72f44e1126SVitaliy Gusev break;
73f44e1126SVitaliy Gusev rc = (bcmp(recp->name, ibrp->name, ibrp->len) == 0);
74f44e1126SVitaliy Gusev break;
75f44e1126SVitaliy Gusev
76f44e1126SVitaliy Gusev case AUTH_SYS:
77f44e1126SVitaliy Gusev case AUTH_NONE:
78f44e1126SVitaliy Gusev default:
79f44e1126SVitaliy Gusev rc = 1;
80f44e1126SVitaliy Gusev break;
81f44e1126SVitaliy Gusev }
82f44e1126SVitaliy Gusev return (rc);
83f44e1126SVitaliy Gusev }
84f44e1126SVitaliy Gusev
85f44e1126SVitaliy Gusev static rpc_gss_principal_t
rfs4_dup_princ(rpc_gss_principal_t ppl)86f44e1126SVitaliy Gusev rfs4_dup_princ(rpc_gss_principal_t ppl)
87f44e1126SVitaliy Gusev {
88f44e1126SVitaliy Gusev rpc_gss_principal_t pdup;
89f44e1126SVitaliy Gusev size_t len;
90f44e1126SVitaliy Gusev
91f44e1126SVitaliy Gusev if (ppl == NULL)
92f44e1126SVitaliy Gusev return (NULL);
93f44e1126SVitaliy Gusev
94f44e1126SVitaliy Gusev len = sizeof (int) + ppl->len;
95f44e1126SVitaliy Gusev pdup = (rpc_gss_principal_t)kmem_alloc(len, KM_SLEEP);
96f44e1126SVitaliy Gusev bcopy(ppl, pdup, len);
97f44e1126SVitaliy Gusev return (pdup);
98f44e1126SVitaliy Gusev }
99f44e1126SVitaliy Gusev
100f44e1126SVitaliy Gusev void
rfs4_set_cred_set(cred_set_t * p,struct compound_state * cs)101f44e1126SVitaliy Gusev rfs4_set_cred_set(cred_set_t *p, struct compound_state *cs)
102f44e1126SVitaliy Gusev {
103f44e1126SVitaliy Gusev ASSERT(p->cp_cr == NULL);
104f44e1126SVitaliy Gusev
105f44e1126SVitaliy Gusev p->cp_cr = crdup(cs->basecr);
106f44e1126SVitaliy Gusev p->cp_aflavor = cs->req->rq_cred.oa_flavor;
107f44e1126SVitaliy Gusev p->cp_secmod = cs->nfsflavor; /* secmod != flavor for RPCSEC_GSS */
108f44e1126SVitaliy Gusev
109f44e1126SVitaliy Gusev /*
110f44e1126SVitaliy Gusev * Set principal as per security flavor
111f44e1126SVitaliy Gusev */
112f44e1126SVitaliy Gusev switch (p->cp_aflavor) {
113f44e1126SVitaliy Gusev case AUTH_DES:
114f44e1126SVitaliy Gusev p->cp_princ = strdup(cs->principal);
115f44e1126SVitaliy Gusev break;
116f44e1126SVitaliy Gusev
117f44e1126SVitaliy Gusev case RPCSEC_GSS:
118f44e1126SVitaliy Gusev p->cp_princ =
119f44e1126SVitaliy Gusev (caddr_t)rfs4_dup_princ((rpc_gss_principal_t)cs->principal);
120f44e1126SVitaliy Gusev break;
121f44e1126SVitaliy Gusev
122f44e1126SVitaliy Gusev case AUTH_SYS:
123f44e1126SVitaliy Gusev case AUTH_NONE:
124f44e1126SVitaliy Gusev default:
125f44e1126SVitaliy Gusev break;
126f44e1126SVitaliy Gusev }
127f44e1126SVitaliy Gusev }
128f44e1126SVitaliy Gusev
129f44e1126SVitaliy Gusev void
rfs4_free_cred_set(cred_set_t * p)130f44e1126SVitaliy Gusev rfs4_free_cred_set(cred_set_t *p)
131f44e1126SVitaliy Gusev {
132f44e1126SVitaliy Gusev rpc_gss_principal_t ppl;
133f44e1126SVitaliy Gusev
134f44e1126SVitaliy Gusev if (p->cp_cr == NULL)
135f44e1126SVitaliy Gusev return;
136f44e1126SVitaliy Gusev
137f44e1126SVitaliy Gusev switch (p->cp_aflavor) {
138f44e1126SVitaliy Gusev case AUTH_DES:
139f44e1126SVitaliy Gusev kmem_free(p->cp_princ, strlen(p->cp_princ) + 1);
140f44e1126SVitaliy Gusev break;
141f44e1126SVitaliy Gusev
142f44e1126SVitaliy Gusev case RPCSEC_GSS:
143f44e1126SVitaliy Gusev ppl = (rpc_gss_principal_t)p->cp_princ;
144f44e1126SVitaliy Gusev kmem_free(ppl, ppl->len + sizeof (int));
145f44e1126SVitaliy Gusev break;
146f44e1126SVitaliy Gusev }
147f44e1126SVitaliy Gusev
148f44e1126SVitaliy Gusev crfree(p->cp_cr);
149f44e1126SVitaliy Gusev p->cp_cr = NULL;
150f44e1126SVitaliy Gusev }
151f44e1126SVitaliy Gusev
152f44e1126SVitaliy Gusev /* principal end */
153f44e1126SVitaliy Gusev
154f44e1126SVitaliy Gusev bool_t
nfs_clid4_cmp(nfs_client_id4 * s1,nfs_client_id4 * s2)155f44e1126SVitaliy Gusev nfs_clid4_cmp(nfs_client_id4 *s1, nfs_client_id4 *s2)
156f44e1126SVitaliy Gusev {
157f44e1126SVitaliy Gusev if (s1->verifier != s2->verifier)
158f44e1126SVitaliy Gusev return (FALSE);
159f44e1126SVitaliy Gusev if (s1->id_len != s2->id_len)
160f44e1126SVitaliy Gusev return (FALSE);
161f44e1126SVitaliy Gusev if (bcmp(s1->id_val, s2->id_val, s2->id_len))
162f44e1126SVitaliy Gusev return (FALSE);
163f44e1126SVitaliy Gusev return (TRUE);
164f44e1126SVitaliy Gusev }
165f44e1126SVitaliy Gusev
166f44e1126SVitaliy Gusev /*
167f44e1126SVitaliy Gusev * Rudimentary server implementation (XXX - for now)
168f44e1126SVitaliy Gusev */
169f44e1126SVitaliy Gusev void
rfs4x_get_server_impl_id(EXCHANGE_ID4resok * resp)170f44e1126SVitaliy Gusev rfs4x_get_server_impl_id(EXCHANGE_ID4resok *resp)
171f44e1126SVitaliy Gusev {
172f44e1126SVitaliy Gusev char *sol_impl = "illumos NFSv4.1 Server Implementation";
173f44e1126SVitaliy Gusev char *sol_idom = "nfsv41.ietf.org";
174f44e1126SVitaliy Gusev void *p;
175f44e1126SVitaliy Gusev uint_t len = 0;
176f44e1126SVitaliy Gusev nfs_impl_id4 *nip;
177f44e1126SVitaliy Gusev
178f44e1126SVitaliy Gusev resp->eir_server_impl_id.eir_server_impl_id_len = 1;
179f44e1126SVitaliy Gusev nip = kmem_zalloc(sizeof (nfs_impl_id4), KM_SLEEP);
180f44e1126SVitaliy Gusev resp->eir_server_impl_id.eir_server_impl_id_val = nip;
181f44e1126SVitaliy Gusev
182f44e1126SVitaliy Gusev /* Domain */
183f44e1126SVitaliy Gusev nip->nii_domain.utf8string_len = len = strlen(sol_idom);
184f44e1126SVitaliy Gusev p = kmem_zalloc(len * sizeof (char), KM_SLEEP);
185f44e1126SVitaliy Gusev nip->nii_domain.utf8string_val = p;
186f44e1126SVitaliy Gusev bcopy(sol_idom, p, len);
187f44e1126SVitaliy Gusev
188f44e1126SVitaliy Gusev /* Implementation */
189f44e1126SVitaliy Gusev nip->nii_name.utf8string_len = len = strlen(sol_impl);
190f44e1126SVitaliy Gusev p = kmem_zalloc(len * sizeof (char), KM_SLEEP);
191f44e1126SVitaliy Gusev nip->nii_name.utf8string_val = p;
192f44e1126SVitaliy Gusev bcopy(sol_impl, p, len);
193f44e1126SVitaliy Gusev
194f44e1126SVitaliy Gusev /* Time is zero for now */
195f44e1126SVitaliy Gusev }
196f44e1126SVitaliy Gusev
197f44e1126SVitaliy Gusev static void
rfs4x_set_trunkinfo(EXCHANGE_ID4resok * rok)198f44e1126SVitaliy Gusev rfs4x_set_trunkinfo(EXCHANGE_ID4resok *rok)
199f44e1126SVitaliy Gusev {
200f44e1126SVitaliy Gusev const char *nodename = uts_nodename();
201f44e1126SVitaliy Gusev size_t nd_len = strlen(nodename);
202f44e1126SVitaliy Gusev size_t hw_len = strlen(hw_serial);
203f44e1126SVitaliy Gusev size_t id_len = nd_len + 1 + hw_len;
204f44e1126SVitaliy Gusev char *s = kmem_alloc(id_len, KM_SLEEP);
205f44e1126SVitaliy Gusev server_owner4 *so = &rok->eir_server_owner;
206f44e1126SVitaliy Gusev struct eir_server_scope *ss = &rok->eir_server_scope;
207f44e1126SVitaliy Gusev
208f44e1126SVitaliy Gusev (void) memcpy(s, nodename, nd_len);
209f44e1126SVitaliy Gusev s[nd_len] = ' ';
210f44e1126SVitaliy Gusev (void) memcpy(s + nd_len + 1, hw_serial, hw_len);
211f44e1126SVitaliy Gusev
212f44e1126SVitaliy Gusev so->so_major_id.so_major_id_len = id_len;
213f44e1126SVitaliy Gusev so->so_major_id.so_major_id_val = s;
214f44e1126SVitaliy Gusev
215f44e1126SVitaliy Gusev ss->eir_server_scope_len = id_len;
216f44e1126SVitaliy Gusev ss->eir_server_scope_val = kmem_alloc(id_len, KM_SLEEP);
217f44e1126SVitaliy Gusev (void) memcpy(ss->eir_server_scope_val, s, id_len);
218f44e1126SVitaliy Gusev
219f44e1126SVitaliy Gusev rok->eir_server_owner.so_minor_id = 0;
220f44e1126SVitaliy Gusev }
221f44e1126SVitaliy Gusev
222f44e1126SVitaliy Gusev static bool_t
client_has_state_locked(rfs4_client_t * cp)223f44e1126SVitaliy Gusev client_has_state_locked(rfs4_client_t *cp)
224f44e1126SVitaliy Gusev {
225f44e1126SVitaliy Gusev if (list_head(&cp->rc_sessions) != NULL ||
226f44e1126SVitaliy Gusev list_head(&cp->rc_openownerlist) != NULL)
227f44e1126SVitaliy Gusev return (TRUE);
228f44e1126SVitaliy Gusev else
229f44e1126SVitaliy Gusev return (FALSE);
230f44e1126SVitaliy Gusev }
231f44e1126SVitaliy Gusev
232f44e1126SVitaliy Gusev /* OPERATIONS */
233f44e1126SVitaliy Gusev
234f44e1126SVitaliy Gusev /*
235f44e1126SVitaliy Gusev * EXCHANGE_ID
236f44e1126SVitaliy Gusev * RFC5661 sec. 18.35
237f44e1126SVitaliy Gusev */
238f44e1126SVitaliy Gusev void
rfs4x_op_exchange_id(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)239f44e1126SVitaliy Gusev rfs4x_op_exchange_id(nfs_argop4 *argop, nfs_resop4 *resop,
240f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs)
241f44e1126SVitaliy Gusev {
242f44e1126SVitaliy Gusev EXCHANGE_ID4args *args = &argop->nfs_argop4_u.opexchange_id;
243f44e1126SVitaliy Gusev EXCHANGE_ID4res *resp = &resop->nfs_resop4_u.opexchange_id;
244f44e1126SVitaliy Gusev EXCHANGE_ID4resok *rok = &resp->EXCHANGE_ID4res_u.eir_resok4;
245f44e1126SVitaliy Gusev rfs4_client_t *cp, *conf;
246f44e1126SVitaliy Gusev bool_t update, create;
247f44e1126SVitaliy Gusev client_owner4 *cop;
248f44e1126SVitaliy Gusev nfs_client_id4 cid; /* cip */
249f44e1126SVitaliy Gusev nfsstat4 status = NFS4_OK;
250f44e1126SVitaliy Gusev nfs4_srv_t *nsrv4;
251f44e1126SVitaliy Gusev
252f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__exchange__id__start,
253f44e1126SVitaliy Gusev struct compound_state *, cs,
254f44e1126SVitaliy Gusev EXCHANGE_ID4args *, args);
255f44e1126SVitaliy Gusev
256f44e1126SVitaliy Gusev /*
257f44e1126SVitaliy Gusev * EXCHANGE_ID's may be preceded by SEQUENCE
258f44e1126SVitaliy Gusev *
259f44e1126SVitaliy Gusev * Check that eia_flags only has "valid" spec bits
260f44e1126SVitaliy Gusev * and that no 'eir_flag' ONLY bits are specified.
261f44e1126SVitaliy Gusev */
262f44e1126SVitaliy Gusev if (args->eia_flags & ~EXID4_FLAG_MASK) {
263f44e1126SVitaliy Gusev status = NFS4ERR_INVAL;
264f44e1126SVitaliy Gusev goto err;
265f44e1126SVitaliy Gusev }
266f44e1126SVitaliy Gusev
267f44e1126SVitaliy Gusev update = (args->eia_flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A);
268f44e1126SVitaliy Gusev cop = &args->eia_clientowner;
269f44e1126SVitaliy Gusev conf = NULL;
270f44e1126SVitaliy Gusev
271f44e1126SVitaliy Gusev cid.verifier = cop->co_verifier;
272f44e1126SVitaliy Gusev cid.id_len = cop->co_ownerid.co_ownerid_len;
273f44e1126SVitaliy Gusev cid.id_val = cop->co_ownerid.co_ownerid_val;
274f44e1126SVitaliy Gusev cid.cl_addr = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
275f44e1126SVitaliy Gusev
276f44e1126SVitaliy Gusev /*
277f44e1126SVitaliy Gusev * Refer to Section 18.35.4
278f44e1126SVitaliy Gusev */
279f44e1126SVitaliy Gusev again:
280f44e1126SVitaliy Gusev create = TRUE;
281f44e1126SVitaliy Gusev cp = rfs4_findclient(&cid, &create, conf);
282f44e1126SVitaliy Gusev
283f44e1126SVitaliy Gusev if (cp == NULL) {
284f44e1126SVitaliy Gusev status = NFS4ERR_RESOURCE;
285f44e1126SVitaliy Gusev if (conf)
286f44e1126SVitaliy Gusev rfs4_client_rele(conf);
287f44e1126SVitaliy Gusev goto err;
288f44e1126SVitaliy Gusev }
289f44e1126SVitaliy Gusev
290f44e1126SVitaliy Gusev if (conf) {
291f44e1126SVitaliy Gusev rfs4_dbe_lock(cp->rc_dbe);
292f44e1126SVitaliy Gusev if (cp->rc_cp_confirmed == NULL)
293f44e1126SVitaliy Gusev cp->rc_cp_confirmed = conf;
294f44e1126SVitaliy Gusev else
295f44e1126SVitaliy Gusev rfs4_client_rele(conf);
296f44e1126SVitaliy Gusev rfs4_dbe_unlock(cp->rc_dbe);
297f44e1126SVitaliy Gusev conf = NULL;
298f44e1126SVitaliy Gusev }
299f44e1126SVitaliy Gusev
300f44e1126SVitaliy Gusev if (create) {
301f44e1126SVitaliy Gusev /* Record just created */
302f44e1126SVitaliy Gusev if (!update) {
303f44e1126SVitaliy Gusev /* case 1 - utok */
304f44e1126SVitaliy Gusev rfs4_set_cred_set(&cp->rc_cr_set, cs);
305f44e1126SVitaliy Gusev
306f44e1126SVitaliy Gusev rok->eir_clientid = cp->rc_clientid;
307f44e1126SVitaliy Gusev rok->eir_sequenceid = cp->rc_contrived.xi_sid;
308f44e1126SVitaliy Gusev goto out;
309f44e1126SVitaliy Gusev } else {
310f44e1126SVitaliy Gusev /* no record and trying to update */
311f44e1126SVitaliy Gusev status = NFS4ERR_NOENT;
312f44e1126SVitaliy Gusev goto err_out;
313f44e1126SVitaliy Gusev }
314f44e1126SVitaliy Gusev }
315f44e1126SVitaliy Gusev
316f44e1126SVitaliy Gusev /* Record exists */
317f44e1126SVitaliy Gusev
318f44e1126SVitaliy Gusev /* expired clients should be ignored and released */
319f44e1126SVitaliy Gusev if (rfs4_lease_expired(cp)) {
320f44e1126SVitaliy Gusev rfs4_client_close(cp);
321f44e1126SVitaliy Gusev update = FALSE;
322f44e1126SVitaliy Gusev goto again;
323f44e1126SVitaliy Gusev }
324f44e1126SVitaliy Gusev
325f44e1126SVitaliy Gusev if (cp->rc_need_confirm) {
326f44e1126SVitaliy Gusev /* UNCONFIRMED */
327f44e1126SVitaliy Gusev if (!update) {
328f44e1126SVitaliy Gusev /* case 4 - utok */
329f44e1126SVitaliy Gusev rfs4_client_close(cp);
330f44e1126SVitaliy Gusev
331f44e1126SVitaliy Gusev ASSERT(!update);
332f44e1126SVitaliy Gusev goto again;
333f44e1126SVitaliy Gusev } else {
334f44e1126SVitaliy Gusev /* case 7 - utok */
335f44e1126SVitaliy Gusev status = NFS4ERR_NOENT;
336f44e1126SVitaliy Gusev goto err_out;
337f44e1126SVitaliy Gusev }
338f44e1126SVitaliy Gusev }
339f44e1126SVitaliy Gusev
340f44e1126SVitaliy Gusev /* record exists and confirmed */
341f44e1126SVitaliy Gusev if (!update) {
342f44e1126SVitaliy Gusev if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
343f44e1126SVitaliy Gusev /* case 3 */
344f44e1126SVitaliy Gusev /* lease is checked above */
345f44e1126SVitaliy Gusev rfs4_dbe_lock(cp->rc_dbe);
346f44e1126SVitaliy Gusev if (!client_has_state_locked(cp)) {
347f44e1126SVitaliy Gusev rfs4_dbe_unlock(cp->rc_dbe);
348f44e1126SVitaliy Gusev
349f44e1126SVitaliy Gusev rfs4_client_close(cp);
350f44e1126SVitaliy Gusev ASSERT(!update);
351f44e1126SVitaliy Gusev goto again;
352f44e1126SVitaliy Gusev }
353f44e1126SVitaliy Gusev rfs4_dbe_unlock(cp->rc_dbe);
354f44e1126SVitaliy Gusev
355f44e1126SVitaliy Gusev /*
356f44e1126SVitaliy Gusev * clid_in_use. old_client_ret has unexpired
357f44e1126SVitaliy Gusev * lease with state.
358f44e1126SVitaliy Gusev */
359f44e1126SVitaliy Gusev status = NFS4ERR_CLID_INUSE;
360f44e1126SVitaliy Gusev goto err_out;
361f44e1126SVitaliy Gusev } else if (cp->rc_nfs_client.verifier != cid.verifier) {
362f44e1126SVitaliy Gusev /* case 5: Client Restart */
363f44e1126SVitaliy Gusev /*
364f44e1126SVitaliy Gusev * Skip confirmed client record to allow confirmed
365f44e1126SVitaliy Gusev * and unconfirmed state at the same time. The number
366f44e1126SVitaliy Gusev * of states can collapse to one once the server
367f44e1126SVitaliy Gusev * receives an applicable CREATE_SESSION or EXCHANGE_ID.
368f44e1126SVitaliy Gusev */
369f44e1126SVitaliy Gusev ASSERT(conf == NULL);
370f44e1126SVitaliy Gusev conf = cp;
371f44e1126SVitaliy Gusev ASSERT(!update);
372f44e1126SVitaliy Gusev goto again;
373f44e1126SVitaliy Gusev
374f44e1126SVitaliy Gusev } else if (nfs_clid4_cmp(&cp->rc_nfs_client, &cid)) {
375f44e1126SVitaliy Gusev /* case 2 - utok */
376f44e1126SVitaliy Gusev rok->eir_clientid = cp->rc_clientid;
377f44e1126SVitaliy Gusev rok->eir_sequenceid = cp->rc_contrived.xi_sid;
378f44e1126SVitaliy Gusev /* trickle down to "out" */
379f44e1126SVitaliy Gusev
380f44e1126SVitaliy Gusev } else {
381f44e1126SVitaliy Gusev /* something is really wacky in srv state */
382f44e1126SVitaliy Gusev status = NFS4ERR_SERVERFAULT;
383f44e1126SVitaliy Gusev goto err_out;
384f44e1126SVitaliy Gusev }
385f44e1126SVitaliy Gusev
386f44e1126SVitaliy Gusev } else { /* UPDATE */
387f44e1126SVitaliy Gusev if (cp->rc_nfs_client.verifier != cid.verifier) {
388f44e1126SVitaliy Gusev /* 18.35.4 case 8 */
389f44e1126SVitaliy Gusev status = NFS4ERR_NOT_SAME;
390f44e1126SVitaliy Gusev goto err_out;
391f44e1126SVitaliy Gusev }
392f44e1126SVitaliy Gusev if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
393f44e1126SVitaliy Gusev /* 18.35.4 case 9 */
394f44e1126SVitaliy Gusev status = NFS4ERR_PERM;
395f44e1126SVitaliy Gusev goto err_out;
396f44e1126SVitaliy Gusev }
397f44e1126SVitaliy Gusev
398f44e1126SVitaliy Gusev /* case 6 - utok */
399f44e1126SVitaliy Gusev rok->eir_clientid = cp->rc_clientid;
400f44e1126SVitaliy Gusev rok->eir_sequenceid = cp->rc_contrived.xi_sid;
401f44e1126SVitaliy Gusev /* trickle down to "out" */
402f44e1126SVitaliy Gusev }
403f44e1126SVitaliy Gusev out:
404f44e1126SVitaliy Gusev rok->eir_flags = 0;
405f44e1126SVitaliy Gusev if (resp->eir_status == NFS4_OK && !cp->rc_need_confirm)
406f44e1126SVitaliy Gusev rok->eir_flags |= EXCHGID4_FLAG_CONFIRMED_R;
407f44e1126SVitaliy Gusev
408f44e1126SVitaliy Gusev /*
409f44e1126SVitaliy Gusev * State Protection (See sec. 2.10.8.3)
410f44e1126SVitaliy Gusev */
411f44e1126SVitaliy Gusev cp->rc_state_prot.sp_type = args->eia_state_protect.spa_how;
412f44e1126SVitaliy Gusev switch (cp->rc_state_prot.sp_type) {
413f44e1126SVitaliy Gusev case SP4_NONE:
414f44e1126SVitaliy Gusev break;
415f44e1126SVitaliy Gusev
416f44e1126SVitaliy Gusev case SP4_MACH_CRED:
417f44e1126SVitaliy Gusev break;
418f44e1126SVitaliy Gusev
419f44e1126SVitaliy Gusev case SP4_SSV:
420f44e1126SVitaliy Gusev /*
421f44e1126SVitaliy Gusev * SSV state protection is not implemented.
422f44e1126SVitaliy Gusev */
423f44e1126SVitaliy Gusev status = NFS4ERR_ENCR_ALG_UNSUPP;
424f44e1126SVitaliy Gusev goto err_out;
425f44e1126SVitaliy Gusev default:
426f44e1126SVitaliy Gusev status = NFS4ERR_INVAL;
427f44e1126SVitaliy Gusev goto err_out;
428f44e1126SVitaliy Gusev
429f44e1126SVitaliy Gusev }
430f44e1126SVitaliy Gusev
431f44e1126SVitaliy Gusev /*
432f44e1126SVitaliy Gusev * Referrals supports
433f44e1126SVitaliy Gusev */
434f44e1126SVitaliy Gusev if (args->eia_flags & EXCHGID4_FLAG_SUPP_MOVED_REFER) {
435f44e1126SVitaliy Gusev rok->eir_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
436f44e1126SVitaliy Gusev }
437f44e1126SVitaliy Gusev
438f44e1126SVitaliy Gusev /*
439f44e1126SVitaliy Gusev * Migration/Replication not (yet) supported
440f44e1126SVitaliy Gusev */
441f44e1126SVitaliy Gusev if (args->eia_flags & EXCHGID4_FLAG_SUPP_MOVED_MIGR)
442f44e1126SVitaliy Gusev rok->eir_flags &= ~EXCHGID4_FLAG_SUPP_MOVED_MIGR;
443f44e1126SVitaliy Gusev
444f44e1126SVitaliy Gusev /*
445f44e1126SVitaliy Gusev * RFC8881 Section 13.1 Client ID and Session Considerations
446f44e1126SVitaliy Gusev * Non-metadata server, do not support pNFS (yet).
447f44e1126SVitaliy Gusev */
448f44e1126SVitaliy Gusev rok->eir_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
449f44e1126SVitaliy Gusev
450f44e1126SVitaliy Gusev /* force no state protection for now */
451f44e1126SVitaliy Gusev rok->eir_state_protect.spr_how = SP4_NONE;
452f44e1126SVitaliy Gusev
453f44e1126SVitaliy Gusev /* Implementation specific mojo */
454f44e1126SVitaliy Gusev if (args->eia_client_impl_id.eia_client_impl_id_len != 0) {
455f44e1126SVitaliy Gusev /* EMPTY */;
456f44e1126SVitaliy Gusev }
457f44e1126SVitaliy Gusev
458f44e1126SVitaliy Gusev nsrv4 = nfs4_get_srv();
459f44e1126SVitaliy Gusev
460f44e1126SVitaliy Gusev /* Record clientid in stable storage */
461f44e1126SVitaliy Gusev rfs4_ss_clid(nsrv4, cp);
462f44e1126SVitaliy Gusev
463f44e1126SVitaliy Gusev /* Server's implementation */
464f44e1126SVitaliy Gusev rfs4x_get_server_impl_id(rok);
465f44e1126SVitaliy Gusev
466f44e1126SVitaliy Gusev /* compute trunking capabilities */
467f44e1126SVitaliy Gusev bzero(&rok->eir_server_scope, sizeof (rok->eir_server_scope));
468f44e1126SVitaliy Gusev bzero(&rok->eir_server_owner, sizeof (server_owner4));
469f44e1126SVitaliy Gusev
470f44e1126SVitaliy Gusev /* Add trunk handling */
471f44e1126SVitaliy Gusev rfs4x_set_trunkinfo(rok);
472f44e1126SVitaliy Gusev
473f44e1126SVitaliy Gusev /*
474f44e1126SVitaliy Gusev * Check to see if client can perform reclaims
475f44e1126SVitaliy Gusev */
476f44e1126SVitaliy Gusev rfs4_ss_chkclid(nsrv4, cp);
477f44e1126SVitaliy Gusev
478f44e1126SVitaliy Gusev err_out:
479f44e1126SVitaliy Gusev rfs4_client_rele(cp);
480f44e1126SVitaliy Gusev err:
481f44e1126SVitaliy Gusev *cs->statusp = resp->eir_status = status;
482f44e1126SVitaliy Gusev
483f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__exchange__id__done,
484f44e1126SVitaliy Gusev struct compound_state *, cs,
485f44e1126SVitaliy Gusev EXCHANGE_ID4res *, resp);
486f44e1126SVitaliy Gusev }
487f44e1126SVitaliy Gusev
488f44e1126SVitaliy Gusev void
rfs4x_exchange_id_free(nfs_resop4 * resop)489f44e1126SVitaliy Gusev rfs4x_exchange_id_free(nfs_resop4 *resop)
490f44e1126SVitaliy Gusev {
491f44e1126SVitaliy Gusev EXCHANGE_ID4res *resp = &resop->nfs_resop4_u.opexchange_id;
492f44e1126SVitaliy Gusev EXCHANGE_ID4resok *rok = &resp->EXCHANGE_ID4res_u.eir_resok4;
493f44e1126SVitaliy Gusev struct server_owner4 *sop = &rok->eir_server_owner;
494f44e1126SVitaliy Gusev nfs_impl_id4 *nip;
495f44e1126SVitaliy Gusev int len = 0;
496f44e1126SVitaliy Gusev
497f44e1126SVitaliy Gusev /* Server Owner: major */
498f44e1126SVitaliy Gusev if ((len = sop->so_major_id.so_major_id_len) != 0)
499f44e1126SVitaliy Gusev kmem_free(sop->so_major_id.so_major_id_val, len);
500f44e1126SVitaliy Gusev
501f44e1126SVitaliy Gusev if ((nip = rok->eir_server_impl_id.eir_server_impl_id_val) != NULL) {
502f44e1126SVitaliy Gusev /* Immplementation */
503f44e1126SVitaliy Gusev len = nip->nii_name.utf8string_len;
504f44e1126SVitaliy Gusev kmem_free(nip->nii_name.utf8string_val, len * sizeof (char));
505f44e1126SVitaliy Gusev
506f44e1126SVitaliy Gusev /* Domain */
507f44e1126SVitaliy Gusev len = nip->nii_domain.utf8string_len;
508f44e1126SVitaliy Gusev kmem_free(nip->nii_domain.utf8string_val, len * sizeof (char));
509f44e1126SVitaliy Gusev
510f44e1126SVitaliy Gusev /* Server Impl */
511f44e1126SVitaliy Gusev kmem_free(nip, sizeof (nfs_impl_id4));
512f44e1126SVitaliy Gusev }
513f44e1126SVitaliy Gusev }
514f44e1126SVitaliy Gusev
515f44e1126SVitaliy Gusev void
rfs4x_op_create_session(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)516f44e1126SVitaliy Gusev rfs4x_op_create_session(nfs_argop4 *argop, nfs_resop4 *resop,
517f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs)
518f44e1126SVitaliy Gusev {
519f44e1126SVitaliy Gusev CREATE_SESSION4args *args = &argop->nfs_argop4_u.opcreate_session;
520f44e1126SVitaliy Gusev CREATE_SESSION4res *resp = &resop->nfs_resop4_u.opcreate_session;
521f44e1126SVitaliy Gusev CREATE_SESSION4resok *rok = &resp->CREATE_SESSION4res_u.csr_resok4;
522f44e1126SVitaliy Gusev CREATE_SESSION4resok *crp;
523f44e1126SVitaliy Gusev rfs4_client_t *cp;
524f44e1126SVitaliy Gusev rfs4_session_t *sp;
525f44e1126SVitaliy Gusev session41_create_t sca;
526f44e1126SVitaliy Gusev sequenceid4 stseq;
527f44e1126SVitaliy Gusev sequenceid4 agseq;
528f44e1126SVitaliy Gusev nfsstat4 status = NFS4_OK;
529f44e1126SVitaliy Gusev
530f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__create__session__start,
531f44e1126SVitaliy Gusev struct compound_state *, cs,
532f44e1126SVitaliy Gusev CREATE_SESSION4args*, args);
533f44e1126SVitaliy Gusev
534f44e1126SVitaliy Gusev /*
535f44e1126SVitaliy Gusev * A CREATE_SESSION request can be prefixed by OP_SEQUENCE.
536f44e1126SVitaliy Gusev * In this case, the newly created session has no relation
537f44e1126SVitaliy Gusev * to the sessid used for the OP_SEQUENCE.
538f44e1126SVitaliy Gusev */
539f44e1126SVitaliy Gusev
540f44e1126SVitaliy Gusev /*
541f44e1126SVitaliy Gusev * Find the clientid
542f44e1126SVitaliy Gusev */
543f44e1126SVitaliy Gusev cp = rfs4_findclient_by_id(args->csa_clientid, TRUE);
544f44e1126SVitaliy Gusev if (cp == NULL) {
545f44e1126SVitaliy Gusev status = NFS4ERR_STALE_CLIENTID;
546f44e1126SVitaliy Gusev goto out;
547f44e1126SVitaliy Gusev }
548f44e1126SVitaliy Gusev
549f44e1126SVitaliy Gusev /*
550f44e1126SVitaliy Gusev * Make sure the lease is still valid.
551f44e1126SVitaliy Gusev */
552f44e1126SVitaliy Gusev if (rfs4_lease_expired(cp)) {
553f44e1126SVitaliy Gusev rfs4_client_close(cp);
554f44e1126SVitaliy Gusev status = NFS4ERR_STALE_CLIENTID;
555f44e1126SVitaliy Gusev goto out;
556f44e1126SVitaliy Gusev }
557f44e1126SVitaliy Gusev
558f44e1126SVitaliy Gusev /*
559f44e1126SVitaliy Gusev * Sequenceid processing (handling replay's, etc)
560f44e1126SVitaliy Gusev */
561f44e1126SVitaliy Gusev agseq = args->csa_sequence;
562f44e1126SVitaliy Gusev stseq = cp->rc_contrived.xi_sid;
563f44e1126SVitaliy Gusev if (stseq == agseq + 1) {
564f44e1126SVitaliy Gusev /*
565f44e1126SVitaliy Gusev * If the previous sequenceid, then must be a replay of a
566f44e1126SVitaliy Gusev * previous CREATE_SESSION; return the cached result.
567f44e1126SVitaliy Gusev */
568f44e1126SVitaliy Gusev crp = (CREATE_SESSION4resok *)&cp->rc_contrived.cs_res;
569f44e1126SVitaliy Gusev status = cp->rc_contrived.cs_status;
570f44e1126SVitaliy Gusev rok->csr_sequence = agseq;
571f44e1126SVitaliy Gusev bcopy(crp->csr_sessionid, rok->csr_sessionid,
572f44e1126SVitaliy Gusev sizeof (sessionid4));
573f44e1126SVitaliy Gusev rok->csr_flags = crp->csr_flags;
574f44e1126SVitaliy Gusev rok->csr_fore_chan_attrs = crp->csr_fore_chan_attrs;
575f44e1126SVitaliy Gusev rok->csr_back_chan_attrs = crp->csr_back_chan_attrs;
576f44e1126SVitaliy Gusev
577f44e1126SVitaliy Gusev rfs4_update_lease(cp);
578f44e1126SVitaliy Gusev rfs4_client_rele(cp);
579f44e1126SVitaliy Gusev goto out;
580f44e1126SVitaliy Gusev }
581f44e1126SVitaliy Gusev
582f44e1126SVitaliy Gusev if (stseq != agseq) {
583f44e1126SVitaliy Gusev /*
584f44e1126SVitaliy Gusev * No way to differentiate MISORD_NEWREQ vs. MISORD_REPLAY,
585f44e1126SVitaliy Gusev * so anything else, we simply treat as SEQ_MISORDERED.
586f44e1126SVitaliy Gusev */
587f44e1126SVitaliy Gusev status = NFS4ERR_SEQ_MISORDERED;
588f44e1126SVitaliy Gusev rfs4_client_rele(cp);
589f44e1126SVitaliy Gusev goto out;
590f44e1126SVitaliy Gusev }
591f44e1126SVitaliy Gusev
592f44e1126SVitaliy Gusev /*
593f44e1126SVitaliy Gusev * Clientid confirmation
594f44e1126SVitaliy Gusev */
595f44e1126SVitaliy Gusev if (cp->rc_need_confirm) {
596f44e1126SVitaliy Gusev if (rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
597f44e1126SVitaliy Gusev cp->rc_need_confirm = FALSE;
598f44e1126SVitaliy Gusev if (cp->rc_cp_confirmed != NULL) {
599f44e1126SVitaliy Gusev rfs4_client_close(cp->rc_cp_confirmed);
600f44e1126SVitaliy Gusev cp->rc_cp_confirmed = NULL;
601f44e1126SVitaliy Gusev }
602f44e1126SVitaliy Gusev } else {
603f44e1126SVitaliy Gusev status = NFS4ERR_CLID_INUSE;
604f44e1126SVitaliy Gusev rfs4_client_rele(cp);
605f44e1126SVitaliy Gusev goto out;
606f44e1126SVitaliy Gusev }
607f44e1126SVitaliy Gusev }
608f44e1126SVitaliy Gusev
609f44e1126SVitaliy Gusev /*
610f44e1126SVitaliy Gusev * Session creation
611f44e1126SVitaliy Gusev */
612f44e1126SVitaliy Gusev sca.cs_error = 0;
613f44e1126SVitaliy Gusev sca.cs_req = req;
614f44e1126SVitaliy Gusev sca.cs_client = cp;
615f44e1126SVitaliy Gusev sca.cs_aotw = *args;
616f44e1126SVitaliy Gusev sp = rfs4x_createsession(&sca);
617f44e1126SVitaliy Gusev
618f44e1126SVitaliy Gusev if (sca.cs_error) {
619f44e1126SVitaliy Gusev status = sca.cs_error;
620f44e1126SVitaliy Gusev rfs4_client_rele(cp);
621f44e1126SVitaliy Gusev if (sp != NULL)
622f44e1126SVitaliy Gusev rfs4x_session_rele(sp);
623f44e1126SVitaliy Gusev goto out;
624f44e1126SVitaliy Gusev }
625f44e1126SVitaliy Gusev
626f44e1126SVitaliy Gusev if (sp == NULL) {
627f44e1126SVitaliy Gusev status = NFS4ERR_SERVERFAULT;
628f44e1126SVitaliy Gusev rfs4_client_rele(cp);
629f44e1126SVitaliy Gusev goto out;
630f44e1126SVitaliy Gusev }
631f44e1126SVitaliy Gusev
632f44e1126SVitaliy Gusev /*
633f44e1126SVitaliy Gusev * Need to store the result in the rfs4_client_t's contrived
634f44e1126SVitaliy Gusev * result slot and then respond from there. This way, when the
635f44e1126SVitaliy Gusev * csa_sequence == contrived.cc_sid, we can return the latest
636f44e1126SVitaliy Gusev * cached result. (see replay: above)
637f44e1126SVitaliy Gusev */
638f44e1126SVitaliy Gusev crp = (CREATE_SESSION4resok *)&cp->rc_contrived.cs_res;
639f44e1126SVitaliy Gusev cp->rc_contrived.cs_status = NFS4_OK;
640f44e1126SVitaliy Gusev rok->csr_sequence = crp->csr_sequence = cp->rc_contrived.xi_sid;
641f44e1126SVitaliy Gusev bcopy(sp->sn_sessid, rok->csr_sessionid, sizeof (sessionid4));
642f44e1126SVitaliy Gusev bcopy(sp->sn_sessid, crp->csr_sessionid, sizeof (sessionid4));
643f44e1126SVitaliy Gusev rok->csr_flags = crp->csr_flags = sp->sn_csflags;
644f44e1126SVitaliy Gusev
645f44e1126SVitaliy Gusev cp->rc_contrived.xi_sid++;
646f44e1126SVitaliy Gusev
647f44e1126SVitaliy Gusev rok->csr_fore_chan_attrs =
648f44e1126SVitaliy Gusev crp->csr_fore_chan_attrs = sp->sn_fore->cn_attrs;
649f44e1126SVitaliy Gusev rok->csr_back_chan_attrs = crp->csr_back_chan_attrs =
650f44e1126SVitaliy Gusev args->csa_back_chan_attrs;
651f44e1126SVitaliy Gusev
652f44e1126SVitaliy Gusev rfs4_update_lease(cp);
653f44e1126SVitaliy Gusev
654f44e1126SVitaliy Gusev /*
655f44e1126SVitaliy Gusev * References from the session to the client are
656f44e1126SVitaliy Gusev * accounted for while session is being created.
657f44e1126SVitaliy Gusev */
658f44e1126SVitaliy Gusev rfs4_client_rele(cp);
659f44e1126SVitaliy Gusev rfs4x_session_rele(sp);
660f44e1126SVitaliy Gusev out:
661f44e1126SVitaliy Gusev *cs->statusp = resp->csr_status = status;
662f44e1126SVitaliy Gusev
663f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__create__session__done,
664f44e1126SVitaliy Gusev struct compound_state *, cs,
665f44e1126SVitaliy Gusev CREATE_SESSION4res *, resp);
666f44e1126SVitaliy Gusev }
667f44e1126SVitaliy Gusev
668f44e1126SVitaliy Gusev /* ARGSUSED */
669f44e1126SVitaliy Gusev void
rfs4x_op_destroy_session(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)670f44e1126SVitaliy Gusev rfs4x_op_destroy_session(nfs_argop4 *argop, nfs_resop4 *resop,
671f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs)
672f44e1126SVitaliy Gusev {
673f44e1126SVitaliy Gusev DESTROY_SESSION4args *args = &argop->nfs_argop4_u.opdestroy_session;
674f44e1126SVitaliy Gusev DESTROY_SESSION4res *resp = &resop->nfs_resop4_u.opdestroy_session;
675f44e1126SVitaliy Gusev rfs4_session_t *sp;
676f44e1126SVitaliy Gusev rfs4_client_t *cp;
677f44e1126SVitaliy Gusev nfsstat4 status = NFS4_OK;
678f44e1126SVitaliy Gusev int addref = 0; /* additional reference */
679f44e1126SVitaliy Gusev
680f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__destroy__session__start,
681f44e1126SVitaliy Gusev struct compound_state *, cs,
682f44e1126SVitaliy Gusev DESTROY_SESSION4args *, args);
683f44e1126SVitaliy Gusev
684f44e1126SVitaliy Gusev /* section 18.37.3 rfc5661 */
685f44e1126SVitaliy Gusev if (rfs4_has_session(cs)) {
686f44e1126SVitaliy Gusev /* compound with a sequence */
687f44e1126SVitaliy Gusev if (bcmp(args->dsa_sessionid, cs->sp->sn_sessid,
688f44e1126SVitaliy Gusev sizeof (sessionid4)) == 0) {
689f44e1126SVitaliy Gusev /*
690f44e1126SVitaliy Gusev * Same session.
691f44e1126SVitaliy Gusev * must be the final operation in the COMPOUND request
692f44e1126SVitaliy Gusev */
693f44e1126SVitaliy Gusev if ((cs->op_pos + 1) != cs->op_len) {
694f44e1126SVitaliy Gusev status = NFS4ERR_NOT_ONLY_OP;
695f44e1126SVitaliy Gusev goto out;
696f44e1126SVitaliy Gusev }
697f44e1126SVitaliy Gusev addref++;
698f44e1126SVitaliy Gusev } else {
699f44e1126SVitaliy Gusev /* Not the same session */
700f44e1126SVitaliy Gusev DTRACE_PROBE(nfss41__i__destroy_encap_session);
701f44e1126SVitaliy Gusev
702f44e1126SVitaliy Gusev }
703f44e1126SVitaliy Gusev }
704f44e1126SVitaliy Gusev
705f44e1126SVitaliy Gusev sp = rfs4x_findsession_by_id(args->dsa_sessionid);
706f44e1126SVitaliy Gusev if (sp == NULL) {
707f44e1126SVitaliy Gusev status = NFS4ERR_BADSESSION;
708f44e1126SVitaliy Gusev goto out;
709f44e1126SVitaliy Gusev }
710f44e1126SVitaliy Gusev
711f44e1126SVitaliy Gusev /*
712f44e1126SVitaliy Gusev * State Protection (See sec. 2.10.8.3)
713f44e1126SVitaliy Gusev *
714f44e1126SVitaliy Gusev * verify cred that was used to create the session matches and is in
715f44e1126SVitaliy Gusev * concordance w/the state protection type used.
716f44e1126SVitaliy Gusev */
717f44e1126SVitaliy Gusev cp = sp->sn_clnt;
718f44e1126SVitaliy Gusev switch (cp->rc_state_prot.sp_type) {
719f44e1126SVitaliy Gusev case SP4_MACH_CRED:
720f44e1126SVitaliy Gusev if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
721f44e1126SVitaliy Gusev status = NFS4ERR_PERM;
722f44e1126SVitaliy Gusev goto err_out;
723f44e1126SVitaliy Gusev }
724f44e1126SVitaliy Gusev break;
725f44e1126SVitaliy Gusev
726f44e1126SVitaliy Gusev case SP4_SSV:
727f44e1126SVitaliy Gusev /*
728f44e1126SVitaliy Gusev * Todo -- Missing SSV validation here, if/when
729f44e1126SVitaliy Gusev * SSV state protection is implemented.
730f44e1126SVitaliy Gusev * Should not get this after check in EXCHANGE_ID
731f44e1126SVitaliy Gusev */
732f44e1126SVitaliy Gusev status = NFS4ERR_PERM;
733f44e1126SVitaliy Gusev goto err_out;
734f44e1126SVitaliy Gusev
735f44e1126SVitaliy Gusev case SP4_NONE:
736f44e1126SVitaliy Gusev break;
737f44e1126SVitaliy Gusev
738f44e1126SVitaliy Gusev default:
739f44e1126SVitaliy Gusev break;
740f44e1126SVitaliy Gusev }
741f44e1126SVitaliy Gusev
742f44e1126SVitaliy Gusev status = rfs4x_destroysession(sp, 2 + addref);
743f44e1126SVitaliy Gusev err_out:
744f44e1126SVitaliy Gusev rfs4x_session_rele(sp);
745f44e1126SVitaliy Gusev out:
746f44e1126SVitaliy Gusev *cs->statusp = resp->dsr_status = status;
747f44e1126SVitaliy Gusev
748f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__destroy__session__done,
749f44e1126SVitaliy Gusev struct compound_state *, cs,
750f44e1126SVitaliy Gusev DESTROY_SESSION4res *, resp);
751f44e1126SVitaliy Gusev }
752f44e1126SVitaliy Gusev
753f44e1126SVitaliy Gusev /*
754f44e1126SVitaliy Gusev * Find session and validate sequence args.
755f44e1126SVitaliy Gusev * If this function successfully completes the compound state
756f44e1126SVitaliy Gusev * will contain a session pointer.
757f44e1126SVitaliy Gusev */
758f44e1126SVitaliy Gusev static nfsstat4
rfs4x_find_session(SEQUENCE4args * sargs,struct compound_state * cs)759f44e1126SVitaliy Gusev rfs4x_find_session(SEQUENCE4args *sargs, struct compound_state *cs)
760f44e1126SVitaliy Gusev {
761f44e1126SVitaliy Gusev rfs4_session_t *sp;
762f44e1126SVitaliy Gusev slotid4 slot;
763f44e1126SVitaliy Gusev
764f44e1126SVitaliy Gusev ASSERT(sargs != NULL);
765f44e1126SVitaliy Gusev
766f44e1126SVitaliy Gusev if ((sp = rfs4x_findsession_by_id(sargs->sa_sessionid)) == NULL)
767f44e1126SVitaliy Gusev return (NFS4ERR_BADSESSION);
768f44e1126SVitaliy Gusev
769f44e1126SVitaliy Gusev slot = sargs->sa_slotid;
770f44e1126SVitaliy Gusev if (slot >= sp->sn_fore->cn_attrs.ca_maxrequests) {
771f44e1126SVitaliy Gusev rfs4x_session_rele(sp);
772f44e1126SVitaliy Gusev return (NFS4ERR_BADSLOT);
773f44e1126SVitaliy Gusev }
774f44e1126SVitaliy Gusev cs->sp = sp;
775f44e1126SVitaliy Gusev cs->cachethis = sargs->sa_cachethis;
776f44e1126SVitaliy Gusev
777f44e1126SVitaliy Gusev return (NFS4_OK);
778f44e1126SVitaliy Gusev }
779f44e1126SVitaliy Gusev
780f44e1126SVitaliy Gusev /* called under held lock */
781f44e1126SVitaliy Gusev static nfsstat4
check_slot_seqid(rfs4_slot_t * slot,sequenceid4 seqid)782f44e1126SVitaliy Gusev check_slot_seqid(rfs4_slot_t *slot, sequenceid4 seqid)
783f44e1126SVitaliy Gusev {
784f44e1126SVitaliy Gusev nfsstat4 status = NFS4ERR_SEQ_MISORDERED;
785f44e1126SVitaliy Gusev
786f44e1126SVitaliy Gusev if (slot->se_flags & RFS4_SLOT_INUSE) {
787f44e1126SVitaliy Gusev /*
788f44e1126SVitaliy Gusev * There are three cases:
789f44e1126SVitaliy Gusev * 1. Duplicated requests for currently performing
790f44e1126SVitaliy Gusev * duplicated request.
791f44e1126SVitaliy Gusev * 2. New request for currently performing duplicated
792f44e1126SVitaliy Gusev * request.
793f44e1126SVitaliy Gusev * 3. Request with bad seqid for non finished performing
794f44e1126SVitaliy Gusev * request (due to a little window between 'prep'
795f44e1126SVitaliy Gusev * stage and actual renew se_seqid).
796f44e1126SVitaliy Gusev * In all cases tell a client to retry request later.
797f44e1126SVitaliy Gusev */
798f44e1126SVitaliy Gusev if (slot->se_seqid == seqid || slot->se_seqid + 1 == seqid) {
799f44e1126SVitaliy Gusev status = NFS4ERR_DELAY;
800f44e1126SVitaliy Gusev }
801f44e1126SVitaliy Gusev } else {
802f44e1126SVitaliy Gusev if (seqid == slot->se_seqid + 1)
803f44e1126SVitaliy Gusev status = NFS4_OK;
804f44e1126SVitaliy Gusev else if (seqid == slot->se_seqid)
805f44e1126SVitaliy Gusev status = nfserr_replay_cache;
806f44e1126SVitaliy Gusev }
807f44e1126SVitaliy Gusev return (status);
808f44e1126SVitaliy Gusev }
809f44e1126SVitaliy Gusev
810f44e1126SVitaliy Gusev /*
811f44e1126SVitaliy Gusev * Prep stage for SEQUENCE operation.
812f44e1126SVitaliy Gusev *
813f44e1126SVitaliy Gusev * Main purpose to call this:
814f44e1126SVitaliy Gusev * - check on cached replay
815f44e1126SVitaliy Gusev * - Set cs.sp and cs.slot
816f44e1126SVitaliy Gusev */
817f44e1126SVitaliy Gusev int
rfs4x_sequence_prep(COMPOUND4args * args,COMPOUND4res * resp,compound_state_t * cs)818f44e1126SVitaliy Gusev rfs4x_sequence_prep(COMPOUND4args *args, COMPOUND4res *resp,
819f44e1126SVitaliy Gusev compound_state_t *cs)
820f44e1126SVitaliy Gusev {
821f44e1126SVitaliy Gusev SEQUENCE4args *sargs;
822f44e1126SVitaliy Gusev nfsstat4 status;
823f44e1126SVitaliy Gusev rfs4_slot_t *slot;
824f44e1126SVitaliy Gusev
825f44e1126SVitaliy Gusev if (args->array_len == 0 || args->array[0].argop != OP_SEQUENCE)
826f44e1126SVitaliy Gusev return (NFS4_OK);
827f44e1126SVitaliy Gusev
828f44e1126SVitaliy Gusev sargs = &args->array[0].nfs_argop4_u.opsequence;
829f44e1126SVitaliy Gusev
830f44e1126SVitaliy Gusev status = rfs4x_find_session(sargs, cs);
831f44e1126SVitaliy Gusev if (status != NFS4_OK)
832f44e1126SVitaliy Gusev return (status);
833f44e1126SVitaliy Gusev
834*b45434deSVitaliy Gusev if (args->array_len > cs->sp->sn_fore->cn_attrs.ca_maxoperations)
835*b45434deSVitaliy Gusev return (NFS4ERR_TOO_MANY_OPS);
836*b45434deSVitaliy Gusev
837f44e1126SVitaliy Gusev /* have reference to session */
838f44e1126SVitaliy Gusev slot = &cs->sp->sn_slots[sargs->sa_slotid];
839f44e1126SVitaliy Gusev
840f44e1126SVitaliy Gusev mutex_enter(&slot->se_lock);
841f44e1126SVitaliy Gusev status = check_slot_seqid(slot, sargs->sa_sequenceid);
842f44e1126SVitaliy Gusev if (status == nfserr_replay_cache) {
843f44e1126SVitaliy Gusev if (slot->se_flags & RFS4_SLOT_CACHED) {
844f44e1126SVitaliy Gusev slot->se_flags |= RFS4_SLOT_INUSE;
845f44e1126SVitaliy Gusev cs->slot = slot;
846f44e1126SVitaliy Gusev *resp = slot->se_buf;
847f44e1126SVitaliy Gusev } else {
848f44e1126SVitaliy Gusev status = NFS4ERR_SEQ_MISORDERED;
849f44e1126SVitaliy Gusev }
850f44e1126SVitaliy Gusev } else if (status == NFS4_OK) {
851f44e1126SVitaliy Gusev slot->se_flags |= RFS4_SLOT_INUSE;
852f44e1126SVitaliy Gusev cs->slot = slot;
853f44e1126SVitaliy Gusev }
854f44e1126SVitaliy Gusev mutex_exit(&slot->se_lock);
855f44e1126SVitaliy Gusev
856f44e1126SVitaliy Gusev return (status);
857f44e1126SVitaliy Gusev }
858f44e1126SVitaliy Gusev
859f44e1126SVitaliy Gusev /*
860f44e1126SVitaliy Gusev * Do cleanup things
861f44e1126SVitaliy Gusev * 1. cache reply
862f44e1126SVitaliy Gusev * 2. release slot
863f44e1126SVitaliy Gusev */
864f44e1126SVitaliy Gusev void
rfs4x_sequence_done(COMPOUND4res * resp,compound_state_t * cs)865f44e1126SVitaliy Gusev rfs4x_sequence_done(COMPOUND4res *resp, compound_state_t *cs)
866f44e1126SVitaliy Gusev {
867f44e1126SVitaliy Gusev rfs4_slot_t *slot = cs->slot;
868f44e1126SVitaliy Gusev rfs4_session_t *sp = cs->sp;
869f44e1126SVitaliy Gusev int add = 0;
870f44e1126SVitaliy Gusev
871f44e1126SVitaliy Gusev ASSERT(slot != NULL);
872f44e1126SVitaliy Gusev ASSERT(sp != NULL);
873f44e1126SVitaliy Gusev
874f44e1126SVitaliy Gusev mutex_enter(&slot->se_lock);
875f44e1126SVitaliy Gusev slot->se_flags &= ~RFS4_SLOT_INUSE;
876f44e1126SVitaliy Gusev
877f44e1126SVitaliy Gusev if (*cs->statusp != nfserr_replay_cache) {
878f44e1126SVitaliy Gusev if (slot->se_flags & RFS4_SLOT_CACHED) {
879f44e1126SVitaliy Gusev rfs4_compound_free(&slot->se_buf);
880f44e1126SVitaliy Gusev slot->se_flags &= ~RFS4_SLOT_CACHED;
881f44e1126SVitaliy Gusev add = -1;
882f44e1126SVitaliy Gusev }
883f44e1126SVitaliy Gusev
884f44e1126SVitaliy Gusev if (*cs->statusp == NFS4_OK && cs->cachethis) {
885f44e1126SVitaliy Gusev slot->se_flags |= RFS4_SLOT_CACHED;
886f44e1126SVitaliy Gusev slot->se_buf = *resp; /* cache a reply */
887f44e1126SVitaliy Gusev add += 1;
888f44e1126SVitaliy Gusev } else {
889f44e1126SVitaliy Gusev rfs4_compound_free(resp);
890f44e1126SVitaliy Gusev }
891f44e1126SVitaliy Gusev }
892f44e1126SVitaliy Gusev mutex_exit(&slot->se_lock);
893f44e1126SVitaliy Gusev
894f44e1126SVitaliy Gusev if (add != 0)
895f44e1126SVitaliy Gusev atomic_add_32(&sp->sn_rcached, add);
896f44e1126SVitaliy Gusev }
897f44e1126SVitaliy Gusev
898f44e1126SVitaliy Gusev /*
899f44e1126SVitaliy Gusev * Process the SEQUENCE operation. The session pointer has already been
900f44e1126SVitaliy Gusev * cached in the compound state, so we just dereference
901f44e1126SVitaliy Gusev */
902f44e1126SVitaliy Gusev /*ARGSUSED*/
903f44e1126SVitaliy Gusev void
rfs4x_op_sequence(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)904f44e1126SVitaliy Gusev rfs4x_op_sequence(nfs_argop4 *argop, nfs_resop4 *resop,
905f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs)
906f44e1126SVitaliy Gusev {
907f44e1126SVitaliy Gusev SEQUENCE4args *args = &argop->nfs_argop4_u.opsequence;
908f44e1126SVitaliy Gusev SEQUENCE4res *resp = &resop->nfs_resop4_u.opsequence;
909f44e1126SVitaliy Gusev SEQUENCE4resok *rok = &resp->SEQUENCE4res_u.sr_resok4;
910f44e1126SVitaliy Gusev rfs4_session_t *sp = cs->sp;
911f44e1126SVitaliy Gusev rfs4_slot_t *slot = cs->slot;
912f44e1126SVitaliy Gusev nfsstat4 status = NFS4_OK;
913f44e1126SVitaliy Gusev uint32_t cbstat = 0;
914f44e1126SVitaliy Gusev
915f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__sequence__start,
916f44e1126SVitaliy Gusev struct compound_state *, cs,
917f44e1126SVitaliy Gusev SEQUENCE4args *, args);
918f44e1126SVitaliy Gusev
919f44e1126SVitaliy Gusev ASSERT(sp != NULL && slot != NULL);
920f44e1126SVitaliy Gusev
921f44e1126SVitaliy Gusev if (cs->op_pos != 0) {
922f44e1126SVitaliy Gusev status = NFS4ERR_SEQUENCE_POS;
923f44e1126SVitaliy Gusev goto out;
924f44e1126SVitaliy Gusev }
925f44e1126SVitaliy Gusev
926f44e1126SVitaliy Gusev if (rfs4_lease_expired(sp->sn_clnt)) {
927f44e1126SVitaliy Gusev status = NFS4ERR_BADSESSION;
928f44e1126SVitaliy Gusev goto out;
929f44e1126SVitaliy Gusev }
930f44e1126SVitaliy Gusev
931f44e1126SVitaliy Gusev rfs4_dbe_lock(sp->sn_dbe);
932f44e1126SVitaliy Gusev cs->client = sp->sn_clnt;
933f44e1126SVitaliy Gusev
934f44e1126SVitaliy Gusev DTRACE_PROBE1(compound_clid, clientid4, cs->client->rc_clientid);
935f44e1126SVitaliy Gusev
936f44e1126SVitaliy Gusev ASSERT(args->sa_sequenceid == slot->se_seqid + 1);
937f44e1126SVitaliy Gusev
938f44e1126SVitaliy Gusev /*
939f44e1126SVitaliy Gusev * New request.
940f44e1126SVitaliy Gusev */
941f44e1126SVitaliy Gusev mutex_enter(&slot->se_lock);
942f44e1126SVitaliy Gusev slot->se_seqid = args->sa_sequenceid;
943f44e1126SVitaliy Gusev mutex_exit(&slot->se_lock);
944f44e1126SVitaliy Gusev
945f44e1126SVitaliy Gusev cs->slotno = args->sa_slotid;
946f44e1126SVitaliy Gusev
947f44e1126SVitaliy Gusev /* Update access time */
948f44e1126SVitaliy Gusev sp->sn_laccess = nfs_sys_uptime();
949f44e1126SVitaliy Gusev
950f44e1126SVitaliy Gusev /* Prepare result */
951f44e1126SVitaliy Gusev bcopy(sp->sn_sessid, rok->sr_sessionid, sizeof (sessionid4));
952f44e1126SVitaliy Gusev rok->sr_sequenceid = slot->se_seqid;
953f44e1126SVitaliy Gusev rok->sr_slotid = args->sa_slotid;
954f44e1126SVitaliy Gusev rok->sr_highest_slotid =
955f44e1126SVitaliy Gusev sp->sn_fore->cn_attrs.ca_maxrequests - 1;
956f44e1126SVitaliy Gusev rok->sr_target_highest_slotid =
957f44e1126SVitaliy Gusev sp->sn_fore->cn_attrs.ca_maxrequests - 1;
958f44e1126SVitaliy Gusev rok->sr_status_flags |= cbstat;
959f44e1126SVitaliy Gusev rfs4_dbe_unlock(sp->sn_dbe);
960f44e1126SVitaliy Gusev
961f44e1126SVitaliy Gusev /* Update lease (out of session lock) */
962f44e1126SVitaliy Gusev rfs4_update_lease(cs->client);
963f44e1126SVitaliy Gusev
964f44e1126SVitaliy Gusev out:
965f44e1126SVitaliy Gusev *cs->statusp = resp->sr_status = status;
966f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__sequence__done,
967f44e1126SVitaliy Gusev struct compound_state *, cs,
968f44e1126SVitaliy Gusev SEQUENCE4res *, resp);
969f44e1126SVitaliy Gusev }
970f44e1126SVitaliy Gusev
971f44e1126SVitaliy Gusev /* ARGSUSED */
972f44e1126SVitaliy Gusev void
rfs4x_op_reclaim_complete(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)973f44e1126SVitaliy Gusev rfs4x_op_reclaim_complete(nfs_argop4 *argop, nfs_resop4 *resop,
974f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs)
975f44e1126SVitaliy Gusev {
976f44e1126SVitaliy Gusev RECLAIM_COMPLETE4args *args = &argop->nfs_argop4_u.opreclaim_complete;
977f44e1126SVitaliy Gusev RECLAIM_COMPLETE4res *resp = &resop->nfs_resop4_u.opreclaim_complete;
978f44e1126SVitaliy Gusev rfs4_client_t *cp;
979f44e1126SVitaliy Gusev nfsstat4 status = NFS4_OK;
980f44e1126SVitaliy Gusev
981f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__reclaim__complete__start,
982f44e1126SVitaliy Gusev struct compound_state *, cs,
983f44e1126SVitaliy Gusev RECLAIM_COMPLETE4args *, args);
984f44e1126SVitaliy Gusev
985f44e1126SVitaliy Gusev cp = cs->client;
986f44e1126SVitaliy Gusev rfs4_dbe_lock(cp->rc_dbe);
987f44e1126SVitaliy Gusev if (args->rca_one_fs) {
988f44e1126SVitaliy Gusev /* do what? we don't track this */
989f44e1126SVitaliy Gusev goto out;
990f44e1126SVitaliy Gusev }
991f44e1126SVitaliy Gusev
992f44e1126SVitaliy Gusev if (cp->rc_reclaim_completed) {
993f44e1126SVitaliy Gusev status = NFS4ERR_COMPLETE_ALREADY;
994f44e1126SVitaliy Gusev goto out;
995f44e1126SVitaliy Gusev }
996f44e1126SVitaliy Gusev
997f44e1126SVitaliy Gusev if (cp->rc_can_reclaim) {
998f44e1126SVitaliy Gusev ASSERT(rfs4_servinst(cp)->nreclaim > 0);
999f44e1126SVitaliy Gusev atomic_add_32(&(rfs4_servinst(cp))->nreclaim, -1);
1000f44e1126SVitaliy Gusev }
1001f44e1126SVitaliy Gusev
1002f44e1126SVitaliy Gusev cp->rc_reclaim_completed = 1;
1003f44e1126SVitaliy Gusev out:
1004f44e1126SVitaliy Gusev rfs4_dbe_unlock(cp->rc_dbe);
1005f44e1126SVitaliy Gusev
1006f44e1126SVitaliy Gusev *cs->statusp = resp->rcr_status = status;
1007f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__reclaim__complete__done,
1008f44e1126SVitaliy Gusev struct compound_state *, cs,
1009f44e1126SVitaliy Gusev RECLAIM_COMPLETE4res *, resp);
1010f44e1126SVitaliy Gusev }
1011f44e1126SVitaliy Gusev
1012f44e1126SVitaliy Gusev /* ARGSUSED */
1013f44e1126SVitaliy Gusev void
rfs4x_op_destroy_clientid(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)1014f44e1126SVitaliy Gusev rfs4x_op_destroy_clientid(nfs_argop4 *argop, nfs_resop4 *resop,
1015f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs)
1016f44e1126SVitaliy Gusev {
1017f44e1126SVitaliy Gusev DESTROY_CLIENTID4args *args = &argop->nfs_argop4_u.opdestroy_clientid;
1018f44e1126SVitaliy Gusev DESTROY_CLIENTID4res *resp = &resop->nfs_resop4_u.opdestroy_clientid;
1019f44e1126SVitaliy Gusev rfs4_client_t *cp;
1020f44e1126SVitaliy Gusev nfsstat4 status = NFS4_OK;
1021f44e1126SVitaliy Gusev
1022f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__destroy__clientid__start,
1023f44e1126SVitaliy Gusev struct compound_state *, cs,
1024f44e1126SVitaliy Gusev DESTROY_CLIENTID4args *, args);
1025f44e1126SVitaliy Gusev
1026f44e1126SVitaliy Gusev cp = rfs4_findclient_by_id(args->dca_clientid, TRUE);
1027f44e1126SVitaliy Gusev if (cp == NULL) {
1028f44e1126SVitaliy Gusev status = NFS4ERR_STALE_CLIENTID;
1029f44e1126SVitaliy Gusev goto end;
1030f44e1126SVitaliy Gusev }
1031f44e1126SVitaliy Gusev
1032f44e1126SVitaliy Gusev rfs4_dbe_lock(cp->rc_dbe);
1033f44e1126SVitaliy Gusev if (client_has_state_locked(cp))
1034f44e1126SVitaliy Gusev status = NFS4ERR_CLIENTID_BUSY;
1035f44e1126SVitaliy Gusev else
1036f44e1126SVitaliy Gusev cp->rc_destroying = TRUE;
1037f44e1126SVitaliy Gusev rfs4_dbe_unlock(cp->rc_dbe);
1038f44e1126SVitaliy Gusev
1039f44e1126SVitaliy Gusev if (status == NFS4_OK)
1040f44e1126SVitaliy Gusev rfs4_client_close(cp);
1041f44e1126SVitaliy Gusev else
1042f44e1126SVitaliy Gusev rfs4_client_rele(cp);
1043f44e1126SVitaliy Gusev end:
1044f44e1126SVitaliy Gusev *cs->statusp = resp->dcr_status = status;
1045f44e1126SVitaliy Gusev
1046f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__destroy__clientid__done,
1047f44e1126SVitaliy Gusev struct compound_state *, cs,
1048f44e1126SVitaliy Gusev DESTROY_CLIENTID4res *, resp);
1049f44e1126SVitaliy Gusev }
1050f44e1126SVitaliy Gusev
1051f44e1126SVitaliy Gusev /*ARGSUSED*/
1052f44e1126SVitaliy Gusev void
rfs4x_op_bind_conn_to_session(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)1053f44e1126SVitaliy Gusev rfs4x_op_bind_conn_to_session(nfs_argop4 *argop, nfs_resop4 *resop,
1054f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs)
1055f44e1126SVitaliy Gusev {
1056f44e1126SVitaliy Gusev BIND_CONN_TO_SESSION4args *args =
1057f44e1126SVitaliy Gusev &argop->nfs_argop4_u.opbind_conn_to_session;
1058f44e1126SVitaliy Gusev BIND_CONN_TO_SESSION4res *resp =
1059f44e1126SVitaliy Gusev &resop->nfs_resop4_u.opbind_conn_to_session;
1060f44e1126SVitaliy Gusev BIND_CONN_TO_SESSION4resok *rok =
1061f44e1126SVitaliy Gusev &resp->BIND_CONN_TO_SESSION4res_u.bctsr_resok4;
1062f44e1126SVitaliy Gusev rfs4_session_t *sp;
1063f44e1126SVitaliy Gusev nfsstat4 status = NFS4_OK;
1064f44e1126SVitaliy Gusev
1065f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__bind__conn__to__session__start,
1066f44e1126SVitaliy Gusev struct compound_state *, cs,
1067f44e1126SVitaliy Gusev BIND_CONN_TO_SESSION4args *, args);
1068f44e1126SVitaliy Gusev
1069f44e1126SVitaliy Gusev if (cs->op_pos != 0) {
1070f44e1126SVitaliy Gusev status = NFS4ERR_NOT_ONLY_OP;
1071f44e1126SVitaliy Gusev goto end;
1072f44e1126SVitaliy Gusev }
1073f44e1126SVitaliy Gusev
1074f44e1126SVitaliy Gusev sp = rfs4x_findsession_by_id(args->bctsa_sessid);
1075f44e1126SVitaliy Gusev if (sp == NULL) {
1076f44e1126SVitaliy Gusev status = NFS4ERR_BADSESSION;
1077f44e1126SVitaliy Gusev goto end;
1078f44e1126SVitaliy Gusev }
1079f44e1126SVitaliy Gusev
1080f44e1126SVitaliy Gusev rfs4_update_lease(sp->sn_clnt); /* no need lock protection */
1081f44e1126SVitaliy Gusev
1082f44e1126SVitaliy Gusev rfs4_dbe_lock(sp->sn_dbe);
1083f44e1126SVitaliy Gusev sp->sn_laccess = nfs_sys_uptime();
1084f44e1126SVitaliy Gusev rfs4_dbe_unlock(sp->sn_dbe);
1085f44e1126SVitaliy Gusev
1086f44e1126SVitaliy Gusev rok->bctsr_use_conn_in_rdma_mode = FALSE;
1087f44e1126SVitaliy Gusev
1088f44e1126SVitaliy Gusev switch (args->bctsa_dir) {
1089f44e1126SVitaliy Gusev case CDFC4_FORE:
1090f44e1126SVitaliy Gusev case CDFC4_FORE_OR_BOTH:
1091f44e1126SVitaliy Gusev /* always map to Fore */
1092f44e1126SVitaliy Gusev rok->bctsr_dir = CDFS4_FORE;
1093f44e1126SVitaliy Gusev break;
1094f44e1126SVitaliy Gusev
1095f44e1126SVitaliy Gusev case CDFC4_BACK:
1096f44e1126SVitaliy Gusev case CDFC4_BACK_OR_BOTH:
1097f44e1126SVitaliy Gusev /* TODO: always map to Back */
1098f44e1126SVitaliy Gusev rok->bctsr_dir = CDFS4_FORE;
1099f44e1126SVitaliy Gusev break;
1100f44e1126SVitaliy Gusev default:
1101f44e1126SVitaliy Gusev break;
1102f44e1126SVitaliy Gusev }
1103f44e1126SVitaliy Gusev
1104f44e1126SVitaliy Gusev bcopy(sp->sn_sessid, rok->bctsr_sessid, sizeof (sessionid4));
1105f44e1126SVitaliy Gusev rfs4x_session_rele(sp);
1106f44e1126SVitaliy Gusev end:
1107f44e1126SVitaliy Gusev *cs->statusp = resp->bctsr_status = status;
1108f44e1126SVitaliy Gusev
1109f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__bind__conn__to__session__done,
1110f44e1126SVitaliy Gusev struct compound_state *, cs,
1111f44e1126SVitaliy Gusev BIND_CONN_TO_SESSION4res *, resp);
1112f44e1126SVitaliy Gusev }
1113f44e1126SVitaliy Gusev
1114f44e1126SVitaliy Gusev /* ARGSUSED */
1115f44e1126SVitaliy Gusev void
rfs4x_op_secinfo_noname(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)1116f44e1126SVitaliy Gusev rfs4x_op_secinfo_noname(nfs_argop4 *argop, nfs_resop4 *resop,
1117f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs)
1118f44e1126SVitaliy Gusev {
1119f44e1126SVitaliy Gusev SECINFO_NO_NAME4res *resp = &resop->nfs_resop4_u.opsecinfo_no_name;
1120f44e1126SVitaliy Gusev nfsstat4 status;
1121f44e1126SVitaliy Gusev bool_t dotdot;
1122f44e1126SVitaliy Gusev
1123f44e1126SVitaliy Gusev DTRACE_NFSV4_1(op__secinfo__no__name__start,
1124f44e1126SVitaliy Gusev struct compound_state *, cs);
1125f44e1126SVitaliy Gusev
1126f44e1126SVitaliy Gusev if (cs->vp == NULL) {
1127f44e1126SVitaliy Gusev status = NFS4ERR_NOFILEHANDLE;
1128f44e1126SVitaliy Gusev goto out;
1129f44e1126SVitaliy Gusev }
1130f44e1126SVitaliy Gusev
1131f44e1126SVitaliy Gusev if (cs->vp->v_type != VDIR) {
1132f44e1126SVitaliy Gusev status = NFS4ERR_NOTDIR;
1133f44e1126SVitaliy Gusev goto out;
1134f44e1126SVitaliy Gusev }
1135f44e1126SVitaliy Gusev
1136f44e1126SVitaliy Gusev dotdot =
1137f44e1126SVitaliy Gusev (argop->nfs_argop4_u.opsecinfo_no_name == SECINFO_STYLE4_PARENT);
1138f44e1126SVitaliy Gusev
1139f44e1126SVitaliy Gusev status = do_rfs4_op_secinfo(cs, dotdot ? ".." : ".", resp);
1140f44e1126SVitaliy Gusev
1141f44e1126SVitaliy Gusev /* Cleanup FH as described at 18.45.3 and 2.6.3.1.1.8 */
1142f44e1126SVitaliy Gusev if (status == NFS4_OK) {
1143f44e1126SVitaliy Gusev VN_RELE(cs->vp);
1144f44e1126SVitaliy Gusev cs->vp = NULL;
1145f44e1126SVitaliy Gusev }
1146f44e1126SVitaliy Gusev out:
1147f44e1126SVitaliy Gusev *cs->statusp = resp->status = status;
1148f44e1126SVitaliy Gusev
1149f44e1126SVitaliy Gusev DTRACE_NFSV4_2(op__secinfo__no__name__done,
1150f44e1126SVitaliy Gusev struct compound_state *, cs,
1151f44e1126SVitaliy Gusev SECINFO_NO_NAME4res *, resp);
1152f44e1126SVitaliy Gusev }
1153