xref: /reactos/base/services/nfsd/callback_xdr.c (revision c2c66aff)
1 /* NFSv4.1 client for Windows
2  * Copyright � 2012 The Regents of the University of Michigan
3  *
4  * Olga Kornievskaia <aglo@umich.edu>
5  * Casey Bodley <cbodley@umich.edu>
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or (at
10  * your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but
13  * without any warranty; without even the implied warranty of merchantability
14  * or fitness for a particular purpose.  See the GNU Lesser General Public
15  * License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  */
21 
22 #include "nfs41_callback.h"
23 #include "nfs41_ops.h"
24 #include "util.h"
25 #include "daemon_debug.h"
26 
27 
28 #define CBXLVL 2 /* dprintf level for callback xdr logging */
29 #ifdef __REACTOS__
30 #define CBX_ERR(msg) dprintf((CBXLVL), "%s: failed at %s\n", __FUNCTION__, msg)
31 #else
32 #define CBX_ERR(msg) dprintf((CBXLVL), __FUNCTION__ ": failed at " msg "\n")
33 #endif
34 
35 /* common types */
36 bool_t xdr_bitmap4(XDR *xdr, bitmap4 *bitmap);
37 bool_t xdr_fattr4(XDR *xdr, fattr4 *fattr);
38 
common_stateid(XDR * xdr,stateid4 * stateid)39 static bool_t common_stateid(XDR *xdr, stateid4 *stateid)
40 {
41     return xdr_u_int32_t(xdr, &stateid->seqid)
42         && xdr_opaque(xdr, (char*)stateid->other, NFS4_STATEID_OTHER);
43 }
44 
common_fh(XDR * xdr,nfs41_fh * fh)45 static bool_t common_fh(XDR *xdr, nfs41_fh *fh)
46 {
47     return xdr_u_int32_t(xdr, &fh->len)
48         && fh->len <= NFS4_FHSIZE
49         && xdr_opaque(xdr, (char*)fh->fh, fh->len);
50 }
51 
common_fsid(XDR * xdr,nfs41_fsid * fsid)52 static bool_t common_fsid(XDR *xdr, nfs41_fsid *fsid)
53 {
54     return xdr_u_int64_t(xdr, &fsid->major)
55         && xdr_u_int64_t(xdr, &fsid->minor);
56 }
57 
common_notify4(XDR * xdr,struct notify4 * notify)58 static bool_t common_notify4(XDR *xdr, struct notify4 *notify)
59 {
60     return xdr_bitmap4(xdr, &notify->mask)
61         && xdr_bytes(xdr, &notify->list, &notify->len, NFS4_OPAQUE_LIMIT);
62 }
63 
64 /* OP_CB_LAYOUTRECALL */
op_cb_layoutrecall_file(XDR * xdr,struct cb_recall_file * args)65 static bool_t op_cb_layoutrecall_file(XDR *xdr, struct cb_recall_file *args)
66 {
67     bool_t result;
68 
69     result = common_fh(xdr, &args->fh);
70     if (!result) { CBX_ERR("layoutrecall_file.fh"); goto out; }
71 
72     result = xdr_u_int64_t(xdr, &args->offset);
73     if (!result) { CBX_ERR("layoutrecall_file.offset"); goto out; }
74 
75     result = xdr_u_int64_t(xdr, &args->length);
76     if (!result) { CBX_ERR("layoutrecall_file.length"); goto out; }
77 
78     result = common_stateid(xdr, &args->stateid);
79     if (!result) { CBX_ERR("layoutrecall_file.stateid"); goto out; }
80 out:
81     return result;
82 }
83 
op_cb_layoutrecall_fsid(XDR * xdr,union cb_recall_file_args * args)84 static bool_t op_cb_layoutrecall_fsid(XDR *xdr, union cb_recall_file_args *args)
85 {
86     bool_t result;
87 
88     result = common_fsid(xdr, &args->fsid);
89     if (!result) { CBX_ERR("layoutrecall_fsid.fsid"); goto out; }
90 out:
91     return result;
92 }
93 
94 static const struct xdr_discrim cb_layoutrecall_discrim[] = {
95     { PNFS_RETURN_FILE,     (xdrproc_t)op_cb_layoutrecall_file },
96     { PNFS_RETURN_FSID,     (xdrproc_t)op_cb_layoutrecall_fsid },
97     { PNFS_RETURN_ALL,      (xdrproc_t)xdr_void },
98     { 0,                    NULL_xdrproc_t }
99 };
100 
op_cb_layoutrecall_args(XDR * xdr,struct cb_layoutrecall_args * args)101 static bool_t op_cb_layoutrecall_args(XDR *xdr, struct cb_layoutrecall_args *args)
102 {
103     bool_t result;
104 
105     result = xdr_enum(xdr, (enum_t*)&args->type);
106     if (!result) { CBX_ERR("layoutrecall_args.type"); goto out; }
107 
108     result = xdr_enum(xdr, (enum_t*)&args->iomode);
109     if (!result) { CBX_ERR("layoutrecall_args.iomode"); goto out; }
110 
111     result = xdr_bool(xdr, &args->changed);
112     if (!result) { CBX_ERR("layoutrecall_args.changed"); goto out; }
113 
114     result = xdr_union(xdr, (enum_t*)&args->recall.type,
115         (char*)&args->recall.args, cb_layoutrecall_discrim, NULL_xdrproc_t);
116     if (!result) { CBX_ERR("layoutrecall_args.recall"); goto out; }
117 out:
118     return result;
119 }
120 
op_cb_layoutrecall_res(XDR * xdr,struct cb_layoutrecall_res * res)121 static bool_t op_cb_layoutrecall_res(XDR *xdr, struct cb_layoutrecall_res *res)
122 {
123     bool_t result;
124 
125     result = xdr_enum(xdr, &res->status);
126     if (!result) { CBX_ERR("layoutrecall_res.status"); goto out; }
127 out:
128     return result;
129 }
130 
131 
132 /* OP_CB_RECALL_SLOT */
op_cb_recall_slot_args(XDR * xdr,struct cb_recall_slot_args * res)133 static bool_t op_cb_recall_slot_args(XDR *xdr, struct cb_recall_slot_args *res)
134 {
135     bool_t result;
136 
137     result = xdr_u_int32_t(xdr, &res->target_highest_slotid);
138     if (!result) { CBX_ERR("recall_slot.target_highest_slotid"); goto out; }
139 out:
140     return result;
141 }
142 
op_cb_recall_slot_res(XDR * xdr,struct cb_recall_slot_res * res)143 static bool_t op_cb_recall_slot_res(XDR *xdr, struct cb_recall_slot_res *res)
144 {
145     bool_t result;
146 
147     result = xdr_enum(xdr, &res->status);
148     if (!result) { CBX_ERR("recall_slot.status"); goto out; }
149 out:
150     return result;
151 }
152 
153 
154 /* OP_CB_SEQUENCE */
op_cb_sequence_ref(XDR * xdr,struct cb_sequence_ref * args)155 static bool_t op_cb_sequence_ref(XDR *xdr, struct cb_sequence_ref *args)
156 {
157     bool_t result;
158 
159     result = xdr_u_int32_t(xdr, &args->sequenceid);
160     if (!result) { CBX_ERR("sequence_ref.sequenceid"); goto out; }
161 
162     result = xdr_u_int32_t(xdr, &args->slotid);
163     if (!result) { CBX_ERR("sequence_ref.slotid"); goto out; }
164 out:
165     return result;
166 }
167 
op_cb_sequence_ref_list(XDR * xdr,struct cb_sequence_ref_list * args)168 static bool_t op_cb_sequence_ref_list(XDR *xdr, struct cb_sequence_ref_list *args)
169 {
170     bool_t result;
171 
172     result = xdr_opaque(xdr, args->sessionid, NFS4_SESSIONID_SIZE);
173     if (!result) { CBX_ERR("sequence_ref_list.sessionid"); goto out; }
174 
175     result = xdr_array(xdr, (char**)&args->calls, &args->call_count,
176         64, sizeof(struct cb_sequence_ref), (xdrproc_t)op_cb_sequence_ref);
177     if (!result) { CBX_ERR("sequence_ref_list.calls"); goto out; }
178 out:
179     return result;
180 }
181 
op_cb_sequence_args(XDR * xdr,struct cb_sequence_args * args)182 static bool_t op_cb_sequence_args(XDR *xdr, struct cb_sequence_args *args)
183 {
184     bool_t result;
185 
186     result = xdr_opaque(xdr, args->sessionid, NFS4_SESSIONID_SIZE);
187     if (!result) { CBX_ERR("sequence_args.sessionid"); goto out; }
188 
189     result = xdr_u_int32_t(xdr, &args->sequenceid);
190     if (!result) { CBX_ERR("sequence_args.sequenceid"); goto out; }
191 
192     result = xdr_u_int32_t(xdr, &args->slotid);
193     if (!result) { CBX_ERR("sequence_args.slotid"); goto out; }
194 
195     result = xdr_u_int32_t(xdr, &args->highest_slotid);
196     if (!result) { CBX_ERR("sequence_args.highest_slotid"); goto out; }
197 
198     result = xdr_bool(xdr, &args->cachethis);
199     if (!result) { CBX_ERR("sequence_args.cachethis"); goto out; }
200 
201     result = xdr_array(xdr, (char**)&args->ref_lists,
202         &args->ref_list_count, 64, sizeof(struct cb_sequence_ref_list),
203         (xdrproc_t)op_cb_sequence_ref_list);
204     if (!result) { CBX_ERR("sequence_args.ref_lists"); goto out; }
205 out:
206     return result;
207 }
208 
op_cb_sequence_res_ok(XDR * xdr,struct cb_sequence_res_ok * res)209 static bool_t op_cb_sequence_res_ok(XDR *xdr, struct cb_sequence_res_ok *res)
210 {
211     bool_t result;
212 
213     result = xdr_opaque(xdr, res->sessionid, NFS4_SESSIONID_SIZE);
214     if (!result) { CBX_ERR("sequence_res.sessionid"); goto out; }
215 
216     result = xdr_u_int32_t(xdr, &res->sequenceid);
217     if (!result) { CBX_ERR("sequence_res.sequenceid"); goto out; }
218 
219     result = xdr_u_int32_t(xdr, &res->slotid);
220     if (!result) { CBX_ERR("sequence_res.slotid"); goto out; }
221 
222     result = xdr_u_int32_t(xdr, &res->highest_slotid);
223     if (!result) { CBX_ERR("sequence_res.highest_slotid"); goto out; }
224 
225     result = xdr_u_int32_t(xdr, &res->target_highest_slotid);
226     if (!result) { CBX_ERR("sequence_res.target_highest_slotid"); goto out; }
227 out:
228     return result;
229 }
230 
231 static const struct xdr_discrim cb_sequence_res_discrim[] = {
232     { NFS4_OK,              (xdrproc_t)op_cb_sequence_res_ok },
233     { 0,                    NULL_xdrproc_t }
234 };
235 
op_cb_sequence_res(XDR * xdr,struct cb_sequence_res * res)236 static bool_t op_cb_sequence_res(XDR *xdr, struct cb_sequence_res *res)
237 {
238     bool_t result;
239 
240     result = xdr_union(xdr, &res->status, (char*)&res->ok,
241         cb_sequence_res_discrim, (xdrproc_t)xdr_void);
242     if (!result) { CBX_ERR("seq:argop.args"); goto out; }
243 out:
244     return result;
245 }
246 
247 /* OP_CB_GETATTR */
op_cb_getattr_args(XDR * xdr,struct cb_getattr_args * args)248 static bool_t op_cb_getattr_args(XDR *xdr, struct cb_getattr_args *args)
249 {
250     bool_t result;
251 
252     result = common_fh(xdr, &args->fh);
253     if (!result) { CBX_ERR("getattr.fh"); goto out; }
254 
255     result = xdr_bitmap4(xdr, &args->attr_request);
256     if (!result) { CBX_ERR("getattr.attr_request"); goto out; }
257 out:
258     return result;
259 }
260 
info_to_fattr4(nfs41_file_info * info,fattr4 * fattr)261 static bool_t info_to_fattr4(nfs41_file_info *info, fattr4 *fattr)
262 {
263     XDR fattr_xdr;
264     bool_t result = TRUE;
265 
266     /* encode nfs41_file_info into fattr4 */
267     xdrmem_create(&fattr_xdr, (char*)fattr->attr_vals,
268         NFS4_OPAQUE_LIMIT, XDR_ENCODE);
269 
270     /* The only attributes that the server can reliably
271      * query via CB_GETATTR are size and change. */
272     if (bitmap_isset(&info->attrmask, 0, FATTR4_WORD0_CHANGE)) {
273         result = xdr_u_hyper(&fattr_xdr, &info->change);
274         if (!result) { CBX_ERR("getattr.info.change"); goto out; }
275         bitmap_set(&fattr->attrmask, 0, FATTR4_WORD0_CHANGE);
276     }
277     if (bitmap_isset(&info->attrmask, 0, FATTR4_WORD0_SIZE)) {
278         result = xdr_u_hyper(&fattr_xdr, &info->size);
279         if (!result) { CBX_ERR("getattr.info.size"); goto out; }
280         bitmap_set(&fattr->attrmask, 0, FATTR4_WORD0_SIZE);
281     }
282     fattr->attr_vals_len = xdr_getpos(&fattr_xdr);
283 out:
284     return result;
285 }
286 
op_cb_getattr_res(XDR * xdr,struct cb_getattr_res * res)287 static bool_t op_cb_getattr_res(XDR *xdr, struct cb_getattr_res *res)
288 {
289     bool_t result;
290 
291     result = xdr_enum(xdr, &res->status);
292     if (!result) { CBX_ERR("getattr.status"); goto out; }
293 
294     if (res->status == NFS4_OK) {
295         fattr4 fattr = { 0 };
296 
297         result = info_to_fattr4(&res->info, &fattr);
298         if (!result) { goto out; }
299 
300         result = xdr_fattr4(xdr, &fattr);
301         if (!result) { CBX_ERR("getattr.obj_attributes"); goto out; }
302     }
303 out:
304     return result;
305 }
306 
307 /* OP_CB_RECALL */
op_cb_recall_args(XDR * xdr,struct cb_recall_args * args)308 static bool_t op_cb_recall_args(XDR *xdr, struct cb_recall_args *args)
309 {
310     bool_t result;
311 
312     result = common_stateid(xdr, &args->stateid);
313     if (!result) { CBX_ERR("recall.stateid"); goto out; }
314 
315     result = xdr_bool(xdr, &args->truncate);
316     if (!result) { CBX_ERR("recall.truncate"); goto out; }
317 
318     result = common_fh(xdr, &args->fh);
319     if (!result) { CBX_ERR("recall.fh"); goto out; }
320 out:
321     return result;
322 }
323 
op_cb_recall_res(XDR * xdr,struct cb_recall_res * res)324 static bool_t op_cb_recall_res(XDR *xdr, struct cb_recall_res *res)
325 {
326     bool_t result;
327 
328     result = xdr_enum(xdr, &res->status);
329     if (!result) { CBX_ERR("recall.status"); goto out; }
330 out:
331     return result;
332 }
333 
334 /* OP_CB_NOTIFY */
op_cb_notify_args(XDR * xdr,struct cb_notify_args * res)335 static bool_t op_cb_notify_args(XDR *xdr, struct cb_notify_args *res)
336 {
337     bool_t result;
338 
339     result = xdr_u_int32_t(xdr, &res->target_highest_slotid);
340     if (!result) { CBX_ERR("notify.target_highest_slotid"); goto out; }
341 out:
342     return result;
343 }
344 
op_cb_notify_res(XDR * xdr,struct cb_notify_res * res)345 static bool_t op_cb_notify_res(XDR *xdr, struct cb_notify_res *res)
346 {
347     bool_t result;
348 
349     result = xdr_enum(xdr, &res->status);
350     if (!result) { CBX_ERR("notify.status"); goto out; }
351 out:
352     return result;
353 }
354 
355 /* OP_CB_PUSH_DELEG */
op_cb_push_deleg_args(XDR * xdr,struct cb_push_deleg_args * res)356 static bool_t op_cb_push_deleg_args(XDR *xdr, struct cb_push_deleg_args *res)
357 {
358     bool_t result;
359 
360     result = xdr_u_int32_t(xdr, &res->target_highest_slotid);
361     if (!result) { CBX_ERR("push_deleg.target_highest_slotid"); goto out; }
362 out:
363     return result;
364 }
365 
op_cb_push_deleg_res(XDR * xdr,struct cb_push_deleg_res * res)366 static bool_t op_cb_push_deleg_res(XDR *xdr, struct cb_push_deleg_res *res)
367 {
368     bool_t result;
369 
370     result = xdr_enum(xdr, &res->status);
371     if (!result) { CBX_ERR("push_deleg.status"); goto out; }
372 out:
373     return result;
374 }
375 
376 /* OP_CB_RECALL_ANY */
op_cb_recall_any_args(XDR * xdr,struct cb_recall_any_args * res)377 static bool_t op_cb_recall_any_args(XDR *xdr, struct cb_recall_any_args *res)
378 {
379     bool_t result;
380 
381     result = xdr_u_int32_t(xdr, &res->target_highest_slotid);
382     if (!result) { CBX_ERR("recall_any.target_highest_slotid"); goto out; }
383 out:
384     return result;
385 }
386 
op_cb_recall_any_res(XDR * xdr,struct cb_recall_any_res * res)387 static bool_t op_cb_recall_any_res(XDR *xdr, struct cb_recall_any_res *res)
388 {
389     bool_t result;
390 
391     result = xdr_enum(xdr, &res->status);
392     if (!result) { CBX_ERR("recall_any.status"); goto out; }
393 out:
394     return result;
395 }
396 
397 /* OP_CB_RECALLABLE_OBJ_AVAIL */
op_cb_recallable_obj_avail_args(XDR * xdr,struct cb_recallable_obj_avail_args * res)398 static bool_t op_cb_recallable_obj_avail_args(XDR *xdr, struct cb_recallable_obj_avail_args *res)
399 {
400     bool_t result;
401 
402     result = xdr_u_int32_t(xdr, &res->target_highest_slotid);
403     if (!result) { CBX_ERR("recallable_obj_avail.target_highest_slotid"); goto out; }
404 out:
405     return result;
406 }
407 
op_cb_recallable_obj_avail_res(XDR * xdr,struct cb_recallable_obj_avail_res * res)408 static bool_t op_cb_recallable_obj_avail_res(XDR *xdr, struct cb_recallable_obj_avail_res *res)
409 {
410     bool_t result;
411 
412     result = xdr_enum(xdr, &res->status);
413     if (!result) { CBX_ERR("recallable_obj_avail.status"); goto out; }
414 out:
415     return result;
416 }
417 
418 /* OP_CB_WANTS_CANCELLED */
op_cb_wants_cancelled_args(XDR * xdr,struct cb_wants_cancelled_args * res)419 static bool_t op_cb_wants_cancelled_args(XDR *xdr, struct cb_wants_cancelled_args *res)
420 {
421     bool_t result;
422 
423     result = xdr_u_int32_t(xdr, &res->target_highest_slotid);
424     if (!result) { CBX_ERR("wants_cancelled.target_highest_slotid"); goto out; }
425 out:
426     return result;
427 }
428 
op_cb_wants_cancelled_res(XDR * xdr,struct cb_wants_cancelled_res * res)429 static bool_t op_cb_wants_cancelled_res(XDR *xdr, struct cb_wants_cancelled_res *res)
430 {
431     bool_t result;
432 
433     result = xdr_enum(xdr, &res->status);
434     if (!result) { CBX_ERR("wants_cancelled.status"); goto out; }
435 out:
436     return result;
437 }
438 
439 /* OP_CB_NOTIFY_LOCK */
op_cb_notify_lock_args(XDR * xdr,struct cb_notify_lock_args * res)440 static bool_t op_cb_notify_lock_args(XDR *xdr, struct cb_notify_lock_args *res)
441 {
442     bool_t result;
443 
444     result = xdr_u_int32_t(xdr, &res->target_highest_slotid);
445     if (!result) { CBX_ERR("notify_lock.target_highest_slotid"); goto out; }
446 out:
447     return result;
448 }
449 
op_cb_notify_lock_res(XDR * xdr,struct cb_notify_lock_res * res)450 static bool_t op_cb_notify_lock_res(XDR *xdr, struct cb_notify_lock_res *res)
451 {
452     bool_t result;
453 
454     result = xdr_enum(xdr, &res->status);
455     if (!result) { CBX_ERR("notify_lock.status"); goto out; }
456 out:
457     return result;
458 }
459 
460 /* OP_CB_NOTIFY_DEVICEID */
cb_notify_deviceid_change(XDR * xdr,struct notify_deviceid4 * change)461 static bool_t cb_notify_deviceid_change(XDR *xdr, struct notify_deviceid4 *change)
462 {
463     bool_t result;
464 
465     result = xdr_u_int32_t(xdr, (uint32_t*)&change->layouttype);
466     if (!result) { CBX_ERR("notify_deviceid.change.layouttype"); goto out; }
467 
468     result = xdr_opaque(xdr, (char*)change->deviceid, PNFS_DEVICEID_SIZE);
469     if (!result) { CBX_ERR("notify_deviceid.change.deviceid"); goto out; }
470 
471     result = xdr_bool(xdr, &change->immediate);
472     if (!result) { CBX_ERR("notify_deviceid.change.immediate"); goto out; }
473 out:
474     return result;
475 }
476 
cb_notify_deviceid_delete(XDR * xdr,struct notify_deviceid4 * change)477 static bool_t cb_notify_deviceid_delete(XDR *xdr, struct notify_deviceid4 *change)
478 {
479     bool_t result;
480 
481     result = xdr_u_int32_t(xdr, (uint32_t*)&change->layouttype);
482     if (!result) { CBX_ERR("notify_deviceid.delete.layouttype"); goto out; }
483 
484     result = xdr_opaque(xdr, (char*)change->deviceid, PNFS_DEVICEID_SIZE);
485     if (!result) { CBX_ERR("notify_deviceid.delete.deviceid"); goto out; }
486 out:
487     return result;
488 }
489 
op_cb_notify_deviceid_args(XDR * xdr,struct cb_notify_deviceid_args * args)490 static bool_t op_cb_notify_deviceid_args(XDR *xdr, struct cb_notify_deviceid_args *args)
491 {
492     XDR notify_xdr;
493     uint32_t i, j, c;
494     bool_t result;
495 
496     /* decode the generic notify4 list */
497     result = xdr_array(xdr, (char**)&args->notify_list,
498         &args->notify_count, CB_COMPOUND_MAX_OPERATIONS,
499         sizeof(struct notify4), (xdrproc_t)common_notify4);
500     if (!result) { CBX_ERR("notify_deviceid.notify_list"); goto out; }
501 
502     switch (xdr->x_op) {
503     case XDR_FREE:
504         free(args->change_list);
505     case XDR_ENCODE:
506         return TRUE;
507     }
508 
509     /* count the number of device changes */
510     args->change_count = 0;
511     for (i = 0; i < args->notify_count; i++)
512         args->change_count += args->notify_list[i].mask.count;
513 
514     args->change_list = calloc(args->change_count, sizeof(struct notify_deviceid4));
515     if (args->change_list == NULL)
516         return FALSE;
517 
518     c = 0;
519     for (i = 0; i < args->notify_count; i++) {
520         struct notify4 *notify = &args->notify_list[i];
521 
522         /* decode the device notifications out of the opaque buffer */
523         xdrmem_create(&notify_xdr, notify->list, notify->len, XDR_DECODE);
524 
525         for (j = 0; j < notify->mask.count; j++) {
526             struct notify_deviceid4 *change = &args->change_list[c++];
527             change->type = notify->mask.arr[j];
528 
529             switch (change->type) {
530             case NOTIFY_DEVICEID4_CHANGE:
531                 result = cb_notify_deviceid_change(&notify_xdr, change);
532                 if (!result) { CBX_ERR("notify_deviceid.change"); goto out; }
533                 break;
534             case NOTIFY_DEVICEID4_DELETE:
535                 result = cb_notify_deviceid_delete(&notify_xdr, change);
536                 if (!result) { CBX_ERR("notify_deviceid.delete"); goto out; }
537                 break;
538             }
539         }
540     }
541 out:
542     return result;
543 }
544 
op_cb_notify_deviceid_res(XDR * xdr,struct cb_notify_deviceid_res * res)545 static bool_t op_cb_notify_deviceid_res(XDR *xdr, struct cb_notify_deviceid_res *res)
546 {
547     bool_t result;
548 
549     result = xdr_enum(xdr, &res->status);
550     if (!result) { CBX_ERR("notify_deviceid.status"); goto out; }
551 out:
552     return result;
553 }
554 
555 /* CB_COMPOUND */
cb_compound_tag(XDR * xdr,struct cb_compound_tag * args)556 static bool_t cb_compound_tag(XDR *xdr, struct cb_compound_tag *args)
557 {
558     return xdr_u_int32_t(xdr, &args->len)
559         && args->len <= CB_COMPOUND_MAX_TAG
560         && xdr_opaque(xdr, args->str, args->len);
561 }
562 
563 static const struct xdr_discrim cb_argop_discrim[] = {
564     { OP_CB_LAYOUTRECALL,   (xdrproc_t)op_cb_layoutrecall_args },
565     { OP_CB_RECALL_SLOT,    (xdrproc_t)op_cb_recall_slot_args },
566     { OP_CB_SEQUENCE,       (xdrproc_t)op_cb_sequence_args },
567     { OP_CB_GETATTR,        (xdrproc_t)op_cb_getattr_args },
568     { OP_CB_RECALL,         (xdrproc_t)op_cb_recall_args },
569     { OP_CB_NOTIFY,         (xdrproc_t)op_cb_notify_args },
570     { OP_CB_PUSH_DELEG,     (xdrproc_t)op_cb_push_deleg_args },
571     { OP_CB_RECALL_ANY,     (xdrproc_t)op_cb_recall_any_args },
572     { OP_CB_RECALLABLE_OBJ_AVAIL, (xdrproc_t)op_cb_recallable_obj_avail_args },
573     { OP_CB_WANTS_CANCELLED, (xdrproc_t)op_cb_wants_cancelled_args },
574     { OP_CB_NOTIFY_LOCK,     (xdrproc_t)op_cb_notify_lock_args },
575     { OP_CB_NOTIFY_DEVICEID, (xdrproc_t)op_cb_notify_deviceid_args },
576     { OP_CB_ILLEGAL,         NULL_xdrproc_t },
577 };
578 
cb_compound_argop(XDR * xdr,struct cb_argop * args)579 static bool_t cb_compound_argop(XDR *xdr, struct cb_argop *args)
580 {
581     bool_t result;
582 
583     result = xdr_union(xdr, &args->opnum, (char*)&args->args,
584         cb_argop_discrim, NULL_xdrproc_t);
585     if (!result) { CBX_ERR("cmb:argop.args"); goto out; }
586 out:
587     return result;
588 }
589 
proc_cb_compound_args(XDR * xdr,struct cb_compound_args * args)590 bool_t proc_cb_compound_args(XDR *xdr, struct cb_compound_args *args)
591 {
592     bool_t result;
593 
594     result = cb_compound_tag(xdr, &args->tag);
595     if (!result) { CBX_ERR("compound.tag"); goto out; }
596 
597     result = xdr_u_int32_t(xdr, &args->minorversion);
598     if (!result) { CBX_ERR("compound.minorversion"); goto out; }
599 
600     /* "superfluous in NFSv4.1 and MUST be ignored by the client" */
601     result = xdr_u_int32_t(xdr, &args->callback_ident);
602     if (!result) { CBX_ERR("compound.callback_ident"); goto out; }
603 
604     result = xdr_array(xdr, (char**)&args->argarray,
605         &args->argarray_count, CB_COMPOUND_MAX_OPERATIONS,
606         sizeof(struct cb_argop), (xdrproc_t)cb_compound_argop);
607     if (!result) { CBX_ERR("compound.argarray"); goto out; }
608 out:
609     return result;
610 }
611 
612 static const struct xdr_discrim cb_resop_discrim[] = {
613     { OP_CB_LAYOUTRECALL,   (xdrproc_t)op_cb_layoutrecall_res },
614     { OP_CB_RECALL_SLOT,    (xdrproc_t)op_cb_recall_slot_res },
615     { OP_CB_SEQUENCE,       (xdrproc_t)op_cb_sequence_res },
616     { OP_CB_GETATTR,        (xdrproc_t)op_cb_getattr_res },
617     { OP_CB_RECALL,         (xdrproc_t)op_cb_recall_res },
618     { OP_CB_NOTIFY,         (xdrproc_t)op_cb_notify_res },
619     { OP_CB_PUSH_DELEG,     (xdrproc_t)op_cb_push_deleg_res },
620     { OP_CB_RECALL_ANY,     (xdrproc_t)op_cb_recall_any_res },
621     { OP_CB_RECALLABLE_OBJ_AVAIL, (xdrproc_t)op_cb_recallable_obj_avail_res },
622     { OP_CB_WANTS_CANCELLED, (xdrproc_t)op_cb_wants_cancelled_res },
623     { OP_CB_NOTIFY_LOCK,     (xdrproc_t)op_cb_notify_lock_res },
624     { OP_CB_NOTIFY_DEVICEID, (xdrproc_t)op_cb_notify_deviceid_res },
625     { OP_CB_ILLEGAL,         NULL_xdrproc_t },
626 };
627 
cb_compound_resop(XDR * xdr,struct cb_resop * res)628 static bool_t cb_compound_resop(XDR *xdr, struct cb_resop *res)
629 {
630     /* save xdr encode/decode status to see which operation failed */
631     res->xdr_ok = xdr_union(xdr, &res->opnum, (char*)&res->res,
632         cb_resop_discrim, NULL_xdrproc_t);
633     if (!res->xdr_ok) { CBX_ERR("resop.res"); goto out; }
634 out:
635     return res->xdr_ok;
636 }
637 
proc_cb_compound_res(XDR * xdr,struct cb_compound_res * res)638 bool_t proc_cb_compound_res(XDR *xdr, struct cb_compound_res *res)
639 {
640     bool_t result;
641 
642     if (res == NULL)
643         return TRUE;
644 
645     result = xdr_enum(xdr, &res->status);
646     if (!result) { CBX_ERR("compound_res.status"); goto out; }
647 
648     result = cb_compound_tag(xdr, &res->tag);
649     if (!result) { CBX_ERR("compound_res.tag"); goto out; }
650 
651     result = xdr_array(xdr, (char**)&res->resarray,
652         &res->resarray_count, CB_COMPOUND_MAX_OPERATIONS,
653         sizeof(struct cb_resop), (xdrproc_t)cb_compound_resop);
654     if (!result) { CBX_ERR("compound_res.resarray"); goto out; }
655 out:
656     if (xdr->x_op == XDR_FREE)
657         free(res);
658     return result;
659 }
660