Keep around a list of sequence numbers so the client can better handle the case where a there are several retransmissions before the server responds to the original request. diff -puN include/linux/sunrpc/sched.h~clnt-remember-more-seqnos include/linux/sunrpc/sched.h diff -puN net/sunrpc/auth_gss/auth_gss.c~clnt-remember-more-seqnos net/sunrpc/auth_gss/auth_gss.c --- linux-2.5.72/net/sunrpc/auth_gss/auth_gss.c~clnt-remember-more-seqnos 2003-06-19 18:38:57.000000000 -0400 +++ linux-2.5.72-bfields/net/sunrpc/auth_gss/auth_gss.c 2003-06-19 18:38:57.000000000 -0400 @@ -592,6 +592,15 @@ gss_match(struct auth_cred *acred, struc return (rc->cr_uid == acred->uid); } +static void +shift_seqnos(u32 *seqnos) +{ + int i; + + for (i=1; i < GSS_SEQNO_CACHE; i++) + seqnos[i] = seqnos[i-1]; +} + /* * Marshal credentials. * Maybe we should keep a cached credential for performance reasons. @@ -622,13 +631,14 @@ gss_marshal(struct rpc_task *task, u32 * gss_cred->gc_flavor); goto out_put_ctx; } + shift_seqnos(req->rq_seqnos); spin_lock(&ctx->gc_seq_lock); - req->rq_seqno = ctx->gc_seq++; + req->rq_seqnos[0] = ctx->gc_seq++; spin_unlock(&ctx->gc_seq_lock); *p++ = htonl((u32) RPC_GSS_VERSION); *p++ = htonl((u32) ctx->gc_proc); - *p++ = htonl((u32) req->rq_seqno); + *p++ = htonl((u32) req->rq_seqnos[0]); *p++ = htonl((u32) service); p = xdr_encode_netobj(p, &ctx->gc_wire_ctx); *cred_len = htonl((p - (cred_len + 1)) << 2); @@ -682,6 +692,32 @@ out: return err; } +static int +verify_checksum(struct gss_ctx *ctx, struct xdr_netobj *mic, u32 *seqnos) +{ + u32 seq, qop_state; + struct xdr_buf verf_buf; + struct iovec iov; + int i; + + for (i=0; i < GSS_SEQNO_CACHE; i++) { + if (i && !seqnos[i]) + goto fail; + seq = htonl(seqnos[i]); + iov.iov_base = &seq; + iov.iov_len = sizeof(seq); + xdr_buf_from_iov(&iov, &verf_buf); + if (!gss_verify_mic(ctx, &verf_buf, mic, &qop_state)) + goto success; + } +fail: + return -1; +success: + /* So unwrap knows which seqno we used: */ + seqnos[0] = seqnos[i]; + return 0; +} + static u32 * gss_validate(struct rpc_task *task, u32 *p) { @@ -689,9 +725,6 @@ gss_validate(struct rpc_task *task, u32 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); - u32 seq, qop_state; - struct iovec iov; - struct xdr_buf verf_buf; struct xdr_netobj mic; u32 flav,len; u32 service; @@ -705,14 +738,9 @@ gss_validate(struct rpc_task *task, u32 if (flav != RPC_AUTH_GSS) goto out; - seq = htonl(task->tk_rqstp->rq_seqno); - iov.iov_base = &seq; - iov.iov_len = sizeof(seq); - xdr_buf_from_iov(&iov, &verf_buf); mic.data = (u8 *)p; mic.len = len; - - if (gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic, &qop_state)) + if (verify_checksum(ctx->gc_gss_ctx, &mic, task->tk_rqstp->rq_seqnos)) goto out; service = gss_pseudoflavor_to_service(gss_cred->gc_flavor); switch (service) { @@ -771,7 +799,7 @@ gss_wrap_req(struct rpc_task *task, integ_len = p++; offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; - *p++ = htonl(req->rq_seqno); + *p++ = htonl(req->rq_seqnos[0]); status = encode(rqstp, p, obj); if (status) @@ -847,7 +875,7 @@ gss_unwrap_resp(struct rpc_task *task, mic_offset = integ_len + data_offset; if (mic_offset > rcv_buf->len) goto out; - if (ntohl(*p++) != req->rq_seqno) + if (ntohl(*p++) != req->rq_seqnos[0]) goto out; if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, diff -puN net/sunrpc/xprt.c~clnt-remember-more-seqnos net/sunrpc/xprt.c --- linux-2.5.72/net/sunrpc/xprt.c~clnt-remember-more-seqnos 2003-06-19 18:38:57.000000000 -0400 +++ linux-2.5.72-bfields/net/sunrpc/xprt.c 2003-06-19 18:38:57.000000000 -0400 @@ -1312,6 +1312,7 @@ xprt_request_init(struct rpc_task *task, req->rq_task = task; req->rq_xprt = xprt; req->rq_xid = xprt_alloc_xid(); + memset(req->rq_seqnos, 0, sizeof(req->rq_seqnos)); INIT_LIST_HEAD(&req->rq_list); dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, req->rq_xid); diff -puN include/linux/sunrpc/xprt.h~clnt-remember-more-seqnos include/linux/sunrpc/xprt.h --- linux-2.5.72/include/linux/sunrpc/xprt.h~clnt-remember-more-seqnos 2003-06-19 18:38:57.000000000 -0400 +++ linux-2.5.72-bfields/include/linux/sunrpc/xprt.h 2003-06-19 18:38:57.000000000 -0400 @@ -95,7 +95,9 @@ struct rpc_rqst { struct rpc_rqst * rq_next; /* free list */ int rq_cong; /* has incremented xprt->cong */ int rq_received; /* receive completed */ - u32 rq_seqno; /* gss seq no. used on req. */ +#define GSS_SEQNO_CACHE 4 + u32 rq_seqnos[GSS_SEQNO_CACHE]; + /* gss seq no.s used on req. */ struct list_head rq_list; _