summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Brown <neilb@cse.unsw.edu.au>2004-06-26 20:58:19 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-06-26 20:58:19 -0700
commit7a9eaffa9ae8beab1127636546367159feda5820 (patch)
treeccaedd986eec21d1009df3e7b10f6e8bea9b57d4
parent0bf213ab44a4ecebf41b453a9422a008c7048486 (diff)
[PATCH] knfsd: parse nsfd4 callback information
Preparation for delegations: parse callback information provided in setclientid request. From: Andy Adamson <andros@citi.umich.edu> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/nfsd/nfs4state.c94
-rw-r--r--include/linux/nfsd/state.h18
2 files changed, 111 insertions, 1 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fd441850ef79..11602e6501f4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -339,6 +339,95 @@ move_to_confirmed(struct nfs4_client *clp, unsigned int idhashval)
renew_client(clp);
}
+
+/* a helper function for parse_callback */
+static int
+parse_octet(unsigned int *lenp, char **addrp)
+{
+ unsigned int len = *lenp;
+ char *p = *addrp;
+ int n = -1;
+ char c;
+
+ for (;;) {
+ if (!len)
+ break;
+ len--;
+ c = *p++;
+ if (c == '.')
+ break;
+ if ((c < '0') || (c > '9')) {
+ n = -1;
+ break;
+ }
+ if (n < 0)
+ n = 0;
+ n = (n * 10) + (c - '0');
+ if (n > 255) {
+ n = -1;
+ break;
+ }
+ }
+ *lenp = len;
+ *addrp = p;
+ return n;
+}
+
+/* parse and set the setclientid ipv4 callback address */
+int
+parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp)
+{
+ int temp = 0;
+ u32 cbaddr = 0;
+ u16 cbport = 0;
+ u32 addrlen = addr_len;
+ char *addr = addr_val;
+ int i, shift;
+
+ /* ipaddress */
+ shift = 24;
+ for(i = 4; i > 0 ; i--) {
+ if ((temp = parse_octet(&addrlen, &addr)) < 0) {
+ return 0;
+ }
+ cbaddr |= (temp << shift);
+ if(shift > 0)
+ shift -= 8;
+ }
+ *cbaddrp = cbaddr;
+
+ /* port */
+ shift = 8;
+ for(i = 2; i > 0 ; i--) {
+ if ((temp = parse_octet(&addrlen, &addr)) < 0) {
+ return 0;
+ }
+ cbport |= (temp << shift);
+ if(shift > 0)
+ shift -= 8;
+ }
+ *cbportp = cbport;
+ return 1;
+}
+
+void
+gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
+{
+ struct nfs4_callback *cb = &clp->cl_callback;
+
+ if( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val,
+ &cb->cb_addr, &cb->cb_port))) {
+ printk(KERN_INFO "NFSD: BAD callback address. client will not receive delegations\n");
+ cb->cb_parsed = 0;
+ return;
+ }
+ cb->cb_netid.len = se->se_callback_netid_len;
+ cb->cb_netid.data = se->se_callback_netid_val;
+ cb->cb_prog = se->se_callback_prog;
+ cb->cb_ident = se->se_callback_ident;
+ cb->cb_parsed = 1;
+}
+
/*
* RFC 3010 has a complex implmentation description of processing a
* SETCLIENTID request consisting of 5 bullets, labeled as
@@ -450,6 +539,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
copy_cred(&new->cl_cred,&rqstp->rq_cred);
gen_clid(new);
gen_confirm(new);
+ gen_callback(new, setclid);
add_to_unconfirmed(new, strhashval);
} else if (cmp_verf(&conf->cl_verifier, &clverifier)) {
/*
@@ -477,6 +567,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
copy_cred(&new->cl_cred,&rqstp->rq_cred);
copy_clid(new, conf);
gen_confirm(new);
+ gen_callback(new, setclid);
add_to_unconfirmed(new,strhashval);
} else if (!unconf) {
/*
@@ -494,6 +585,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
copy_cred(&new->cl_cred,&rqstp->rq_cred);
gen_clid(new);
gen_confirm(new);
+ gen_callback(new, setclid);
add_to_unconfirmed(new, strhashval);
} else if (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
/*
@@ -519,6 +611,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
copy_cred(&new->cl_cred,&rqstp->rq_cred);
gen_clid(new);
gen_confirm(new);
+ gen_callback(new, setclid);
add_to_unconfirmed(new, strhashval);
} else {
/* No cases hit !!! */
@@ -529,7 +622,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
- printk(KERN_INFO "NFSD: this client will not receive delegations\n");
status = nfs_ok;
out:
nfs4_unlock_state();
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 06da18506122..51d00f6ebf97 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -38,6 +38,7 @@
#define _NFSD4_STATE_H
#include <linux/list.h>
+#include <linux/sunrpc/clnt.h>
#define NFS4_OPAQUE_LIMIT 1024
typedef struct {
@@ -65,6 +66,22 @@ extern stateid_t onestateid;
#define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
#define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
+/* client delegation callback info */
+struct nfs4_callback {
+ /* SETCLIENTID info */
+ u32 cb_parsed; /* addr parsed */
+ u32 cb_addr;
+ unsigned short cb_port;
+ u32 cb_prog;
+ u32 cb_ident;
+ struct xdr_netobj cb_netid;
+ /* RPC client info */
+ u32 cb_set; /* successful CB_NULL call */
+ struct rpc_program cb_program;
+ struct rpc_stat cb_stat;
+ struct rpc_clnt * cb_client;
+};
+
/*
* struct nfs4_client - one per client. Clientids live here.
* o Each nfs4_client is hashed by clientid.
@@ -87,6 +104,7 @@ struct nfs4_client {
struct svc_cred cl_cred; /* setclientid principal */
clientid_t cl_clientid; /* generated by server */
nfs4_verifier cl_confirm; /* generated by server */
+ struct nfs4_callback cl_callback; /* callback info */
};
static inline void