svc: Move the sockaddr information to svc_xprt
[safe/jmp/linux-2.6] / net / sunrpc / svc_xprt.c
1 /*
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 */
39 static DEFINE_SPINLOCK(svc_xprt_class_lock);
40 static LIST_HEAD(svc_xprt_class_list);
41
42 int 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;
58 out:
59         spin_unlock(&svc_xprt_class_lock);
60         return res;
61 }
62 EXPORT_SYMBOL_GPL(svc_reg_xprt_class);
63
64 void 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 }
71 EXPORT_SYMBOL_GPL(svc_unreg_xprt_class);
72
73 static 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;
78         if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)
79             && xprt->xpt_auth_cache != NULL)
80                 svcauth_unix_info_release(xprt->xpt_auth_cache);
81         xprt->xpt_ops->xpo_free(xprt);
82         module_put(owner);
83 }
84
85 void svc_xprt_put(struct svc_xprt *xprt)
86 {
87         kref_put(&xprt->xpt_ref, svc_xprt_free);
88 }
89 EXPORT_SYMBOL_GPL(svc_xprt_put);
90
91 /*
92  * Called by transport drivers to initialize the transport independent
93  * portion of the transport instance.
94  */
95 void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
96                    struct svc_serv *serv)
97 {
98         memset(xprt, 0, sizeof(*xprt));
99         xprt->xpt_class = xcl;
100         xprt->xpt_ops = xcl->xcl_ops;
101         kref_init(&xprt->xpt_ref);
102         xprt->xpt_server = serv;
103         INIT_LIST_HEAD(&xprt->xpt_list);
104         INIT_LIST_HEAD(&xprt->xpt_ready);
105         INIT_LIST_HEAD(&xprt->xpt_deferred);
106         mutex_init(&xprt->xpt_mutex);
107         spin_lock_init(&xprt->xpt_lock);
108 }
109 EXPORT_SYMBOL_GPL(svc_xprt_init);
110
111 int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
112                     int flags)
113 {
114         struct svc_xprt_class *xcl;
115         int ret = -ENOENT;
116         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) {
124                 if (strcmp(xprt_name, xcl->xcl_name) == 0) {
125                         spin_unlock(&svc_xprt_class_lock);
126                         if (try_module_get(xcl->xcl_owner)) {
127                                 struct svc_xprt *newxprt;
128                                 newxprt = xcl->xcl_ops->xpo_create
129                                         (serv,
130                                          (struct sockaddr *)&sin, sizeof(sin),
131                                          flags);
132                                 if (IS_ERR(newxprt)) {
133                                         module_put(xcl->xcl_owner);
134                                         ret = PTR_ERR(newxprt);
135                                 } else
136                                         ret = svc_xprt_local_port(newxprt);
137                         }
138                         goto out;
139                 }
140         }
141         spin_unlock(&svc_xprt_class_lock);
142         dprintk("svc: transport %s not found\n", xprt_name);
143  out:
144         return ret;
145 }
146 EXPORT_SYMBOL_GPL(svc_create_xprt);
147
148 /*
149  * Copy the local and remote xprt addresses to the rqstp structure
150  */
151 void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt)
152 {
153         struct sockaddr *sin;
154
155         memcpy(&rqstp->rq_addr, &xprt->xpt_remote, xprt->xpt_remotelen);
156         rqstp->rq_addrlen = xprt->xpt_remotelen;
157
158         /*
159          * Destination address in request is needed for binding the
160          * source address in RPC replies/callbacks later.
161          */
162         sin = (struct sockaddr *)&xprt->xpt_local;
163         switch (sin->sa_family) {
164         case AF_INET:
165                 rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
166                 break;
167         case AF_INET6:
168                 rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
169                 break;
170         }
171 }
172 EXPORT_SYMBOL_GPL(svc_xprt_copy_addrs);
173