Commit | Line | Data |
---|---|---|
457c8996 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
a509050b CL |
2 | /* |
3 | * In-kernel rpcbind client supporting versions 2, 3, and 4 of the rpcbind | |
4 | * protocol | |
5 | * | |
6 | * Based on RFC 1833: "Binding Protocols for ONC RPC Version 2" and | |
7 | * RFC 3530: "Network File System (NFS) version 4 Protocol" | |
8 | * | |
9 | * Original: Gilles Quillard, Bull Open Source, 2005 <gilles.quillard@bull.net> | |
10 | * Updated: Chuck Lever, Oracle Corporation, 2007 <chuck.lever@oracle.com> | |
11 | * | |
12 | * Descended from net/sunrpc/pmap_clnt.c, | |
13 | * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> | |
14 | */ | |
15 | ||
cce63cd6 CL |
16 | #include <linux/module.h> |
17 | ||
a509050b CL |
18 | #include <linux/types.h> |
19 | #include <linux/socket.h> | |
7402ab19 | 20 | #include <linux/un.h> |
d5b64430 CL |
21 | #include <linux/in.h> |
22 | #include <linux/in6.h> | |
a509050b CL |
23 | #include <linux/kernel.h> |
24 | #include <linux/errno.h> | |
c526611d | 25 | #include <linux/mutex.h> |
5a0e3ad6 | 26 | #include <linux/slab.h> |
9d548b9c | 27 | #include <net/ipv6.h> |
a509050b CL |
28 | |
29 | #include <linux/sunrpc/clnt.h> | |
5976687a | 30 | #include <linux/sunrpc/addr.h> |
a509050b | 31 | #include <linux/sunrpc/sched.h> |
0896a725 | 32 | #include <linux/sunrpc/xprtsock.h> |
a509050b | 33 | |
e465cc3f CL |
34 | #include <trace/events/sunrpc.h> |
35 | ||
dff02d49 SK |
36 | #include "netns.h" |
37 | ||
7402ab19 CL |
38 | #define RPCBIND_SOCK_PATHNAME "/var/run/rpcbind.sock" |
39 | ||
a509050b CL |
40 | #define RPCBIND_PROGRAM (100000u) |
41 | #define RPCBIND_PORT (111u) | |
42 | ||
fc200e79 CL |
43 | #define RPCBVERS_2 (2u) |
44 | #define RPCBVERS_3 (3u) | |
45 | #define RPCBVERS_4 (4u) | |
46 | ||
a509050b CL |
47 | enum { |
48 | RPCBPROC_NULL, | |
49 | RPCBPROC_SET, | |
50 | RPCBPROC_UNSET, | |
51 | RPCBPROC_GETPORT, | |
52 | RPCBPROC_GETADDR = 3, /* alias for GETPORT */ | |
53 | RPCBPROC_DUMP, | |
54 | RPCBPROC_CALLIT, | |
55 | RPCBPROC_BCAST = 5, /* alias for CALLIT */ | |
56 | RPCBPROC_GETTIME, | |
57 | RPCBPROC_UADDR2TADDR, | |
58 | RPCBPROC_TADDR2UADDR, | |
59 | RPCBPROC_GETVERSADDR, | |
60 | RPCBPROC_INDIRECT, | |
61 | RPCBPROC_GETADDRLIST, | |
62 | RPCBPROC_GETSTAT, | |
63 | }; | |
64 | ||
a509050b CL |
65 | /* |
66 | * r_owner | |
67 | * | |
68 | * The "owner" is allowed to unset a service in the rpcbind database. | |
126e4bc3 CL |
69 | * |
70 | * For AF_LOCAL SET/UNSET requests, rpcbind treats this string as a | |
71 | * UID which it maps to a local user name via a password lookup. | |
72 | * In all other cases it is ignored. | |
73 | * | |
74 | * For SET/UNSET requests, user space provides a value, even for | |
75 | * network requests, and GETADDR uses an empty string. We follow | |
76 | * those precedents here. | |
a509050b | 77 | */ |
126e4bc3 | 78 | #define RPCB_OWNER_STRING "0" |
a509050b CL |
79 | #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING) |
80 | ||
0b10bf5e CL |
81 | /* |
82 | * XDR data type sizes | |
83 | */ | |
84 | #define RPCB_program_sz (1) | |
85 | #define RPCB_version_sz (1) | |
86 | #define RPCB_protocol_sz (1) | |
87 | #define RPCB_port_sz (1) | |
88 | #define RPCB_boolean_sz (1) | |
89 | ||
90 | #define RPCB_netid_sz (1 + XDR_QUADLEN(RPCBIND_MAXNETIDLEN)) | |
91 | #define RPCB_addr_sz (1 + XDR_QUADLEN(RPCBIND_MAXUADDRLEN)) | |
92 | #define RPCB_ownerstring_sz (1 + XDR_QUADLEN(RPCB_MAXOWNERLEN)) | |
93 | ||
94 | /* | |
95 | * XDR argument and result sizes | |
96 | */ | |
97 | #define RPCB_mappingargs_sz (RPCB_program_sz + RPCB_version_sz + \ | |
98 | RPCB_protocol_sz + RPCB_port_sz) | |
99 | #define RPCB_getaddrargs_sz (RPCB_program_sz + RPCB_version_sz + \ | |
100 | RPCB_netid_sz + RPCB_addr_sz + \ | |
101 | RPCB_ownerstring_sz) | |
102 | ||
103 | #define RPCB_getportres_sz RPCB_port_sz | |
104 | #define RPCB_setres_sz RPCB_boolean_sz | |
105 | ||
106 | /* | |
107 | * Note that RFC 1833 does not put any size restrictions on the | |
108 | * address string returned by the remote rpcbind database. | |
109 | */ | |
110 | #define RPCB_getaddrres_sz RPCB_addr_sz | |
111 | ||
a509050b | 112 | static void rpcb_getport_done(struct rpc_task *, void *); |
381ba74a | 113 | static void rpcb_map_release(void *data); |
a613fa16 | 114 | static const struct rpc_program rpcb_program; |
a509050b CL |
115 | |
116 | struct rpcbind_args { | |
117 | struct rpc_xprt * r_xprt; | |
118 | ||
119 | u32 r_prog; | |
120 | u32 r_vers; | |
121 | u32 r_prot; | |
122 | unsigned short r_port; | |
86d61d86 TM |
123 | const char * r_netid; |
124 | const char * r_addr; | |
125 | const char * r_owner; | |
381ba74a TM |
126 | |
127 | int r_status; | |
a509050b CL |
128 | }; |
129 | ||
499b4988 CH |
130 | static const struct rpc_procinfo rpcb_procedures2[]; |
131 | static const struct rpc_procinfo rpcb_procedures3[]; | |
132 | static const struct rpc_procinfo rpcb_procedures4[]; | |
a509050b | 133 | |
d5b64430 | 134 | struct rpcb_info { |
fc200e79 | 135 | u32 rpc_vers; |
499b4988 | 136 | const struct rpc_procinfo *rpc_proc; |
d5b64430 CL |
137 | }; |
138 | ||
a613fa16 TM |
139 | static const struct rpcb_info rpcb_next_version[]; |
140 | static const struct rpcb_info rpcb_next_version6[]; | |
a509050b | 141 | |
a509050b | 142 | static const struct rpc_call_ops rpcb_getport_ops = { |
a509050b CL |
143 | .rpc_call_done = rpcb_getport_done, |
144 | .rpc_release = rpcb_map_release, | |
145 | }; | |
146 | ||
147 | static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status) | |
148 | { | |
149 | xprt_clear_binding(xprt); | |
150 | rpc_wake_up_status(&xprt->binding, status); | |
151 | } | |
152 | ||
381ba74a TM |
153 | static void rpcb_map_release(void *data) |
154 | { | |
155 | struct rpcbind_args *map = data; | |
156 | ||
157 | rpcb_wake_rpcbind_waiters(map->r_xprt, map->r_status); | |
158 | xprt_put(map->r_xprt); | |
ba809130 | 159 | kfree(map->r_addr); |
381ba74a TM |
160 | kfree(map); |
161 | } | |
162 | ||
2ea75a10 | 163 | static int rpcb_get_local(struct net *net) |
914edb1b SK |
164 | { |
165 | int cnt; | |
2ea75a10 | 166 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
914edb1b | 167 | |
dff02d49 SK |
168 | spin_lock(&sn->rpcb_clnt_lock); |
169 | if (sn->rpcb_users) | |
170 | sn->rpcb_users++; | |
171 | cnt = sn->rpcb_users; | |
172 | spin_unlock(&sn->rpcb_clnt_lock); | |
914edb1b SK |
173 | |
174 | return cnt; | |
175 | } | |
176 | ||
f7a30c18 | 177 | void rpcb_put_local(struct net *net) |
914edb1b | 178 | { |
f7a30c18 | 179 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
dff02d49 SK |
180 | struct rpc_clnt *clnt = sn->rpcb_local_clnt; |
181 | struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4; | |
9793f7c8 | 182 | int shutdown = 0; |
914edb1b | 183 | |
dff02d49 | 184 | spin_lock(&sn->rpcb_clnt_lock); |
9793f7c8 SK |
185 | if (sn->rpcb_users) { |
186 | if (--sn->rpcb_users == 0) { | |
187 | sn->rpcb_local_clnt = NULL; | |
188 | sn->rpcb_local_clnt4 = NULL; | |
189 | } | |
190 | shutdown = !sn->rpcb_users; | |
914edb1b | 191 | } |
dff02d49 | 192 | spin_unlock(&sn->rpcb_clnt_lock); |
914edb1b SK |
193 | |
194 | if (shutdown) { | |
195 | /* | |
196 | * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister | |
197 | */ | |
198 | if (clnt4) | |
199 | rpc_shutdown_client(clnt4); | |
200 | if (clnt) | |
201 | rpc_shutdown_client(clnt); | |
202 | } | |
203 | } | |
204 | ||
2ea75a10 | 205 | static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt, |
786615bc TM |
206 | struct rpc_clnt *clnt4, |
207 | bool is_af_local) | |
914edb1b | 208 | { |
2ea75a10 | 209 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
dff02d49 | 210 | |
914edb1b | 211 | /* Protected by rpcb_create_local_mutex */ |
dff02d49 SK |
212 | sn->rpcb_local_clnt = clnt; |
213 | sn->rpcb_local_clnt4 = clnt4; | |
786615bc | 214 | sn->rpcb_is_af_local = is_af_local ? 1 : 0; |
8fdee4cc | 215 | smp_wmb(); |
dff02d49 | 216 | sn->rpcb_users = 1; |
914edb1b SK |
217 | } |
218 | ||
7402ab19 CL |
219 | /* |
220 | * Returns zero on success, otherwise a negative errno value | |
221 | * is returned. | |
222 | */ | |
2ea75a10 | 223 | static int rpcb_create_local_unix(struct net *net) |
7402ab19 CL |
224 | { |
225 | static const struct sockaddr_un rpcb_localaddr_rpcbind = { | |
226 | .sun_family = AF_LOCAL, | |
227 | .sun_path = RPCBIND_SOCK_PATHNAME, | |
228 | }; | |
229 | struct rpc_create_args args = { | |
2ea75a10 | 230 | .net = net, |
7402ab19 CL |
231 | .protocol = XPRT_TRANSPORT_LOCAL, |
232 | .address = (struct sockaddr *)&rpcb_localaddr_rpcbind, | |
233 | .addrsize = sizeof(rpcb_localaddr_rpcbind), | |
234 | .servername = "localhost", | |
235 | .program = &rpcb_program, | |
236 | .version = RPCBVERS_2, | |
237 | .authflavor = RPC_AUTH_NULL, | |
79caa5fa | 238 | .cred = current_cred(), |
00326ed6 TM |
239 | /* |
240 | * We turn off the idle timeout to prevent the kernel | |
241 | * from automatically disconnecting the socket. | |
242 | * Otherwise, we'd have to cache the mount namespace | |
243 | * of the caller and somehow pass that to the socket | |
244 | * reconnect code. | |
245 | */ | |
246 | .flags = RPC_CLNT_CREATE_NO_IDLE_TIMEOUT, | |
7402ab19 CL |
247 | }; |
248 | struct rpc_clnt *clnt, *clnt4; | |
249 | int result = 0; | |
250 | ||
251 | /* | |
252 | * Because we requested an RPC PING at transport creation time, | |
253 | * this works only if the user space portmapper is rpcbind, and | |
254 | * it's listening on AF_LOCAL on the named socket. | |
255 | */ | |
256 | clnt = rpc_create(&args); | |
257 | if (IS_ERR(clnt)) { | |
caea33da | 258 | result = PTR_ERR(clnt); |
7402ab19 CL |
259 | goto out; |
260 | } | |
261 | ||
262 | clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4); | |
1e664987 | 263 | if (IS_ERR(clnt4)) |
7402ab19 | 264 | clnt4 = NULL; |
7402ab19 | 265 | |
786615bc | 266 | rpcb_set_local(net, clnt, clnt4, true); |
cc5598b7 | 267 | |
7402ab19 CL |
268 | out: |
269 | return result; | |
270 | } | |
c526611d CL |
271 | |
272 | /* | |
273 | * Returns zero on success, otherwise a negative errno value | |
274 | * is returned. | |
275 | */ | |
2ea75a10 | 276 | static int rpcb_create_local_net(struct net *net) |
cc5598b7 | 277 | { |
7402ab19 CL |
278 | static const struct sockaddr_in rpcb_inaddr_loopback = { |
279 | .sin_family = AF_INET, | |
280 | .sin_addr.s_addr = htonl(INADDR_LOOPBACK), | |
281 | .sin_port = htons(RPCBIND_PORT), | |
282 | }; | |
cc5598b7 | 283 | struct rpc_create_args args = { |
2ea75a10 | 284 | .net = net, |
2a76b3bf | 285 | .protocol = XPRT_TRANSPORT_TCP, |
5a462115 CL |
286 | .address = (struct sockaddr *)&rpcb_inaddr_loopback, |
287 | .addrsize = sizeof(rpcb_inaddr_loopback), | |
cc5598b7 CL |
288 | .servername = "localhost", |
289 | .program = &rpcb_program, | |
c526611d | 290 | .version = RPCBVERS_2, |
cc5598b7 | 291 | .authflavor = RPC_AUTH_UNIX, |
79caa5fa | 292 | .cred = current_cred(), |
cc5598b7 CL |
293 | .flags = RPC_CLNT_CREATE_NOPING, |
294 | }; | |
c526611d CL |
295 | struct rpc_clnt *clnt, *clnt4; |
296 | int result = 0; | |
297 | ||
c526611d CL |
298 | clnt = rpc_create(&args); |
299 | if (IS_ERR(clnt)) { | |
caea33da | 300 | result = PTR_ERR(clnt); |
c526611d CL |
301 | goto out; |
302 | } | |
cc5598b7 | 303 | |
c526611d CL |
304 | /* |
305 | * This results in an RPC ping. On systems running portmapper, | |
306 | * the v4 ping will fail. Proceed anyway, but disallow rpcb | |
307 | * v4 upcalls. | |
308 | */ | |
309 | clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4); | |
1e664987 | 310 | if (IS_ERR(clnt4)) |
c526611d | 311 | clnt4 = NULL; |
c526611d | 312 | |
786615bc | 313 | rpcb_set_local(net, clnt, clnt4, false); |
c526611d | 314 | |
7402ab19 CL |
315 | out: |
316 | return result; | |
317 | } | |
318 | ||
319 | /* | |
320 | * Returns zero on success, otherwise a negative errno value | |
321 | * is returned. | |
322 | */ | |
f7a30c18 | 323 | int rpcb_create_local(struct net *net) |
7402ab19 CL |
324 | { |
325 | static DEFINE_MUTEX(rpcb_create_local_mutex); | |
326 | int result = 0; | |
327 | ||
2ea75a10 | 328 | if (rpcb_get_local(net)) |
7402ab19 CL |
329 | return result; |
330 | ||
331 | mutex_lock(&rpcb_create_local_mutex); | |
2ea75a10 | 332 | if (rpcb_get_local(net)) |
7402ab19 CL |
333 | goto out; |
334 | ||
2ea75a10 SK |
335 | if (rpcb_create_local_unix(net) != 0) |
336 | result = rpcb_create_local_net(net); | |
7402ab19 | 337 | |
c526611d CL |
338 | out: |
339 | mutex_unlock(&rpcb_create_local_mutex); | |
340 | return result; | |
cc5598b7 CL |
341 | } |
342 | ||
03a9a42a TM |
343 | static struct rpc_clnt *rpcb_create(struct net *net, const char *nodename, |
344 | const char *hostname, | |
c2550e07 | 345 | struct sockaddr *srvaddr, size_t salen, |
79caa5fa | 346 | int proto, u32 version, |
6b996476 EG |
347 | const struct cred *cred, |
348 | const struct rpc_timeout *timeo) | |
a509050b CL |
349 | { |
350 | struct rpc_create_args args = { | |
c2550e07 | 351 | .net = net, |
a509050b CL |
352 | .protocol = proto, |
353 | .address = srvaddr, | |
9f6ad26d | 354 | .addrsize = salen, |
6b996476 | 355 | .timeout = timeo, |
a509050b | 356 | .servername = hostname, |
03a9a42a | 357 | .nodename = nodename, |
a509050b CL |
358 | .program = &rpcb_program, |
359 | .version = version, | |
360 | .authflavor = RPC_AUTH_UNIX, | |
79caa5fa | 361 | .cred = cred, |
423d8b06 CL |
362 | .flags = (RPC_CLNT_CREATE_NOPING | |
363 | RPC_CLNT_CREATE_NONPRIVPORT), | |
a509050b CL |
364 | }; |
365 | ||
d5b64430 CL |
366 | switch (srvaddr->sa_family) { |
367 | case AF_INET: | |
368 | ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT); | |
369 | break; | |
370 | case AF_INET6: | |
371 | ((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT); | |
372 | break; | |
373 | default: | |
c636b572 | 374 | return ERR_PTR(-EAFNOSUPPORT); |
d5b64430 CL |
375 | } |
376 | ||
a509050b CL |
377 | return rpc_create(&args); |
378 | } | |
379 | ||
786615bc | 380 | static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt *clnt, struct rpc_message *msg, bool is_set) |
babe80eb | 381 | { |
786615bc TM |
382 | int flags = RPC_TASK_NOCONNECT; |
383 | int error, result = 0; | |
babe80eb | 384 | |
786615bc TM |
385 | if (is_set || !sn->rpcb_is_af_local) |
386 | flags = RPC_TASK_SOFTCONN; | |
14aeb211 | 387 | msg->rpc_resp = &result; |
babe80eb | 388 | |
786615bc | 389 | error = rpc_call_sync(clnt, msg, flags); |
1e664987 | 390 | if (error < 0) |
14aeb211 | 391 | return error; |
14aeb211 | 392 | |
db820d63 | 393 | if (!result) |
14aeb211 | 394 | return -EACCES; |
14aeb211 | 395 | return 0; |
babe80eb CL |
396 | } |
397 | ||
a509050b CL |
398 | /** |
399 | * rpcb_register - set or unset a port registration with the local rpcbind svc | |
bda14606 | 400 | * @net: target network namespace |
a509050b CL |
401 | * @prog: RPC program number to bind |
402 | * @vers: RPC version number to bind | |
c2e1b09f | 403 | * @prot: transport protocol to register |
a509050b | 404 | * @port: port value to register |
14aeb211 CL |
405 | * |
406 | * Returns zero if the registration request was dispatched successfully | |
407 | * and the rpcbind daemon returned success. Otherwise, returns an errno | |
408 | * value that reflects the nature of the error (request could not be | |
409 | * dispatched, timed out, or rpcbind returned an error). | |
c2e1b09f CL |
410 | * |
411 | * RPC services invoke this function to advertise their contact | |
412 | * information via the system's rpcbind daemon. RPC services | |
413 | * invoke this function once for each [program, version, transport] | |
414 | * tuple they wish to advertise. | |
415 | * | |
416 | * Callers may also unregister RPC services that are no longer | |
417 | * available by setting the passed-in port to zero. This removes | |
418 | * all registered transports for [program, version] from the local | |
419 | * rpcbind database. | |
420 | * | |
c2e1b09f CL |
421 | * This function uses rpcbind protocol version 2 to contact the |
422 | * local rpcbind daemon. | |
423 | * | |
424 | * Registration works over both AF_INET and AF_INET6, and services | |
425 | * registered via this function are advertised as available for any | |
426 | * address. If the local rpcbind daemon is listening on AF_INET6, | |
427 | * services registered via this function will be advertised on | |
428 | * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 | |
429 | * addresses). | |
a509050b | 430 | */ |
977ac315 | 431 | int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short port) |
a509050b | 432 | { |
a509050b CL |
433 | struct rpcbind_args map = { |
434 | .r_prog = prog, | |
435 | .r_vers = vers, | |
436 | .r_prot = prot, | |
437 | .r_port = port, | |
438 | }; | |
439 | struct rpc_message msg = { | |
a509050b | 440 | .rpc_argp = &map, |
a509050b | 441 | }; |
977ac315 | 442 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
786615bc | 443 | bool is_set = false; |
a509050b | 444 | |
c3adcc7d | 445 | trace_pmap_register(prog, vers, prot, port); |
a509050b | 446 | |
babe80eb | 447 | msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET]; |
786615bc | 448 | if (port != 0) { |
babe80eb | 449 | msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; |
786615bc TM |
450 | is_set = true; |
451 | } | |
a509050b | 452 | |
786615bc | 453 | return rpcb_register_call(sn, sn->rpcb_local_clnt, &msg, is_set); |
a509050b CL |
454 | } |
455 | ||
c2e1b09f CL |
456 | /* |
457 | * Fill in AF_INET family-specific arguments to register | |
458 | */ | |
1a114a66 SK |
459 | static int rpcb_register_inet4(struct sunrpc_net *sn, |
460 | const struct sockaddr *sap, | |
1673d0de | 461 | struct rpc_message *msg) |
c2e1b09f | 462 | { |
3aba4553 | 463 | const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; |
c2e1b09f | 464 | struct rpcbind_args *map = msg->rpc_argp; |
3aba4553 | 465 | unsigned short port = ntohs(sin->sin_port); |
786615bc | 466 | bool is_set = false; |
ba809130 | 467 | int result; |
c2e1b09f | 468 | |
d77385f2 | 469 | map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); |
c2e1b09f | 470 | |
c2e1b09f | 471 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; |
786615bc | 472 | if (port != 0) { |
c2e1b09f | 473 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; |
786615bc TM |
474 | is_set = true; |
475 | } | |
c2e1b09f | 476 | |
786615bc | 477 | result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set); |
ba809130 CL |
478 | kfree(map->r_addr); |
479 | return result; | |
c2e1b09f CL |
480 | } |
481 | ||
482 | /* | |
483 | * Fill in AF_INET6 family-specific arguments to register | |
484 | */ | |
1a114a66 SK |
485 | static int rpcb_register_inet6(struct sunrpc_net *sn, |
486 | const struct sockaddr *sap, | |
1673d0de | 487 | struct rpc_message *msg) |
c2e1b09f | 488 | { |
3aba4553 | 489 | const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; |
c2e1b09f | 490 | struct rpcbind_args *map = msg->rpc_argp; |
3aba4553 | 491 | unsigned short port = ntohs(sin6->sin6_port); |
786615bc | 492 | bool is_set = false; |
ba809130 | 493 | int result; |
c2e1b09f | 494 | |
d77385f2 | 495 | map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); |
c2e1b09f | 496 | |
c2e1b09f | 497 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; |
786615bc | 498 | if (port != 0) { |
c2e1b09f | 499 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; |
786615bc TM |
500 | is_set = true; |
501 | } | |
c2e1b09f | 502 | |
786615bc | 503 | result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set); |
ba809130 CL |
504 | kfree(map->r_addr); |
505 | return result; | |
c2e1b09f CL |
506 | } |
507 | ||
1a114a66 SK |
508 | static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn, |
509 | struct rpc_message *msg) | |
1673d0de CL |
510 | { |
511 | struct rpcbind_args *map = msg->rpc_argp; | |
512 | ||
c3adcc7d | 513 | trace_rpcb_unregister(map->r_prog, map->r_vers, map->r_netid); |
1673d0de CL |
514 | |
515 | map->r_addr = ""; | |
516 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; | |
517 | ||
786615bc | 518 | return rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, false); |
1673d0de CL |
519 | } |
520 | ||
c2e1b09f CL |
521 | /** |
522 | * rpcb_v4_register - set or unset a port registration with the local rpcbind | |
bda14606 | 523 | * @net: target network namespace |
c2e1b09f CL |
524 | * @program: RPC program number of service to (un)register |
525 | * @version: RPC version number of service to (un)register | |
526 | * @address: address family, IP address, and port to (un)register | |
527 | * @netid: netid of transport protocol to (un)register | |
14aeb211 CL |
528 | * |
529 | * Returns zero if the registration request was dispatched successfully | |
530 | * and the rpcbind daemon returned success. Otherwise, returns an errno | |
531 | * value that reflects the nature of the error (request could not be | |
532 | * dispatched, timed out, or rpcbind returned an error). | |
c2e1b09f CL |
533 | * |
534 | * RPC services invoke this function to advertise their contact | |
535 | * information via the system's rpcbind daemon. RPC services | |
536 | * invoke this function once for each [program, version, address, | |
537 | * netid] tuple they wish to advertise. | |
538 | * | |
1673d0de CL |
539 | * Callers may also unregister RPC services that are registered at a |
540 | * specific address by setting the port number in @address to zero. | |
541 | * They may unregister all registered protocol families at once for | |
542 | * a service by passing a NULL @address argument. If @netid is "" | |
543 | * then all netids for [program, version, address] are unregistered. | |
c2e1b09f | 544 | * |
c2e1b09f CL |
545 | * This function uses rpcbind protocol version 4 to contact the |
546 | * local rpcbind daemon. The local rpcbind daemon must support | |
547 | * version 4 of the rpcbind protocol in order for these functions | |
548 | * to register a service successfully. | |
549 | * | |
550 | * Supported netids include "udp" and "tcp" for UDP and TCP over | |
551 | * IPv4, and "udp6" and "tcp6" for UDP and TCP over IPv6, | |
552 | * respectively. | |
553 | * | |
554 | * The contents of @address determine the address family and the | |
555 | * port to be registered. The usual practice is to pass INADDR_ANY | |
556 | * as the raw address, but specifying a non-zero address is also | |
557 | * supported by this API if the caller wishes to advertise an RPC | |
558 | * service on a specific network interface. | |
559 | * | |
560 | * Note that passing in INADDR_ANY does not create the same service | |
561 | * registration as IN6ADDR_ANY. The former advertises an RPC | |
562 | * service on any IPv4 address, but not on IPv6. The latter | |
563 | * advertises the service on all IPv4 and IPv6 addresses. | |
564 | */ | |
977ac315 | 565 | int rpcb_v4_register(struct net *net, const u32 program, const u32 version, |
14aeb211 | 566 | const struct sockaddr *address, const char *netid) |
c2e1b09f CL |
567 | { |
568 | struct rpcbind_args map = { | |
569 | .r_prog = program, | |
570 | .r_vers = version, | |
571 | .r_netid = netid, | |
572 | .r_owner = RPCB_OWNER_STRING, | |
573 | }; | |
574 | struct rpc_message msg = { | |
575 | .rpc_argp = &map, | |
c2e1b09f | 576 | }; |
977ac315 | 577 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
c526611d | 578 | |
dff02d49 | 579 | if (sn->rpcb_local_clnt4 == NULL) |
c526611d | 580 | return -EPROTONOSUPPORT; |
c2e1b09f | 581 | |
1673d0de | 582 | if (address == NULL) |
1a114a66 | 583 | return rpcb_unregister_all_protofamilies(sn, &msg); |
1673d0de | 584 | |
c3adcc7d CL |
585 | trace_rpcb_register(map.r_prog, map.r_vers, map.r_addr, map.r_netid); |
586 | ||
c2e1b09f CL |
587 | switch (address->sa_family) { |
588 | case AF_INET: | |
1a114a66 | 589 | return rpcb_register_inet4(sn, address, &msg); |
c2e1b09f | 590 | case AF_INET6: |
1a114a66 | 591 | return rpcb_register_inet6(sn, address, &msg); |
c2e1b09f CL |
592 | } |
593 | ||
594 | return -EAFNOSUPPORT; | |
595 | } | |
596 | ||
499b4988 CH |
597 | static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, |
598 | struct rpcbind_args *map, const struct rpc_procinfo *proc) | |
5138fde0 TM |
599 | { |
600 | struct rpc_message msg = { | |
803a9067 | 601 | .rpc_proc = proc, |
5138fde0 | 602 | .rpc_argp = map, |
c0c077df | 603 | .rpc_resp = map, |
5138fde0 TM |
604 | }; |
605 | struct rpc_task_setup task_setup_data = { | |
606 | .rpc_client = rpcb_clnt, | |
607 | .rpc_message = &msg, | |
608 | .callback_ops = &rpcb_getport_ops, | |
609 | .callback_data = map, | |
012da158 | 610 | .flags = RPC_TASK_ASYNC | RPC_TASK_SOFTCONN, |
5138fde0 TM |
611 | }; |
612 | ||
613 | return rpc_run_task(&task_setup_data); | |
614 | } | |
615 | ||
9a4bd29f TM |
616 | /* |
617 | * In the case where rpc clients have been cloned, we want to make | |
618 | * sure that we use the program number/version etc of the actual | |
619 | * owner of the xprt. To do so, we walk back up the tree of parents | |
620 | * to find whoever created the transport and/or whoever has the | |
621 | * autobind flag set. | |
622 | */ | |
623 | static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) | |
624 | { | |
625 | struct rpc_clnt *parent = clnt->cl_parent; | |
ad01b2c6 | 626 | struct rpc_xprt_switch *xps = rcu_access_pointer(clnt->cl_xpi.xpi_xpswitch); |
9a4bd29f TM |
627 | |
628 | while (parent != clnt) { | |
ad01b2c6 | 629 | if (rcu_access_pointer(parent->cl_xpi.xpi_xpswitch) != xps) |
9a4bd29f TM |
630 | break; |
631 | if (clnt->cl_autobind) | |
632 | break; | |
633 | clnt = parent; | |
634 | parent = parent->cl_parent; | |
635 | } | |
636 | return clnt; | |
637 | } | |
638 | ||
a509050b | 639 | /** |
45160d62 | 640 | * rpcb_getport_async - obtain the port for a given RPC service on a given host |
a509050b CL |
641 | * @task: task that is waiting for portmapper request |
642 | * | |
643 | * This one can be called for an ongoing RPC request, and can be used in | |
644 | * an async (rpciod) context. | |
645 | */ | |
45160d62 | 646 | void rpcb_getport_async(struct rpc_task *task) |
a509050b | 647 | { |
9a4bd29f | 648 | struct rpc_clnt *clnt; |
499b4988 | 649 | const struct rpc_procinfo *proc; |
0a48f5d7 | 650 | u32 bind_version; |
9a4bd29f | 651 | struct rpc_xprt *xprt; |
a509050b | 652 | struct rpc_clnt *rpcb_clnt; |
ec0dd267 | 653 | struct rpcbind_args *map; |
a509050b | 654 | struct rpc_task *child; |
9f6ad26d CL |
655 | struct sockaddr_storage addr; |
656 | struct sockaddr *sap = (struct sockaddr *)&addr; | |
657 | size_t salen; | |
a509050b CL |
658 | int status; |
659 | ||
2446ab60 | 660 | rcu_read_lock(); |
fb43d172 | 661 | clnt = rpcb_find_transport_owner(task->tk_client); |
2446ab60 | 662 | rcu_read_unlock(); |
fb43d172 | 663 | xprt = xprt_get(task->tk_xprt); |
9a4bd29f | 664 | |
381ba74a TM |
665 | /* Put self on the wait queue to ensure we get notified if |
666 | * some other task is already attempting to bind the port */ | |
6b2e6856 TM |
667 | rpc_sleep_on_timeout(&xprt->binding, task, |
668 | NULL, jiffies + xprt->bind_timeout); | |
381ba74a | 669 | |
a509050b | 670 | if (xprt_test_and_set_binding(xprt)) { |
2446ab60 | 671 | xprt_put(xprt); |
381ba74a | 672 | return; |
a509050b CL |
673 | } |
674 | ||
a509050b CL |
675 | /* Someone else may have bound if we slept */ |
676 | if (xprt_bound(xprt)) { | |
677 | status = 0; | |
a509050b CL |
678 | goto bailout_nofree; |
679 | } | |
680 | ||
ba809130 | 681 | /* Parent transport's destination address */ |
9f6ad26d | 682 | salen = rpc_peeraddr(clnt, sap, sizeof(addr)); |
d5b64430 CL |
683 | |
684 | /* Don't ever use rpcbind v2 for AF_INET6 requests */ | |
9f6ad26d | 685 | switch (sap->sa_family) { |
d5b64430 | 686 | case AF_INET: |
803a9067 TM |
687 | proc = rpcb_next_version[xprt->bind_index].rpc_proc; |
688 | bind_version = rpcb_next_version[xprt->bind_index].rpc_vers; | |
d5b64430 CL |
689 | break; |
690 | case AF_INET6: | |
803a9067 TM |
691 | proc = rpcb_next_version6[xprt->bind_index].rpc_proc; |
692 | bind_version = rpcb_next_version6[xprt->bind_index].rpc_vers; | |
d5b64430 CL |
693 | break; |
694 | default: | |
695 | status = -EAFNOSUPPORT; | |
d5b64430 CL |
696 | goto bailout_nofree; |
697 | } | |
803a9067 | 698 | if (proc == NULL) { |
a509050b | 699 | xprt->bind_index = 0; |
906462af | 700 | status = -EPFNOSUPPORT; |
a509050b CL |
701 | goto bailout_nofree; |
702 | } | |
a509050b | 703 | |
e465cc3f | 704 | trace_rpcb_getport(clnt, task, bind_version); |
a509050b | 705 | |
03a9a42a TM |
706 | rpcb_clnt = rpcb_create(xprt->xprt_net, |
707 | clnt->cl_nodename, | |
708 | xprt->servername, sap, salen, | |
79caa5fa | 709 | xprt->prot, bind_version, |
6b996476 EG |
710 | clnt->cl_cred, |
711 | task->tk_client->cl_timeout); | |
143b6c40 CL |
712 | if (IS_ERR(rpcb_clnt)) { |
713 | status = PTR_ERR(rpcb_clnt); | |
143b6c40 CL |
714 | goto bailout_nofree; |
715 | } | |
716 | ||
b2648015 | 717 | map = kzalloc(sizeof(struct rpcbind_args), rpc_task_gfp_mask()); |
a509050b CL |
718 | if (!map) { |
719 | status = -ENOMEM; | |
96165e2b | 720 | goto bailout_release_client; |
a509050b CL |
721 | } |
722 | map->r_prog = clnt->cl_prog; | |
723 | map->r_vers = clnt->cl_vers; | |
724 | map->r_prot = xprt->prot; | |
725 | map->r_port = 0; | |
864cf9bf | 726 | map->r_xprt = xprt; |
381ba74a | 727 | map->r_status = -EIO; |
a509050b | 728 | |
ba809130 CL |
729 | switch (bind_version) { |
730 | case RPCBVERS_4: | |
731 | case RPCBVERS_3: | |
2446ab60 | 732 | map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID]; |
b2648015 | 733 | map->r_addr = rpc_sockaddr2uaddr(sap, rpc_task_gfp_mask()); |
81c88b18 BF |
734 | if (!map->r_addr) { |
735 | status = -ENOMEM; | |
81c88b18 BF |
736 | goto bailout_free_args; |
737 | } | |
ba809130 CL |
738 | map->r_owner = ""; |
739 | break; | |
740 | case RPCBVERS_2: | |
741 | map->r_addr = NULL; | |
742 | break; | |
743 | default: | |
744 | BUG(); | |
745 | } | |
746 | ||
803a9067 | 747 | child = rpcb_call_async(rpcb_clnt, map, proc); |
4c402b40 | 748 | rpc_release_client(rpcb_clnt); |
a509050b | 749 | |
9a4bd29f TM |
750 | xprt->stat.bind_count++; |
751 | rpc_put_task(child); | |
a509050b CL |
752 | return; |
753 | ||
81c88b18 BF |
754 | bailout_free_args: |
755 | kfree(map); | |
96165e2b TM |
756 | bailout_release_client: |
757 | rpc_release_client(rpcb_clnt); | |
a509050b CL |
758 | bailout_nofree: |
759 | rpcb_wake_rpcbind_waiters(xprt, status); | |
a509050b | 760 | task->tk_status = status; |
2446ab60 | 761 | xprt_put(xprt); |
a509050b | 762 | } |
12444809 | 763 | EXPORT_SYMBOL_GPL(rpcb_getport_async); |
a509050b CL |
764 | |
765 | /* | |
766 | * Rpcbind child task calls this callback via tk_exit. | |
767 | */ | |
768 | static void rpcb_getport_done(struct rpc_task *child, void *data) | |
769 | { | |
770 | struct rpcbind_args *map = data; | |
771 | struct rpc_xprt *xprt = map->r_xprt; | |
ac1ae534 CL |
772 | |
773 | map->r_status = child->tk_status; | |
a509050b | 774 | |
4784cb51 | 775 | /* Garbage reply: retry with a lesser rpcbind version */ |
ac1ae534 CL |
776 | if (map->r_status == -EIO) |
777 | map->r_status = -EPROTONOSUPPORT; | |
4784cb51 | 778 | |
a509050b | 779 | /* rpcbind server doesn't support this rpcbind protocol version */ |
ac1ae534 | 780 | if (map->r_status == -EPROTONOSUPPORT) |
a509050b CL |
781 | xprt->bind_index++; |
782 | ||
ac1ae534 | 783 | if (map->r_status < 0) { |
a509050b | 784 | /* rpcbind server not available on remote host? */ |
ac1ae534 CL |
785 | map->r_port = 0; |
786 | ||
a509050b CL |
787 | } else if (map->r_port == 0) { |
788 | /* Requested RPC service wasn't registered on remote host */ | |
ac1ae534 | 789 | map->r_status = -EACCES; |
a509050b CL |
790 | } else { |
791 | /* Succeeded */ | |
ac1ae534 | 792 | map->r_status = 0; |
a509050b CL |
793 | } |
794 | ||
ac1ae534 CL |
795 | trace_rpcb_setport(child, map->r_status, map->r_port); |
796 | xprt->ops->set_port(xprt, map->r_port); | |
797 | if (map->r_port) | |
798 | xprt_set_bound(xprt); | |
a509050b CL |
799 | } |
800 | ||
166b88d7 CL |
801 | /* |
802 | * XDR functions for rpcbind | |
803 | */ | |
804 | ||
9f06c719 | 805 | static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr, |
7d55f7fe | 806 | const void *data) |
6f2c2db7 | 807 | { |
7d55f7fe | 808 | const struct rpcbind_args *rpcb = data; |
9f06c719 | 809 | __be32 *p; |
6f2c2db7 | 810 | |
9f06c719 | 811 | p = xdr_reserve_space(xdr, RPCB_mappingargs_sz << 2); |
4129ccf3 CL |
812 | *p++ = cpu_to_be32(rpcb->r_prog); |
813 | *p++ = cpu_to_be32(rpcb->r_vers); | |
814 | *p++ = cpu_to_be32(rpcb->r_prot); | |
815 | *p = cpu_to_be32(rpcb->r_port); | |
6f2c2db7 CL |
816 | } |
817 | ||
bf269551 | 818 | static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, |
605d712f | 819 | void *data) |
c0c077df | 820 | { |
605d712f | 821 | struct rpcbind_args *rpcb = data; |
c0c077df | 822 | unsigned long port; |
bf269551 | 823 | __be32 *p; |
c0c077df CL |
824 | |
825 | rpcb->r_port = 0; | |
826 | ||
bf269551 | 827 | p = xdr_inline_decode(xdr, 4); |
c0c077df CL |
828 | if (unlikely(p == NULL)) |
829 | return -EIO; | |
830 | ||
4129ccf3 | 831 | port = be32_to_cpup(p); |
4be929be | 832 | if (unlikely(port > USHRT_MAX)) |
c0c077df CL |
833 | return -EIO; |
834 | ||
835 | rpcb->r_port = port; | |
836 | return 0; | |
837 | } | |
838 | ||
bf269551 | 839 | static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr, |
605d712f | 840 | void *data) |
7ed0ff98 | 841 | { |
605d712f | 842 | unsigned int *boolp = data; |
bf269551 | 843 | __be32 *p; |
7ed0ff98 | 844 | |
bf269551 | 845 | p = xdr_inline_decode(xdr, 4); |
7ed0ff98 CL |
846 | if (unlikely(p == NULL)) |
847 | return -EIO; | |
848 | ||
849 | *boolp = 0; | |
bf269551 | 850 | if (*p != xdr_zero) |
7ed0ff98 | 851 | *boolp = 1; |
7ed0ff98 CL |
852 | return 0; |
853 | } | |
854 | ||
4129ccf3 CL |
855 | static void encode_rpcb_string(struct xdr_stream *xdr, const char *string, |
856 | const u32 maxstrlen) | |
6f2c2db7 | 857 | { |
6f2c2db7 | 858 | __be32 *p; |
4129ccf3 | 859 | u32 len; |
6f2c2db7 | 860 | |
6f2c2db7 | 861 | len = strlen(string); |
332e008a WAA |
862 | WARN_ON_ONCE(len > maxstrlen); |
863 | if (len > maxstrlen) | |
864 | /* truncate and hope for the best */ | |
865 | len = maxstrlen; | |
4129ccf3 | 866 | p = xdr_reserve_space(xdr, 4 + len); |
6f2c2db7 | 867 | xdr_encode_opaque(p, string, len); |
6f2c2db7 CL |
868 | } |
869 | ||
9f06c719 | 870 | static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, |
7d55f7fe | 871 | const void *data) |
6f2c2db7 | 872 | { |
7d55f7fe | 873 | const struct rpcbind_args *rpcb = data; |
9f06c719 | 874 | __be32 *p; |
6f2c2db7 | 875 | |
9f06c719 | 876 | p = xdr_reserve_space(xdr, (RPCB_program_sz + RPCB_version_sz) << 2); |
4129ccf3 CL |
877 | *p++ = cpu_to_be32(rpcb->r_prog); |
878 | *p = cpu_to_be32(rpcb->r_vers); | |
6f2c2db7 | 879 | |
9f06c719 CL |
880 | encode_rpcb_string(xdr, rpcb->r_netid, RPCBIND_MAXNETIDLEN); |
881 | encode_rpcb_string(xdr, rpcb->r_addr, RPCBIND_MAXUADDRLEN); | |
882 | encode_rpcb_string(xdr, rpcb->r_owner, RPCB_MAXOWNERLEN); | |
6f2c2db7 CL |
883 | } |
884 | ||
bf269551 | 885 | static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, |
605d712f | 886 | void *data) |
c0c077df | 887 | { |
605d712f | 888 | struct rpcbind_args *rpcb = data; |
c0c077df CL |
889 | struct sockaddr_storage address; |
890 | struct sockaddr *sap = (struct sockaddr *)&address; | |
bf269551 | 891 | __be32 *p; |
c0c077df CL |
892 | u32 len; |
893 | ||
894 | rpcb->r_port = 0; | |
895 | ||
bf269551 | 896 | p = xdr_inline_decode(xdr, 4); |
c0c077df CL |
897 | if (unlikely(p == NULL)) |
898 | goto out_fail; | |
4129ccf3 | 899 | len = be32_to_cpup(p); |
c0c077df CL |
900 | |
901 | /* | |
902 | * If the returned universal address is a null string, | |
903 | * the requested RPC service was not registered. | |
904 | */ | |
15a798d6 | 905 | if (len == 0) |
c0c077df | 906 | return 0; |
c0c077df CL |
907 | |
908 | if (unlikely(len > RPCBIND_MAXUADDRLEN)) | |
909 | goto out_fail; | |
910 | ||
bf269551 | 911 | p = xdr_inline_decode(xdr, len); |
c0c077df CL |
912 | if (unlikely(p == NULL)) |
913 | goto out_fail; | |
c0c077df | 914 | |
b030fb0b SK |
915 | if (rpc_uaddr2sockaddr(req->rq_xprt->xprt_net, (char *)p, len, |
916 | sap, sizeof(address)) == 0) | |
c0c077df CL |
917 | goto out_fail; |
918 | rpcb->r_port = rpc_get_port(sap); | |
919 | ||
920 | return 0; | |
921 | ||
922 | out_fail: | |
c0c077df CL |
923 | return -EIO; |
924 | } | |
925 | ||
a509050b CL |
926 | /* |
927 | * Not all rpcbind procedures described in RFC 1833 are implemented | |
928 | * since the Linux kernel RPC code requires only these. | |
929 | */ | |
f8b761ef | 930 | |
499b4988 | 931 | static const struct rpc_procinfo rpcb_procedures2[] = { |
f8b761ef CL |
932 | [RPCBPROC_SET] = { |
933 | .p_proc = RPCBPROC_SET, | |
7d55f7fe | 934 | .p_encode = rpcb_enc_mapping, |
605d712f | 935 | .p_decode = rpcb_dec_set, |
f8b761ef CL |
936 | .p_arglen = RPCB_mappingargs_sz, |
937 | .p_replen = RPCB_setres_sz, | |
938 | .p_statidx = RPCBPROC_SET, | |
939 | .p_timer = 0, | |
940 | .p_name = "SET", | |
941 | }, | |
942 | [RPCBPROC_UNSET] = { | |
943 | .p_proc = RPCBPROC_UNSET, | |
7d55f7fe | 944 | .p_encode = rpcb_enc_mapping, |
605d712f | 945 | .p_decode = rpcb_dec_set, |
f8b761ef CL |
946 | .p_arglen = RPCB_mappingargs_sz, |
947 | .p_replen = RPCB_setres_sz, | |
948 | .p_statidx = RPCBPROC_UNSET, | |
949 | .p_timer = 0, | |
950 | .p_name = "UNSET", | |
951 | }, | |
952 | [RPCBPROC_GETPORT] = { | |
953 | .p_proc = RPCBPROC_GETPORT, | |
7d55f7fe | 954 | .p_encode = rpcb_enc_mapping, |
605d712f | 955 | .p_decode = rpcb_dec_getport, |
f8b761ef CL |
956 | .p_arglen = RPCB_mappingargs_sz, |
957 | .p_replen = RPCB_getportres_sz, | |
958 | .p_statidx = RPCBPROC_GETPORT, | |
959 | .p_timer = 0, | |
960 | .p_name = "GETPORT", | |
961 | }, | |
a509050b CL |
962 | }; |
963 | ||
499b4988 | 964 | static const struct rpc_procinfo rpcb_procedures3[] = { |
f8b761ef CL |
965 | [RPCBPROC_SET] = { |
966 | .p_proc = RPCBPROC_SET, | |
7d55f7fe | 967 | .p_encode = rpcb_enc_getaddr, |
605d712f | 968 | .p_decode = rpcb_dec_set, |
f8b761ef CL |
969 | .p_arglen = RPCB_getaddrargs_sz, |
970 | .p_replen = RPCB_setres_sz, | |
971 | .p_statidx = RPCBPROC_SET, | |
972 | .p_timer = 0, | |
973 | .p_name = "SET", | |
974 | }, | |
975 | [RPCBPROC_UNSET] = { | |
976 | .p_proc = RPCBPROC_UNSET, | |
7d55f7fe | 977 | .p_encode = rpcb_enc_getaddr, |
605d712f | 978 | .p_decode = rpcb_dec_set, |
f8b761ef CL |
979 | .p_arglen = RPCB_getaddrargs_sz, |
980 | .p_replen = RPCB_setres_sz, | |
981 | .p_statidx = RPCBPROC_UNSET, | |
982 | .p_timer = 0, | |
983 | .p_name = "UNSET", | |
984 | }, | |
985 | [RPCBPROC_GETADDR] = { | |
986 | .p_proc = RPCBPROC_GETADDR, | |
7d55f7fe | 987 | .p_encode = rpcb_enc_getaddr, |
605d712f | 988 | .p_decode = rpcb_dec_getaddr, |
f8b761ef CL |
989 | .p_arglen = RPCB_getaddrargs_sz, |
990 | .p_replen = RPCB_getaddrres_sz, | |
991 | .p_statidx = RPCBPROC_GETADDR, | |
992 | .p_timer = 0, | |
993 | .p_name = "GETADDR", | |
994 | }, | |
a509050b CL |
995 | }; |
996 | ||
499b4988 | 997 | static const struct rpc_procinfo rpcb_procedures4[] = { |
f8b761ef CL |
998 | [RPCBPROC_SET] = { |
999 | .p_proc = RPCBPROC_SET, | |
7d55f7fe | 1000 | .p_encode = rpcb_enc_getaddr, |
605d712f | 1001 | .p_decode = rpcb_dec_set, |
f8b761ef CL |
1002 | .p_arglen = RPCB_getaddrargs_sz, |
1003 | .p_replen = RPCB_setres_sz, | |
1004 | .p_statidx = RPCBPROC_SET, | |
1005 | .p_timer = 0, | |
1006 | .p_name = "SET", | |
1007 | }, | |
1008 | [RPCBPROC_UNSET] = { | |
1009 | .p_proc = RPCBPROC_UNSET, | |
7d55f7fe | 1010 | .p_encode = rpcb_enc_getaddr, |
605d712f | 1011 | .p_decode = rpcb_dec_set, |
f8b761ef CL |
1012 | .p_arglen = RPCB_getaddrargs_sz, |
1013 | .p_replen = RPCB_setres_sz, | |
1014 | .p_statidx = RPCBPROC_UNSET, | |
1015 | .p_timer = 0, | |
1016 | .p_name = "UNSET", | |
1017 | }, | |
1018 | [RPCBPROC_GETADDR] = { | |
1019 | .p_proc = RPCBPROC_GETADDR, | |
7d55f7fe | 1020 | .p_encode = rpcb_enc_getaddr, |
605d712f | 1021 | .p_decode = rpcb_dec_getaddr, |
f8b761ef CL |
1022 | .p_arglen = RPCB_getaddrargs_sz, |
1023 | .p_replen = RPCB_getaddrres_sz, | |
1024 | .p_statidx = RPCBPROC_GETADDR, | |
1025 | .p_timer = 0, | |
1026 | .p_name = "GETADDR", | |
1027 | }, | |
a509050b CL |
1028 | }; |
1029 | ||
a613fa16 | 1030 | static const struct rpcb_info rpcb_next_version[] = { |
fc200e79 CL |
1031 | { |
1032 | .rpc_vers = RPCBVERS_2, | |
1033 | .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT], | |
1034 | }, | |
1035 | { | |
1036 | .rpc_proc = NULL, | |
1037 | }, | |
a509050b CL |
1038 | }; |
1039 | ||
a613fa16 | 1040 | static const struct rpcb_info rpcb_next_version6[] = { |
fc200e79 CL |
1041 | { |
1042 | .rpc_vers = RPCBVERS_4, | |
8842413a | 1043 | .rpc_proc = &rpcb_procedures4[RPCBPROC_GETADDR], |
fc200e79 CL |
1044 | }, |
1045 | { | |
1046 | .rpc_vers = RPCBVERS_3, | |
1047 | .rpc_proc = &rpcb_procedures3[RPCBPROC_GETADDR], | |
1048 | }, | |
fc200e79 CL |
1049 | { |
1050 | .rpc_proc = NULL, | |
1051 | }, | |
d5b64430 CL |
1052 | }; |
1053 | ||
1c5876dd | 1054 | static unsigned int rpcb_version2_counts[ARRAY_SIZE(rpcb_procedures2)]; |
a613fa16 | 1055 | static const struct rpc_version rpcb_version2 = { |
fc200e79 | 1056 | .number = RPCBVERS_2, |
1ac7c23e | 1057 | .nrprocs = ARRAY_SIZE(rpcb_procedures2), |
1c5876dd CH |
1058 | .procs = rpcb_procedures2, |
1059 | .counts = rpcb_version2_counts, | |
a509050b CL |
1060 | }; |
1061 | ||
1c5876dd | 1062 | static unsigned int rpcb_version3_counts[ARRAY_SIZE(rpcb_procedures3)]; |
a613fa16 | 1063 | static const struct rpc_version rpcb_version3 = { |
fc200e79 | 1064 | .number = RPCBVERS_3, |
1ac7c23e | 1065 | .nrprocs = ARRAY_SIZE(rpcb_procedures3), |
1c5876dd CH |
1066 | .procs = rpcb_procedures3, |
1067 | .counts = rpcb_version3_counts, | |
a509050b CL |
1068 | }; |
1069 | ||
1c5876dd | 1070 | static unsigned int rpcb_version4_counts[ARRAY_SIZE(rpcb_procedures4)]; |
a613fa16 | 1071 | static const struct rpc_version rpcb_version4 = { |
fc200e79 | 1072 | .number = RPCBVERS_4, |
1ac7c23e | 1073 | .nrprocs = ARRAY_SIZE(rpcb_procedures4), |
1c5876dd CH |
1074 | .procs = rpcb_procedures4, |
1075 | .counts = rpcb_version4_counts, | |
a509050b CL |
1076 | }; |
1077 | ||
a613fa16 | 1078 | static const struct rpc_version *rpcb_version[] = { |
a509050b CL |
1079 | NULL, |
1080 | NULL, | |
1081 | &rpcb_version2, | |
1082 | &rpcb_version3, | |
1083 | &rpcb_version4 | |
1084 | }; | |
1085 | ||
1086 | static struct rpc_stat rpcb_stats; | |
1087 | ||
a613fa16 | 1088 | static const struct rpc_program rpcb_program = { |
a509050b CL |
1089 | .name = "rpcbind", |
1090 | .number = RPCBIND_PROGRAM, | |
1091 | .nrvers = ARRAY_SIZE(rpcb_version), | |
1092 | .version = rpcb_version, | |
1093 | .stats = &rpcb_stats, | |
1094 | }; |