int                     (*crkey_timeout)(struct rpc_cred *);
        bool                    (*crkey_to_expire)(struct rpc_cred *);
        char *                  (*crstringify_acceptor)(struct rpc_cred *);
+       bool                    (*crneed_reencode)(struct rpc_task *);
 };
 
 extern const struct rpc_authops        authunix_ops;
 __be32 *               rpcauth_checkverf(struct rpc_task *, __be32 *);
 int                    rpcauth_wrap_req(struct rpc_task *task, kxdreproc_t encode, void *rqstp, __be32 *data, void *obj);
 int                    rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, __be32 *data, void *obj);
+bool                   rpcauth_xmit_need_reencode(struct rpc_task *task);
 int                    rpcauth_refreshcred(struct rpc_task *);
 void                   rpcauth_invalcred(struct rpc_task *);
 int                    rpcauth_uptodatecred(struct rpc_task *);
 
        refcount_t              count;
        enum rpc_gss_proc       gc_proc;
        u32                     gc_seq;
+       u32                     gc_seq_xmit;
        spinlock_t              gc_seq_lock;
        struct gss_ctx          *gc_gss_ctx;
        struct xdr_netobj       gc_wire_ctx;
 
        return rpcauth_unwrap_req_decode(decode, rqstp, data, obj);
 }
 
+bool
+rpcauth_xmit_need_reencode(struct rpc_task *task)
+{
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
+
+       if (!cred || !cred->cr_ops->crneed_reencode)
+               return false;
+       return cred->cr_ops->crneed_reencode(task);
+}
+
 int
 rpcauth_refreshcred(struct rpc_task *task)
 {
 
        return decode(rqstp, &xdr, obj);
 }
 
+static bool
+gss_seq_is_newer(u32 new, u32 old)
+{
+       return (s32)(new - old) > 0;
+}
+
+static bool
+gss_xmit_need_reencode(struct rpc_task *task)
+{
+       struct rpc_rqst *req = task->tk_rqstp;
+       struct rpc_cred *cred = req->rq_cred;
+       struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
+       u32 win, seq_xmit;
+       bool ret = true;
+
+       if (!ctx)
+               return true;
+
+       if (gss_seq_is_newer(req->rq_seqno, READ_ONCE(ctx->gc_seq)))
+               goto out;
+
+       seq_xmit = READ_ONCE(ctx->gc_seq_xmit);
+       while (gss_seq_is_newer(req->rq_seqno, seq_xmit)) {
+               u32 tmp = seq_xmit;
+
+               seq_xmit = cmpxchg(&ctx->gc_seq_xmit, tmp, req->rq_seqno);
+               if (seq_xmit == tmp) {
+                       ret = false;
+                       goto out;
+               }
+       }
+
+       win = ctx->gc_win;
+       if (win > 0)
+               ret = !gss_seq_is_newer(req->rq_seqno, seq_xmit - win);
+out:
+       gss_put_ctx(ctx);
+       return ret;
+}
+
 static int
 gss_unwrap_resp(struct rpc_task *task,
                kxdrdproc_t decode, void *rqstp, __be32 *p, void *obj)
        .crunwrap_resp          = gss_unwrap_resp,
        .crkey_timeout          = gss_key_timeout,
        .crstringify_acceptor   = gss_stringify_acceptor,
+       .crneed_reencode        = gss_xmit_need_reencode,
 };
 
 static const struct rpc_credops gss_nullops = {
 
                /* shutdown or soft timeout */
                rpc_exit(task, status);
                break;
+       case -EBADMSG:
+               task->tk_action = call_transmit;
+               break;
        default:
                if (clnt->cl_chatty)
                        printk("%s: RPC call returned error %d\n",
 
        dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen);
 
        if (!req->rq_reply_bytes_recvd) {
+
+               /* Verify that our message lies in the RPCSEC_GSS window */
+               if (!req->rq_bytes_sent && rpcauth_xmit_need_reencode(task)) {
+                       task->tk_status = -EBADMSG;
+                       return;
+               }
+
                if (list_empty(&req->rq_list) && rpc_reply_expected(task)) {
                        /*
                         * Add to the list only if we're expecting a reply