2007-03-30 00:48:04 +04:00
/*
* In - kernel rpcbind client supporting versions 2 , 3 , and 4 of the rpcbind
* protocol
*
* Based on RFC 1833 : " Binding Protocols for ONC RPC Version 2 " and
* RFC 3530 : " Network File System (NFS) version 4 Protocol "
*
* Original : Gilles Quillard , Bull Open Source , 2005 < gilles . quillard @ bull . net >
* Updated : Chuck Lever , Oracle Corporation , 2007 < chuck . lever @ oracle . com >
*
* Descended from net / sunrpc / pmap_clnt . c ,
* Copyright ( C ) 1996 , Olaf Kirch < okir @ monad . swb . de >
*/
2007-07-01 20:13:12 +04:00
# include <linux/module.h>
2007-03-30 00:48:04 +04:00
# include <linux/types.h>
# include <linux/socket.h>
2007-08-06 19:57:18 +04:00
# include <linux/in.h>
# include <linux/in6.h>
2007-03-30 00:48:04 +04:00
# include <linux/kernel.h>
# include <linux/errno.h>
2008-09-16 01:27:30 +04:00
# include <net/ipv6.h>
2007-03-30 00:48:04 +04:00
# include <linux/sunrpc/clnt.h>
# include <linux/sunrpc/sched.h>
2007-09-10 21:48:23 +04:00
# include <linux/sunrpc/xprtsock.h>
2007-03-30 00:48:04 +04:00
# ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_BIND
# endif
# define RPCBIND_PROGRAM (100000u)
# define RPCBIND_PORT (111u)
2008-06-26 01:24:31 +04:00
# define RPCBVERS_2 (2u)
# define RPCBVERS_3 (3u)
# define RPCBVERS_4 (4u)
2007-03-30 00:48:04 +04:00
enum {
RPCBPROC_NULL ,
RPCBPROC_SET ,
RPCBPROC_UNSET ,
RPCBPROC_GETPORT ,
RPCBPROC_GETADDR = 3 , /* alias for GETPORT */
RPCBPROC_DUMP ,
RPCBPROC_CALLIT ,
RPCBPROC_BCAST = 5 , /* alias for CALLIT */
RPCBPROC_GETTIME ,
RPCBPROC_UADDR2TADDR ,
RPCBPROC_TADDR2UADDR ,
RPCBPROC_GETVERSADDR ,
RPCBPROC_INDIRECT ,
RPCBPROC_GETADDRLIST ,
RPCBPROC_GETSTAT ,
} ;
# define RPCB_HIGHPROC_2 RPCBPROC_CALLIT
# define RPCB_HIGHPROC_3 RPCBPROC_TADDR2UADDR
# define RPCB_HIGHPROC_4 RPCBPROC_GETSTAT
/*
* r_owner
*
* The " owner " is allowed to unset a service in the rpcbind database .
* We always use the following ( arbitrary ) fixed string .
*/
# define RPCB_OWNER_STRING "rpcb"
# define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING)
static void rpcb_getport_done ( struct rpc_task * , void * ) ;
2008-07-07 20:18:53 +04:00
static void rpcb_map_release ( void * data ) ;
2007-06-13 03:03:13 +04:00
static struct rpc_program rpcb_program ;
2007-03-30 00:48:04 +04:00
struct rpcbind_args {
struct rpc_xprt * r_xprt ;
u32 r_prog ;
u32 r_vers ;
u32 r_prot ;
unsigned short r_port ;
2008-01-08 05:16:56 +03:00
const char * r_netid ;
const char * r_addr ;
const char * r_owner ;
2008-07-07 20:18:53 +04:00
int r_status ;
2007-03-30 00:48:04 +04:00
} ;
static struct rpc_procinfo rpcb_procedures2 [ ] ;
static struct rpc_procinfo rpcb_procedures3 [ ] ;
2008-07-15 00:03:30 +04:00
static struct rpc_procinfo rpcb_procedures4 [ ] ;
2007-03-30 00:48:04 +04:00
2007-08-06 19:57:18 +04:00
struct rpcb_info {
2008-06-26 01:24:31 +04:00
u32 rpc_vers ;
2007-03-30 00:48:04 +04:00
struct rpc_procinfo * rpc_proc ;
2007-08-06 19:57:18 +04:00
} ;
static struct rpcb_info rpcb_next_version [ ] ;
static struct rpcb_info rpcb_next_version6 [ ] ;
2007-03-30 00:48:04 +04:00
static const struct rpc_call_ops rpcb_getport_ops = {
. rpc_call_done = rpcb_getport_done ,
. rpc_release = rpcb_map_release ,
} ;
static void rpcb_wake_rpcbind_waiters ( struct rpc_xprt * xprt , int status )
{
xprt_clear_binding ( xprt ) ;
rpc_wake_up_status ( & xprt - > binding , status ) ;
}
2008-07-07 20:18:53 +04:00
static void rpcb_map_release ( void * data )
{
struct rpcbind_args * map = data ;
rpcb_wake_rpcbind_waiters ( map - > r_xprt , map - > r_status ) ;
xprt_put ( map - > r_xprt ) ;
kfree ( map ) ;
}
2008-07-15 00:03:27 +04:00
static const struct sockaddr_in rpcb_inaddr_loopback = {
. sin_family = AF_INET ,
. sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ,
. sin_port = htons ( RPCBIND_PORT ) ,
} ;
2008-07-15 00:03:30 +04:00
static const struct sockaddr_in6 rpcb_in6addr_loopback = {
. sin6_family = AF_INET6 ,
. sin6_addr = IN6ADDR_LOOPBACK_INIT ,
. sin6_port = htons ( RPCBIND_PORT ) ,
} ;
2008-07-15 00:03:27 +04:00
static struct rpc_clnt * rpcb_create_local ( struct sockaddr * addr ,
size_t addrlen , u32 version )
{
struct rpc_create_args args = {
. protocol = XPRT_TRANSPORT_UDP ,
. address = addr ,
. addrsize = addrlen ,
. servername = " localhost " ,
. program = & rpcb_program ,
. version = version ,
. authflavor = RPC_AUTH_UNIX ,
. flags = RPC_CLNT_CREATE_NOPING ,
} ;
return rpc_create ( & args ) ;
}
2007-03-30 00:48:04 +04:00
static struct rpc_clnt * rpcb_create ( char * hostname , struct sockaddr * srvaddr ,
2008-07-15 00:03:28 +04:00
size_t salen , int proto , u32 version )
2007-03-30 00:48:04 +04:00
{
struct rpc_create_args args = {
. protocol = proto ,
. address = srvaddr ,
2007-12-10 22:56:31 +03:00
. addrsize = salen ,
2007-03-30 00:48:04 +04:00
. servername = hostname ,
. program = & rpcb_program ,
. version = version ,
. authflavor = RPC_AUTH_UNIX ,
2008-07-15 00:03:28 +04:00
. flags = ( RPC_CLNT_CREATE_NOPING |
RPC_CLNT_CREATE_NONPRIVPORT ) ,
2007-03-30 00:48:04 +04:00
} ;
2007-08-06 19:57:18 +04:00
switch ( srvaddr - > sa_family ) {
case AF_INET :
( ( struct sockaddr_in * ) srvaddr ) - > sin_port = htons ( RPCBIND_PORT ) ;
break ;
case AF_INET6 :
( ( struct sockaddr_in6 * ) srvaddr ) - > sin6_port = htons ( RPCBIND_PORT ) ;
break ;
default :
return NULL ;
}
2007-03-30 00:48:04 +04:00
return rpc_create ( & args ) ;
}
2008-07-15 00:03:29 +04:00
static int rpcb_register_call ( struct sockaddr * addr , size_t addrlen ,
2008-08-19 03:34:00 +04:00
u32 version , struct rpc_message * msg )
2008-07-15 00:03:29 +04:00
{
struct rpc_clnt * rpcb_clnt ;
2008-08-19 03:34:00 +04:00
int result , error = 0 ;
2008-07-15 00:03:29 +04:00
2008-08-19 03:34:00 +04:00
msg - > rpc_resp = & result ;
2008-07-15 00:03:29 +04:00
rpcb_clnt = rpcb_create_local ( addr , addrlen , version ) ;
if ( ! IS_ERR ( rpcb_clnt ) ) {
error = rpc_call_sync ( rpcb_clnt , msg , 0 ) ;
rpc_shutdown_client ( rpcb_clnt ) ;
} else
error = PTR_ERR ( rpcb_clnt ) ;
2008-08-19 03:34:00 +04:00
if ( error < 0 ) {
2008-07-15 00:03:29 +04:00
printk ( KERN_WARNING " RPC: failed to contact local rpcbind "
" server (errno %d). \n " , - error ) ;
2008-08-19 03:34:00 +04:00
return error ;
}
2008-09-25 19:57:05 +04:00
if ( ! result )
2008-08-19 03:34:00 +04:00
return - EACCES ;
return 0 ;
2008-07-15 00:03:29 +04:00
}
2007-03-30 00:48:04 +04:00
/**
* rpcb_register - set or unset a port registration with the local rpcbind svc
* @ prog : RPC program number to bind
* @ vers : RPC version number to bind
2008-07-15 00:03:30 +04:00
* @ prot : transport protocol to register
2007-03-30 00:48:04 +04:00
* @ port : port value to register
2008-08-19 03:34:00 +04:00
*
* Returns zero if the registration request was dispatched successfully
* and the rpcbind daemon returned success . Otherwise , returns an errno
* value that reflects the nature of the error ( request could not be
* dispatched , timed out , or rpcbind returned an error ) .
2008-07-15 00:03:30 +04:00
*
* RPC services invoke this function to advertise their contact
* information via the system ' s rpcbind daemon . RPC services
* invoke this function once for each [ program , version , transport ]
* tuple they wish to advertise .
*
* Callers may also unregister RPC services that are no longer
* available by setting the passed - in port to zero . This removes
* all registered transports for [ program , version ] from the local
* rpcbind database .
*
* This function uses rpcbind protocol version 2 to contact the
* local rpcbind daemon .
*
* Registration works over both AF_INET and AF_INET6 , and services
* registered via this function are advertised as available for any
* address . If the local rpcbind daemon is listening on AF_INET6 ,
* services registered via this function will be advertised on
* IN6ADDR_ANY ( ie available for all AF_INET and AF_INET6
* addresses ) .
2007-03-30 00:48:04 +04:00
*/
2008-08-19 03:34:00 +04:00
int rpcb_register ( u32 prog , u32 vers , int prot , unsigned short port )
2007-03-30 00:48:04 +04:00
{
struct rpcbind_args map = {
. r_prog = prog ,
. r_vers = vers ,
. r_prot = prot ,
. r_port = port ,
} ;
struct rpc_message msg = {
. rpc_argp = & map ,
} ;
dprintk ( " RPC: %sregistering (%u, %u, %d, %u) with local "
" rpcbind \n " , ( port ? " " : " un " ) ,
prog , vers , prot , port ) ;
2008-07-15 00:03:29 +04:00
msg . rpc_proc = & rpcb_procedures2 [ RPCBPROC_UNSET ] ;
if ( port )
msg . rpc_proc = & rpcb_procedures2 [ RPCBPROC_SET ] ;
2007-03-30 00:48:04 +04:00
2008-07-15 00:03:29 +04:00
return rpcb_register_call ( ( struct sockaddr * ) & rpcb_inaddr_loopback ,
sizeof ( rpcb_inaddr_loopback ) ,
2008-08-19 03:34:00 +04:00
RPCBVERS_2 , & msg ) ;
2007-03-30 00:48:04 +04:00
}
2008-07-15 00:03:30 +04:00
/*
* Fill in AF_INET family - specific arguments to register
*/
static int rpcb_register_netid4 ( struct sockaddr_in * address_to_register ,
struct rpc_message * msg )
{
struct rpcbind_args * map = msg - > rpc_argp ;
unsigned short port = ntohs ( address_to_register - > sin_port ) ;
char buf [ 32 ] ;
/* Construct AF_INET universal address */
snprintf ( buf , sizeof ( buf ) ,
NIPQUAD_FMT " .%u.%u " ,
NIPQUAD ( address_to_register - > sin_addr . s_addr ) ,
port > > 8 , port & 0xff ) ;
map - > r_addr = buf ;
dprintk ( " RPC: %sregistering [%u, %u, %s, '%s'] with "
" local rpcbind \n " , ( port ? " " : " un " ) ,
map - > r_prog , map - > r_vers ,
map - > r_addr , map - > r_netid ) ;
msg - > rpc_proc = & rpcb_procedures4 [ RPCBPROC_UNSET ] ;
if ( port )
msg - > rpc_proc = & rpcb_procedures4 [ RPCBPROC_SET ] ;
return rpcb_register_call ( ( struct sockaddr * ) & rpcb_inaddr_loopback ,
sizeof ( rpcb_inaddr_loopback ) ,
2008-08-19 03:34:00 +04:00
RPCBVERS_4 , msg ) ;
2008-07-15 00:03:30 +04:00
}
/*
* Fill in AF_INET6 family - specific arguments to register
*/
static int rpcb_register_netid6 ( struct sockaddr_in6 * address_to_register ,
struct rpc_message * msg )
{
struct rpcbind_args * map = msg - > rpc_argp ;
unsigned short port = ntohs ( address_to_register - > sin6_port ) ;
char buf [ 64 ] ;
/* Construct AF_INET6 universal address */
2008-09-16 01:27:30 +04:00
if ( ipv6_addr_any ( & address_to_register - > sin6_addr ) )
snprintf ( buf , sizeof ( buf ) , " ::.%u.%u " ,
port > > 8 , port & 0xff ) ;
else
snprintf ( buf , sizeof ( buf ) , NIP6_FMT " .%u.%u " ,
NIP6 ( address_to_register - > sin6_addr ) ,
port > > 8 , port & 0xff ) ;
2008-07-15 00:03:30 +04:00
map - > r_addr = buf ;
dprintk ( " RPC: %sregistering [%u, %u, %s, '%s'] with "
" local rpcbind \n " , ( port ? " " : " un " ) ,
map - > r_prog , map - > r_vers ,
map - > r_addr , map - > r_netid ) ;
msg - > rpc_proc = & rpcb_procedures4 [ RPCBPROC_UNSET ] ;
if ( port )
msg - > rpc_proc = & rpcb_procedures4 [ RPCBPROC_SET ] ;
return rpcb_register_call ( ( struct sockaddr * ) & rpcb_in6addr_loopback ,
sizeof ( rpcb_in6addr_loopback ) ,
2008-08-19 03:34:00 +04:00
RPCBVERS_4 , msg ) ;
2008-07-15 00:03:30 +04:00
}
/**
* rpcb_v4_register - set or unset a port registration with the local rpcbind
* @ program : RPC program number of service to ( un ) register
* @ version : RPC version number of service to ( un ) register
* @ address : address family , IP address , and port to ( un ) register
* @ netid : netid of transport protocol to ( un ) register
2008-08-19 03:34:00 +04:00
*
* Returns zero if the registration request was dispatched successfully
* and the rpcbind daemon returned success . Otherwise , returns an errno
* value that reflects the nature of the error ( request could not be
* dispatched , timed out , or rpcbind returned an error ) .
2008-07-15 00:03:30 +04:00
*
* RPC services invoke this function to advertise their contact
* information via the system ' s rpcbind daemon . RPC services
* invoke this function once for each [ program , version , address ,
* netid ] tuple they wish to advertise .
*
* Callers may also unregister RPC services that are no longer
* available by setting the port number in the passed - in address
* to zero . Callers pass a netid of " " to unregister all
* transport netids associated with [ program , version , address ] .
*
* This function uses rpcbind protocol version 4 to contact the
* local rpcbind daemon . The local rpcbind daemon must support
* version 4 of the rpcbind protocol in order for these functions
* to register a service successfully .
*
* Supported netids include " udp " and " tcp " for UDP and TCP over
* IPv4 , and " udp6 " and " tcp6 " for UDP and TCP over IPv6 ,
* respectively .
*
* The contents of @ address determine the address family and the
* port to be registered . The usual practice is to pass INADDR_ANY
* as the raw address , but specifying a non - zero address is also
* supported by this API if the caller wishes to advertise an RPC
* service on a specific network interface .
*
* Note that passing in INADDR_ANY does not create the same service
* registration as IN6ADDR_ANY . The former advertises an RPC
* service on any IPv4 address , but not on IPv6 . The latter
* advertises the service on all IPv4 and IPv6 addresses .
*/
int rpcb_v4_register ( const u32 program , const u32 version ,
2008-08-19 03:34:00 +04:00
const struct sockaddr * address , const char * netid )
2008-07-15 00:03:30 +04:00
{
struct rpcbind_args map = {
. r_prog = program ,
. r_vers = version ,
. r_netid = netid ,
. r_owner = RPCB_OWNER_STRING ,
} ;
struct rpc_message msg = {
. rpc_argp = & map ,
} ;
switch ( address - > sa_family ) {
case AF_INET :
return rpcb_register_netid4 ( ( struct sockaddr_in * ) address ,
& msg ) ;
case AF_INET6 :
return rpcb_register_netid6 ( ( struct sockaddr_in6 * ) address ,
& msg ) ;
}
return - EAFNOSUPPORT ;
}
2007-03-30 00:48:04 +04:00
/**
2007-07-01 20:13:12 +04:00
* rpcb_getport_sync - obtain the port for an RPC service on a given host
2007-03-30 00:48:04 +04:00
* @ sin : address of remote peer
* @ prog : RPC program number to bind
* @ vers : RPC version number to bind
* @ prot : transport protocol to use to make this request
*
2008-01-14 23:12:01 +03:00
* Return value is the requested advertised port number ,
* or a negative errno value .
*
2007-03-30 00:48:04 +04:00
* Called from outside the RPC client in a synchronous task context .
2007-07-01 20:13:12 +04:00
* Uses default timeout parameters specified by underlying transport .
2007-03-30 00:48:04 +04:00
*
2008-01-14 23:12:01 +03:00
* XXX : Needs to support IPv6
2007-03-30 00:48:04 +04:00
*/
2008-01-14 23:11:53 +03:00
int rpcb_getport_sync ( struct sockaddr_in * sin , u32 prog , u32 vers , int prot )
2007-03-30 00:48:04 +04:00
{
struct rpcbind_args map = {
. r_prog = prog ,
. r_vers = vers ,
. r_prot = prot ,
. r_port = 0 ,
} ;
struct rpc_message msg = {
. rpc_proc = & rpcb_procedures2 [ RPCBPROC_GETPORT ] ,
. rpc_argp = & map ,
. rpc_resp = & map . r_port ,
} ;
struct rpc_clnt * rpcb_clnt ;
int status ;
2007-07-01 20:13:12 +04:00
dprintk ( " RPC: %s( " NIPQUAD_FMT " , %u, %u, %d) \n " ,
2008-03-06 07:47:47 +03:00
__func__ , NIPQUAD ( sin - > sin_addr . s_addr ) , prog , vers , prot ) ;
2007-03-30 00:48:04 +04:00
2008-01-14 23:11:46 +03:00
rpcb_clnt = rpcb_create ( NULL , ( struct sockaddr * ) sin ,
2008-07-15 00:03:28 +04:00
sizeof ( * sin ) , prot , RPCBVERS_2 ) ;
2007-03-30 00:48:04 +04:00
if ( IS_ERR ( rpcb_clnt ) )
return PTR_ERR ( rpcb_clnt ) ;
status = rpc_call_sync ( rpcb_clnt , & msg , 0 ) ;
2007-06-10 03:49:36 +04:00
rpc_shutdown_client ( rpcb_clnt ) ;
2007-03-30 00:48:04 +04:00
if ( status > = 0 ) {
if ( map . r_port ! = 0 )
return map . r_port ;
status = - EACCES ;
}
return status ;
}
2007-07-01 20:13:12 +04:00
EXPORT_SYMBOL_GPL ( rpcb_getport_sync ) ;
2007-03-30 00:48:04 +04:00
2008-07-01 23:20:55 +04:00
static struct rpc_task * rpcb_call_async ( struct rpc_clnt * rpcb_clnt , struct rpcbind_args * map , struct rpc_procinfo * proc )
2007-07-14 23:40:01 +04:00
{
struct rpc_message msg = {
2008-07-01 23:20:55 +04:00
. rpc_proc = proc ,
2007-07-14 23:40:01 +04:00
. rpc_argp = map ,
. rpc_resp = & map - > r_port ,
} ;
struct rpc_task_setup task_setup_data = {
. rpc_client = rpcb_clnt ,
. rpc_message = & msg ,
. callback_ops = & rpcb_getport_ops ,
. callback_data = map ,
. flags = RPC_TASK_ASYNC ,
} ;
return rpc_run_task ( & task_setup_data ) ;
}
2008-10-04 00:48:34 +04:00
/*
* In the case where rpc clients have been cloned , we want to make
* sure that we use the program number / version etc of the actual
* owner of the xprt . To do so , we walk back up the tree of parents
* to find whoever created the transport and / or whoever has the
* autobind flag set .
*/
static struct rpc_clnt * rpcb_find_transport_owner ( struct rpc_clnt * clnt )
{
struct rpc_clnt * parent = clnt - > cl_parent ;
while ( parent ! = clnt ) {
if ( parent - > cl_xprt ! = clnt - > cl_xprt )
break ;
if ( clnt - > cl_autobind )
break ;
clnt = parent ;
parent = parent - > cl_parent ;
}
return clnt ;
}
2007-03-30 00:48:04 +04:00
/**
2007-07-01 20:13:17 +04:00
* rpcb_getport_async - obtain the port for a given RPC service on a given host
2007-03-30 00:48:04 +04:00
* @ task : task that is waiting for portmapper request
*
* This one can be called for an ongoing RPC request , and can be used in
* an async ( rpciod ) context .
*/
2007-07-01 20:13:17 +04:00
void rpcb_getport_async ( struct rpc_task * task )
2007-03-30 00:48:04 +04:00
{
2008-10-04 00:48:34 +04:00
struct rpc_clnt * clnt ;
2008-07-01 23:20:55 +04:00
struct rpc_procinfo * proc ;
2007-12-10 22:56:38 +03:00
u32 bind_version ;
2008-10-04 00:48:34 +04:00
struct rpc_xprt * xprt ;
2007-03-30 00:48:04 +04:00
struct rpc_clnt * rpcb_clnt ;
static struct rpcbind_args * map ;
struct rpc_task * child ;
2007-12-10 22:56:31 +03:00
struct sockaddr_storage addr ;
struct sockaddr * sap = ( struct sockaddr * ) & addr ;
size_t salen ;
2007-03-30 00:48:04 +04:00
int status ;
2008-10-04 00:48:34 +04:00
clnt = rpcb_find_transport_owner ( task - > tk_client ) ;
xprt = clnt - > cl_xprt ;
2007-07-01 20:13:17 +04:00
dprintk ( " RPC: %5u %s(%s, %u, %u, %d) \n " ,
2008-03-06 07:47:47 +03:00
task - > tk_pid , __func__ ,
2007-07-01 20:13:17 +04:00
clnt - > cl_server , clnt - > cl_prog , clnt - > cl_vers , xprt - > prot ) ;
2007-03-30 00:48:04 +04:00
2008-07-07 20:18:53 +04:00
/* Put self on the wait queue to ensure we get notified if
* some other task is already attempting to bind the port */
rpc_sleep_on ( & xprt - > binding , task , NULL ) ;
2007-03-30 00:48:04 +04:00
if ( xprt_test_and_set_binding ( xprt ) ) {
2007-07-01 20:13:17 +04:00
dprintk ( " RPC: %5u %s: waiting for another binder \n " ,
2008-03-06 07:47:47 +03:00
task - > tk_pid , __func__ ) ;
2008-07-07 20:18:53 +04:00
return ;
2007-03-30 00:48:04 +04:00
}
/* Someone else may have bound if we slept */
if ( xprt_bound ( xprt ) ) {
status = 0 ;
2007-07-01 20:13:17 +04:00
dprintk ( " RPC: %5u %s: already bound \n " ,
2008-03-06 07:47:47 +03:00
task - > tk_pid , __func__ ) ;
2007-03-30 00:48:04 +04:00
goto bailout_nofree ;
}
2007-12-10 22:56:31 +03:00
salen = rpc_peeraddr ( clnt , sap , sizeof ( addr ) ) ;
2007-08-06 19:57:18 +04:00
/* Don't ever use rpcbind v2 for AF_INET6 requests */
2007-12-10 22:56:31 +03:00
switch ( sap - > sa_family ) {
2007-08-06 19:57:18 +04:00
case AF_INET :
2008-07-01 23:20:55 +04:00
proc = rpcb_next_version [ xprt - > bind_index ] . rpc_proc ;
bind_version = rpcb_next_version [ xprt - > bind_index ] . rpc_vers ;
2007-08-06 19:57:18 +04:00
break ;
case AF_INET6 :
2008-07-01 23:20:55 +04:00
proc = rpcb_next_version6 [ xprt - > bind_index ] . rpc_proc ;
bind_version = rpcb_next_version6 [ xprt - > bind_index ] . rpc_vers ;
2007-08-06 19:57:18 +04:00
break ;
default :
status = - EAFNOSUPPORT ;
dprintk ( " RPC: %5u %s: bad address family \n " ,
2008-03-06 07:47:47 +03:00
task - > tk_pid , __func__ ) ;
2007-08-06 19:57:18 +04:00
goto bailout_nofree ;
}
2008-07-01 23:20:55 +04:00
if ( proc = = NULL ) {
2007-03-30 00:48:04 +04:00
xprt - > bind_index = 0 ;
2007-09-12 02:00:47 +04:00
status = - EPFNOSUPPORT ;
2007-07-01 20:13:17 +04:00
dprintk ( " RPC: %5u %s: no more getport versions available \n " ,
2008-03-06 07:47:47 +03:00
task - > tk_pid , __func__ ) ;
2007-03-30 00:48:04 +04:00
goto bailout_nofree ;
}
2007-07-01 20:13:17 +04:00
dprintk ( " RPC: %5u %s: trying rpcbind version %u \n " ,
2008-03-06 07:47:47 +03:00
task - > tk_pid , __func__ , bind_version ) ;
2007-03-30 00:48:04 +04:00
2007-12-10 22:56:31 +03:00
rpcb_clnt = rpcb_create ( clnt - > cl_server , sap , salen , xprt - > prot ,
2008-07-15 00:03:28 +04:00
bind_version ) ;
2007-08-17 00:03:31 +04:00
if ( IS_ERR ( rpcb_clnt ) ) {
status = PTR_ERR ( rpcb_clnt ) ;
dprintk ( " RPC: %5u %s: rpcb_create failed, error %ld \n " ,
2008-03-06 07:47:47 +03:00
task - > tk_pid , __func__ , PTR_ERR ( rpcb_clnt ) ) ;
2007-08-17 00:03:31 +04:00
goto bailout_nofree ;
}
2007-03-30 00:48:04 +04:00
map = kzalloc ( sizeof ( struct rpcbind_args ) , GFP_ATOMIC ) ;
if ( ! map ) {
status = - ENOMEM ;
2007-07-01 20:13:17 +04:00
dprintk ( " RPC: %5u %s: no memory available \n " ,
2008-03-06 07:47:47 +03:00
task - > tk_pid , __func__ ) ;
2008-10-04 00:48:40 +04:00
goto bailout_release_client ;
2007-03-30 00:48:04 +04:00
}
map - > r_prog = clnt - > cl_prog ;
map - > r_vers = clnt - > cl_vers ;
map - > r_prot = xprt - > prot ;
map - > r_port = 0 ;
map - > r_xprt = xprt_get ( xprt ) ;
2008-01-08 05:16:56 +03:00
map - > r_netid = rpc_peeraddr2str ( clnt , RPC_DISPLAY_NETID ) ;
map - > r_addr = rpc_peeraddr2str ( rpcb_clnt , RPC_DISPLAY_UNIVERSAL_ADDR ) ;
2007-03-30 00:48:04 +04:00
map - > r_owner = RPCB_OWNER_STRING ; /* ignored for GETADDR */
2008-07-07 20:18:53 +04:00
map - > r_status = - EIO ;
2007-03-30 00:48:04 +04:00
2008-07-01 23:20:55 +04:00
child = rpcb_call_async ( rpcb_clnt , map , proc ) ;
2007-06-15 00:40:32 +04:00
rpc_release_client ( rpcb_clnt ) ;
2007-03-30 00:48:04 +04:00
if ( IS_ERR ( child ) ) {
2008-07-07 20:18:52 +04:00
/* rpcb_map_release() has freed the arguments */
2007-07-01 20:13:17 +04:00
dprintk ( " RPC: %5u %s: rpc_run_task failed \n " ,
2008-03-06 07:47:47 +03:00
task - > tk_pid , __func__ ) ;
2008-07-07 20:18:53 +04:00
return ;
2007-03-30 00:48:04 +04:00
}
2008-10-04 00:48:34 +04:00
xprt - > stat . bind_count + + ;
rpc_put_task ( child ) ;
2007-03-30 00:48:04 +04:00
return ;
2008-10-04 00:48:40 +04:00
bailout_release_client :
rpc_release_client ( rpcb_clnt ) ;
2007-03-30 00:48:04 +04:00
bailout_nofree :
rpcb_wake_rpcbind_waiters ( xprt , status ) ;
task - > tk_status = status ;
}
2007-09-10 21:45:36 +04:00
EXPORT_SYMBOL_GPL ( rpcb_getport_async ) ;
2007-03-30 00:48:04 +04:00
/*
* Rpcbind child task calls this callback via tk_exit .
*/
static void rpcb_getport_done ( struct rpc_task * child , void * data )
{
struct rpcbind_args * map = data ;
struct rpc_xprt * xprt = map - > r_xprt ;
int status = child - > tk_status ;
2007-09-12 02:00:36 +04:00
/* Garbage reply: retry with a lesser rpcbind version */
if ( status = = - EIO )
status = - EPROTONOSUPPORT ;
2007-03-30 00:48:04 +04:00
/* rpcbind server doesn't support this rpcbind protocol version */
if ( status = = - EPROTONOSUPPORT )
xprt - > bind_index + + ;
if ( status < 0 ) {
/* rpcbind server not available on remote host? */
xprt - > ops - > set_port ( xprt , 0 ) ;
} else if ( map - > r_port = = 0 ) {
/* Requested RPC service wasn't registered on remote host */
xprt - > ops - > set_port ( xprt , 0 ) ;
status = - EACCES ;
} else {
/* Succeeded */
xprt - > ops - > set_port ( xprt , map - > r_port ) ;
xprt_set_bound ( xprt ) ;
status = 0 ;
}
dprintk ( " RPC: %5u rpcb_getport_done(status %d, port %u) \n " ,
child - > tk_pid , status , map - > r_port ) ;
2008-07-07 20:18:53 +04:00
map - > r_status = status ;
2007-03-30 00:48:04 +04:00
}
2008-07-15 00:03:26 +04:00
/*
* XDR functions for rpcbind
*/
2007-03-30 00:48:04 +04:00
static int rpcb_encode_mapping ( struct rpc_rqst * req , __be32 * p ,
struct rpcbind_args * rpcb )
{
2008-09-25 19:57:05 +04:00
dprintk ( " RPC: encoding rpcb request (%u, %u, %d, %u) \n " ,
2007-03-30 00:48:04 +04:00
rpcb - > r_prog , rpcb - > r_vers , rpcb - > r_prot , rpcb - > r_port ) ;
* p + + = htonl ( rpcb - > r_prog ) ;
* p + + = htonl ( rpcb - > r_vers ) ;
* p + + = htonl ( rpcb - > r_prot ) ;
* p + + = htonl ( rpcb - > r_port ) ;
req - > rq_slen = xdr_adjust_iovec ( req - > rq_svec , p ) ;
return 0 ;
}
static int rpcb_decode_getport ( struct rpc_rqst * req , __be32 * p ,
unsigned short * portp )
{
* portp = ( unsigned short ) ntohl ( * p + + ) ;
2008-09-25 19:57:05 +04:00
dprintk ( " RPC: rpcb getport result: %u \n " ,
2007-03-30 00:48:04 +04:00
* portp ) ;
return 0 ;
}
static int rpcb_decode_set ( struct rpc_rqst * req , __be32 * p ,
unsigned int * boolp )
{
* boolp = ( unsigned int ) ntohl ( * p + + ) ;
2008-09-25 19:57:05 +04:00
dprintk ( " RPC: rpcb set/unset call %s \n " ,
2008-06-26 01:24:23 +04:00
( * boolp ? " succeeded " : " failed " ) ) ;
2007-03-30 00:48:04 +04:00
return 0 ;
}
static int rpcb_encode_getaddr ( struct rpc_rqst * req , __be32 * p ,
struct rpcbind_args * rpcb )
{
2008-09-25 19:57:05 +04:00
dprintk ( " RPC: encoding rpcb request (%u, %u, %s) \n " ,
2007-03-30 00:48:04 +04:00
rpcb - > r_prog , rpcb - > r_vers , rpcb - > r_addr ) ;
* p + + = htonl ( rpcb - > r_prog ) ;
* p + + = htonl ( rpcb - > r_vers ) ;
p = xdr_encode_string ( p , rpcb - > r_netid ) ;
p = xdr_encode_string ( p , rpcb - > r_addr ) ;
p = xdr_encode_string ( p , rpcb - > r_owner ) ;
req - > rq_slen = xdr_adjust_iovec ( req - > rq_svec , p ) ;
return 0 ;
}
static int rpcb_decode_getaddr ( struct rpc_rqst * req , __be32 * p ,
unsigned short * portp )
{
char * addr ;
2007-08-06 19:56:31 +04:00
u32 addr_len ;
int c , i , f , first , val ;
2007-03-30 00:48:04 +04:00
* portp = 0 ;
2007-08-06 19:56:31 +04:00
addr_len = ntohl ( * p + + ) ;
2007-03-30 00:48:04 +04:00
2007-09-12 02:00:31 +04:00
/*
* Simple sanity check . The smallest possible universal
* address is an IPv4 address string containing 11 bytes .
*/
2007-12-10 22:56:46 +03:00
if ( addr_len < 11 | | addr_len > RPCBIND_MAXUADDRLEN )
2007-09-12 02:00:31 +04:00
goto out_err ;
/*
* Start at the end and walk backwards until the first dot
* is encountered . When the second dot is found , we have
* both parts of the port number .
*/
2007-03-30 00:48:04 +04:00
addr = ( char * ) p ;
val = 0 ;
first = 1 ;
f = 1 ;
for ( i = addr_len - 1 ; i > 0 ; i - - ) {
c = addr [ i ] ;
if ( c > = ' 0 ' & & c < = ' 9 ' ) {
val + = ( c - ' 0 ' ) * f ;
f * = 10 ;
} else if ( c = = ' . ' ) {
if ( first ) {
* portp = val ;
val = first = 0 ;
f = 1 ;
} else {
* portp | = ( val < < 8 ) ;
break ;
}
}
}
2007-09-12 02:00:31 +04:00
/*
* Simple sanity check . If we never saw a dot in the reply ,
* then this was probably just garbage .
*/
if ( first )
goto out_err ;
2007-03-30 00:48:04 +04:00
dprintk ( " RPC: rpcb_decode_getaddr port=%u \n " , * portp ) ;
return 0 ;
2007-09-12 02:00:31 +04:00
out_err :
dprintk ( " RPC: rpcbind server returned malformed reply \n " ) ;
return - EIO ;
2007-03-30 00:48:04 +04:00
}
# define RPCB_program_sz (1u)
# define RPCB_version_sz (1u)
# define RPCB_protocol_sz (1u)
# define RPCB_port_sz (1u)
# define RPCB_boolean_sz (1u)
2007-09-10 21:42:38 +04:00
# define RPCB_netid_sz (1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
2007-12-10 22:56:46 +03:00
# define RPCB_addr_sz (1+XDR_QUADLEN(RPCBIND_MAXUADDRLEN))
2007-03-30 00:48:04 +04:00
# define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
# define RPCB_mappingargs_sz RPCB_program_sz+RPCB_version_sz+ \
RPCB_protocol_sz + RPCB_port_sz
# define RPCB_getaddrargs_sz RPCB_program_sz+RPCB_version_sz+ \
RPCB_netid_sz + RPCB_addr_sz + \
RPCB_ownerstring_sz
# define RPCB_setres_sz RPCB_boolean_sz
# define RPCB_getportres_sz RPCB_port_sz
/*
* Note that RFC 1833 does not put any size restrictions on the
* address string returned by the remote rpcbind database .
*/
# define RPCB_getaddrres_sz RPCB_addr_sz
# define PROC(proc, argtype, restype) \
[ RPCBPROC_ # # proc ] = { \
. p_proc = RPCBPROC_ # # proc , \
. p_encode = ( kxdrproc_t ) rpcb_encode_ # # argtype , \
. p_decode = ( kxdrproc_t ) rpcb_decode_ # # restype , \
. p_arglen = RPCB_ # # argtype # # args_sz , \
. p_replen = RPCB_ # # restype # # res_sz , \
. p_statidx = RPCBPROC_ # # proc , \
. p_timer = 0 , \
. p_name = # proc , \
}
/*
* Not all rpcbind procedures described in RFC 1833 are implemented
* since the Linux kernel RPC code requires only these .
*/
static struct rpc_procinfo rpcb_procedures2 [ ] = {
PROC ( SET , mapping , set ) ,
PROC ( UNSET , mapping , set ) ,
2008-06-26 01:24:39 +04:00
PROC ( GETPORT , mapping , getport ) ,
2007-03-30 00:48:04 +04:00
} ;
static struct rpc_procinfo rpcb_procedures3 [ ] = {
2008-07-15 00:03:26 +04:00
PROC ( SET , getaddr , set ) ,
PROC ( UNSET , getaddr , set ) ,
2007-03-30 00:48:04 +04:00
PROC ( GETADDR , getaddr , getaddr ) ,
} ;
static struct rpc_procinfo rpcb_procedures4 [ ] = {
2008-07-15 00:03:26 +04:00
PROC ( SET , getaddr , set ) ,
PROC ( UNSET , getaddr , set ) ,
2008-06-26 01:24:47 +04:00
PROC ( GETADDR , getaddr , getaddr ) ,
2007-03-30 00:48:04 +04:00
PROC ( GETVERSADDR , getaddr , getaddr ) ,
} ;
static struct rpcb_info rpcb_next_version [ ] = {
2008-06-26 01:24:31 +04:00
{
. rpc_vers = RPCBVERS_2 ,
. rpc_proc = & rpcb_procedures2 [ RPCBPROC_GETPORT ] ,
} ,
{
. rpc_proc = NULL ,
} ,
2007-03-30 00:48:04 +04:00
} ;
2007-08-06 19:57:18 +04:00
static struct rpcb_info rpcb_next_version6 [ ] = {
2008-06-26 01:24:31 +04:00
{
. rpc_vers = RPCBVERS_4 ,
2008-06-26 01:24:47 +04:00
. rpc_proc = & rpcb_procedures4 [ RPCBPROC_GETADDR ] ,
2008-06-26 01:24:31 +04:00
} ,
{
. rpc_vers = RPCBVERS_3 ,
. rpc_proc = & rpcb_procedures3 [ RPCBPROC_GETADDR ] ,
} ,
{
. rpc_proc = NULL ,
} ,
2007-08-06 19:57:18 +04:00
} ;
2007-03-30 00:48:04 +04:00
static struct rpc_version rpcb_version2 = {
2008-06-26 01:24:31 +04:00
. number = RPCBVERS_2 ,
2007-03-30 00:48:04 +04:00
. nrprocs = RPCB_HIGHPROC_2 ,
. procs = rpcb_procedures2
} ;
static struct rpc_version rpcb_version3 = {
2008-06-26 01:24:31 +04:00
. number = RPCBVERS_3 ,
2007-03-30 00:48:04 +04:00
. nrprocs = RPCB_HIGHPROC_3 ,
. procs = rpcb_procedures3
} ;
static struct rpc_version rpcb_version4 = {
2008-06-26 01:24:31 +04:00
. number = RPCBVERS_4 ,
2007-03-30 00:48:04 +04:00
. nrprocs = RPCB_HIGHPROC_4 ,
. procs = rpcb_procedures4
} ;
static struct rpc_version * rpcb_version [ ] = {
NULL ,
NULL ,
& rpcb_version2 ,
& rpcb_version3 ,
& rpcb_version4
} ;
static struct rpc_stat rpcb_stats ;
2007-06-13 03:03:13 +04:00
static struct rpc_program rpcb_program = {
2007-03-30 00:48:04 +04:00
. name = " rpcbind " ,
. number = RPCBIND_PROGRAM ,
. nrvers = ARRAY_SIZE ( rpcb_version ) ,
. version = rpcb_version ,
. stats = & rpcb_stats ,
} ;