diff options
| -rw-r--r-- | include/linux/sunrpc/clnt.h | 3 | ||||
| -rw-r--r-- | net/sunrpc/rpcb_clnt.c | 178 |
2 files changed, 177 insertions, 4 deletions
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 764fd4c286e0..e5bfe01ee305 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
| @@ -125,6 +125,9 @@ void rpc_shutdown_client(struct rpc_clnt *); | |||
| 125 | void rpc_release_client(struct rpc_clnt *); | 125 | void rpc_release_client(struct rpc_clnt *); |
| 126 | 126 | ||
| 127 | int rpcb_register(u32, u32, int, unsigned short, int *); | 127 | int rpcb_register(u32, u32, int, unsigned short, int *); |
| 128 | int rpcb_v4_register(const u32 program, const u32 version, | ||
| 129 | const struct sockaddr *address, | ||
| 130 | const char *netid, int *result); | ||
| 128 | int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int); | 131 | int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int); |
| 129 | void rpcb_getport_async(struct rpc_task *); | 132 | void rpcb_getport_async(struct rpc_task *); |
| 130 | 133 | ||
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 8b75c306e661..24db2b4d12d3 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
| @@ -87,6 +87,7 @@ struct rpcbind_args { | |||
| 87 | 87 | ||
| 88 | static struct rpc_procinfo rpcb_procedures2[]; | 88 | static struct rpc_procinfo rpcb_procedures2[]; |
| 89 | static struct rpc_procinfo rpcb_procedures3[]; | 89 | static struct rpc_procinfo rpcb_procedures3[]; |
| 90 | static struct rpc_procinfo rpcb_procedures4[]; | ||
| 90 | 91 | ||
| 91 | struct rpcb_info { | 92 | struct rpcb_info { |
| 92 | u32 rpc_vers; | 93 | u32 rpc_vers; |
| @@ -122,6 +123,12 @@ static const struct sockaddr_in rpcb_inaddr_loopback = { | |||
| 122 | .sin_port = htons(RPCBIND_PORT), | 123 | .sin_port = htons(RPCBIND_PORT), |
| 123 | }; | 124 | }; |
| 124 | 125 | ||
| 126 | static const struct sockaddr_in6 rpcb_in6addr_loopback = { | ||
| 127 | .sin6_family = AF_INET6, | ||
| 128 | .sin6_addr = IN6ADDR_LOOPBACK_INIT, | ||
| 129 | .sin6_port = htons(RPCBIND_PORT), | ||
| 130 | }; | ||
| 131 | |||
| 125 | static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr, | 132 | static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr, |
| 126 | size_t addrlen, u32 version) | 133 | size_t addrlen, u32 version) |
| 127 | { | 134 | { |
| @@ -196,13 +203,38 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, | |||
| 196 | * rpcb_register - set or unset a port registration with the local rpcbind svc | 203 | * rpcb_register - set or unset a port registration with the local rpcbind svc |
| 197 | * @prog: RPC program number to bind | 204 | * @prog: RPC program number to bind |
| 198 | * @vers: RPC version number to bind | 205 | * @vers: RPC version number to bind |
| 199 | * @prot: transport protocol to use to make this request | 206 | * @prot: transport protocol to register |
| 200 | * @port: port value to register | 207 | * @port: port value to register |
| 201 | * @okay: result code | 208 | * @okay: OUT: result code |
| 209 | * | ||
| 210 | * RPC services invoke this function to advertise their contact | ||
| 211 | * information via the system's rpcbind daemon. RPC services | ||
| 212 | * invoke this function once for each [program, version, transport] | ||
| 213 | * tuple they wish to advertise. | ||
| 214 | * | ||
| 215 | * Callers may also unregister RPC services that are no longer | ||
| 216 | * available by setting the passed-in port to zero. This removes | ||
| 217 | * all registered transports for [program, version] from the local | ||
| 218 | * rpcbind database. | ||
| 219 | * | ||
| 220 | * Returns zero if the registration request was dispatched | ||
| 221 | * successfully and a reply was received. The rpcbind daemon's | ||
| 222 | * boolean result code is stored in *okay. | ||
| 202 | * | 223 | * |
| 203 | * port == 0 means unregister, port != 0 means register. | 224 | * Returns an errno value and sets *result to zero if there was |
| 225 | * some problem that prevented the rpcbind request from being | ||
| 226 | * dispatched, or if the rpcbind daemon did not respond within | ||
| 227 | * the timeout. | ||
| 204 | * | 228 | * |
| 205 | * This routine supports only rpcbind version 2. | 229 | * This function uses rpcbind protocol version 2 to contact the |
| 230 | * local rpcbind daemon. | ||
| 231 | * | ||
| 232 | * Registration works over both AF_INET and AF_INET6, and services | ||
| 233 | * registered via this function are advertised as available for any | ||
| 234 | * address. If the local rpcbind daemon is listening on AF_INET6, | ||
| 235 | * services registered via this function will be advertised on | ||
| 236 | * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 | ||
| 237 | * addresses). | ||
| 206 | */ | 238 | */ |
| 207 | int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | 239 | int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) |
| 208 | { | 240 | { |
| @@ -230,6 +262,144 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |||
| 230 | RPCBVERS_2, &msg, okay); | 262 | RPCBVERS_2, &msg, okay); |
| 231 | } | 263 | } |
| 232 | 264 | ||
| 265 | /* | ||
| 266 | * Fill in AF_INET family-specific arguments to register | ||
| 267 | */ | ||
| 268 | static int rpcb_register_netid4(struct sockaddr_in *address_to_register, | ||
| 269 | struct rpc_message *msg) | ||
| 270 | { | ||
| 271 | struct rpcbind_args *map = msg->rpc_argp; | ||
| 272 | unsigned short port = ntohs(address_to_register->sin_port); | ||
| 273 | char buf[32]; | ||
| 274 | |||
| 275 | /* Construct AF_INET universal address */ | ||
| 276 | snprintf(buf, sizeof(buf), | ||
| 277 | NIPQUAD_FMT".%u.%u", | ||
| 278 | NIPQUAD(address_to_register->sin_addr.s_addr), | ||
| 279 | port >> 8, port & 0xff); | ||
| 280 | map->r_addr = buf; | ||
| 281 | |||
| 282 | dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " | ||
| 283 | "local rpcbind\n", (port ? "" : "un"), | ||
| 284 | map->r_prog, map->r_vers, | ||
| 285 | map->r_addr, map->r_netid); | ||
| 286 | |||
| 287 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; | ||
| 288 | if (port) | ||
| 289 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; | ||
| 290 | |||
| 291 | return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, | ||
| 292 | sizeof(rpcb_inaddr_loopback), | ||
| 293 | RPCBVERS_4, msg, msg->rpc_resp); | ||
| 294 | } | ||
| 295 | |||
| 296 | /* | ||
| 297 | * Fill in AF_INET6 family-specific arguments to register | ||
| 298 | */ | ||
| 299 | static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, | ||
| 300 | struct rpc_message *msg) | ||
| 301 | { | ||
| 302 | struct rpcbind_args *map = msg->rpc_argp; | ||
| 303 | unsigned short port = ntohs(address_to_register->sin6_port); | ||
| 304 | char buf[64]; | ||
| 305 | |||
| 306 | /* Construct AF_INET6 universal address */ | ||
| 307 | snprintf(buf, sizeof(buf), | ||
| 308 | NIP6_FMT".%u.%u", | ||
| 309 | NIP6(address_to_register->sin6_addr), | ||
| 310 | port >> 8, port & 0xff); | ||
| 311 | map->r_addr = buf; | ||
| 312 | |||
| 313 | dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " | ||
| 314 | "local rpcbind\n", (port ? "" : "un"), | ||
| 315 | map->r_prog, map->r_vers, | ||
| 316 | map->r_addr, map->r_netid); | ||
| 317 | |||
| 318 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; | ||
| 319 | if (port) | ||
| 320 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; | ||
| 321 | |||
| 322 | return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback, | ||
| 323 | sizeof(rpcb_in6addr_loopback), | ||
| 324 | RPCBVERS_4, msg, msg->rpc_resp); | ||
| 325 | } | ||
| 326 | |||
| 327 | /** | ||
| 328 | * rpcb_v4_register - set or unset a port registration with the local rpcbind | ||
| 329 | * @program: RPC program number of service to (un)register | ||
| 330 | * @version: RPC version number of service to (un)register | ||
| 331 | * @address: address family, IP address, and port to (un)register | ||
| 332 | * @netid: netid of transport protocol to (un)register | ||
| 333 | * @result: result code from rpcbind RPC call | ||
| 334 | * | ||
| 335 | * RPC services invoke this function to advertise their contact | ||
| 336 | * information via the system's rpcbind daemon. RPC services | ||
| 337 | * invoke this function once for each [program, version, address, | ||
| 338 | * netid] tuple they wish to advertise. | ||
| 339 | * | ||
| 340 | * Callers may also unregister RPC services that are no longer | ||
| 341 | * available by setting the port number in the passed-in address | ||
| 342 | * to zero. Callers pass a netid of "" to unregister all | ||
| 343 | * transport netids associated with [program, version, address]. | ||
| 344 | * | ||
| 345 | * Returns zero if the registration request was dispatched | ||
| 346 | * successfully and a reply was received. The rpcbind daemon's | ||
| 347 | * result code is stored in *result. | ||
| 348 | * | ||
| 349 | * Returns an errno value and sets *result to zero if there was | ||
| 350 | * some problem that prevented the rpcbind request from being | ||
| 351 | * dispatched, or if the rpcbind daemon did not respond within | ||
| 352 | * the timeout. | ||
| 353 | * | ||
| 354 | * This function uses rpcbind protocol version 4 to contact the | ||
| 355 | * local rpcbind daemon. The local rpcbind daemon must support | ||
| 356 | * version 4 of the rpcbind protocol in order for these functions | ||
| 357 | * to register a service successfully. | ||
| 358 | * | ||
| 359 | * Supported netids include "udp" and "tcp" for UDP and TCP over | ||
| 360 | * IPv4, and "udp6" and "tcp6" for UDP and TCP over IPv6, | ||
| 361 | * respectively. | ||
| 362 | * | ||
| 363 | * The contents of @address determine the address family and the | ||
| 364 | * port to be registered. The usual practice is to pass INADDR_ANY | ||
| 365 | * as the raw address, but specifying a non-zero address is also | ||
| 366 | * supported by this API if the caller wishes to advertise an RPC | ||
| 367 | * service on a specific network interface. | ||
| 368 | * | ||
| 369 | * Note that passing in INADDR_ANY does not create the same service | ||
| 370 | * registration as IN6ADDR_ANY. The former advertises an RPC | ||
| 371 | * service on any IPv4 address, but not on IPv6. The latter | ||
| 372 | * advertises the service on all IPv4 and IPv6 addresses. | ||
| 373 | */ | ||
| 374 | int rpcb_v4_register(const u32 program, const u32 version, | ||
| 375 | const struct sockaddr *address, const char *netid, | ||
| 376 | int *result) | ||
| 377 | { | ||
| 378 | struct rpcbind_args map = { | ||
| 379 | .r_prog = program, | ||
| 380 | .r_vers = version, | ||
| 381 | .r_netid = netid, | ||
| 382 | .r_owner = RPCB_OWNER_STRING, | ||
| 383 | }; | ||
| 384 | struct rpc_message msg = { | ||
| 385 | .rpc_argp = &map, | ||
| 386 | .rpc_resp = result, | ||
| 387 | }; | ||
| 388 | |||
| 389 | *result = 0; | ||
| 390 | |||
| 391 | switch (address->sa_family) { | ||
| 392 | case AF_INET: | ||
| 393 | return rpcb_register_netid4((struct sockaddr_in *)address, | ||
| 394 | &msg); | ||
| 395 | case AF_INET6: | ||
| 396 | return rpcb_register_netid6((struct sockaddr_in6 *)address, | ||
| 397 | &msg); | ||
| 398 | } | ||
| 399 | |||
| 400 | return -EAFNOSUPPORT; | ||
| 401 | } | ||
| 402 | |||
| 233 | /** | 403 | /** |
| 234 | * rpcb_getport_sync - obtain the port for an RPC service on a given host | 404 | * rpcb_getport_sync - obtain the port for an RPC service on a given host |
| 235 | * @sin: address of remote peer | 405 | * @sin: address of remote peer |
