blob: 271467c5138d72d961d7cb62c8aa4ccd752a1bb6 [file] [log] [blame]
Tom Tucker1d8206b92007-12-30 21:07:15 -06001/*
2 * linux/net/sunrpc/svc_xprt.c
3 *
4 * Author: Tom Tucker <tom@opengridcomputing.com>
5 */
6
7#include <linux/sched.h>
8#include <linux/errno.h>
9#include <linux/fcntl.h>
10#include <linux/net.h>
11#include <linux/in.h>
12#include <linux/inet.h>
13#include <linux/udp.h>
14#include <linux/tcp.h>
15#include <linux/unistd.h>
16#include <linux/slab.h>
17#include <linux/netdevice.h>
18#include <linux/skbuff.h>
19#include <linux/file.h>
20#include <linux/freezer.h>
21#include <net/sock.h>
22#include <net/checksum.h>
23#include <net/ip.h>
24#include <net/ipv6.h>
25#include <net/tcp_states.h>
26#include <linux/uaccess.h>
27#include <asm/ioctls.h>
28
29#include <linux/sunrpc/types.h>
30#include <linux/sunrpc/clnt.h>
31#include <linux/sunrpc/xdr.h>
32#include <linux/sunrpc/svcsock.h>
33#include <linux/sunrpc/stats.h>
34#include <linux/sunrpc/svc_xprt.h>
35
36#define RPCDBG_FACILITY RPCDBG_SVCXPRT
37
38/* List of registered transport classes */
39static DEFINE_SPINLOCK(svc_xprt_class_lock);
40static LIST_HEAD(svc_xprt_class_list);
41
42int svc_reg_xprt_class(struct svc_xprt_class *xcl)
43{
44 struct svc_xprt_class *cl;
45 int res = -EEXIST;
46
47 dprintk("svc: Adding svc transport class '%s'\n", xcl->xcl_name);
48
49 INIT_LIST_HEAD(&xcl->xcl_list);
50 spin_lock(&svc_xprt_class_lock);
51 /* Make sure there isn't already a class with the same name */
52 list_for_each_entry(cl, &svc_xprt_class_list, xcl_list) {
53 if (strcmp(xcl->xcl_name, cl->xcl_name) == 0)
54 goto out;
55 }
56 list_add_tail(&xcl->xcl_list, &svc_xprt_class_list);
57 res = 0;
58out:
59 spin_unlock(&svc_xprt_class_lock);
60 return res;
61}
62EXPORT_SYMBOL_GPL(svc_reg_xprt_class);
63
64void svc_unreg_xprt_class(struct svc_xprt_class *xcl)
65{
66 dprintk("svc: Removing svc transport class '%s'\n", xcl->xcl_name);
67 spin_lock(&svc_xprt_class_lock);
68 list_del_init(&xcl->xcl_list);
69 spin_unlock(&svc_xprt_class_lock);
70}
71EXPORT_SYMBOL_GPL(svc_unreg_xprt_class);
72
Tom Tuckere1b31572007-12-30 21:07:46 -060073static void svc_xprt_free(struct kref *kref)
74{
75 struct svc_xprt *xprt =
76 container_of(kref, struct svc_xprt, xpt_ref);
77 struct module *owner = xprt->xpt_class->xcl_owner;
Tom Tuckerdef13d72007-12-30 21:08:08 -060078 if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)
79 && xprt->xpt_auth_cache != NULL)
80 svcauth_unix_info_release(xprt->xpt_auth_cache);
Tom Tuckere1b31572007-12-30 21:07:46 -060081 xprt->xpt_ops->xpo_free(xprt);
82 module_put(owner);
83}
84
85void svc_xprt_put(struct svc_xprt *xprt)
86{
87 kref_put(&xprt->xpt_ref, svc_xprt_free);
88}
89EXPORT_SYMBOL_GPL(svc_xprt_put);
90
Tom Tucker1d8206b92007-12-30 21:07:15 -060091/*
92 * Called by transport drivers to initialize the transport independent
93 * portion of the transport instance.
94 */
Tom Tuckerbb5cf162007-12-30 21:07:50 -060095void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
96 struct svc_serv *serv)
Tom Tucker1d8206b92007-12-30 21:07:15 -060097{
98 memset(xprt, 0, sizeof(*xprt));
99 xprt->xpt_class = xcl;
100 xprt->xpt_ops = xcl->xcl_ops;
Tom Tuckere1b31572007-12-30 21:07:46 -0600101 kref_init(&xprt->xpt_ref);
Tom Tuckerbb5cf162007-12-30 21:07:50 -0600102 xprt->xpt_server = serv;
Tom Tucker7a182082007-12-30 21:07:53 -0600103 INIT_LIST_HEAD(&xprt->xpt_list);
104 INIT_LIST_HEAD(&xprt->xpt_ready);
Tom Tucker8c7b0172007-12-30 21:08:10 -0600105 INIT_LIST_HEAD(&xprt->xpt_deferred);
Tom Tuckera50fea22007-12-30 21:07:59 -0600106 mutex_init(&xprt->xpt_mutex);
Tom Tuckerdef13d72007-12-30 21:08:08 -0600107 spin_lock_init(&xprt->xpt_lock);
Tom Tucker4e5caaa2007-12-30 21:08:20 -0600108 set_bit(XPT_BUSY, &xprt->xpt_flags);
Tom Tucker1d8206b92007-12-30 21:07:15 -0600109}
110EXPORT_SYMBOL_GPL(svc_xprt_init);
Tom Tuckerb700cbb2007-12-30 21:07:42 -0600111
112int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
113 int flags)
114{
115 struct svc_xprt_class *xcl;
Tom Tuckerb700cbb2007-12-30 21:07:42 -0600116 struct sockaddr_in sin = {
117 .sin_family = AF_INET,
118 .sin_addr.s_addr = INADDR_ANY,
119 .sin_port = htons(port),
120 };
121 dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
122 spin_lock(&svc_xprt_class_lock);
123 list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
Tom Tucker4e5caaa2007-12-30 21:08:20 -0600124 struct svc_xprt *newxprt;
125
126 if (strcmp(xprt_name, xcl->xcl_name))
127 continue;
128
129 if (!try_module_get(xcl->xcl_owner))
130 goto err;
131
132 spin_unlock(&svc_xprt_class_lock);
133 newxprt = xcl->xcl_ops->
134 xpo_create(serv, (struct sockaddr *)&sin, sizeof(sin),
135 flags);
136 if (IS_ERR(newxprt)) {
137 module_put(xcl->xcl_owner);
138 return PTR_ERR(newxprt);
Tom Tuckerb700cbb2007-12-30 21:07:42 -0600139 }
Tom Tucker4e5caaa2007-12-30 21:08:20 -0600140
141 clear_bit(XPT_TEMP, &newxprt->xpt_flags);
142 spin_lock_bh(&serv->sv_lock);
143 list_add(&newxprt->xpt_list, &serv->sv_permsocks);
144 spin_unlock_bh(&serv->sv_lock);
145 clear_bit(XPT_BUSY, &newxprt->xpt_flags);
146 return svc_xprt_local_port(newxprt);
Tom Tuckerb700cbb2007-12-30 21:07:42 -0600147 }
Tom Tucker4e5caaa2007-12-30 21:08:20 -0600148 err:
Tom Tuckerb700cbb2007-12-30 21:07:42 -0600149 spin_unlock(&svc_xprt_class_lock);
150 dprintk("svc: transport %s not found\n", xprt_name);
Tom Tucker4e5caaa2007-12-30 21:08:20 -0600151 return -ENOENT;
Tom Tuckerb700cbb2007-12-30 21:07:42 -0600152}
153EXPORT_SYMBOL_GPL(svc_create_xprt);
Tom Tucker9dbc2402007-12-30 21:08:12 -0600154
155/*
156 * Copy the local and remote xprt addresses to the rqstp structure
157 */
158void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt)
159{
160 struct sockaddr *sin;
161
162 memcpy(&rqstp->rq_addr, &xprt->xpt_remote, xprt->xpt_remotelen);
163 rqstp->rq_addrlen = xprt->xpt_remotelen;
164
165 /*
166 * Destination address in request is needed for binding the
167 * source address in RPC replies/callbacks later.
168 */
169 sin = (struct sockaddr *)&xprt->xpt_local;
170 switch (sin->sa_family) {
171 case AF_INET:
172 rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
173 break;
174 case AF_INET6:
175 rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
176 break;
177 }
178}
179EXPORT_SYMBOL_GPL(svc_xprt_copy_addrs);
180