Make sure the client gives us an adequate backchannel.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
 #include "nfsd.h"
 #include "state.h"
 #include "netns.h"
+#include "xdr4cb.h"
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
        NFSPROC4_CLNT_CB_SEQUENCE,
 };
 
-#define NFS4_MAXTAGLEN         20
-
-#define NFS4_enc_cb_null_sz            0
-#define NFS4_dec_cb_null_sz            0
-#define cb_compound_enc_hdr_sz         4
-#define cb_compound_dec_hdr_sz         (3 + (NFS4_MAXTAGLEN >> 2))
-#define sessionid_sz                   (NFS4_MAX_SESSIONID_LEN >> 2)
-#define cb_sequence_enc_sz             (sessionid_sz + 4 +             \
-                                       1 /* no referring calls list yet */)
-#define cb_sequence_dec_sz             (op_dec_sz + sessionid_sz + 4)
-
-#define op_enc_sz                      1
-#define op_dec_sz                      2
-#define enc_nfs4_fh_sz                 (1 + (NFS4_FHSIZE >> 2))
-#define enc_stateid_sz                 (NFS4_STATEID_SIZE >> 2)
-#define NFS4_enc_cb_recall_sz          (cb_compound_enc_hdr_sz +       \
-                                       cb_sequence_enc_sz +            \
-                                       1 + enc_stateid_sz +            \
-                                       enc_nfs4_fh_sz)
-
-#define NFS4_dec_cb_recall_sz          (cb_compound_dec_hdr_sz  +      \
-                                       cb_sequence_dec_sz +            \
-                                       op_dec_sz)
-
 struct nfs4_cb_compound_hdr {
        /* args */
        u32             ident;  /* minorversion 0 only */
 
 #include <linux/sunrpc/svcauth_gss.h>
 #include <linux/sunrpc/addr.h>
 #include "xdr4.h"
+#include "xdr4cb.h"
 #include "vfs.h"
 #include "current_stateid.h"
 
        return nfs_ok;
 }
 
+static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
+{
+       ca->headerpadsz = 0;
+
+       /*
+        * These RPC_MAX_HEADER macros are overkill, especially since we
+        * don't even do gss on the backchannel yet.  But this is still
+        * less than 1k.  Tighten up this estimate in the unlikely event
+        * it turns out to be a problem for some client:
+        */
+       if (ca->maxreq_sz < NFS4_enc_cb_recall_sz + RPC_MAX_HEADER_WITH_AUTH)
+               return nfserr_toosmall;
+       if (ca->maxresp_sz < NFS4_dec_cb_recall_sz + RPC_MAX_REPHEADER_WITH_AUTH)
+               return nfserr_toosmall;
+       ca->maxresp_cached = 0;
+       if (ca->maxops < 2)
+               return nfserr_toosmall;
+
+       return nfs_ok;
+}
+
 __be32
 nfsd4_create_session(struct svc_rqst *rqstp,
                     struct nfsd4_compound_state *cstate,
        if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
                return nfserr_inval;
        status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
+       if (status)
+               return status;
+       status = check_backchannel_attrs(&cr_ses->back_channel);
        if (status)
                return status;
        status = nfserr_jukebox;
 
--- /dev/null
+#define NFS4_MAXTAGLEN         20
+
+#define NFS4_enc_cb_null_sz            0
+#define NFS4_dec_cb_null_sz            0
+#define cb_compound_enc_hdr_sz         4
+#define cb_compound_dec_hdr_sz         (3 + (NFS4_MAXTAGLEN >> 2))
+#define sessionid_sz                   (NFS4_MAX_SESSIONID_LEN >> 2)
+#define cb_sequence_enc_sz             (sessionid_sz + 4 +             \
+                                       1 /* no referring calls list yet */)
+#define cb_sequence_dec_sz             (op_dec_sz + sessionid_sz + 4)
+
+#define op_enc_sz                      1
+#define op_dec_sz                      2
+#define enc_nfs4_fh_sz                 (1 + (NFS4_FHSIZE >> 2))
+#define enc_stateid_sz                 (NFS4_STATEID_SIZE >> 2)
+#define NFS4_enc_cb_recall_sz          (cb_compound_enc_hdr_sz +       \
+                                       cb_sequence_enc_sz +            \
+                                       1 + enc_stateid_sz +            \
+                                       enc_nfs4_fh_sz)
+
+#define NFS4_dec_cb_recall_sz          (cb_compound_dec_hdr_sz  +      \
+                                       cb_sequence_dec_sz +            \
+                                       op_dec_sz)
 
 #define RPC_MAX_HEADER_WITH_AUTH \
        (RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4))
 
+#define RPC_MAX_REPHEADER_WITH_AUTH \
+       (RPC_REPHDRSIZE + (2 + RPC_MAX_AUTH_SIZE/4))
+
 /*
  * RFC1833/RFC3530 rpcbind (v3+) well-known netid's.
  */