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, ¬ify->mask)
61 && xdr_bytes(xdr, ¬ify->list, ¬ify->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(¬ify_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(¬ify_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(¬ify_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