diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /include/linux/sunrpc |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'include/linux/sunrpc')
-rw-r--r-- | include/linux/sunrpc/auth.h | 149 | ||||
-rw-r--r-- | include/linux/sunrpc/auth_gss.h | 97 | ||||
-rw-r--r-- | include/linux/sunrpc/cache.h | 312 | ||||
-rw-r--r-- | include/linux/sunrpc/clnt.h | 153 | ||||
-rw-r--r-- | include/linux/sunrpc/debug.h | 99 | ||||
-rw-r--r-- | include/linux/sunrpc/gss_api.h | 122 | ||||
-rw-r--r-- | include/linux/sunrpc/gss_asn1.h | 81 | ||||
-rw-r--r-- | include/linux/sunrpc/gss_err.h | 177 | ||||
-rw-r--r-- | include/linux/sunrpc/gss_krb5.h | 148 | ||||
-rw-r--r-- | include/linux/sunrpc/gss_spkm3.h | 61 | ||||
-rw-r--r-- | include/linux/sunrpc/msg_prot.h | 80 | ||||
-rw-r--r-- | include/linux/sunrpc/rpc_pipe_fs.h | 50 | ||||
-rw-r--r-- | include/linux/sunrpc/sched.h | 273 | ||||
-rw-r--r-- | include/linux/sunrpc/stats.h | 78 | ||||
-rw-r--r-- | include/linux/sunrpc/svc.h | 306 | ||||
-rw-r--r-- | include/linux/sunrpc/svcauth.h | 167 | ||||
-rw-r--r-- | include/linux/sunrpc/svcauth_gss.h | 27 | ||||
-rw-r--r-- | include/linux/sunrpc/svcsock.h | 65 | ||||
-rw-r--r-- | include/linux/sunrpc/timer.h | 49 | ||||
-rw-r--r-- | include/linux/sunrpc/types.h | 22 | ||||
-rw-r--r-- | include/linux/sunrpc/xdr.h | 192 | ||||
-rw-r--r-- | include/linux/sunrpc/xprt.h | 232 |
22 files changed, 2940 insertions, 0 deletions
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h new file mode 100644 index 00000000000..04ebc24db34 --- /dev/null +++ b/include/linux/sunrpc/auth.h @@ -0,0 +1,149 @@ +/* + * linux/include/linux/sunrpc/auth.h + * + * Declarations for the RPC client authentication machinery. + * + * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _LINUX_SUNRPC_AUTH_H +#define _LINUX_SUNRPC_AUTH_H + +#ifdef __KERNEL__ + +#include <linux/config.h> +#include <linux/sunrpc/sched.h> +#include <linux/sunrpc/msg_prot.h> +#include <linux/sunrpc/xdr.h> + +#include <asm/atomic.h> + +/* size of the nodename buffer */ +#define UNX_MAXNODENAME 32 + +/* Maximum size (in bytes) of an rpc credential or verifier */ +#define RPC_MAX_AUTH_SIZE (400) + +/* Work around the lack of a VFS credential */ +struct auth_cred { + uid_t uid; + gid_t gid; + struct group_info *group_info; +}; + +/* + * Client user credentials + */ +struct rpc_cred { + struct hlist_node cr_hash; /* hash chain */ + struct rpc_credops * cr_ops; + unsigned long cr_expire; /* when to gc */ + atomic_t cr_count; /* ref count */ + unsigned short cr_flags; /* various flags */ +#ifdef RPC_DEBUG + unsigned long cr_magic; /* 0x0f4aa4f0 */ +#endif + + uid_t cr_uid; + + /* per-flavor data */ +}; +#define RPCAUTH_CRED_LOCKED 0x0001 +#define RPCAUTH_CRED_UPTODATE 0x0002 + +#define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 + +/* + * Client authentication handle + */ +#define RPC_CREDCACHE_NR 8 +#define RPC_CREDCACHE_MASK (RPC_CREDCACHE_NR - 1) +struct rpc_cred_cache { + struct hlist_head hashtable[RPC_CREDCACHE_NR]; + unsigned long nextgc; /* next garbage collection */ + unsigned long expire; /* cache expiry interval */ +}; + +struct rpc_auth { + unsigned int au_cslack; /* call cred size estimate */ + unsigned int au_rslack; /* reply verf size guess */ + unsigned int au_flags; /* various flags */ + struct rpc_authops * au_ops; /* operations */ + rpc_authflavor_t au_flavor; /* pseudoflavor (note may + * differ from the flavor in + * au_ops->au_flavor in gss + * case) */ + atomic_t au_count; /* Reference counter */ + + struct rpc_cred_cache * au_credcache; + /* per-flavor data */ +}; +#define RPC_AUTH_PROC_CREDS 0x0010 /* process creds (including + * uid/gid, fs[ug]id, gids) + */ + +/* + * Client authentication ops + */ +struct rpc_authops { + struct module *owner; + rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */ +#ifdef RPC_DEBUG + char * au_name; +#endif + struct rpc_auth * (*create)(struct rpc_clnt *, rpc_authflavor_t); + void (*destroy)(struct rpc_auth *); + + struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); + struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int); +}; + +struct rpc_credops { + const char * cr_name; /* Name of the auth flavour */ + void (*crdestroy)(struct rpc_cred *); + + int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); + u32 * (*crmarshal)(struct rpc_task *, u32 *); + int (*crrefresh)(struct rpc_task *); + u32 * (*crvalidate)(struct rpc_task *, u32 *); + int (*crwrap_req)(struct rpc_task *, kxdrproc_t, + void *, u32 *, void *); + int (*crunwrap_resp)(struct rpc_task *, kxdrproc_t, + void *, u32 *, void *); +}; + +extern struct rpc_authops authunix_ops; +extern struct rpc_authops authnull_ops; +#ifdef CONFIG_SUNRPC_SECURE +extern struct rpc_authops authdes_ops; +#endif + +int rpcauth_register(struct rpc_authops *); +int rpcauth_unregister(struct rpc_authops *); +struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); +void rpcauth_destroy(struct rpc_auth *); +struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); +struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); +struct rpc_cred * rpcauth_bindcred(struct rpc_task *); +void rpcauth_holdcred(struct rpc_task *); +void put_rpccred(struct rpc_cred *); +void rpcauth_unbindcred(struct rpc_task *); +u32 * rpcauth_marshcred(struct rpc_task *, u32 *); +u32 * rpcauth_checkverf(struct rpc_task *, u32 *); +int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, u32 *data, void *obj); +int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, u32 *data, void *obj); +int rpcauth_refreshcred(struct rpc_task *); +void rpcauth_invalcred(struct rpc_task *); +int rpcauth_uptodatecred(struct rpc_task *); +int rpcauth_init_credcache(struct rpc_auth *, unsigned long); +void rpcauth_free_credcache(struct rpc_auth *); + +static inline +struct rpc_cred * get_rpccred(struct rpc_cred *cred) +{ + atomic_inc(&cred->cr_count); + return cred; +} + +#endif /* __KERNEL__ */ +#endif /* _LINUX_SUNRPC_AUTH_H */ diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h new file mode 100644 index 00000000000..03084dc4bb6 --- /dev/null +++ b/include/linux/sunrpc/auth_gss.h @@ -0,0 +1,97 @@ +/* + * linux/include/linux/auth_gss.h + * + * Declarations for RPCSEC_GSS + * + * Dug Song <dugsong@monkey.org> + * Andy Adamson <andros@umich.edu> + * Bruce Fields <bfields@umich.edu> + * Copyright (c) 2000 The Regents of the University of Michigan + * + * $Id$ + */ + +#ifndef _LINUX_SUNRPC_AUTH_GSS_H +#define _LINUX_SUNRPC_AUTH_GSS_H + +#ifdef __KERNEL__ +#include <linux/sunrpc/auth.h> +#include <linux/sunrpc/svc.h> +#include <linux/sunrpc/gss_api.h> + +#define RPC_GSS_VERSION 1 + +#define MAXSEQ 0x80000000 /* maximum legal sequence number, from rfc 2203 */ + +enum rpc_gss_proc { + RPC_GSS_PROC_DATA = 0, + RPC_GSS_PROC_INIT = 1, + RPC_GSS_PROC_CONTINUE_INIT = 2, + RPC_GSS_PROC_DESTROY = 3 +}; + +enum rpc_gss_svc { + RPC_GSS_SVC_NONE = 1, + RPC_GSS_SVC_INTEGRITY = 2, + RPC_GSS_SVC_PRIVACY = 3 +}; + +/* on-the-wire gss cred: */ +struct rpc_gss_wire_cred { + u32 gc_v; /* version */ + u32 gc_proc; /* control procedure */ + u32 gc_seq; /* sequence number */ + u32 gc_svc; /* service */ + struct xdr_netobj gc_ctx; /* context handle */ +}; + +/* on-the-wire gss verifier: */ +struct rpc_gss_wire_verf { + u32 gv_flavor; + struct xdr_netobj gv_verf; +}; + +/* return from gss NULL PROC init sec context */ +struct rpc_gss_init_res { + struct xdr_netobj gr_ctx; /* context handle */ + u32 gr_major; /* major status */ + u32 gr_minor; /* minor status */ + u32 gr_win; /* sequence window */ + struct xdr_netobj gr_token; /* token */ +}; + +/* The gss_cl_ctx struct holds all the information the rpcsec_gss client + * code needs to know about a single security context. In particular, + * gc_gss_ctx is the context handle that is used to do gss-api calls, while + * gc_wire_ctx is the context handle that is used to identify the context on + * the wire when communicating with a server. */ + +struct gss_cl_ctx { + atomic_t count; + enum rpc_gss_proc gc_proc; + u32 gc_seq; + spinlock_t gc_seq_lock; + struct gss_ctx *gc_gss_ctx; + struct xdr_netobj gc_wire_ctx; + u32 gc_win; + unsigned long gc_expiry; +}; + +struct gss_upcall_msg; +struct gss_cred { + struct rpc_cred gc_base; + enum rpc_gss_svc gc_service; + struct gss_cl_ctx *gc_ctx; + struct gss_upcall_msg *gc_upcall; +}; + +#define gc_uid gc_base.cr_uid +#define gc_count gc_base.cr_count +#define gc_flags gc_base.cr_flags +#define gc_expire gc_base.cr_expire + +void print_hexl(u32 *p, u_int length, u_int offset); + +#endif /* __KERNEL__ */ +#endif /* _LINUX_SUNRPC_AUTH_GSS_H */ + diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h new file mode 100644 index 00000000000..6864063d1b9 --- /dev/null +++ b/include/linux/sunrpc/cache.h @@ -0,0 +1,312 @@ +/* + * include/linux/sunrpc/cache.h + * + * Generic code for various authentication-related caches + * used by sunrpc clients and servers. + * + * Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au> + * + * Released under terms in GPL version 2. See COPYING. + * + */ + +#ifndef _LINUX_SUNRPC_CACHE_H_ +#define _LINUX_SUNRPC_CACHE_H_ + +#include <linux/slab.h> +#include <asm/atomic.h> +#include <linux/proc_fs.h> + +/* + * Each cache requires: + * - A 'struct cache_detail' which contains information specific to the cache + * for common code to use. + * - An item structure that must contain a "struct cache_head" + * - A lookup function defined using DefineCacheLookup + * - A 'put' function that can release a cache item. It will only + * be called after cache_put has succeed, so there are guarantee + * to be no references. + * - A function to calculate a hash of an item's key. + * + * as well as assorted code fragments (e.g. compare keys) and numbers + * (e.g. hash size, goal_age, etc). + * + * Each cache must be registered so that it can be cleaned regularly. + * When the cache is unregistered, it is flushed completely. + * + * Entries have a ref count and a 'hashed' flag which counts the existance + * in the hash table. + * We only expire entries when refcount is zero. + * Existance in the cache is counted the refcount. + */ + +/* Every cache item has a common header that is used + * for expiring and refreshing entries. + * + */ +struct cache_head { + struct cache_head * next; + time_t expiry_time; /* After time time, don't use the data */ + time_t last_refresh; /* If CACHE_PENDING, this is when upcall + * was sent, else this is when update was received + */ + atomic_t refcnt; + unsigned long flags; +}; +#define CACHE_VALID 0 /* Entry contains valid data */ +#define CACHE_NEGATIVE 1 /* Negative entry - there is no match for the key */ +#define CACHE_PENDING 2 /* An upcall has been sent but no reply received yet*/ + +#define CACHE_NEW_EXPIRY 120 /* keep new things pending confirmation for 120 seconds */ + +struct cache_detail { + int hash_size; + struct cache_head ** hash_table; + rwlock_t hash_lock; + + atomic_t inuse; /* active user-space update or lookup */ + + char *name; + void (*cache_put)(struct cache_head *, + struct cache_detail*); + + void (*cache_request)(struct cache_detail *cd, + struct cache_head *h, + char **bpp, int *blen); + int (*cache_parse)(struct cache_detail *, + char *buf, int len); + + int (*cache_show)(struct seq_file *m, + struct cache_detail *cd, + struct cache_head *h); + + /* fields below this comment are for internal use + * and should not be touched by cache owners + */ + time_t flush_time; /* flush all cache items with last_refresh + * earlier than this */ + struct list_head others; + time_t nextcheck; + int entries; + + /* fields for communication over channel */ + struct list_head queue; + struct proc_dir_entry *proc_ent; + struct proc_dir_entry *flush_ent, *channel_ent, *content_ent; + + atomic_t readers; /* how many time is /chennel open */ + time_t last_close; /* if no readers, when did last close */ + time_t last_warn; /* when we last warned about no readers */ + void (*warn_no_listener)(struct cache_detail *cd); +}; + + +/* this must be embedded in any request structure that + * identifies an object that will want a callback on + * a cache fill + */ +struct cache_req { + struct cache_deferred_req *(*defer)(struct cache_req *req); +}; +/* this must be embedded in a deferred_request that is being + * delayed awaiting cache-fill + */ +struct cache_deferred_req { + struct list_head hash; /* on hash chain */ + struct list_head recent; /* on fifo */ + struct cache_head *item; /* cache item we wait on */ + time_t recv_time; + void *owner; /* we might need to discard all defered requests + * owned by someone */ + void (*revisit)(struct cache_deferred_req *req, + int too_many); +}; + +/* + * just like a template in C++, this macro does cache lookup + * for us. + * The function is passed some sort of HANDLE from which a cache_detail + * structure can be determined (via SETUP, DETAIL), a template + * cache entry (type RTN*), and a "set" flag. Using the HASHFN and the + * TEST, the function will try to find a matching cache entry in the cache. + * If "set" == 0 : + * If an entry is found, it is returned + * If no entry is found, a new non-VALID entry is created. + * If "set" == 1 and INPLACE == 0 : + * If no entry is found a new one is inserted with data from "template" + * If a non-CACHE_VALID entry is found, it is updated from template using UPDATE + * If a CACHE_VALID entry is found, a new entry is swapped in with data + * from "template" + * If set == 1, and INPLACE == 1 : + * As above, except that if a CACHE_VALID entry is found, we UPDATE in place + * instead of swapping in a new entry. + * + * If the passed handle has the CACHE_NEGATIVE flag set, then UPDATE is not + * run but insteead CACHE_NEGATIVE is set in any new item. + + * In any case, the new entry is returned with a reference count. + * + * + * RTN is a struct type for a cache entry + * MEMBER is the member of the cache which is cache_head, which must be first + * FNAME is the name for the function + * ARGS are arguments to function and must contain RTN *item, int set. May + * also contain something to be usedby SETUP or DETAIL to find cache_detail. + * SETUP locates the cache detail and makes it available as... + * DETAIL identifies the cache detail, possibly set up by SETUP + * HASHFN returns a hash value of the cache entry "item" + * TEST tests if "tmp" matches "item" + * INIT copies key information from "item" to "new" + * UPDATE copies content information from "item" to "tmp" + * INPLACE is true if updates can happen inplace rather than allocating a new structure + * + * WARNING: any substantial changes to this must be reflected in + * net/sunrpc/svcauth.c(auth_domain_lookup) + * which is a similar routine that is open-coded. + */ +#define DefineCacheLookup(RTN,MEMBER,FNAME,ARGS,SETUP,DETAIL,HASHFN,TEST,INIT,UPDATE,INPLACE) \ +RTN *FNAME ARGS \ +{ \ + RTN *tmp, *new=NULL; \ + struct cache_head **hp, **head; \ + SETUP; \ + head = &(DETAIL)->hash_table[HASHFN]; \ + retry: \ + if (set||new) write_lock(&(DETAIL)->hash_lock); \ + else read_lock(&(DETAIL)->hash_lock); \ + for(hp=head; *hp != NULL; hp = &tmp->MEMBER.next) { \ + tmp = container_of(*hp, RTN, MEMBER); \ + if (TEST) { /* found a match */ \ + \ + if (set && !INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags) && !new) \ + break; \ + \ + if (new) \ + {INIT;} \ + if (set) { \ + if (!INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\ + { /* need to swap in new */ \ + RTN *t2; \ + \ + new->MEMBER.next = tmp->MEMBER.next; \ + *hp = &new->MEMBER; \ + tmp->MEMBER.next = NULL; \ + t2 = tmp; tmp = new; new = t2; \ + } \ + if (test_bit(CACHE_NEGATIVE, &item->MEMBER.flags)) \ + set_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags); \ + else { \ + UPDATE; \ + clear_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags); \ + } \ + } \ + cache_get(&tmp->MEMBER); \ + if (set||new) write_unlock(&(DETAIL)->hash_lock); \ + else read_unlock(&(DETAIL)->hash_lock); \ + if (set) \ + cache_fresh(DETAIL, &tmp->MEMBER, item->MEMBER.expiry_time); \ + if (set && !INPLACE && new) cache_fresh(DETAIL, &new->MEMBER, 0); \ + if (new) (DETAIL)->cache_put(&new->MEMBER, DETAIL); \ + return tmp; \ + } \ + } \ + /* Didn't find anything */ \ + if (new) { \ + INIT; \ + new->MEMBER.next = *head; \ + *head = &new->MEMBER; \ + (DETAIL)->entries ++; \ + cache_get(&new->MEMBER); \ + if (set) { \ + tmp = new; \ + if (test_bit(CACHE_NEGATIVE, &item->MEMBER.flags)) \ + set_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags); \ + else {UPDATE;} \ + } \ + } \ + if (set||new) write_unlock(&(DETAIL)->hash_lock); \ + else read_unlock(&(DETAIL)->hash_lock); \ + if (new && set) \ + cache_fresh(DETAIL, &new->MEMBER, item->MEMBER.expiry_time); \ + if (new) \ + return new; \ + new = kmalloc(sizeof(*new), GFP_KERNEL); \ + if (new) { \ + cache_init(&new->MEMBER); \ + goto retry; \ + } \ + return NULL; \ +} + +#define DefineSimpleCacheLookup(STRUCT,INPLACE) \ + DefineCacheLookup(struct STRUCT, h, STRUCT##_lookup, (struct STRUCT *item, int set), /*no setup */, \ + & STRUCT##_cache, STRUCT##_hash(item), STRUCT##_match(item, tmp),\ + STRUCT##_init(new, item), STRUCT##_update(tmp, item),INPLACE) + +#define cache_for_each(pos, detail, index, member) \ + for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ; \ + ({if (index==0)read_unlock(&(detail)->hash_lock); index--;}); \ + ) \ + for (pos = container_of((detail)->hash_table[index], typeof(*pos), member); \ + &pos->member; \ + pos = container_of(pos->member.next, typeof(*pos), member)) + + + +extern void cache_clean_deferred(void *owner); + +static inline struct cache_head *cache_get(struct cache_head *h) +{ + atomic_inc(&h->refcnt); + return h; +} + + +static inline int cache_put(struct cache_head *h, struct cache_detail *cd) +{ + if (atomic_read(&h->refcnt) <= 2 && + h->expiry_time < cd->nextcheck) + cd->nextcheck = h->expiry_time; + return atomic_dec_and_test(&h->refcnt); +} + +extern void cache_init(struct cache_head *h); +extern void cache_fresh(struct cache_detail *detail, + struct cache_head *head, time_t expiry); +extern int cache_check(struct cache_detail *detail, + struct cache_head *h, struct cache_req *rqstp); +extern void cache_flush(void); +extern void cache_purge(struct cache_detail *detail); +#define NEVER (0x7FFFFFFF) +extern void cache_register(struct cache_detail *cd); +extern int cache_unregister(struct cache_detail *cd); + +extern void qword_add(char **bpp, int *lp, char *str); +extern void qword_addhex(char **bpp, int *lp, char *buf, int blen); +extern int qword_get(char **bpp, char *dest, int bufsize); + +static inline int get_int(char **bpp, int *anint) +{ + char buf[50]; + char *ep; + int rv; + int len = qword_get(bpp, buf, 50); + if (len < 0) return -EINVAL; + if (len ==0) return -ENOENT; + rv = simple_strtol(buf, &ep, 0); + if (*ep) return -EINVAL; + *anint = rv; + return 0; +} + +static inline time_t get_expiry(char **bpp) +{ + int rv; + if (get_int(bpp, &rv)) + return 0; + if (rv < 0) + return 0; + return rv; +} + +#endif /* _LINUX_SUNRPC_CACHE_H_ */ diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h new file mode 100644 index 00000000000..2709caf4d12 --- /dev/null +++ b/include/linux/sunrpc/clnt.h @@ -0,0 +1,153 @@ +/* + * linux/include/linux/sunrpc/clnt.h + * + * Declarations for the high-level RPC client interface + * + * Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _LINUX_SUNRPC_CLNT_H +#define _LINUX_SUNRPC_CLNT_H + +#include <linux/sunrpc/msg_prot.h> +#include <linux/sunrpc/sched.h> +#include <linux/sunrpc/xprt.h> +#include <linux/sunrpc/auth.h> +#include <linux/sunrpc/stats.h> +#include <linux/sunrpc/xdr.h> +#include <linux/sunrpc/timer.h> +#include <asm/signal.h> + +/* + * This defines an RPC port mapping + */ +struct rpc_portmap { + __u32 pm_prog; + __u32 pm_vers; + __u32 pm_prot; + __u16 pm_port; + unsigned char pm_binding : 1; /* doing a getport() */ + struct rpc_wait_queue pm_bindwait; /* waiting on getport() */ +}; + +struct rpc_inode; + +/* + * The high-level client handle + */ +struct rpc_clnt { + atomic_t cl_count; /* Number of clones */ + atomic_t cl_users; /* number of references */ + struct rpc_xprt * cl_xprt; /* transport */ + struct rpc_procinfo * cl_procinfo; /* procedure info */ + u32 cl_maxproc; /* max procedure number */ + + char * cl_server; /* server machine name */ + char * cl_protname; /* protocol name */ + struct rpc_auth * cl_auth; /* authenticator */ + struct rpc_stat * cl_stats; /* statistics */ + + unsigned int cl_softrtry : 1,/* soft timeouts */ + cl_intr : 1,/* interruptible */ + cl_chatty : 1,/* be verbose */ + cl_autobind : 1,/* use getport() */ + cl_oneshot : 1,/* dispose after use */ + cl_dead : 1;/* abandoned */ + + struct rpc_rtt * cl_rtt; /* RTO estimator data */ + struct rpc_portmap * cl_pmap; /* port mapping */ + + int cl_nodelen; /* nodename length */ + char cl_nodename[UNX_MAXNODENAME]; + char cl_pathname[30];/* Path in rpc_pipe_fs */ + struct dentry * cl_dentry; /* inode */ + struct rpc_clnt * cl_parent; /* Points to parent of clones */ + struct rpc_rtt cl_rtt_default; + struct rpc_portmap cl_pmap_default; + char cl_inline_name[32]; +}; +#define cl_timeout cl_xprt->timeout +#define cl_prog cl_pmap->pm_prog +#define cl_vers cl_pmap->pm_vers +#define cl_port cl_pmap->pm_port +#define cl_prot cl_pmap->pm_prot + +/* + * General RPC program info + */ +#define RPC_MAXVERSION 4 +struct rpc_program { + char * name; /* protocol name */ + u32 number; /* program number */ + unsigned int nrvers; /* number of versions */ + struct rpc_version ** version; /* version array */ + struct rpc_stat * stats; /* statistics */ + char * pipe_dir_name; /* path to rpc_pipefs dir */ +}; + +struct rpc_version { + u32 number; /* version number */ + unsigned int nrprocs; /* number of procs */ + struct rpc_procinfo * procs; /* procedure array */ +}; + +/* + * Procedure information + */ +struct rpc_procinfo { + u32 p_proc; /* RPC procedure number */ + kxdrproc_t p_encode; /* XDR encode function */ + kxdrproc_t p_decode; /* XDR decode function */ + unsigned int p_bufsiz; /* req. buffer size */ + unsigned int p_count; /* call count */ + unsigned int p_timer; /* Which RTT timer to use */ +}; + +#define RPC_CONGESTED(clnt) (RPCXPRT_CONGESTED((clnt)->cl_xprt)) +#define RPC_PEERADDR(clnt) (&(clnt)->cl_xprt->addr) + +#ifdef __KERNEL__ + +struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, + struct rpc_program *info, + u32 version, rpc_authflavor_t authflavor); +struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); +int rpc_shutdown_client(struct rpc_clnt *); +int rpc_destroy_client(struct rpc_clnt *); +void rpc_release_client(struct rpc_clnt *); +void rpc_getport(struct rpc_task *, struct rpc_clnt *); +int rpc_register(u32, u32, int, unsigned short, int *); + +void rpc_call_setup(struct rpc_task *, struct rpc_message *, int); + +int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, + int flags, rpc_action callback, void *clntdata); +int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, + int flags); +void rpc_restart_call(struct rpc_task *); +void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset); +void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); +void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); +size_t rpc_max_payload(struct rpc_clnt *); + +static __inline__ +int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) +{ + struct rpc_message msg = { + .rpc_proc = &clnt->cl_procinfo[proc], + .rpc_argp = argp, + .rpc_resp = resp, + .rpc_cred = NULL + }; + return rpc_call_sync(clnt, &msg, flags); +} + +extern void rpciod_wake_up(void); + +/* + * Helper function for NFSroot support + */ +int rpc_getport_external(struct sockaddr_in *, __u32, __u32, int); + +#endif /* __KERNEL__ */ +#endif /* _LINUX_SUNRPC_CLNT_H */ diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h new file mode 100644 index 00000000000..eadb31e3c19 --- /dev/null +++ b/include/linux/sunrpc/debug.h @@ -0,0 +1,99 @@ +/* + * linux/include/linux/sunrpc/debug.h + * + * Debugging support for sunrpc module + * + * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _LINUX_SUNRPC_DEBUG_H_ +#define _LINUX_SUNRPC_DEBUG_H_ + +#include <linux/config.h> + +#include <linux/timer.h> +#include <linux/workqueue.h> + +/* + * Enable RPC debugging/profiling. + */ +#ifdef CONFIG_SYSCTL +#define RPC_DEBUG +#endif +/* #define RPC_PROFILE */ + +/* + * RPC debug facilities + */ +#define RPCDBG_XPRT 0x0001 +#define RPCDBG_CALL 0x0002 +#define RPCDBG_DEBUG 0x0004 +#define RPCDBG_NFS 0x0008 +#define RPCDBG_AUTH 0x0010 +#define RPCDBG_PMAP 0x0020 +#define RPCDBG_SCHED 0x0040 +#define RPCDBG_SVCSOCK 0x0100 +#define RPCDBG_SVCDSP 0x0200 +#define RPCDBG_MISC 0x0400 +#define RPCDBG_CACHE 0x0800 +#define RPCDBG_ALL 0x7fff + +#ifdef __KERNEL__ + +/* + * Debugging macros etc + */ +#ifdef RPC_DEBUG +extern unsigned int rpc_debug; +extern unsigned int nfs_debug; +extern unsigned int nfsd_debug; +extern unsigned int nlm_debug; +#endif + +#define dprintk(args...) dfprintk(FACILITY, ## args) + +#undef ifdebug +#ifdef RPC_DEBUG +# define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac)) +# define dfprintk(fac, args...) do { ifdebug(fac) printk(args); } while(0) +# define RPC_IFDEBUG(x) x +#else +# define ifdebug(fac) if (0) +# define dfprintk(fac, args...) do ; while (0) +# define RPC_IFDEBUG(x) +#endif + +#ifdef RPC_PROFILE +# define pprintk(args...) printk(## args) +#else +# define pprintk(args...) do ; while (0) +#endif + +/* + * Sysctl interface for RPC debugging + */ +#ifdef RPC_DEBUG +void rpc_register_sysctl(void); +void rpc_unregister_sysctl(void); +#endif + +#endif /* __KERNEL__ */ + +/* + * Declarations for the sysctl debug interface, which allows to read or + * change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc + * module currently registers its sysctl table dynamically, the sysctl path + * for module FOO is <CTL_SUNRPC, CTL_FOODEBUG>. + */ +#define CTL_SUNRPC 7249 /* arbitrary and hopefully unused */ + +enum { + CTL_RPCDEBUG = 1, + CTL_NFSDEBUG, + CTL_NFSDDEBUG, + CTL_NLMDEBUG, + CTL_SLOTTABLE_UDP, + CTL_SLOTTABLE_TCP, +}; + +#endif /* _LINUX_SUNRPC_DEBUG_H_ */ diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h new file mode 100644 index 00000000000..689262f6305 --- /dev/null +++ b/include/linux/sunrpc/gss_api.h @@ -0,0 +1,122 @@ +/* + * linux/include/linux/gss_api.h + * + * Somewhat simplified version of the gss api. + * + * Dug Song <dugsong@monkey.org> + * Andy Adamson <andros@umich.edu> + * Bruce Fields <bfields@umich.edu> + * Copyright (c) 2000 The Regents of the University of Michigan + * + * $Id$ + */ + +#ifndef _LINUX_SUNRPC_GSS_API_H +#define _LINUX_SUNRPC_GSS_API_H + +#ifdef __KERNEL__ +#include <linux/sunrpc/xdr.h> +#include <linux/uio.h> + +/* The mechanism-independent gss-api context: */ +struct gss_ctx { + struct gss_api_mech *mech_type; + void *internal_ctx_id; +}; + +#define GSS_C_NO_BUFFER ((struct xdr_netobj) 0) +#define GSS_C_NO_CONTEXT ((struct gss_ctx *) 0) +#define GSS_C_NULL_OID ((struct xdr_netobj) 0) + +/*XXX arbitrary length - is this set somewhere? */ +#define GSS_OID_MAX_LEN 32 + +/* gss-api prototypes; note that these are somewhat simplified versions of + * the prototypes specified in RFC 2744. */ +int gss_import_sec_context( + const void* input_token, + size_t bufsize, + struct gss_api_mech *mech, + struct gss_ctx **ctx_id); +u32 gss_get_mic( + struct gss_ctx *ctx_id, + u32 qop, + struct xdr_buf *message, + struct xdr_netobj *mic_token); +u32 gss_verify_mic( + struct gss_ctx *ctx_id, + struct xdr_buf *message, + struct xdr_netobj *mic_token, + u32 *qstate); +u32 gss_delete_sec_context( + struct gss_ctx **ctx_id); + +u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor); +char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); + +struct pf_desc { + u32 pseudoflavor; + u32 qop; + u32 service; + char *name; + char *auth_domain_name; +}; + +/* Different mechanisms (e.g., krb5 or spkm3) may implement gss-api, and + * mechanisms may be dynamically registered or unregistered by modules. */ + +/* Each mechanism is described by the following struct: */ +struct gss_api_mech { + struct list_head gm_list; + struct module *gm_owner; + struct xdr_netobj gm_oid; + char *gm_name; + struct gss_api_ops *gm_ops; + /* pseudoflavors supported by this mechanism: */ + int gm_pf_num; + struct pf_desc * gm_pfs; +}; + +/* and must provide the following operations: */ +struct gss_api_ops { + int (*gss_import_sec_context)( + const void *input_token, + size_t bufsize, + struct gss_ctx *ctx_id); + u32 (*gss_get_mic)( + struct gss_ctx *ctx_id, + u32 qop, + struct xdr_buf *message, + struct xdr_netobj *mic_token); + u32 (*gss_verify_mic)( + struct gss_ctx *ctx_id, + struct xdr_buf *message, + struct xdr_netobj *mic_token, + u32 *qstate); + void (*gss_delete_sec_context)( + void *internal_ctx_id); +}; + +int gss_mech_register(struct gss_api_mech *); +void gss_mech_unregister(struct gss_api_mech *); + +/* returns a mechanism descriptor given an OID, and increments the mechanism's + * reference count. */ +struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *); + +/* Returns a reference to a mechanism, given a name like "krb5" etc. */ +struct gss_api_mech *gss_mech_get_by_name(const char *); + +/* Similar, but get by pseudoflavor. */ +struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); + +/* Just increments the mechanism's reference count and returns its input: */ +struct gss_api_mech * gss_mech_get(struct gss_api_mech *); + +/* For every succesful gss_mech_get or gss_mech_get_by_* call there must be a + * corresponding call to gss_mech_put. */ +void gss_mech_put(struct gss_api_mech *); + +#endif /* __KERNEL__ */ +#endif /* _LINUX_SUNRPC_GSS_API_H */ + diff --git a/include/linux/sunrpc/gss_asn1.h b/include/linux/sunrpc/gss_asn1.h new file mode 100644 index 00000000000..3ccecd0ad22 --- /dev/null +++ b/include/linux/sunrpc/gss_asn1.h @@ -0,0 +1,81 @@ +/* + * linux/include/linux/sunrpc/gss_asn1.h + * + * minimal asn1 for generic encoding/decoding of gss tokens + * + * Adapted from MIT Kerberos 5-1.2.1 lib/include/krb5.h, + * lib/gssapi/krb5/gssapiP_krb5.h, and others + * + * Copyright (c) 2000 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson <andros@umich.edu> + */ + +/* + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + + +#include <linux/sunrpc/gss_api.h> + +#define SIZEOF_INT 4 + +/* from gssapi_err_generic.h */ +#define G_BAD_SERVICE_NAME (-2045022976L) +#define G_BAD_STRING_UID (-2045022975L) +#define G_NOUSER (-2045022974L) +#define G_VALIDATE_FAILED (-2045022973L) +#define G_BUFFER_ALLOC (-2045022972L) +#define G_BAD_MSG_CTX (-2045022971L) +#define G_WRONG_SIZE (-2045022970L) +#define G_BAD_USAGE (-2045022969L) +#define G_UNKNOWN_QOP (-2045022968L) +#define G_NO_HOSTNAME (-2045022967L) +#define G_BAD_HOSTNAME (-2045022966L) +#define G_WRONG_MECH (-2045022965L) +#define G_BAD_TOK_HEADER (-2045022964L) +#define G_BAD_DIRECTION (-2045022963L) +#define G_TOK_TRUNC (-2045022962L) +#define G_REFLECT (-2045022961L) +#define G_WRONG_TOKID (-2045022960L) + +#define g_OID_equal(o1,o2) \ + (((o1)->len == (o2)->len) && \ + (memcmp((o1)->data,(o2)->data,(int) (o1)->len) == 0)) + +u32 g_verify_token_header( + struct xdr_netobj *mech, + int *body_size, + unsigned char **buf_in, + int toksize); + +int g_token_size( + struct xdr_netobj *mech, + unsigned int body_size); + +void g_make_token_header( + struct xdr_netobj *mech, + int body_size, + unsigned char **buf); diff --git a/include/linux/sunrpc/gss_err.h b/include/linux/sunrpc/gss_err.h new file mode 100644 index 00000000000..92608a2e574 --- /dev/null +++ b/include/linux/sunrpc/gss_err.h @@ -0,0 +1,177 @@ +/* + * linux/include/sunrpc/gss_err.h + * + * Adapted from MIT Kerberos 5-1.2.1 include/gssapi/gssapi.h + * + * Copyright (c) 2002 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson <andros@umich.edu> + */ + +/* + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LINUX_SUNRPC_GSS_ERR_H +#define _LINUX_SUNRPC_GSS_ERR_H + +#ifdef __KERNEL__ + +typedef unsigned int OM_uint32; + +/* + * Flag bits for context-level services. + */ +#define GSS_C_DELEG_FLAG 1 +#define GSS_C_MUTUAL_FLAG 2 +#define GSS_C_REPLAY_FLAG 4 +#define GSS_C_SEQUENCE_FLAG 8 +#define GSS_C_CONF_FLAG 16 +#define GSS_C_INTEG_FLAG 32 +#define GSS_C_ANON_FLAG 64 +#define GSS_C_PROT_READY_FLAG 128 +#define GSS_C_TRANS_FLAG 256 + +/* + * Credential usage options + */ +#define GSS_C_BOTH 0 +#define GSS_C_INITIATE 1 +#define GSS_C_ACCEPT 2 + +/* + * Status code types for gss_display_status + */ +#define GSS_C_GSS_CODE 1 +#define GSS_C_MECH_CODE 2 + + +/* + * Define the default Quality of Protection for per-message services. Note + * that an implementation that offers multiple levels of QOP may either reserve + * a value (for example zero, as assumed here) to mean "default protection", or + * alternatively may simply equate GSS_C_QOP_DEFAULT to a specific explicit + * QOP value. However a value of 0 should always be interpreted by a GSSAPI + * implementation as a request for the default protection level. + */ +#define GSS_C_QOP_DEFAULT 0 + +/* + * Expiration time of 2^32-1 seconds means infinite lifetime for a + * credential or security context + */ +#define GSS_C_INDEFINITE ((OM_uint32) 0xfffffffful) + + +/* Major status codes */ + +#define GSS_S_COMPLETE 0 + +/* + * Some "helper" definitions to make the status code macros obvious. + */ +#define GSS_C_CALLING_ERROR_OFFSET 24 +#define GSS_C_ROUTINE_ERROR_OFFSET 16 +#define GSS_C_SUPPLEMENTARY_OFFSET 0 +#define GSS_C_CALLING_ERROR_MASK ((OM_uint32) 0377ul) +#define GSS_C_ROUTINE_ERROR_MASK ((OM_uint32) 0377ul) +#define GSS_C_SUPPLEMENTARY_MASK ((OM_uint32) 0177777ul) + +/* + * The macros that test status codes for error conditions. Note that the + * GSS_ERROR() macro has changed slightly from the V1 GSSAPI so that it now + * evaluates its argument only once. + */ +#define GSS_CALLING_ERROR(x) \ + ((x) & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET)) +#define GSS_ROUTINE_ERROR(x) \ + ((x) & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)) +#define GSS_SUPPLEMENTARY_INFO(x) \ + ((x) & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET)) +#define GSS_ERROR(x) \ + ((x) & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \ + (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))) + +/* + * Now the actual status code definitions + */ + +/* + * Calling errors: + */ +#define GSS_S_CALL_INACCESSIBLE_READ \ + (((OM_uint32) 1ul) << GSS_C_CALLING_ERROR_OFFSET) +#define GSS_S_CALL_INACCESSIBLE_WRITE \ + (((OM_uint32) 2ul) << GSS_C_CALLING_ERROR_OFFSET) +#define GSS_S_CALL_BAD_STRUCTURE \ + (((OM_uint32) 3ul) << GSS_C_CALLING_ERROR_OFFSET) + +/* + * Routine errors: + */ +#define GSS_S_BAD_MECH (((OM_uint32) 1ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_NAME (((OM_uint32) 2ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_NAMETYPE (((OM_uint32) 3ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_BINDINGS (((OM_uint32) 4ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_STATUS (((OM_uint32) 5ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_SIG (((OM_uint32) 6ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NO_CRED (((OM_uint32) 7ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NO_CONTEXT (((OM_uint32) 8ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DEFECTIVE_TOKEN (((OM_uint32) 9ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DEFECTIVE_CREDENTIAL \ + (((OM_uint32) 10ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_CREDENTIALS_EXPIRED \ + (((OM_uint32) 11ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_CONTEXT_EXPIRED \ + (((OM_uint32) 12ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_FAILURE (((OM_uint32) 13ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_QOP (((OM_uint32) 14ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_UNAUTHORIZED (((OM_uint32) 15ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_UNAVAILABLE (((OM_uint32) 16ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DUPLICATE_ELEMENT \ + (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NAME_NOT_MN \ + (((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET) + +/* + * Supplementary info bits: + */ +#define GSS_S_CONTINUE_NEEDED (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 0)) +#define GSS_S_DUPLICATE_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1)) +#define GSS_S_OLD_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2)) +#define GSS_S_UNSEQ_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3)) +#define GSS_S_GAP_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4)) + +/* XXXX these are not part of the GSSAPI C bindings! (but should be) */ + +#define GSS_CALLING_ERROR_FIELD(x) \ + (((x) >> GSS_C_CALLING_ERROR_OFFSET) & GSS_C_CALLING_ERROR_MASK) +#define GSS_ROUTINE_ERROR_FIELD(x) \ + (((x) >> GSS_C_ROUTINE_ERROR_OFFSET) & GSS_C_ROUTINE_ERROR_MASK) +#define GSS_SUPPLEMENTARY_INFO_FIELD(x) \ + (((x) >> GSS_C_SUPPLEMENTARY_OFFSET) & GSS_C_SUPPLEMENTARY_MASK) + +/* XXXX This is a necessary evil until the spec is fixed */ +#define GSS_S_CRED_UNAVAIL GSS_S_FAILURE + +#endif /* __KERNEL__ */ +#endif /* __LINUX_SUNRPC_GSS_ERR_H */ diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h new file mode 100644 index 00000000000..ffe31d2eb9e --- /dev/null +++ b/include/linux/sunrpc/gss_krb5.h @@ -0,0 +1,148 @@ +/* + * linux/include/linux/sunrpc/gss_krb5_types.h + * + * Adapted from MIT Kerberos 5-1.2.1 lib/include/krb5.h, + * lib/gssapi/krb5/gssapiP_krb5.h, and others + * + * Copyright (c) 2000 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson <andros@umich.edu> + * Bruce Fields <bfields@umich.edu> + */ + +/* + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#include <linux/sunrpc/auth_gss.h> +#include <linux/sunrpc/gss_err.h> +#include <linux/sunrpc/gss_asn1.h> + +struct krb5_ctx { + int initiate; /* 1 = initiating, 0 = accepting */ + int seed_init; + unsigned char seed[16]; + int signalg; + int sealalg; + struct crypto_tfm *enc; + struct crypto_tfm *seq; + s32 endtime; + u32 seq_send; + struct xdr_netobj mech_used; +}; + +#define KG_TOK_MIC_MSG 0x0101 +#define KG_TOK_WRAP_MSG 0x0201 + +enum sgn_alg { + SGN_ALG_DES_MAC_MD5 = 0x0000, + SGN_ALG_MD2_5 = 0x0001, + SGN_ALG_DES_MAC = 0x0002, + SGN_ALG_3 = 0x0003, /* not published */ + SGN_ALG_HMAC_MD5 = 0x0011, /* microsoft w2k; no support */ + SGN_ALG_HMAC_SHA1_DES3_KD = 0x0004 +}; +enum seal_alg { + SEAL_ALG_NONE = 0xffff, + SEAL_ALG_DES = 0x0000, + SEAL_ALG_1 = 0x0001, /* not published */ + SEAL_ALG_MICROSOFT_RC4 = 0x0010,/* microsoft w2k; no support */ + SEAL_ALG_DES3KD = 0x0002 +}; + +#define KRB5_CKSUM_LENGTH 8 + +#define CKSUMTYPE_CRC32 0x0001 +#define CKSUMTYPE_RSA_MD4 0x0002 +#define CKSUMTYPE_RSA_MD4_DES 0x0003 +#define CKSUMTYPE_DESCBC 0x0004 +#define CKSUMTYPE_RSA_MD5 0x0007 +#define CKSUMTYPE_RSA_MD5_DES 0x0008 +#define CKSUMTYPE_NIST_SHA 0x0009 +#define CKSUMTYPE_HMAC_SHA1_DES3 0x000c + +/* from gssapi_err_krb5.h */ +#define KG_CCACHE_NOMATCH (39756032L) +#define KG_KEYTAB_NOMATCH (39756033L) +#define KG_TGT_MISSING (39756034L) +#define KG_NO_SUBKEY (39756035L) +#define KG_CONTEXT_ESTABLISHED (39756036L) +#define KG_BAD_SIGN_TYPE (39756037L) +#define KG_BAD_LENGTH (39756038L) +#define KG_CTX_INCOMPLETE (39756039L) +#define KG_CONTEXT (39756040L) +#define KG_CRED (39756041L) +#define KG_ENC_DESC (39756042L) +#define KG_BAD_SEQ (39756043L) +#define KG_EMPTY_CCACHE (39756044L) +#define KG_NO_CTYPES (39756045L) + +/* per Kerberos v5 protocol spec crypto types from the wire. + * these get mapped to linux kernel crypto routines. + */ +#define ENCTYPE_NULL 0x0000 +#define ENCTYPE_DES_CBC_CRC 0x0001 /* DES cbc mode with CRC-32 */ +#define ENCTYPE_DES_CBC_MD4 0x0002 /* DES cbc mode with RSA-MD4 */ +#define ENCTYPE_DES_CBC_MD5 0x0003 /* DES cbc mode with RSA-MD5 */ +#define ENCTYPE_DES_CBC_RAW 0x0004 /* DES cbc mode raw */ +/* XXX deprecated? */ +#define ENCTYPE_DES3_CBC_SHA 0x0005 /* DES-3 cbc mode with NIST-SHA */ +#define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */ +#define ENCTYPE_DES_HMAC_SHA1 0x0008 +#define ENCTYPE_DES3_CBC_SHA1 0x0010 +#define ENCTYPE_UNKNOWN 0x01ff + +s32 +make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, + struct xdr_netobj *cksum); + +u32 +krb5_make_token(struct krb5_ctx *context_handle, int qop_req, + struct xdr_buf *input_message_buffer, + struct xdr_netobj *output_message_buffer, int toktype); + +u32 +krb5_read_token(struct krb5_ctx *context_handle, + struct xdr_netobj *input_token_buffer, + struct xdr_buf *message_buffer, + int *qop_state, int toktype); + +u32 +krb5_encrypt(struct crypto_tfm * key, + void *iv, void *in, void *out, int length); + +u32 +krb5_decrypt(struct crypto_tfm * key, + void *iv, void *in, void *out, int length); + +s32 +krb5_make_seq_num(struct crypto_tfm * key, + int direction, + s32 seqnum, unsigned char *cksum, unsigned char *buf); + +s32 +krb5_get_seq_num(struct crypto_tfm * key, + unsigned char *cksum, + unsigned char *buf, int *direction, s32 * seqnum); diff --git a/include/linux/sunrpc/gss_spkm3.h b/include/linux/sunrpc/gss_spkm3.h new file mode 100644 index 00000000000..b5c9968c3c1 --- /dev/null +++ b/include/linux/sunrpc/gss_spkm3.h @@ -0,0 +1,61 @@ +/* + * linux/include/linux/sunrpc/gss_spkm3.h + * + * Copyright (c) 2000 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson <andros@umich.edu> + */ + +#include <linux/sunrpc/auth_gss.h> +#include <linux/sunrpc/gss_err.h> +#include <linux/sunrpc/gss_asn1.h> + +struct spkm3_ctx { + struct xdr_netobj ctx_id; /* per message context id */ + int qop; /* negotiated qop */ + struct xdr_netobj mech_used; + unsigned int ret_flags ; + unsigned int req_flags ; + struct xdr_netobj share_key; + int conf_alg; + struct crypto_tfm* derived_conf_key; + int intg_alg; + struct crypto_tfm* derived_integ_key; + int keyestb_alg; /* alg used to get share_key */ + int owf_alg; /* one way function */ +}; + +/* from openssl/objects.h */ +/* XXX need SEAL_ALG_NONE */ +#define NID_md5 4 +#define NID_dhKeyAgreement 28 +#define NID_des_cbc 31 +#define NID_sha1 64 +#define NID_cast5_cbc 108 + +/* SPKM InnerContext Token types */ + +#define SPKM_ERROR_TOK 3 +#define SPKM_MIC_TOK 4 +#define SPKM_WRAP_TOK 5 +#define SPKM_DEL_TOK 6 + +u32 spkm3_make_token(struct spkm3_ctx *ctx, int qop_req, struct xdr_buf * text, struct xdr_netobj * token, int toktype); + +u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int *qop_state, int toktype); + +#define CKSUMTYPE_RSA_MD5 0x0007 + +s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, + struct xdr_netobj *cksum); +void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits); +int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, + int explen); +void spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, + unsigned char *ctxhdr, int elen, int zbit); +void spkm3_make_mic_token(unsigned char **tokp, int toklen, + struct xdr_netobj *mic_hdr, + struct xdr_netobj *md5cksum, int md5elen, int md5zbit); +u32 spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, + unsigned char **cksum); diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h new file mode 100644 index 00000000000..15f11533238 --- /dev/null +++ b/include/linux/sunrpc/msg_prot.h @@ -0,0 +1,80 @@ +/* + * linux/include/net/sunrpc/msg_prot.h + * + * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _LINUX_SUNRPC_MSGPROT_H_ +#define _LINUX_SUNRPC_MSGPROT_H_ + +#ifdef __KERNEL__ /* user programs should get these from the rpc header files */ + +#define RPC_VERSION 2 + +/* spec defines authentication flavor as an unsigned 32 bit integer */ +typedef u32 rpc_authflavor_t; + +enum rpc_auth_flavors { + RPC_AUTH_NULL = 0, + RPC_AUTH_UNIX = 1, + RPC_AUTH_SHORT = 2, + RPC_AUTH_DES = 3, + RPC_AUTH_KRB = 4, + RPC_AUTH_GSS = 6, + RPC_AUTH_MAXFLAVOR = 8, + /* pseudoflavors: */ + RPC_AUTH_GSS_KRB5 = 390003, + RPC_AUTH_GSS_KRB5I = 390004, + RPC_AUTH_GSS_KRB5P = 390005, + RPC_AUTH_GSS_LKEY = 390006, + RPC_AUTH_GSS_LKEYI = 390007, + RPC_AUTH_GSS_LKEYP = 390008, + RPC_AUTH_GSS_SPKM = 390009, + RPC_AUTH_GSS_SPKMI = 390010, + RPC_AUTH_GSS_SPKMP = 390011, +}; + +enum rpc_msg_type { + RPC_CALL = 0, + RPC_REPLY = 1 +}; + +enum rpc_reply_stat { + RPC_MSG_ACCEPTED = 0, + RPC_MSG_DENIED = 1 +}; + +enum rpc_accept_stat { + RPC_SUCCESS = 0, + RPC_PROG_UNAVAIL = 1, + RPC_PROG_MISMATCH = 2, + RPC_PROC_UNAVAIL = 3, + RPC_GARBAGE_ARGS = 4, + RPC_SYSTEM_ERR = 5 +}; + +enum rpc_reject_stat { + RPC_MISMATCH = 0, + RPC_AUTH_ERROR = 1 +}; + +enum rpc_auth_stat { + RPC_AUTH_OK = 0, + RPC_AUTH_BADCRED = 1, + RPC_AUTH_REJECTEDCRED = 2, + RPC_AUTH_BADVERF = 3, + RPC_AUTH_REJECTEDVERF = 4, + RPC_AUTH_TOOWEAK = 5, + /* RPCSEC_GSS errors */ + RPCSEC_GSS_CREDPROBLEM = 13, + RPCSEC_GSS_CTXPROBLEM = 14 +}; + +#define RPC_PMAP_PROGRAM 100000 +#define RPC_PMAP_VERSION 2 +#define RPC_PMAP_PORT 111 + +#define RPC_MAXNETNAMELEN 256 + +#endif /* __KERNEL__ */ +#endif /* _LINUX_SUNRPC_MSGPROT_H_ */ diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h new file mode 100644 index 00000000000..63929349571 --- /dev/null +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -0,0 +1,50 @@ +#ifndef _LINUX_SUNRPC_RPC_PIPE_FS_H +#define _LINUX_SUNRPC_RPC_PIPE_FS_H + +#ifdef __KERNEL__ + +struct rpc_pipe_msg { + struct list_head list; + void *data; + size_t len; + size_t copied; + int errno; +}; + +struct rpc_pipe_ops { + ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char __user *, size_t); + ssize_t (*downcall)(struct file *, const char __user *, size_t); + void (*release_pipe)(struct inode *); + void (*destroy_msg)(struct rpc_pipe_msg *); +}; + +struct rpc_inode { + struct inode vfs_inode; + void *private; + struct list_head pipe; + struct list_head in_upcall; + int pipelen; + int nreaders; + int nwriters; + wait_queue_head_t waitq; +#define RPC_PIPE_WAIT_FOR_OPEN 1 + int flags; + struct rpc_pipe_ops *ops; + struct work_struct queue_timeout; +}; + +static inline struct rpc_inode * +RPC_I(struct inode *inode) +{ + return container_of(inode, struct rpc_inode, vfs_inode); +} + +extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); + +extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); +extern int rpc_rmdir(char *); +extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags); +extern int rpc_unlink(char *); + +#endif +#endif diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h new file mode 100644 index 00000000000..99d17ed7ceb --- /dev/null +++ b/include/linux/sunrpc/sched.h @@ -0,0 +1,273 @@ +/* + * linux/include/linux/sunrpc/sched.h + * + * Scheduling primitives for kernel Sun RPC. + * + * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _LINUX_SUNRPC_SCHED_H_ +#define _LINUX_SUNRPC_SCHED_H_ + +#include <linux/timer.h> +#include <linux/sunrpc/types.h> +#include <linux/spinlock.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +#include <linux/sunrpc/xdr.h> + +/* + * This is the actual RPC procedure call info. + */ +struct rpc_procinfo; +struct rpc_message { + struct rpc_procinfo * rpc_proc; /* Procedure information */ + void * rpc_argp; /* Arguments */ + void * rpc_resp; /* Result */ + struct rpc_cred * rpc_cred; /* Credentials */ +}; + +struct rpc_wait_queue; +struct rpc_wait { + struct list_head list; /* wait queue links */ + struct list_head links; /* Links to related tasks */ + wait_queue_head_t waitq; /* sync: sleep on this q */ + struct rpc_wait_queue * rpc_waitq; /* RPC wait queue we're on */ +}; + +/* + * This is the RPC task struct + */ +struct rpc_task { +#ifdef RPC_DEBUG + unsigned long tk_magic; /* 0xf00baa */ +#endif + struct list_head tk_task; /* global list of tasks */ + struct rpc_clnt * tk_client; /* RPC client */ + struct rpc_rqst * tk_rqstp; /* RPC request */ + int tk_status; /* result of last operation */ + + /* + * RPC call state + */ + struct rpc_message tk_msg; /* RPC call info */ + __u32 * tk_buffer; /* XDR buffer */ + size_t tk_bufsize; + __u8 tk_garb_retry; + __u8 tk_cred_retry; + + unsigned long tk_cookie; /* Cookie for batching tasks */ + + /* + * timeout_fn to be executed by timer bottom half + * callback to be executed after waking up + * action next procedure for async tasks + * exit exit async task and report to caller + */ + void (*tk_timeout_fn)(struct rpc_task *); + void (*tk_callback)(struct rpc_task *); + void (*tk_action)(struct rpc_task *); + void (*tk_exit)(struct rpc_task *); + void (*tk_release)(struct rpc_task *); + void * tk_calldata; + + /* + * tk_timer is used for async processing by the RPC scheduling + * primitives. You should not access this directly unless + * you have a pathological interest in kernel oopses. + */ + struct timer_list tk_timer; /* kernel timer */ + unsigned long tk_timeout; /* timeout for rpc_sleep() */ + unsigned short tk_flags; /* misc flags */ + unsigned char tk_active : 1;/* Task has been activated */ + unsigned char tk_priority : 2;/* Task priority */ + unsigned long tk_runstate; /* Task run status */ + struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could + * be any workqueue + */ + union { + struct work_struct tk_work; /* Async task work queue */ + struct rpc_wait tk_wait; /* RPC wait */ + } u; +#ifdef RPC_DEBUG + unsigned short tk_pid; /* debugging aid */ +#endif +}; +#define tk_auth tk_client->cl_auth +#define tk_xprt tk_client->cl_xprt + +/* support walking a list of tasks on a wait queue */ +#define task_for_each(task, pos, head) \ + list_for_each(pos, head) \ + if ((task=list_entry(pos, struct rpc_task, u.tk_wait.list)),1) + +#define task_for_first(task, head) \ + if (!list_empty(head) && \ + ((task=list_entry((head)->next, struct rpc_task, u.tk_wait.list)),1)) + +/* .. and walking list of all tasks */ +#define alltask_for_each(task, pos, head) \ + list_for_each(pos, head) \ + if ((task=list_entry(pos, struct rpc_task, tk_task)),1) + +typedef void (*rpc_action)(struct rpc_task *); + +/* + * RPC task flags + */ +#define RPC_TASK_ASYNC 0x0001 /* is an async task */ +#define RPC_TASK_SWAPPER 0x0002 /* is swapping in/out */ +#define RPC_TASK_CHILD 0x0008 /* is child of other task */ +#define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ +#define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */ +#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ +#define RPC_TASK_KILLED 0x0100 /* task was killed */ +#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */ +#define RPC_TASK_NOINTR 0x0400 /* uninterruptible task */ + +#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) +#define RPC_IS_CHILD(t) ((t)->tk_flags & RPC_TASK_CHILD) +#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) +#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) +#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) +#define RPC_IS_ACTIVATED(t) ((t)->tk_active) +#define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL) +#define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT) +#define RPC_TASK_UNINTERRUPTIBLE(t) ((t)->tk_flags & RPC_TASK_NOINTR) + +#define RPC_TASK_RUNNING 0 +#define RPC_TASK_QUEUED 1 +#define RPC_TASK_WAKEUP 2 +#define RPC_TASK_HAS_TIMER 3 + +#define RPC_IS_RUNNING(t) (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) +#define rpc_set_running(t) (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) +#define rpc_test_and_set_running(t) \ + (test_and_set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) +#define rpc_clear_running(t) \ + do { \ + smp_mb__before_clear_bit(); \ + clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate); \ + smp_mb__after_clear_bit(); \ + } while (0) + +#define RPC_IS_QUEUED(t) (test_bit(RPC_TASK_QUEUED, &(t)->tk_runstate)) +#define rpc_set_queued(t) (set_bit(RPC_TASK_QUEUED, &(t)->tk_runstate)) +#define rpc_clear_queued(t) \ + do { \ + smp_mb__before_clear_bit(); \ + clear_bit(RPC_TASK_QUEUED, &(t)->tk_runstate); \ + smp_mb__after_clear_bit(); \ + } while (0) + +#define rpc_start_wakeup(t) \ + (test_and_set_bit(RPC_TASK_WAKEUP, &(t)->tk_runstate) == 0) +#define rpc_finish_wakeup(t) \ + do { \ + smp_mb__before_clear_bit(); \ + clear_bit(RPC_TASK_WAKEUP, &(t)->tk_runstate); \ + smp_mb__after_clear_bit(); \ + } while (0) + +/* + * Task priorities. + * Note: if you change these, you must also change + * the task initialization definitions below. + */ +#define RPC_PRIORITY_LOW 0 +#define RPC_PRIORITY_NORMAL 1 +#define RPC_PRIORITY_HIGH 2 +#define RPC_NR_PRIORITY (RPC_PRIORITY_HIGH+1) + +/* + * RPC synchronization objects + */ +struct rpc_wait_queue { + spinlock_t lock; + struct list_head tasks[RPC_NR_PRIORITY]; /* task queue for each priority level */ + unsigned long cookie; /* cookie of last task serviced */ + unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */ + unsigned char priority; /* current priority */ + unsigned char count; /* # task groups remaining serviced so far */ + unsigned char nr; /* # tasks remaining for cookie */ +#ifdef RPC_DEBUG + const char * name; +#endif +}; + +/* + * This is the # requests to send consecutively + * from a single cookie. The aim is to improve + * performance of NFS operations such as read/write. + */ +#define RPC_BATCH_COUNT 16 + +#ifndef RPC_DEBUG +# define RPC_WAITQ_INIT(var,qname) { \ + .lock = SPIN_LOCK_UNLOCKED, \ + .tasks = { \ + [0] = LIST_HEAD_INIT(var.tasks[0]), \ + [1] = LIST_HEAD_INIT(var.tasks[1]), \ + [2] = LIST_HEAD_INIT(var.tasks[2]), \ + }, \ + } +#else +# define RPC_WAITQ_INIT(var,qname) { \ + .lock = SPIN_LOCK_UNLOCKED, \ + .tasks = { \ + [0] = LIST_HEAD_INIT(var.tasks[0]), \ + [1] = LIST_HEAD_INIT(var.tasks[1]), \ + [2] = LIST_HEAD_INIT(var.tasks[2]), \ + }, \ + .name = qname, \ + } +#endif +# define RPC_WAITQ(var,qname) struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname) + +#define RPC_IS_PRIORITY(q) ((q)->maxpriority > 0) + +/* + * Function prototypes + */ +struct rpc_task *rpc_new_task(struct rpc_clnt *, rpc_action, int flags); +struct rpc_task *rpc_new_child(struct rpc_clnt *, struct rpc_task *parent); +void rpc_init_task(struct rpc_task *, struct rpc_clnt *, + rpc_action exitfunc, int flags); +void rpc_release_task(struct rpc_task *); +void rpc_killall_tasks(struct rpc_clnt *); +int rpc_execute(struct rpc_task *); +void rpc_run_child(struct rpc_task *parent, struct rpc_task *child, + rpc_action action); +void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); +void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); +void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, + rpc_action action, rpc_action timer); +void rpc_wake_up_task(struct rpc_task *); +void rpc_wake_up(struct rpc_wait_queue *); +struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); +void rpc_wake_up_status(struct rpc_wait_queue *, int); +void rpc_delay(struct rpc_task *, unsigned long); +void * rpc_malloc(struct rpc_task *, size_t); +int rpciod_up(void); +void rpciod_down(void); +void rpciod_wake_up(void); +#ifdef RPC_DEBUG +void rpc_show_tasks(void); +#endif +int rpc_init_mempool(void); +void rpc_destroy_mempool(void); + +static inline void rpc_exit(struct rpc_task *task, int status) +{ + task->tk_status = status; + task->tk_action = NULL; +} + +#ifdef RPC_DEBUG +static inline const char * rpc_qname(struct rpc_wait_queue *q) +{ + return ((q && q->name) ? q->name : "unknown"); +} +#endif + +#endif /* _LINUX_SUNRPC_SCHED_H_ */ diff --git a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h new file mode 100644 index 00000000000..0d6ed3c8bdc --- /dev/null +++ b/include/linux/sunrpc/stats.h @@ -0,0 +1,78 @@ +/* + * linux/include/linux/sunrpc/stats.h + * + * Client statistics collection for SUN RPC + * + * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _LINUX_SUNRPC_STATS_H +#define _LINUX_SUNRPC_STATS_H + +#include <linux/config.h> +#include <linux/proc_fs.h> + +struct rpc_stat { + struct rpc_program * program; + + unsigned int netcnt, + netudpcnt, + nettcpcnt, + nettcpconn, + netreconn; + unsigned int rpccnt, + rpcretrans, + rpcauthrefresh, + rpcgarbage; +}; + +struct svc_stat { + struct svc_program * program; + + unsigned int netcnt, + netudpcnt, + nettcpcnt, + nettcpconn; + unsigned int rpccnt, + rpcbadfmt, + rpcbadauth, + rpcbadclnt; +}; + +void rpc_proc_init(void); +void rpc_proc_exit(void); +#ifdef MODULE +void rpc_modcount(struct inode *, int); +#endif + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry * rpc_proc_register(struct rpc_stat *); +void rpc_proc_unregister(const char *); +void rpc_proc_zero(struct rpc_program *); +struct proc_dir_entry * svc_proc_register(struct svc_stat *, + struct file_operations *); +void svc_proc_unregister(const char *); + +void svc_seq_show(struct seq_file *, + const struct svc_stat *); + +extern struct proc_dir_entry *proc_net_rpc; + +#else + +static inline struct proc_dir_entry *rpc_proc_register(struct rpc_stat *s) { return NULL; } +static inline void rpc_proc_unregister(const char *p) {} +static inline void rpc_proc_zero(struct rpc_program *p) {} + +static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s, + struct file_operations *f) { return NULL; } +static inline void svc_proc_unregister(const char *p) {} + +static inline void svc_seq_show(struct seq_file *seq, + const struct svc_stat *st) {} + +#define proc_net_rpc NULL + +#endif + +#endif /* _LINUX_SUNRPC_STATS_H */ diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h new file mode 100644 index 00000000000..37003970cf2 --- /dev/null +++ b/include/linux/sunrpc/svc.h @@ -0,0 +1,306 @@ +/* + * linux/include/linux/sunrpc/svc.h + * + * RPC server declarations. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + + +#ifndef SUNRPC_SVC_H +#define SUNRPC_SVC_H + +#include <linux/in.h> +#include <linux/sunrpc/types.h> +#include <linux/sunrpc/xdr.h> +#include <linux/sunrpc/svcauth.h> +#include <linux/wait.h> +#include <linux/mm.h> + +/* + * RPC service. + * + * An RPC service is a ``daemon,'' possibly multithreaded, which + * receives and processes incoming RPC messages. + * It has one or more transport sockets associated with it, and maintains + * a list of idle threads waiting for input. + * + * We currently do not support more than one RPC program per daemon. + */ +struct svc_serv { + struct list_head sv_threads; /* idle server threads */ + struct list_head sv_sockets; /* pending sockets */ + struct svc_program * sv_program; /* RPC program */ + struct svc_stat * sv_stats; /* RPC statistics */ + spinlock_t sv_lock; + unsigned int sv_nrthreads; /* # of server threads */ + unsigned int sv_bufsz; /* datagram buffer size */ + unsigned int sv_xdrsize; /* XDR buffer size */ + + struct list_head sv_permsocks; /* all permanent sockets */ + struct list_head sv_tempsocks; /* all temporary sockets */ + int sv_tmpcnt; /* count of temporary sockets */ + + char * sv_name; /* service name */ +}; + +/* + * Maximum payload size supported by a kernel RPC server. + * This is use to determine the max number of pages nfsd is + * willing to return in a single READ operation. + */ +#define RPCSVC_MAXPAYLOAD (64*1024u) + +/* + * RPC Requsts and replies are stored in one or more pages. + * We maintain an array of pages for each server thread. + * Requests are copied into these pages as they arrive. Remaining + * pages are available to write the reply into. + * + * Pages are sent using ->sendpage so each server thread needs to + * allocate more to replace those used in sending. To help keep track + * of these pages we have a receive list where all pages initialy live, + * and a send list where pages are moved to when there are to be part + * of a reply. + * + * We use xdr_buf for holding responses as it fits well with NFS + * read responses (that have a header, and some data pages, and possibly + * a tail) and means we can share some client side routines. + * + * The xdr_buf.head kvec always points to the first page in the rq_*pages + * list. The xdr_buf.pages pointer points to the second page on that + * list. xdr_buf.tail points to the end of the first page. + * This assumes that the non-page part of an rpc reply will fit + * in a page - NFSd ensures this. lockd also has no trouble. + * + * Each request/reply pair can have at most one "payload", plus two pages, + * one for the request, and one for the reply. + */ +#define RPCSVC_MAXPAGES ((RPCSVC_MAXPAYLOAD+PAGE_SIZE-1)/PAGE_SIZE + 2) + +static inline u32 svc_getu32(struct kvec *iov) +{ + u32 val, *vp; + vp = iov->iov_base; + val = *vp++; + iov->iov_base = (void*)vp; + iov->iov_len -= sizeof(u32); + return val; +} + +static inline void svc_ungetu32(struct kvec *iov) +{ + u32 *vp = (u32 *)iov->iov_base; + iov->iov_base = (void *)(vp - 1); + iov->iov_len += sizeof(*vp); +} + +static inline void svc_putu32(struct kvec *iov, u32 val) +{ + u32 *vp = iov->iov_base + iov->iov_len; + *vp = val; + iov->iov_len += sizeof(u32); +} + + +/* + * The context of a single thread, including the request currently being + * processed. + * NOTE: First two items must be prev/next. + */ +struct svc_rqst { + struct list_head rq_list; /* idle list */ + struct svc_sock * rq_sock; /* socket */ + struct sockaddr_in rq_addr; /* peer address */ + int rq_addrlen; + + struct svc_serv * rq_server; /* RPC service definition */ + struct svc_procedure * rq_procinfo; /* procedure info */ + struct auth_ops * rq_authop; /* authentication flavour */ + struct svc_cred rq_cred; /* auth info */ + struct sk_buff * rq_skbuff; /* fast recv inet buffer */ + struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */ + + struct xdr_buf rq_arg; + struct xdr_buf rq_res; + struct page * rq_argpages[RPCSVC_MAXPAGES]; + struct page * rq_respages[RPCSVC_MAXPAGES]; + int rq_restailpage; + short rq_argused; /* pages used for argument */ + short rq_arghi; /* pages available in argument page list */ + short rq_resused; /* pages used for result */ + + u32 rq_xid; /* transmission id */ + u32 rq_prog; /* program number */ + u32 rq_vers; /* program version */ + u32 rq_proc; /* procedure number */ + u32 rq_prot; /* IP protocol */ + unsigned short + rq_secure : 1; /* secure port */ + + + __u32 rq_daddr; /* dest addr of request - reply from here */ + + void * rq_argp; /* decoded arguments */ + void * rq_resp; /* xdr'd results */ + void * rq_auth_data; /* flavor-specific data */ + + int rq_reserved; /* space on socket outq + * reserved for this request + */ + + struct cache_req rq_chandle; /* handle passed to caches for + * request delaying + */ + /* Catering to nfsd */ + struct auth_domain * rq_client; /* RPC peer info */ + struct svc_cacherep * rq_cacherep; /* cache info */ + struct knfsd_fh * rq_reffh; /* Referrence filehandle, used to + * determine what device number + * to report (real or virtual) + */ + + wait_queue_head_t rq_wait; /* synchronization */ +}; + +/* + * Check buffer bounds after decoding arguments + */ +static inline int +xdr_argsize_check(struct svc_rqst *rqstp, u32 *p) +{ + char *cp = (char *)p; + struct kvec *vec = &rqstp->rq_arg.head[0]; + return cp - (char*)vec->iov_base <= vec->iov_len; +} + +static inline int +xdr_ressize_check(struct svc_rqst *rqstp, u32 *p) +{ + struct kvec *vec = &rqstp->rq_res.head[0]; + char *cp = (char*)p; + + vec->iov_len = cp - (char*)vec->iov_base; + + return vec->iov_len <= PAGE_SIZE; +} + +static inline int svc_take_page(struct svc_rqst *rqstp) +{ + if (rqstp->rq_arghi <= rqstp->rq_argused) + return -ENOMEM; + rqstp->rq_arghi--; + rqstp->rq_respages[rqstp->rq_resused] = + rqstp->rq_argpages[rqstp->rq_arghi]; + rqstp->rq_resused++; + return 0; +} + +static inline void svc_pushback_allpages(struct svc_rqst *rqstp) +{ + while (rqstp->rq_resused) { + if (rqstp->rq_respages[--rqstp->rq_resused] == NULL) + continue; + rqstp->rq_argpages[rqstp->rq_arghi++] = + rqstp->rq_respages[rqstp->rq_resused]; + rqstp->rq_respages[rqstp->rq_resused] = NULL; + } +} + +static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp) +{ + while (rqstp->rq_resused && + rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) { + + if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) { + rqstp->rq_argpages[rqstp->rq_arghi++] = + rqstp->rq_respages[rqstp->rq_resused]; + rqstp->rq_respages[rqstp->rq_resused] = NULL; + } + } +} + +static inline void svc_free_allpages(struct svc_rqst *rqstp) +{ + while (rqstp->rq_resused) { + if (rqstp->rq_respages[--rqstp->rq_resused] == NULL) + continue; + put_page(rqstp->rq_respages[rqstp->rq_resused]); + rqstp->rq_respages[rqstp->rq_resused] = NULL; + } +} + +struct svc_deferred_req { + u32 prot; /* protocol (UDP or TCP) */ + struct sockaddr_in addr; + struct svc_sock *svsk; /* where reply must go */ + struct cache_deferred_req handle; + int argslen; + u32 args[0]; +}; + +/* + * RPC program + */ +struct svc_program { + u32 pg_prog; /* program number */ + unsigned int pg_lovers; /* lowest version */ + unsigned int pg_hivers; /* lowest version */ + unsigned int pg_nvers; /* number of versions */ + struct svc_version ** pg_vers; /* version array */ + char * pg_name; /* service name */ + char * pg_class; /* class name: services sharing authentication */ + struct svc_stat * pg_stats; /* rpc statistics */ + int (*pg_authenticate)(struct svc_rqst *); +}; + +/* + * RPC program version + */ +struct svc_version { + u32 vs_vers; /* version number */ + u32 vs_nproc; /* number of procedures */ + struct svc_procedure * vs_proc; /* per-procedure info */ + u32 vs_xdrsize; /* xdrsize needed for this version */ + + /* Override dispatch function (e.g. when caching replies). + * A return value of 0 means drop the request. + * vs_dispatch == NULL means use default dispatcher. + */ + int (*vs_dispatch)(struct svc_rqst *, u32 *); +}; + +/* + * RPC procedure info + */ +typedef int (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp); +struct svc_procedure { + svc_procfunc pc_func; /* process the request */ + kxdrproc_t pc_decode; /* XDR decode args */ + kxdrproc_t pc_encode; /* XDR encode result */ + kxdrproc_t pc_release; /* XDR free result */ + unsigned int pc_argsize; /* argument struct size */ + unsigned int pc_ressize; /* result struct size */ + unsigned int pc_count; /* call count */ + unsigned int pc_cachetype; /* cache info (NFS) */ + unsigned int pc_xdrressize; /* maximum size of XDR reply */ +}; + +/* + * This is the RPC server thread function prototype + */ +typedef void (*svc_thread_fn)(struct svc_rqst *); + +/* + * Function prototypes. + */ +struct svc_serv * svc_create(struct svc_program *, unsigned int); +int svc_create_thread(svc_thread_fn, struct svc_serv *); +void svc_exit_thread(struct svc_rqst *); +void svc_destroy(struct svc_serv *); +int svc_process(struct svc_serv *, struct svc_rqst *); +int svc_register(struct svc_serv *, int, unsigned short); +void svc_wake_up(struct svc_serv *); +void svc_reserve(struct svc_rqst *rqstp, int space); + +#endif /* SUNRPC_SVC_H */ diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h new file mode 100644 index 00000000000..c119ce7cbd2 --- /dev/null +++ b/include/linux/sunrpc/svcauth.h @@ -0,0 +1,167 @@ +/* + * linux/include/linux/sunrpc/svcauth.h + * + * RPC server-side authentication stuff. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _LINUX_SUNRPC_SVCAUTH_H_ +#define _LINUX_SUNRPC_SVCAUTH_H_ + +#ifdef __KERNEL__ + +#include <linux/string.h> +#include <linux/sunrpc/msg_prot.h> +#include <linux/sunrpc/cache.h> +#include <linux/hash.h> + +#define SVC_CRED_NGROUPS 32 +struct svc_cred { + uid_t cr_uid; + gid_t cr_gid; + struct group_info *cr_group_info; +}; + +struct svc_rqst; /* forward decl */ + +/* Authentication is done in the context of a domain. + * + * Currently, the nfs server uses the auth_domain to stand + * for the "client" listed in /etc/exports. + * + * More generally, a domain might represent a group of clients using + * a common mechanism for authentication and having a common mapping + * between local identity (uid) and network identity. All clients + * in a domain have similar general access rights. Each domain can + * contain multiple principals which will have different specific right + * based on normal Discretionary Access Control. + * + * A domain is created by an authentication flavour module based on name + * only. Userspace then fills in detail on demand. + * + * In the case of auth_unix and auth_null, the auth_domain is also + * associated with entries in another cache representing the mapping + * of ip addresses to the given client. + */ +struct auth_domain { + struct cache_head h; + char *name; + int flavour; +}; + +/* + * Each authentication flavour registers an auth_ops + * structure. + * name is simply the name. + * flavour gives the auth flavour. It determines where the flavour is registered + * accept() is given a request and should verify it. + * It should inspect the authenticator and verifier, and possibly the data. + * If there is a problem with the authentication *authp should be set. + * The return value of accept() can indicate: + * OK - authorised. client and credential are set in rqstp. + * reqbuf points to arguments + * resbuf points to good place for results. verfier + * is (probably) already in place. Certainly space is + * reserved for it. + * DROP - simply drop the request. It may have been deferred + * GARBAGE - rpc garbage_args error + * SYSERR - rpc system_err error + * DENIED - authp holds reason for denial. + * COMPLETE - the reply is encoded already and ready to be sent; no + * further processing is necessary. (This is used for processing + * null procedure calls which are used to set up encryption + * contexts.) + * + * accept is passed the proc number so that it can accept NULL rpc requests + * even if it cannot authenticate the client (as is sometimes appropriate). + * + * release() is given a request after the procedure has been run. + * It should sign/encrypt the results if needed + * It should return: + * OK - the resbuf is ready to be sent + * DROP - the reply should be quitely dropped + * DENIED - authp holds a reason for MSG_DENIED + * SYSERR - rpc system_err + * + * domain_release() + * This call releases a domain. + */ +struct auth_ops { + char * name; + struct module *owner; + int flavour; + int (*accept)(struct svc_rqst *rq, u32 *authp); + int (*release)(struct svc_rqst *rq); + void (*domain_release)(struct auth_domain *); + int (*set_client)(struct svc_rqst *rq); +}; + +#define SVC_GARBAGE 1 +#define SVC_SYSERR 2 +#define SVC_VALID 3 +#define SVC_NEGATIVE 4 +#define SVC_OK 5 +#define SVC_DROP 6 +#define SVC_DENIED 7 +#define SVC_PENDING 8 +#define SVC_COMPLETE 9 + + +extern int svc_authenticate(struct svc_rqst *rqstp, u32 *authp); +extern int svc_authorise(struct svc_rqst *rqstp); +extern int svc_set_client(struct svc_rqst *rqstp); +extern int svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops); +extern void svc_auth_unregister(rpc_authflavor_t flavor); + +extern struct auth_domain *unix_domain_find(char *name); +extern void auth_domain_put(struct auth_domain *item); +extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom); +extern struct auth_domain *auth_domain_lookup(struct auth_domain *item, int set); +extern struct auth_domain *auth_domain_find(char *name); +extern struct auth_domain *auth_unix_lookup(struct in_addr addr); +extern int auth_unix_forget_old(struct auth_domain *dom); +extern void svcauth_unix_purge(void); + +static inline unsigned long hash_str(char *name, int bits) +{ + unsigned long hash = 0; + unsigned long l = 0; + int len = 0; + unsigned char c; + do { + if (unlikely(!(c = *name++))) { + c = (char)len; len = -1; + } + l = (l << 8) | c; + len++; + if ((len & (BITS_PER_LONG/8-1))==0) + hash = hash_long(hash^l, BITS_PER_LONG); + } while (len); + return hash >> (BITS_PER_LONG - bits); +} + +static inline unsigned long hash_mem(char *buf, int length, int bits) +{ + unsigned long hash = 0; + unsigned long l = 0; + int len = 0; + unsigned char c; + do { + if (len == length) { + c = (char)len; len = -1; + } else + c = *buf++; + l = (l << 8) | c; + len++; + if ((len & (BITS_PER_LONG/8-1))==0) + hash = hash_long(hash^l, BITS_PER_LONG); + } while (len); + return hash >> (BITS_PER_LONG - bits); +} + +extern struct cache_detail auth_domain_cache, ip_map_cache; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SUNRPC_SVCAUTH_H_ */ diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h new file mode 100644 index 00000000000..3a2206f61de --- /dev/null +++ b/include/linux/sunrpc/svcauth_gss.h @@ -0,0 +1,27 @@ +/* + * linux/include/linux/svcauth_gss.h + * + * Bruce Fields <bfields@umich.edu> + * Copyright (c) 2002 The Regents of the Unviersity of Michigan + * + * $Id$ + * + */ + +#ifndef _LINUX_SUNRPC_SVCAUTH_GSS_H +#define _LINUX_SUNRPC_SVCAUTH_GSS_H + +#ifdef __KERNEL__ +#include <linux/sched.h> +#include <linux/sunrpc/types.h> +#include <linux/sunrpc/xdr.h> +#include <linux/sunrpc/svcauth.h> +#include <linux/sunrpc/svcsock.h> +#include <linux/sunrpc/auth_gss.h> + +int gss_svc_init(void); +void gss_svc_shutdown(void); +int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); + +#endif /* __KERNEL__ */ +#endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */ diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h new file mode 100644 index 00000000000..d33c6face03 --- /dev/null +++ b/include/linux/sunrpc/svcsock.h @@ -0,0 +1,65 @@ +/* + * linux/include/linux/sunrpc/svcsock.h + * + * RPC server socket I/O. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef SUNRPC_SVCSOCK_H +#define SUNRPC_SVCSOCK_H + +#include <linux/sunrpc/svc.h> + +/* + * RPC server socket. + */ +struct svc_sock { + struct list_head sk_ready; /* list of ready sockets */ + struct list_head sk_list; /* list of all sockets */ + struct socket * sk_sock; /* berkeley socket layer */ + struct sock * sk_sk; /* INET layer */ + + struct svc_serv * sk_server; /* service for this socket */ + unsigned int sk_inuse; /* use count */ + unsigned long sk_flags; +#define SK_BUSY 0 /* enqueued/receiving */ +#define SK_CONN 1 /* conn pending */ +#define SK_CLOSE 2 /* dead or dying */ +#define SK_DATA 3 /* data pending */ +#define SK_TEMP 4 /* temp (TCP) socket */ +#define SK_DEAD 6 /* socket closed */ +#define SK_CHNGBUF 7 /* need to change snd/rcv buffer sizes */ +#define SK_DEFERRED 8 /* request on sk_deferred */ + + int sk_reserved; /* space on outq that is reserved */ + + struct list_head sk_deferred; /* deferred requests that need to + * be revisted */ + struct semaphore sk_sem; /* to serialize sending data */ + + int (*sk_recvfrom)(struct svc_rqst *rqstp); + int (*sk_sendto)(struct svc_rqst *rqstp); + + /* We keep the old state_change and data_ready CB's here */ + void (*sk_ostate)(struct sock *); + void (*sk_odata)(struct sock *, int bytes); + void (*sk_owspace)(struct sock *); + + /* private TCP part */ + int sk_reclen; /* length of record */ + int sk_tcplen; /* current read length */ + time_t sk_lastrecv; /* time of last received request */ +}; + +/* + * Function prototypes. + */ +int svc_makesock(struct svc_serv *, int, unsigned short); +void svc_delete_socket(struct svc_sock *); +int svc_recv(struct svc_serv *, struct svc_rqst *, long); +int svc_send(struct svc_rqst *); +void svc_drop(struct svc_rqst *); +void svc_sock_update_bufs(struct svc_serv *serv); + +#endif /* SUNRPC_SVCSOCK_H */ diff --git a/include/linux/sunrpc/timer.h b/include/linux/sunrpc/timer.h new file mode 100644 index 00000000000..a67fd734c73 --- /dev/null +++ b/include/linux/sunrpc/timer.h @@ -0,0 +1,49 @@ +/* + * linux/include/linux/sunrpc/timer.h + * + * Declarations for the RPC transport timer. + * + * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no> + */ + +#ifndef _LINUX_SUNRPC_TIMER_H +#define _LINUX_SUNRPC_TIMER_H + +#include <asm/atomic.h> + +struct rpc_rtt { + unsigned long timeo; /* default timeout value */ + unsigned long srtt[5]; /* smoothed round trip time << 3 */ + unsigned long sdrtt[5]; /* smoothed medium deviation of RTT */ + int ntimeouts[5]; /* Number of timeouts for the last request */ +}; + + +extern void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo); +extern void rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m); +extern unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned timer); + +static inline void rpc_set_timeo(struct rpc_rtt *rt, int timer, int ntimeo) +{ + int *t; + if (!timer) + return; + t = &rt->ntimeouts[timer-1]; + if (ntimeo < *t) { + if (*t > 0) + (*t)--; + } else { + if (ntimeo > 8) + ntimeo = 8; + *t = ntimeo; + } +} + +static inline int rpc_ntimeo(struct rpc_rtt *rt, int timer) +{ + if (!timer) + return 0; + return rt->ntimeouts[timer-1]; +} + +#endif /* _LINUX_SUNRPC_TIMER_H */ diff --git a/include/linux/sunrpc/types.h b/include/linux/sunrpc/types.h new file mode 100644 index 00000000000..d222f47550a --- /dev/null +++ b/include/linux/sunrpc/types.h @@ -0,0 +1,22 @@ +/* + * linux/include/linux/sunrpc/types.h + * + * Generic types and misc stuff for RPC. + * + * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _LINUX_SUNRPC_TYPES_H_ +#define _LINUX_SUNRPC_TYPES_H_ + +#include <linux/timer.h> +#include <linux/workqueue.h> +#include <linux/sunrpc/debug.h> +#include <linux/list.h> + +/* + * Shorthands + */ +#define signalled() (signal_pending(current)) + +#endif /* _LINUX_SUNRPC_TYPES_H_ */ diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h new file mode 100644 index 00000000000..541dcf838ab --- /dev/null +++ b/include/linux/sunrpc/xdr.h @@ -0,0 +1,192 @@ +/* + * include/linux/sunrpc/xdr.h + * + * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _SUNRPC_XDR_H_ +#define _SUNRPC_XDR_H_ + +#ifdef __KERNEL__ + +#include <linux/uio.h> +#include <asm/byteorder.h> + +/* + * Buffer adjustment + */ +#define XDR_QUADLEN(l) (((l) + 3) >> 2) + +/* + * Generic opaque `network object.' At the kernel level, this type + * is used only by lockd. + */ +#define XDR_MAX_NETOBJ 1024 +struct xdr_netobj { + unsigned int len; + u8 * data; +}; + +/* + * This is the generic XDR function. rqstp is either a rpc_rqst (client + * side) or svc_rqst pointer (server side). + * Encode functions always assume there's enough room in the buffer. + */ +typedef int (*kxdrproc_t)(void *rqstp, u32 *data, void *obj); + +/* + * Basic structure for transmission/reception of a client XDR message. + * Features a header (for a linear buffer containing RPC headers + * and the data payload for short messages), and then an array of + * pages. + * The tail iovec allows you to append data after the page array. Its + * main interest is for appending padding to the pages in order to + * satisfy the int_32-alignment requirements in RFC1832. + * + * For the future, we might want to string several of these together + * in a list if anybody wants to make use of NFSv4 COMPOUND + * operations and/or has a need for scatter/gather involving pages. + */ +struct xdr_buf { + struct kvec head[1], /* RPC header + non-page data */ + tail[1]; /* Appended after page data */ + + struct page ** pages; /* Array of contiguous pages */ + unsigned int page_base, /* Start of page data */ + page_len; /* Length of page data */ + + unsigned int buflen, /* Total length of storage buffer */ + len; /* Length of XDR encoded message */ + +}; + +/* + * pre-xdr'ed macros. + */ + +#define xdr_zero __constant_htonl(0) +#define xdr_one __constant_htonl(1) +#define xdr_two __constant_htonl(2) + +#define rpc_success __constant_htonl(RPC_SUCCESS) +#define rpc_prog_unavail __constant_htonl(RPC_PROG_UNAVAIL) +#define rpc_prog_mismatch __constant_htonl(RPC_PROG_MISMATCH) +#define rpc_proc_unavail __constant_htonl(RPC_PROC_UNAVAIL) +#define rpc_garbage_args __constant_htonl(RPC_GARBAGE_ARGS) +#define rpc_system_err __constant_htonl(RPC_SYSTEM_ERR) + +#define rpc_auth_ok __constant_htonl(RPC_AUTH_OK) +#define rpc_autherr_badcred __constant_htonl(RPC_AUTH_BADCRED) +#define rpc_autherr_rejectedcred __constant_htonl(RPC_AUTH_REJECTEDCRED) +#define rpc_autherr_badverf __constant_htonl(RPC_AUTH_BADVERF) +#define rpc_autherr_rejectedverf __constant_htonl(RPC_AUTH_REJECTEDVERF) +#define rpc_autherr_tooweak __constant_htonl(RPC_AUTH_TOOWEAK) +#define rpcsec_gsserr_credproblem __constant_htonl(RPCSEC_GSS_CREDPROBLEM) +#define rpcsec_gsserr_ctxproblem __constant_htonl(RPCSEC_GSS_CTXPROBLEM) +#define rpc_autherr_oldseqnum __constant_htonl(101) + +/* + * Miscellaneous XDR helper functions + */ +u32 * xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int len); +u32 * xdr_encode_opaque(u32 *p, const void *ptr, unsigned int len); +u32 * xdr_encode_string(u32 *p, const char *s); +u32 * xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen); +u32 * xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen); +u32 * xdr_encode_netobj(u32 *p, const struct xdr_netobj *); +u32 * xdr_decode_netobj(u32 *p, struct xdr_netobj *); + +void xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int, + unsigned int); +void xdr_inline_pages(struct xdr_buf *, unsigned int, + struct page **, unsigned int, unsigned int); + +static inline u32 *xdr_encode_array(u32 *p, const void *s, unsigned int len) +{ + return xdr_encode_opaque(p, s, len); +} + +/* + * Decode 64bit quantities (NFSv3 support) + */ +static inline u32 * +xdr_encode_hyper(u32 *p, __u64 val) +{ + *p++ = htonl(val >> 32); + *p++ = htonl(val & 0xFFFFFFFF); + return p; +} + +static inline u32 * +xdr_decode_hyper(u32 *p, __u64 *valp) +{ + *valp = ((__u64) ntohl(*p++)) << 32; + *valp |= ntohl(*p++); + return p; +} + +/* + * Adjust kvec to reflect end of xdr'ed data (RPC client XDR) + */ +static inline int +xdr_adjust_iovec(struct kvec *iov, u32 *p) +{ + return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base); +} + +/* + * Maximum number of iov's we use. + */ +#define MAX_IOVEC (12) + +/* + * XDR buffer helper functions + */ +extern void xdr_shift_buf(struct xdr_buf *, size_t); +extern void xdr_buf_from_iov(struct kvec *, struct xdr_buf *); +extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, int, int); +extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, int); +extern int read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len); + +/* + * Helper structure for copying from an sk_buff. + */ +typedef struct { + struct sk_buff *skb; + unsigned int offset; + size_t count; + unsigned int csum; +} skb_reader_t; + +typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); + +extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, + skb_reader_t *, skb_read_actor_t); + +struct socket; +struct sockaddr; +extern int xdr_sendpages(struct socket *, struct sockaddr *, int, + struct xdr_buf *, unsigned int, int); + +/* + * Provide some simple tools for XDR buffer overflow-checking etc. + */ +struct xdr_stream { + uint32_t *p; /* start of available buffer */ + struct xdr_buf *buf; /* XDR buffer to read/write */ + + uint32_t *end; /* end of available buffer space */ + struct kvec *iov; /* pointer to the current kvec */ +}; + +extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p); +extern uint32_t *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); +extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, + unsigned int base, unsigned int len); +extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p); +extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes); +extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len); + +#endif /* __KERNEL__ */ + +#endif /* _SUNRPC_XDR_H_ */ diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h new file mode 100644 index 00000000000..e618c164981 --- /dev/null +++ b/include/linux/sunrpc/xprt.h @@ -0,0 +1,232 @@ +/* + * linux/include/linux/sunrpc/clnt_xprt.h + * + * Declarations for the RPC transport interface. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef _LINUX_SUNRPC_XPRT_H +#define _LINUX_SUNRPC_XPRT_H + +#include <linux/uio.h> +#include <linux/socket.h> +#include <linux/in.h> +#include <linux/sunrpc/sched.h> +#include <linux/sunrpc/xdr.h> + +/* + * The transport code maintains an estimate on the maximum number of out- + * standing RPC requests, using a smoothed version of the congestion + * avoidance implemented in 44BSD. This is basically the Van Jacobson + * congestion algorithm: If a retransmit occurs, the congestion window is + * halved; otherwise, it is incremented by 1/cwnd when + * + * - a reply is received and + * - a full number of requests are outstanding and + * - the congestion window hasn't been updated recently. + * + * Upper procedures may check whether a request would block waiting for + * a free RPC slot by using the RPC_CONGESTED() macro. + */ +extern unsigned int xprt_udp_slot_table_entries; +extern unsigned int xprt_tcp_slot_table_entries; + +#define RPC_MIN_SLOT_TABLE (2U) +#define RPC_DEF_SLOT_TABLE (16U) +#define RPC_MAX_SLOT_TABLE (128U) + +#define RPC_CWNDSHIFT (8U) +#define RPC_CWNDSCALE (1U << RPC_CWNDSHIFT) +#define RPC_INITCWND RPC_CWNDSCALE +#define RPC_MAXCWND(xprt) ((xprt)->max_reqs << RPC_CWNDSHIFT) +#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd) + +/* Default timeout values */ +#define RPC_MAX_UDP_TIMEOUT (60*HZ) +#define RPC_MAX_TCP_TIMEOUT (600*HZ) + +/* + * Wait duration for an RPC TCP connection to be established. Solaris + * NFS over TCP uses 60 seconds, for example, which is in line with how + * long a server takes to reboot. + */ +#define RPC_CONNECT_TIMEOUT (60*HZ) + +/* + * Delay an arbitrary number of seconds before attempting to reconnect + * after an error. + */ +#define RPC_REESTABLISH_TIMEOUT (15*HZ) + +/* RPC call and reply header size as number of 32bit words (verifier + * size computed separately) + */ +#define RPC_CALLHDRSIZE 6 +#define RPC_REPHDRSIZE 4 + +/* + * This describes a timeout strategy + */ +struct rpc_timeout { + unsigned long to_initval, /* initial timeout */ + to_maxval, /* max timeout */ + to_increment; /* if !exponential */ + unsigned int to_retries; /* max # of retries */ + unsigned char to_exponential; +}; + +/* + * This describes a complete RPC request + */ +struct rpc_rqst { + /* + * This is the user-visible part + */ + struct rpc_xprt * rq_xprt; /* RPC client */ + struct xdr_buf rq_snd_buf; /* send buffer */ + struct xdr_buf rq_rcv_buf; /* recv buffer */ + + /* + * This is the private part + */ + struct rpc_task * rq_task; /* RPC task data */ + __u32 rq_xid; /* request XID */ + int rq_cong; /* has incremented xprt->cong */ + int rq_received; /* receive completed */ + u32 rq_seqno; /* gss seq no. used on req. */ + + struct list_head rq_list; + + struct xdr_buf rq_private_buf; /* The receive buffer + * used in the softirq. + */ + unsigned long rq_majortimeo; /* major timeout alarm */ + unsigned long rq_timeout; /* Current timeout value */ + unsigned int rq_retries; /* # of retries */ + /* + * For authentication (e.g. auth_des) + */ + u32 rq_creddata[2]; + + /* + * Partial send handling + */ + + u32 rq_bytes_sent; /* Bytes we have sent */ + + unsigned long rq_xtime; /* when transmitted */ + int rq_ntrans; +}; +#define rq_svec rq_snd_buf.head +#define rq_slen rq_snd_buf.len + +#define XPRT_LAST_FRAG (1 << 0) +#define XPRT_COPY_RECM (1 << 1) +#define XPRT_COPY_XID (1 << 2) +#define XPRT_COPY_DATA (1 << 3) + +struct rpc_xprt { + struct socket * sock; /* BSD socket layer */ + struct sock * inet; /* INET layer */ + + struct rpc_timeout timeout; /* timeout parms */ + struct sockaddr_in addr; /* server address */ + int prot; /* IP protocol */ + + unsigned long cong; /* current congestion */ + unsigned long cwnd; /* congestion window */ + + unsigned int rcvsize, /* socket receive buffer size */ + sndsize; /* socket send buffer size */ + + size_t max_payload; /* largest RPC payload size, + in bytes */ + + struct rpc_wait_queue sending; /* requests waiting to send */ + struct rpc_wait_queue resend; /* requests waiting to resend */ + struct rpc_wait_queue pending; /* requests in flight */ + struct rpc_wait_queue backlog; /* waiting for slot */ + struct list_head free; /* free slots */ + struct rpc_rqst * slot; /* slot table storage */ + unsigned int max_reqs; /* total slots */ + unsigned long sockstate; /* Socket state */ + unsigned char shutdown : 1, /* being shut down */ + nocong : 1, /* no congestion control */ + resvport : 1, /* use a reserved port */ + stream : 1; /* TCP */ + + /* + * XID + */ + __u32 xid; /* Next XID value to use */ + + /* + * State of TCP reply receive stuff + */ + u32 tcp_recm, /* Fragment header */ + tcp_xid, /* Current XID */ + tcp_reclen, /* fragment length */ + tcp_offset; /* fragment offset */ + unsigned long tcp_copied, /* copied to request */ + tcp_flags; + /* + * Connection of sockets + */ + struct work_struct sock_connect; + unsigned short port; + /* + * Disconnection of idle sockets + */ + struct work_struct task_cleanup; + struct timer_list timer; + unsigned long last_used; + + /* + * Send stuff + */ + spinlock_t sock_lock; /* lock socket info */ + spinlock_t xprt_lock; /* lock xprt info */ + struct rpc_task * snd_task; /* Task blocked in send */ + + struct list_head recv; + + + void (*old_data_ready)(struct sock *, int); + void (*old_state_change)(struct sock *); + void (*old_write_space)(struct sock *); + + wait_queue_head_t cong_wait; +}; + +#ifdef __KERNEL__ + +struct rpc_xprt * xprt_create_proto(int proto, struct sockaddr_in *addr, + struct rpc_timeout *toparms); +int xprt_destroy(struct rpc_xprt *); +void xprt_set_timeout(struct rpc_timeout *, unsigned int, + unsigned long); + +void xprt_reserve(struct rpc_task *); +int xprt_prepare_transmit(struct rpc_task *); +void xprt_transmit(struct rpc_task *); +void xprt_receive(struct rpc_task *); +int xprt_adjust_timeout(struct rpc_rqst *req); +void xprt_release(struct rpc_task *); +void xprt_connect(struct rpc_task *); +void xprt_sock_setbufsize(struct rpc_xprt *); + +#define XPRT_LOCKED 0 +#define XPRT_CONNECT 1 +#define XPRT_CONNECTING 2 + +#define xprt_connected(xp) (test_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_set_connected(xp) (set_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_test_and_set_connected(xp) (test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_test_and_clear_connected(xp) \ + (test_and_clear_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_clear_connected(xp) (clear_bit(XPRT_CONNECT, &(xp)->sockstate)) + +#endif /* __KERNEL__*/ + +#endif /* _LINUX_SUNRPC_XPRT_H */ |