linux/fs/nfs/callback_xdr.c
<<
>>
Prefs
   1/*
   2 * linux/fs/nfs/callback_xdr.c
   3 *
   4 * Copyright (C) 2004 Trond Myklebust
   5 *
   6 * NFSv4 callback encode/decode procedures
   7 */
   8#include <linux/kernel.h>
   9#include <linux/sunrpc/svc.h>
  10#include <linux/nfs4.h>
  11#include <linux/nfs_fs.h>
  12#include <linux/ratelimit.h>
  13#include <linux/printk.h>
  14#include <linux/slab.h>
  15#include <linux/sunrpc/bc_xprt.h>
  16#include "nfs4_fs.h"
  17#include "callback.h"
  18#include "internal.h"
  19#include "nfs4session.h"
  20
  21#define CB_OP_TAGLEN_MAXSZ              (512)
  22#define CB_OP_HDR_RES_MAXSZ             (2 * 4) // opcode, status
  23#define CB_OP_GETATTR_BITMAP_MAXSZ      (4 * 4) // bitmap length, 3 bitmaps
  24#define CB_OP_GETATTR_RES_MAXSZ         (CB_OP_HDR_RES_MAXSZ + \
  25                                         CB_OP_GETATTR_BITMAP_MAXSZ + \
  26                                         /* change, size, ctime, mtime */\
  27                                         (2 + 2 + 3 + 3) * 4)
  28#define CB_OP_RECALL_RES_MAXSZ          (CB_OP_HDR_RES_MAXSZ)
  29
  30#if defined(CONFIG_NFS_V4_1)
  31#define CB_OP_LAYOUTRECALL_RES_MAXSZ    (CB_OP_HDR_RES_MAXSZ)
  32#define CB_OP_DEVICENOTIFY_RES_MAXSZ    (CB_OP_HDR_RES_MAXSZ)
  33#define CB_OP_SEQUENCE_RES_MAXSZ        (CB_OP_HDR_RES_MAXSZ + \
  34                                         NFS4_MAX_SESSIONID_LEN + \
  35                                         (1 + 3) * 4) // seqid, 3 slotids
  36#define CB_OP_RECALLANY_RES_MAXSZ       (CB_OP_HDR_RES_MAXSZ)
  37#define CB_OP_RECALLSLOT_RES_MAXSZ      (CB_OP_HDR_RES_MAXSZ)
  38#endif /* CONFIG_NFS_V4_1 */
  39
  40#define NFSDBG_FACILITY NFSDBG_CALLBACK
  41
  42/* Internal error code */
  43#define NFS4ERR_RESOURCE_HDR    11050
  44
  45typedef __be32 (*callback_process_op_t)(void *, void *,
  46                                        struct cb_process_state *);
  47typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
  48typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
  49
  50
  51struct callback_op {
  52        callback_process_op_t process_op;
  53        callback_decode_arg_t decode_args;
  54        callback_encode_res_t encode_res;
  55        long res_maxsize;
  56};
  57
  58static struct callback_op callback_ops[];
  59
  60static __be32 nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
  61{
  62        return htonl(NFS4_OK);
  63}
  64
  65static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
  66{
  67        return xdr_argsize_check(rqstp, p);
  68}
  69
  70static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
  71{
  72        return xdr_ressize_check(rqstp, p);
  73}
  74
  75static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)
  76{
  77        __be32 *p;
  78
  79        p = xdr_inline_decode(xdr, nbytes);
  80        if (unlikely(p == NULL))
  81                printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n");
  82        return p;
  83}
  84
  85static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
  86{
  87        __be32 *p;
  88
  89        p = read_buf(xdr, 4);
  90        if (unlikely(p == NULL))
  91                return htonl(NFS4ERR_RESOURCE);
  92        *len = ntohl(*p);
  93
  94        if (*len != 0) {
  95                p = read_buf(xdr, *len);
  96                if (unlikely(p == NULL))
  97                        return htonl(NFS4ERR_RESOURCE);
  98                *str = (const char *)p;
  99        } else
 100                *str = NULL;
 101
 102        return 0;
 103}
 104
 105static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
 106{
 107        __be32 *p;
 108
 109        p = read_buf(xdr, 4);
 110        if (unlikely(p == NULL))
 111                return htonl(NFS4ERR_RESOURCE);
 112        fh->size = ntohl(*p);
 113        if (fh->size > NFS4_FHSIZE)
 114                return htonl(NFS4ERR_BADHANDLE);
 115        p = read_buf(xdr, fh->size);
 116        if (unlikely(p == NULL))
 117                return htonl(NFS4ERR_RESOURCE);
 118        memcpy(&fh->data[0], p, fh->size);
 119        memset(&fh->data[fh->size], 0, sizeof(fh->data) - fh->size);
 120        return 0;
 121}
 122
 123static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
 124{
 125        __be32 *p;
 126        unsigned int attrlen;
 127
 128        p = read_buf(xdr, 4);
 129        if (unlikely(p == NULL))
 130                return htonl(NFS4ERR_RESOURCE);
 131        attrlen = ntohl(*p);
 132        p = read_buf(xdr, attrlen << 2);
 133        if (unlikely(p == NULL))
 134                return htonl(NFS4ERR_RESOURCE);
 135        if (likely(attrlen > 0))
 136                bitmap[0] = ntohl(*p++);
 137        if (attrlen > 1)
 138                bitmap[1] = ntohl(*p);
 139        return 0;
 140}
 141
 142static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
 143{
 144        __be32 *p;
 145
 146        p = read_buf(xdr, NFS4_STATEID_SIZE);
 147        if (unlikely(p == NULL))
 148                return htonl(NFS4ERR_RESOURCE);
 149        memcpy(stateid->data, p, NFS4_STATEID_SIZE);
 150        return 0;
 151}
 152
 153static __be32 decode_delegation_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
 154{
 155        stateid->type = NFS4_DELEGATION_STATEID_TYPE;
 156        return decode_stateid(xdr, stateid);
 157}
 158
 159static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr)
 160{
 161        __be32 *p;
 162        __be32 status;
 163
 164        status = decode_string(xdr, &hdr->taglen, &hdr->tag);
 165        if (unlikely(status != 0))
 166                return status;
 167        /* We do not like overly long tags! */
 168        if (hdr->taglen > CB_OP_TAGLEN_MAXSZ) {
 169                printk("NFS: NFSv4 CALLBACK %s: client sent tag of length %u\n",
 170                                __func__, hdr->taglen);
 171                return htonl(NFS4ERR_RESOURCE);
 172        }
 173        p = read_buf(xdr, 12);
 174        if (unlikely(p == NULL))
 175                return htonl(NFS4ERR_RESOURCE);
 176        hdr->minorversion = ntohl(*p++);
 177        /* Check for minor version support */
 178        if (hdr->minorversion <= NFS4_MAX_MINOR_VERSION) {
 179                hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 and v4.2 */
 180        } else {
 181                pr_warn_ratelimited("NFS: %s: NFSv4 server callback with "
 182                        "illegal minor version %u!\n",
 183                        __func__, hdr->minorversion);
 184                return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
 185        }
 186        hdr->nops = ntohl(*p);
 187        dprintk("%s: minorversion %d nops %d\n", __func__,
 188                hdr->minorversion, hdr->nops);
 189        return 0;
 190}
 191
 192static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
 193{
 194        __be32 *p;
 195        p = read_buf(xdr, 4);
 196        if (unlikely(p == NULL))
 197                return htonl(NFS4ERR_RESOURCE_HDR);
 198        *op = ntohl(*p);
 199        return 0;
 200}
 201
 202static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
 203{
 204        __be32 status;
 205
 206        status = decode_fh(xdr, &args->fh);
 207        if (unlikely(status != 0))
 208                goto out;
 209        status = decode_bitmap(xdr, args->bitmap);
 210out:
 211        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
 212        return status;
 213}
 214
 215static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
 216{
 217        __be32 *p;
 218        __be32 status;
 219
 220        status = decode_delegation_stateid(xdr, &args->stateid);
 221        if (unlikely(status != 0))
 222                goto out;
 223        p = read_buf(xdr, 4);
 224        if (unlikely(p == NULL)) {
 225                status = htonl(NFS4ERR_RESOURCE);
 226                goto out;
 227        }
 228        args->truncate = ntohl(*p);
 229        status = decode_fh(xdr, &args->fh);
 230out:
 231        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
 232        return status;
 233}
 234
 235#if defined(CONFIG_NFS_V4_1)
 236static __be32 decode_layout_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
 237{
 238        stateid->type = NFS4_LAYOUT_STATEID_TYPE;
 239        return decode_stateid(xdr, stateid);
 240}
 241
 242static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp,
 243                                       struct xdr_stream *xdr,
 244                                       struct cb_layoutrecallargs *args)
 245{
 246        __be32 *p;
 247        __be32 status = 0;
 248        uint32_t iomode;
 249
 250        p = read_buf(xdr, 4 * sizeof(uint32_t));
 251        if (unlikely(p == NULL)) {
 252                status = htonl(NFS4ERR_BADXDR);
 253                goto out;
 254        }
 255
 256        args->cbl_layout_type = ntohl(*p++);
 257        /* Depite the spec's xdr, iomode really belongs in the FILE switch,
 258         * as it is unusable and ignored with the other types.
 259         */
 260        iomode = ntohl(*p++);
 261        args->cbl_layoutchanged = ntohl(*p++);
 262        args->cbl_recall_type = ntohl(*p++);
 263
 264        if (args->cbl_recall_type == RETURN_FILE) {
 265                args->cbl_range.iomode = iomode;
 266                status = decode_fh(xdr, &args->cbl_fh);
 267                if (unlikely(status != 0))
 268                        goto out;
 269
 270                p = read_buf(xdr, 2 * sizeof(uint64_t));
 271                if (unlikely(p == NULL)) {
 272                        status = htonl(NFS4ERR_BADXDR);
 273                        goto out;
 274                }
 275                p = xdr_decode_hyper(p, &args->cbl_range.offset);
 276                p = xdr_decode_hyper(p, &args->cbl_range.length);
 277                status = decode_layout_stateid(xdr, &args->cbl_stateid);
 278                if (unlikely(status != 0))
 279                        goto out;
 280        } else if (args->cbl_recall_type == RETURN_FSID) {
 281                p = read_buf(xdr, 2 * sizeof(uint64_t));
 282                if (unlikely(p == NULL)) {
 283                        status = htonl(NFS4ERR_BADXDR);
 284                        goto out;
 285                }
 286                p = xdr_decode_hyper(p, &args->cbl_fsid.major);
 287                p = xdr_decode_hyper(p, &args->cbl_fsid.minor);
 288        } else if (args->cbl_recall_type != RETURN_ALL) {
 289                status = htonl(NFS4ERR_BADXDR);
 290                goto out;
 291        }
 292        dprintk("%s: ltype 0x%x iomode %d changed %d recall_type %d\n",
 293                __func__,
 294                args->cbl_layout_type, iomode,
 295                args->cbl_layoutchanged, args->cbl_recall_type);
 296out:
 297        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
 298        return status;
 299}
 300
 301static
 302__be32 decode_devicenotify_args(struct svc_rqst *rqstp,
 303                                struct xdr_stream *xdr,
 304                                struct cb_devicenotifyargs *args)
 305{
 306        __be32 *p;
 307        __be32 status = 0;
 308        u32 tmp;
 309        int n, i;
 310        args->ndevs = 0;
 311
 312        /* Num of device notifications */
 313        p = read_buf(xdr, sizeof(uint32_t));
 314        if (unlikely(p == NULL)) {
 315                status = htonl(NFS4ERR_BADXDR);
 316                goto out;
 317        }
 318        n = ntohl(*p++);
 319        if (n <= 0)
 320                goto out;
 321        if (n > ULONG_MAX / sizeof(*args->devs)) {
 322                status = htonl(NFS4ERR_BADXDR);
 323                goto out;
 324        }
 325
 326        args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL);
 327        if (!args->devs) {
 328                status = htonl(NFS4ERR_DELAY);
 329                goto out;
 330        }
 331
 332        /* Decode each dev notification */
 333        for (i = 0; i < n; i++) {
 334                struct cb_devicenotifyitem *dev = &args->devs[i];
 335
 336                p = read_buf(xdr, (4 * sizeof(uint32_t)) + NFS4_DEVICEID4_SIZE);
 337                if (unlikely(p == NULL)) {
 338                        status = htonl(NFS4ERR_BADXDR);
 339                        goto err;
 340                }
 341
 342                tmp = ntohl(*p++);      /* bitmap size */
 343                if (tmp != 1) {
 344                        status = htonl(NFS4ERR_INVAL);
 345                        goto err;
 346                }
 347                dev->cbd_notify_type = ntohl(*p++);
 348                if (dev->cbd_notify_type != NOTIFY_DEVICEID4_CHANGE &&
 349                    dev->cbd_notify_type != NOTIFY_DEVICEID4_DELETE) {
 350                        status = htonl(NFS4ERR_INVAL);
 351                        goto err;
 352                }
 353
 354                tmp = ntohl(*p++);      /* opaque size */
 355                if (((dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE) &&
 356                     (tmp != NFS4_DEVICEID4_SIZE + 8)) ||
 357                    ((dev->cbd_notify_type == NOTIFY_DEVICEID4_DELETE) &&
 358                     (tmp != NFS4_DEVICEID4_SIZE + 4))) {
 359                        status = htonl(NFS4ERR_INVAL);
 360                        goto err;
 361                }
 362                dev->cbd_layout_type = ntohl(*p++);
 363                memcpy(dev->cbd_dev_id.data, p, NFS4_DEVICEID4_SIZE);
 364                p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
 365
 366                if (dev->cbd_layout_type == NOTIFY_DEVICEID4_CHANGE) {
 367                        p = read_buf(xdr, sizeof(uint32_t));
 368                        if (unlikely(p == NULL)) {
 369                                status = htonl(NFS4ERR_BADXDR);
 370                                goto err;
 371                        }
 372                        dev->cbd_immediate = ntohl(*p++);
 373                } else {
 374                        dev->cbd_immediate = 0;
 375                }
 376
 377                args->ndevs++;
 378
 379                dprintk("%s: type %d layout 0x%x immediate %d\n",
 380                        __func__, dev->cbd_notify_type, dev->cbd_layout_type,
 381                        dev->cbd_immediate);
 382        }
 383out:
 384        dprintk("%s: status %d ndevs %d\n",
 385                __func__, ntohl(status), args->ndevs);
 386        return status;
 387err:
 388        kfree(args->devs);
 389        goto out;
 390}
 391
 392static __be32 decode_sessionid(struct xdr_stream *xdr,
 393                                 struct nfs4_sessionid *sid)
 394{
 395        __be32 *p;
 396
 397        p = read_buf(xdr, NFS4_MAX_SESSIONID_LEN);
 398        if (unlikely(p == NULL))
 399                return htonl(NFS4ERR_RESOURCE);
 400
 401        memcpy(sid->data, p, NFS4_MAX_SESSIONID_LEN);
 402        return 0;
 403}
 404
 405static __be32 decode_rc_list(struct xdr_stream *xdr,
 406                               struct referring_call_list *rc_list)
 407{
 408        __be32 *p;
 409        int i;
 410        __be32 status;
 411
 412        status = decode_sessionid(xdr, &rc_list->rcl_sessionid);
 413        if (status)
 414                goto out;
 415
 416        status = htonl(NFS4ERR_RESOURCE);
 417        p = read_buf(xdr, sizeof(uint32_t));
 418        if (unlikely(p == NULL))
 419                goto out;
 420
 421        rc_list->rcl_nrefcalls = ntohl(*p++);
 422        if (rc_list->rcl_nrefcalls) {
 423                p = read_buf(xdr,
 424                             rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t));
 425                if (unlikely(p == NULL))
 426                        goto out;
 427                rc_list->rcl_refcalls = kmalloc_array(rc_list->rcl_nrefcalls,
 428                                                sizeof(*rc_list->rcl_refcalls),
 429                                                GFP_KERNEL);
 430                if (unlikely(rc_list->rcl_refcalls == NULL))
 431                        goto out;
 432                for (i = 0; i < rc_list->rcl_nrefcalls; i++) {
 433                        rc_list->rcl_refcalls[i].rc_sequenceid = ntohl(*p++);
 434                        rc_list->rcl_refcalls[i].rc_slotid = ntohl(*p++);
 435                }
 436        }
 437        status = 0;
 438
 439out:
 440        return status;
 441}
 442
 443static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp,
 444                                        struct xdr_stream *xdr,
 445                                        struct cb_sequenceargs *args)
 446{
 447        __be32 *p;
 448        int i;
 449        __be32 status;
 450
 451        status = decode_sessionid(xdr, &args->csa_sessionid);
 452        if (status)
 453                goto out;
 454
 455        status = htonl(NFS4ERR_RESOURCE);
 456        p = read_buf(xdr, 5 * sizeof(uint32_t));
 457        if (unlikely(p == NULL))
 458                goto out;
 459
 460        args->csa_addr = svc_addr(rqstp);
 461        args->csa_sequenceid = ntohl(*p++);
 462        args->csa_slotid = ntohl(*p++);
 463        args->csa_highestslotid = ntohl(*p++);
 464        args->csa_cachethis = ntohl(*p++);
 465        args->csa_nrclists = ntohl(*p++);
 466        args->csa_rclists = NULL;
 467        if (args->csa_nrclists) {
 468                args->csa_rclists = kmalloc_array(args->csa_nrclists,
 469                                                  sizeof(*args->csa_rclists),
 470                                                  GFP_KERNEL);
 471                if (unlikely(args->csa_rclists == NULL))
 472                        goto out;
 473
 474                for (i = 0; i < args->csa_nrclists; i++) {
 475                        status = decode_rc_list(xdr, &args->csa_rclists[i]);
 476                        if (status) {
 477                                args->csa_nrclists = i;
 478                                goto out_free;
 479                        }
 480                }
 481        }
 482        status = 0;
 483
 484        dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u slotid %u "
 485                "highestslotid %u cachethis %d nrclists %u\n",
 486                __func__,
 487                ((u32 *)&args->csa_sessionid)[0],
 488                ((u32 *)&args->csa_sessionid)[1],
 489                ((u32 *)&args->csa_sessionid)[2],
 490                ((u32 *)&args->csa_sessionid)[3],
 491                args->csa_sequenceid, args->csa_slotid,
 492                args->csa_highestslotid, args->csa_cachethis,
 493                args->csa_nrclists);
 494out:
 495        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
 496        return status;
 497
 498out_free:
 499        for (i = 0; i < args->csa_nrclists; i++)
 500                kfree(args->csa_rclists[i].rcl_refcalls);
 501        kfree(args->csa_rclists);
 502        goto out;
 503}
 504
 505static __be32 decode_recallany_args(struct svc_rqst *rqstp,
 506                                      struct xdr_stream *xdr,
 507                                      struct cb_recallanyargs *args)
 508{
 509        uint32_t bitmap[2];
 510        __be32 *p, status;
 511
 512        p = read_buf(xdr, 4);
 513        if (unlikely(p == NULL))
 514                return htonl(NFS4ERR_BADXDR);
 515        args->craa_objs_to_keep = ntohl(*p++);
 516        status = decode_bitmap(xdr, bitmap);
 517        if (unlikely(status))
 518                return status;
 519        args->craa_type_mask = bitmap[0];
 520
 521        return 0;
 522}
 523
 524static __be32 decode_recallslot_args(struct svc_rqst *rqstp,
 525                                        struct xdr_stream *xdr,
 526                                        struct cb_recallslotargs *args)
 527{
 528        __be32 *p;
 529
 530        p = read_buf(xdr, 4);
 531        if (unlikely(p == NULL))
 532                return htonl(NFS4ERR_BADXDR);
 533        args->crsa_target_highest_slotid = ntohl(*p++);
 534        return 0;
 535}
 536
 537#endif /* CONFIG_NFS_V4_1 */
 538
 539static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
 540{
 541        __be32 *p;
 542
 543        p = xdr_reserve_space(xdr, 4 + len);
 544        if (unlikely(p == NULL))
 545                return htonl(NFS4ERR_RESOURCE);
 546        xdr_encode_opaque(p, str, len);
 547        return 0;
 548}
 549
 550#define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE)
 551#define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY)
 552static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, __be32 **savep)
 553{
 554        __be32 bm[2];
 555        __be32 *p;
 556
 557        bm[0] = htonl(bitmap[0] & CB_SUPPORTED_ATTR0);
 558        bm[1] = htonl(bitmap[1] & CB_SUPPORTED_ATTR1);
 559        if (bm[1] != 0) {
 560                p = xdr_reserve_space(xdr, 16);
 561                if (unlikely(p == NULL))
 562                        return htonl(NFS4ERR_RESOURCE);
 563                *p++ = htonl(2);
 564                *p++ = bm[0];
 565                *p++ = bm[1];
 566        } else if (bm[0] != 0) {
 567                p = xdr_reserve_space(xdr, 12);
 568                if (unlikely(p == NULL))
 569                        return htonl(NFS4ERR_RESOURCE);
 570                *p++ = htonl(1);
 571                *p++ = bm[0];
 572        } else {
 573                p = xdr_reserve_space(xdr, 8);
 574                if (unlikely(p == NULL))
 575                        return htonl(NFS4ERR_RESOURCE);
 576                *p++ = htonl(0);
 577        }
 578        *savep = p;
 579        return 0;
 580}
 581
 582static __be32 encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change)
 583{
 584        __be32 *p;
 585
 586        if (!(bitmap[0] & FATTR4_WORD0_CHANGE))
 587                return 0;
 588        p = xdr_reserve_space(xdr, 8);
 589        if (unlikely(!p))
 590                return htonl(NFS4ERR_RESOURCE);
 591        p = xdr_encode_hyper(p, change);
 592        return 0;
 593}
 594
 595static __be32 encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size)
 596{
 597        __be32 *p;
 598
 599        if (!(bitmap[0] & FATTR4_WORD0_SIZE))
 600                return 0;
 601        p = xdr_reserve_space(xdr, 8);
 602        if (unlikely(!p))
 603                return htonl(NFS4ERR_RESOURCE);
 604        p = xdr_encode_hyper(p, size);
 605        return 0;
 606}
 607
 608static __be32 encode_attr_time(struct xdr_stream *xdr, const struct timespec *time)
 609{
 610        __be32 *p;
 611
 612        p = xdr_reserve_space(xdr, 12);
 613        if (unlikely(!p))
 614                return htonl(NFS4ERR_RESOURCE);
 615        p = xdr_encode_hyper(p, time->tv_sec);
 616        *p = htonl(time->tv_nsec);
 617        return 0;
 618}
 619
 620static __be32 encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
 621{
 622        if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA))
 623                return 0;
 624        return encode_attr_time(xdr,time);
 625}
 626
 627static __be32 encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
 628{
 629        if (!(bitmap[1] & FATTR4_WORD1_TIME_MODIFY))
 630                return 0;
 631        return encode_attr_time(xdr,time);
 632}
 633
 634static __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
 635{
 636        __be32 status;
 637
 638        hdr->status = xdr_reserve_space(xdr, 4);
 639        if (unlikely(hdr->status == NULL))
 640                return htonl(NFS4ERR_RESOURCE);
 641        status = encode_string(xdr, hdr->taglen, hdr->tag);
 642        if (unlikely(status != 0))
 643                return status;
 644        hdr->nops = xdr_reserve_space(xdr, 4);
 645        if (unlikely(hdr->nops == NULL))
 646                return htonl(NFS4ERR_RESOURCE);
 647        return 0;
 648}
 649
 650static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res)
 651{
 652        __be32 *p;
 653        
 654        p = xdr_reserve_space(xdr, 8);
 655        if (unlikely(p == NULL))
 656                return htonl(NFS4ERR_RESOURCE_HDR);
 657        *p++ = htonl(op);
 658        *p = res;
 659        return 0;
 660}
 661
 662static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
 663{
 664        __be32 *savep = NULL;
 665        __be32 status = res->status;
 666        
 667        if (unlikely(status != 0))
 668                goto out;
 669        status = encode_attr_bitmap(xdr, res->bitmap, &savep);
 670        if (unlikely(status != 0))
 671                goto out;
 672        status = encode_attr_change(xdr, res->bitmap, res->change_attr);
 673        if (unlikely(status != 0))
 674                goto out;
 675        status = encode_attr_size(xdr, res->bitmap, res->size);
 676        if (unlikely(status != 0))
 677                goto out;
 678        status = encode_attr_ctime(xdr, res->bitmap, &res->ctime);
 679        if (unlikely(status != 0))
 680                goto out;
 681        status = encode_attr_mtime(xdr, res->bitmap, &res->mtime);
 682        *savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1)));
 683out:
 684        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
 685        return status;
 686}
 687
 688#if defined(CONFIG_NFS_V4_1)
 689
 690static __be32 encode_sessionid(struct xdr_stream *xdr,
 691                                 const struct nfs4_sessionid *sid)
 692{
 693        __be32 *p;
 694
 695        p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN);
 696        if (unlikely(p == NULL))
 697                return htonl(NFS4ERR_RESOURCE);
 698
 699        memcpy(p, sid, NFS4_MAX_SESSIONID_LEN);
 700        return 0;
 701}
 702
 703static __be32 encode_cb_sequence_res(struct svc_rqst *rqstp,
 704                                       struct xdr_stream *xdr,
 705                                       const struct cb_sequenceres *res)
 706{
 707        __be32 *p;
 708        __be32 status = res->csr_status;
 709
 710        if (unlikely(status != 0))
 711                goto out;
 712
 713        status = encode_sessionid(xdr, &res->csr_sessionid);
 714        if (status)
 715                goto out;
 716
 717        p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t));
 718        if (unlikely(p == NULL))
 719                return htonl(NFS4ERR_RESOURCE);
 720
 721        *p++ = htonl(res->csr_sequenceid);
 722        *p++ = htonl(res->csr_slotid);
 723        *p++ = htonl(res->csr_highestslotid);
 724        *p++ = htonl(res->csr_target_highestslotid);
 725out:
 726        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
 727        return status;
 728}
 729
 730static __be32
 731preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
 732{
 733        if (op_nr == OP_CB_SEQUENCE) {
 734                if (nop != 0)
 735                        return htonl(NFS4ERR_SEQUENCE_POS);
 736        } else {
 737                if (nop == 0)
 738                        return htonl(NFS4ERR_OP_NOT_IN_SESSION);
 739        }
 740
 741        switch (op_nr) {
 742        case OP_CB_GETATTR:
 743        case OP_CB_RECALL:
 744        case OP_CB_SEQUENCE:
 745        case OP_CB_RECALL_ANY:
 746        case OP_CB_RECALL_SLOT:
 747        case OP_CB_LAYOUTRECALL:
 748        case OP_CB_NOTIFY_DEVICEID:
 749                *op = &callback_ops[op_nr];
 750                break;
 751
 752        case OP_CB_NOTIFY:
 753        case OP_CB_PUSH_DELEG:
 754        case OP_CB_RECALLABLE_OBJ_AVAIL:
 755        case OP_CB_WANTS_CANCELLED:
 756        case OP_CB_NOTIFY_LOCK:
 757                return htonl(NFS4ERR_NOTSUPP);
 758
 759        default:
 760                return htonl(NFS4ERR_OP_ILLEGAL);
 761        }
 762
 763        return htonl(NFS_OK);
 764}
 765
 766static void nfs4_callback_free_slot(struct nfs4_session *session,
 767                struct nfs4_slot *slot)
 768{
 769        struct nfs4_slot_table *tbl = &session->bc_slot_table;
 770
 771        spin_lock(&tbl->slot_tbl_lock);
 772        /*
 773         * Let the state manager know callback processing done.
 774         * A single slot, so highest used slotid is either 0 or -1
 775         */
 776        nfs4_free_slot(tbl, slot);
 777        nfs4_slot_tbl_drain_complete(tbl);
 778        spin_unlock(&tbl->slot_tbl_lock);
 779}
 780
 781static void nfs4_cb_free_slot(struct cb_process_state *cps)
 782{
 783        if (cps->slot) {
 784                nfs4_callback_free_slot(cps->clp->cl_session, cps->slot);
 785                cps->slot = NULL;
 786        }
 787}
 788
 789#else /* CONFIG_NFS_V4_1 */
 790
 791static __be32
 792preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
 793{
 794        return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
 795}
 796
 797static void nfs4_cb_free_slot(struct cb_process_state *cps)
 798{
 799}
 800#endif /* CONFIG_NFS_V4_1 */
 801
 802#ifdef CONFIG_NFS_V4_2
 803static __be32
 804preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op)
 805{
 806        __be32 status = preprocess_nfs41_op(nop, op_nr, op);
 807        if (status != htonl(NFS4ERR_OP_ILLEGAL))
 808                return status;
 809
 810        if (op_nr == OP_CB_OFFLOAD)
 811                return htonl(NFS4ERR_NOTSUPP);
 812        return htonl(NFS4ERR_OP_ILLEGAL);
 813}
 814#else /* CONFIG_NFS_V4_2 */
 815static __be32
 816preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op)
 817{
 818        return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
 819}
 820#endif /* CONFIG_NFS_V4_2 */
 821
 822static __be32
 823preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op)
 824{
 825        switch (op_nr) {
 826        case OP_CB_GETATTR:
 827        case OP_CB_RECALL:
 828                *op = &callback_ops[op_nr];
 829                break;
 830        default:
 831                return htonl(NFS4ERR_OP_ILLEGAL);
 832        }
 833
 834        return htonl(NFS_OK);
 835}
 836
 837static __be32 process_op(int nop, struct svc_rqst *rqstp,
 838                struct xdr_stream *xdr_in, void *argp,
 839                struct xdr_stream *xdr_out, void *resp,
 840                struct cb_process_state *cps)
 841{
 842        struct callback_op *op = &callback_ops[0];
 843        unsigned int op_nr;
 844        __be32 status;
 845        long maxlen;
 846        __be32 res;
 847
 848        dprintk("%s: start\n", __func__);
 849        status = decode_op_hdr(xdr_in, &op_nr);
 850        if (unlikely(status))
 851                return status;
 852
 853        dprintk("%s: minorversion=%d nop=%d op_nr=%u\n",
 854                __func__, cps->minorversion, nop, op_nr);
 855
 856        switch (cps->minorversion) {
 857        case 0:
 858                status = preprocess_nfs4_op(op_nr, &op);
 859                break;
 860        case 1:
 861                status = preprocess_nfs41_op(nop, op_nr, &op);
 862                break;
 863        case 2:
 864                status = preprocess_nfs42_op(nop, op_nr, &op);
 865                break;
 866        default:
 867                status = htonl(NFS4ERR_MINOR_VERS_MISMATCH);
 868        }
 869
 870        if (status == htonl(NFS4ERR_OP_ILLEGAL))
 871                op_nr = OP_CB_ILLEGAL;
 872        if (status)
 873                goto encode_hdr;
 874
 875        if (cps->drc_status) {
 876                status = cps->drc_status;
 877                goto encode_hdr;
 878        }
 879
 880        maxlen = xdr_out->end - xdr_out->p;
 881        if (maxlen > 0 && maxlen < PAGE_SIZE) {
 882                status = op->decode_args(rqstp, xdr_in, argp);
 883                if (likely(status == 0))
 884                        status = op->process_op(argp, resp, cps);
 885        } else
 886                status = htonl(NFS4ERR_RESOURCE);
 887
 888encode_hdr:
 889        res = encode_op_hdr(xdr_out, op_nr, status);
 890        if (unlikely(res))
 891                return res;
 892        if (op->encode_res != NULL && status == 0)
 893                status = op->encode_res(rqstp, xdr_out, resp);
 894        dprintk("%s: done, status = %d\n", __func__, ntohl(status));
 895        return status;
 896}
 897
 898/*
 899 * Decode, process and encode a COMPOUND
 900 */
 901static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
 902{
 903        struct cb_compound_hdr_arg hdr_arg = { 0 };
 904        struct cb_compound_hdr_res hdr_res = { NULL };
 905        struct xdr_stream xdr_in, xdr_out;
 906        __be32 *p, status;
 907        struct cb_process_state cps = {
 908                .drc_status = 0,
 909                .clp = NULL,
 910                .net = SVC_NET(rqstp),
 911        };
 912        unsigned int nops = 0;
 913
 914        dprintk("%s: start\n", __func__);
 915
 916        xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);
 917
 918        p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
 919        xdr_init_encode(&xdr_out, &rqstp->rq_res, p);
 920
 921        status = decode_compound_hdr_arg(&xdr_in, &hdr_arg);
 922        if (status == htonl(NFS4ERR_RESOURCE))
 923                return rpc_garbage_args;
 924
 925        if (hdr_arg.minorversion == 0) {
 926                cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident);
 927                if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
 928                        goto out_invalidcred;
 929        }
 930
 931        cps.minorversion = hdr_arg.minorversion;
 932        hdr_res.taglen = hdr_arg.taglen;
 933        hdr_res.tag = hdr_arg.tag;
 934        if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0)
 935                return rpc_system_err;
 936
 937        while (status == 0 && nops != hdr_arg.nops) {
 938                status = process_op(nops, rqstp, &xdr_in,
 939                                    argp, &xdr_out, resp, &cps);
 940                nops++;
 941        }
 942
 943        /* Buffer overflow in decode_ops_hdr or encode_ops_hdr. Return
 944        * resource error in cb_compound status without returning op */
 945        if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) {
 946                status = htonl(NFS4ERR_RESOURCE);
 947                nops--;
 948        }
 949
 950        *hdr_res.status = status;
 951        *hdr_res.nops = htonl(nops);
 952        nfs4_cb_free_slot(&cps);
 953        nfs_put_client(cps.clp);
 954        dprintk("%s: done, status = %u\n", __func__, ntohl(status));
 955        return rpc_success;
 956
 957out_invalidcred:
 958        pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n");
 959        return rpc_autherr_badcred;
 960}
 961
 962/*
 963 * Define NFS4 callback COMPOUND ops.
 964 */
 965static struct callback_op callback_ops[] = {
 966        [0] = {
 967                .res_maxsize = CB_OP_HDR_RES_MAXSZ,
 968        },
 969        [OP_CB_GETATTR] = {
 970                .process_op = (callback_process_op_t)nfs4_callback_getattr,
 971                .decode_args = (callback_decode_arg_t)decode_getattr_args,
 972                .encode_res = (callback_encode_res_t)encode_getattr_res,
 973                .res_maxsize = CB_OP_GETATTR_RES_MAXSZ,
 974        },
 975        [OP_CB_RECALL] = {
 976                .process_op = (callback_process_op_t)nfs4_callback_recall,
 977                .decode_args = (callback_decode_arg_t)decode_recall_args,
 978                .res_maxsize = CB_OP_RECALL_RES_MAXSZ,
 979        },
 980#if defined(CONFIG_NFS_V4_1)
 981        [OP_CB_LAYOUTRECALL] = {
 982                .process_op = (callback_process_op_t)nfs4_callback_layoutrecall,
 983                .decode_args =
 984                        (callback_decode_arg_t)decode_layoutrecall_args,
 985                .res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ,
 986        },
 987        [OP_CB_NOTIFY_DEVICEID] = {
 988                .process_op = (callback_process_op_t)nfs4_callback_devicenotify,
 989                .decode_args =
 990                        (callback_decode_arg_t)decode_devicenotify_args,
 991                .res_maxsize = CB_OP_DEVICENOTIFY_RES_MAXSZ,
 992        },
 993        [OP_CB_SEQUENCE] = {
 994                .process_op = (callback_process_op_t)nfs4_callback_sequence,
 995                .decode_args = (callback_decode_arg_t)decode_cb_sequence_args,
 996                .encode_res = (callback_encode_res_t)encode_cb_sequence_res,
 997                .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ,
 998        },
 999        [OP_CB_RECALL_ANY] = {
1000                .process_op = (callback_process_op_t)nfs4_callback_recallany,
1001                .decode_args = (callback_decode_arg_t)decode_recallany_args,
1002                .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ,
1003        },
1004        [OP_CB_RECALL_SLOT] = {
1005                .process_op = (callback_process_op_t)nfs4_callback_recallslot,
1006                .decode_args = (callback_decode_arg_t)decode_recallslot_args,
1007                .res_maxsize = CB_OP_RECALLSLOT_RES_MAXSZ,
1008        },
1009#endif /* CONFIG_NFS_V4_1 */
1010};
1011
1012/*
1013 * Define NFS4 callback procedures
1014 */
1015static struct svc_procedure nfs4_callback_procedures1[] = {
1016        [CB_NULL] = {
1017                .pc_func = nfs4_callback_null,
1018                .pc_decode = (kxdrproc_t)nfs4_decode_void,
1019                .pc_encode = (kxdrproc_t)nfs4_encode_void,
1020                .pc_xdrressize = 1,
1021        },
1022        [CB_COMPOUND] = {
1023                .pc_func = nfs4_callback_compound,
1024                .pc_encode = (kxdrproc_t)nfs4_encode_void,
1025                .pc_argsize = 256,
1026                .pc_ressize = 256,
1027                .pc_xdrressize = NFS4_CALLBACK_BUFSIZE,
1028        }
1029};
1030
1031struct svc_version nfs4_callback_version1 = {
1032        .vs_vers = 1,
1033        .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
1034        .vs_proc = nfs4_callback_procedures1,
1035        .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
1036        .vs_dispatch = NULL,
1037        .vs_hidden = 1,
1038};
1039
1040struct svc_version nfs4_callback_version4 = {
1041        .vs_vers = 4,
1042        .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
1043        .vs_proc = nfs4_callback_procedures1,
1044        .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
1045        .vs_dispatch = NULL,
1046        .vs_hidden = 1,
1047};
1048