2005-04-16 15:20:36 -07:00
/*
2006-08-22 20:06:16 -04:00
* linux / net / sunrpc / pmap_clnt . c
2005-04-16 15:20:36 -07:00
*
2006-08-22 20:06:16 -04:00
* In - kernel RPC portmapper client .
*
* Portmapper supports version 2 of the rpcbind protocol ( RFC 1833 ) .
2005-04-16 15:20:36 -07:00
*
* Copyright ( C ) 1996 , Olaf Kirch < okir @ monad . swb . de >
*/
# include <linux/types.h>
# include <linux/socket.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/uio.h>
# include <linux/in.h>
# include <linux/sunrpc/clnt.h>
# include <linux/sunrpc/sched.h>
# ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_PMAP
# endif
# define PMAP_SET 1
# define PMAP_UNSET 2
# define PMAP_GETPORT 3
2006-08-22 20:06:15 -04:00
struct portmap_args {
u32 pm_prog ;
u32 pm_vers ;
u32 pm_prot ;
unsigned short pm_port ;
2006-09-03 00:51:55 -04:00
struct rpc_xprt * pm_xprt ;
2006-08-22 20:06:15 -04:00
} ;
2005-04-16 15:20:36 -07:00
static struct rpc_procinfo pmap_procedures [ ] ;
2005-09-22 21:24:59 -04:00
static struct rpc_clnt * pmap_create ( char * , struct sockaddr_in * , int , int ) ;
2006-08-22 20:06:15 -04:00
static void pmap_getport_done ( struct rpc_task * , void * ) ;
2005-04-16 15:20:36 -07:00
static struct rpc_program pmap_program ;
2006-08-22 20:06:15 -04:00
static void pmap_getport_prepare ( struct rpc_task * task , void * calldata )
{
struct portmap_args * map = calldata ;
struct rpc_message msg = {
. rpc_proc = & pmap_procedures [ PMAP_GETPORT ] ,
. rpc_argp = map ,
. rpc_resp = & map - > pm_port ,
} ;
rpc_call_setup ( task , & msg , 0 ) ;
}
static inline struct portmap_args * pmap_map_alloc ( void )
{
return kmalloc ( sizeof ( struct portmap_args ) , GFP_NOFS ) ;
}
static inline void pmap_map_free ( struct portmap_args * map )
{
kfree ( map ) ;
}
static void pmap_map_release ( void * data )
{
pmap_map_free ( data ) ;
}
static const struct rpc_call_ops pmap_getport_ops = {
. rpc_call_prepare = pmap_getport_prepare ,
. rpc_call_done = pmap_getport_done ,
. rpc_release = pmap_map_release ,
} ;
2006-09-03 00:51:55 -04:00
static inline void pmap_wake_portmap_waiters ( struct rpc_xprt * xprt , int status )
2006-08-22 20:06:15 -04:00
{
xprt_clear_binding ( xprt ) ;
2006-09-03 00:51:55 -04:00
rpc_wake_up_status ( & xprt - > binding , status ) ;
2006-08-22 20:06:15 -04:00
}
2005-04-16 15:20:36 -07:00
2006-08-22 20:06:16 -04:00
/**
* rpc_getport - obtain the port for a given RPC service on a given host
* @ 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 .
2005-04-16 15:20:36 -07:00
*/
2006-08-22 20:06:16 -04:00
void rpc_getport ( struct rpc_task * task )
2005-04-16 15:20:36 -07:00
{
2006-08-22 20:06:16 -04:00
struct rpc_clnt * clnt = task - > tk_client ;
2006-08-22 20:06:15 -04:00
struct rpc_xprt * xprt = task - > tk_xprt ;
2006-08-22 20:06:17 -04:00
struct sockaddr_in addr ;
2006-08-22 20:06:15 -04:00
struct portmap_args * map ;
2005-04-16 15:20:36 -07:00
struct rpc_clnt * pmap_clnt ;
2006-08-22 20:06:15 -04:00
struct rpc_task * child ;
2006-09-03 00:51:55 -04:00
int status ;
2005-04-16 15:20:36 -07:00
2006-08-22 20:06:15 -04:00
dprintk ( " RPC: %4d rpc_getport(%s, %u, %u, %d) \n " ,
2005-04-16 15:20:36 -07:00
task - > tk_pid , clnt - > cl_server ,
2006-08-22 20:06:15 -04:00
clnt - > cl_prog , clnt - > cl_vers , xprt - > prot ) ;
2005-04-16 15:20:36 -07:00
2005-06-22 17:16:23 +00:00
/* Autobind on cloned rpc clients is discouraged */
BUG_ON ( clnt - > cl_parent ! = clnt ) ;
2006-10-19 23:28:43 -07:00
/* Put self on queue before sending rpcbind request, in case
* pmap_getport_done completes before we return from rpc_run_task */
rpc_sleep_on ( & xprt - > binding , task , NULL , NULL ) ;
status = - EACCES ; /* tell caller to check again */
if ( xprt_test_and_set_binding ( xprt ) )
goto bailout_nofree ;
2006-08-22 20:06:15 -04:00
/* Someone else may have bound if we slept */
2006-09-03 00:51:55 -04:00
status = 0 ;
if ( xprt_bound ( xprt ) )
2006-08-22 20:06:15 -04:00
goto bailout_nofree ;
2006-09-03 00:51:55 -04:00
status = - ENOMEM ;
2006-08-22 20:06:15 -04:00
map = pmap_map_alloc ( ) ;
2006-09-03 00:51:55 -04:00
if ( ! map )
2006-08-22 20:06:15 -04:00
goto bailout_nofree ;
map - > pm_prog = clnt - > cl_prog ;
map - > pm_vers = clnt - > cl_vers ;
map - > pm_prot = xprt - > prot ;
map - > pm_port = 0 ;
2006-09-03 00:51:55 -04:00
map - > pm_xprt = xprt_get ( xprt ) ;
2005-04-16 15:20:36 -07:00
2006-08-22 20:06:17 -04:00
rpc_peeraddr ( clnt , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
pmap_clnt = pmap_create ( clnt - > cl_server , & addr , map - > pm_prot , 0 ) ;
2006-09-03 00:51:55 -04:00
status = PTR_ERR ( pmap_clnt ) ;
if ( IS_ERR ( pmap_clnt ) )
2005-04-16 15:20:36 -07:00
goto bailout ;
2006-09-03 00:51:55 -04:00
status = - EIO ;
2006-08-22 20:06:15 -04:00
child = rpc_run_task ( pmap_clnt , RPC_TASK_ASYNC , & pmap_getport_ops , map ) ;
2006-09-03 00:51:55 -04:00
if ( IS_ERR ( child ) )
2005-04-16 15:20:36 -07:00
goto bailout ;
2006-08-22 20:06:15 -04:00
rpc_release_task ( child ) ;
2005-04-16 15:20:36 -07:00
2006-03-20 13:44:16 -05:00
task - > tk_xprt - > stat . bind_count + + ;
2005-04-16 15:20:36 -07:00
return ;
bailout :
2006-08-22 20:06:15 -04:00
pmap_map_free ( map ) ;
2006-09-03 00:51:55 -04:00
xprt_put ( xprt ) ;
2006-08-22 20:06:15 -04:00
bailout_nofree :
2006-09-03 00:51:55 -04:00
task - > tk_status = status ;
pmap_wake_portmap_waiters ( xprt , status ) ;
2005-04-16 15:20:36 -07:00
}
# ifdef CONFIG_ROOT_NFS
2006-08-22 20:06:16 -04:00
/**
* rpc_getport_external - obtain the port for a given RPC service on a given host
* @ 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
*
* This one is called from outside the RPC client in a synchronous task context .
*/
int rpc_getport_external ( struct sockaddr_in * sin , __u32 prog , __u32 vers , int prot )
2005-04-16 15:20:36 -07:00
{
2006-08-22 20:06:15 -04:00
struct portmap_args map = {
2005-04-16 15:20:36 -07:00
. pm_prog = prog ,
. pm_vers = vers ,
. pm_prot = prot ,
. pm_port = 0
} ;
2006-03-20 13:44:23 -05:00
struct rpc_message msg = {
. rpc_proc = & pmap_procedures [ PMAP_GETPORT ] ,
. rpc_argp = & map ,
. rpc_resp = & map . pm_port ,
} ;
2005-04-16 15:20:36 -07:00
struct rpc_clnt * pmap_clnt ;
char hostname [ 32 ] ;
int status ;
2006-08-22 20:06:16 -04:00
dprintk ( " RPC: rpc_getport_external(%u.%u.%u.%u, %u, %u, %d) \n " ,
2005-04-16 15:20:36 -07:00
NIPQUAD ( sin - > sin_addr . s_addr ) , prog , vers , prot ) ;
sprintf ( hostname , " %u.%u.%u.%u " , NIPQUAD ( sin - > sin_addr . s_addr ) ) ;
2005-09-22 21:24:59 -04:00
pmap_clnt = pmap_create ( hostname , sin , prot , 0 ) ;
2005-04-16 15:20:36 -07:00
if ( IS_ERR ( pmap_clnt ) )
return PTR_ERR ( pmap_clnt ) ;
/* Setup the call info struct */
2006-03-20 13:44:23 -05:00
status = rpc_call_sync ( pmap_clnt , & msg , 0 ) ;
2005-04-16 15:20:36 -07:00
if ( status > = 0 ) {
if ( map . pm_port ! = 0 )
return map . pm_port ;
status = - EACCES ;
}
return status ;
}
# endif
2006-08-22 20:06:16 -04:00
/*
* Portmapper child task invokes this callback via tk_exit .
*/
static void pmap_getport_done ( struct rpc_task * child , void * data )
2005-04-16 15:20:36 -07:00
{
2006-08-22 20:06:15 -04:00
struct portmap_args * map = data ;
2006-09-03 00:51:55 -04:00
struct rpc_xprt * xprt = map - > pm_xprt ;
2006-08-22 20:06:15 -04:00
int status = child - > tk_status ;
2006-01-03 09:55:51 +01:00
2006-08-22 20:06:15 -04:00
if ( status < 0 ) {
/* Portmapper not available */
2006-08-22 20:06:15 -04:00
xprt - > ops - > set_port ( xprt , 0 ) ;
2006-08-22 20:06:15 -04:00
} else if ( map - > pm_port = = 0 ) {
/* Requested RPC service wasn't registered */
2006-08-22 20:06:15 -04:00
xprt - > ops - > set_port ( xprt , 0 ) ;
2006-09-03 00:51:55 -04:00
status = - EACCES ;
2005-04-16 15:20:36 -07:00
} else {
2006-08-22 20:06:15 -04:00
/* Succeeded */
xprt - > ops - > set_port ( xprt , map - > pm_port ) ;
2006-08-22 20:06:15 -04:00
xprt_set_bound ( xprt ) ;
2006-09-03 00:51:55 -04:00
status = 0 ;
2005-04-16 15:20:36 -07:00
}
2006-08-22 20:06:15 -04:00
dprintk ( " RPC: %4d pmap_getport_done(status %d, port %u) \n " ,
2006-09-03 00:51:55 -04:00
child - > tk_pid , status , map - > pm_port ) ;
2006-08-22 20:06:15 -04:00
2006-09-03 00:51:55 -04:00
pmap_wake_portmap_waiters ( xprt , status ) ;
xprt_put ( xprt ) ;
2005-04-16 15:20:36 -07:00
}
2006-08-22 20:06:16 -04:00
/**
* rpc_register - set or unset a port registration with the local portmapper
* @ prog : RPC program number to bind
* @ vers : RPC version number to bind
* @ prot : transport protocol to use to make this request
* @ port : port value to register
* @ okay : result code
*
2005-04-16 15:20:36 -07:00
* port = = 0 means unregister , port ! = 0 means register .
*/
2006-08-22 20:06:16 -04:00
int rpc_register ( u32 prog , u32 vers , int prot , unsigned short port , int * okay )
2005-04-16 15:20:36 -07:00
{
2006-03-20 13:44:23 -05:00
struct sockaddr_in sin = {
. sin_family = AF_INET ,
. sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ,
} ;
2006-08-22 20:06:15 -04:00
struct portmap_args map = {
2006-03-20 13:44:23 -05:00
. pm_prog = prog ,
. pm_vers = vers ,
. pm_prot = prot ,
. pm_port = port ,
} ;
struct rpc_message msg = {
. rpc_proc = & pmap_procedures [ port ? PMAP_SET : PMAP_UNSET ] ,
. rpc_argp = & map ,
. rpc_resp = okay ,
} ;
2005-04-16 15:20:36 -07:00
struct rpc_clnt * pmap_clnt ;
int error = 0 ;
2006-08-22 20:06:16 -04:00
dprintk ( " RPC: registering (%u, %u, %d, %u) with portmapper. \n " ,
2005-04-16 15:20:36 -07:00
prog , vers , prot , port ) ;
2005-09-22 21:24:59 -04:00
pmap_clnt = pmap_create ( " localhost " , & sin , IPPROTO_UDP , 1 ) ;
2005-04-16 15:20:36 -07:00
if ( IS_ERR ( pmap_clnt ) ) {
error = PTR_ERR ( pmap_clnt ) ;
dprintk ( " RPC: couldn't create pmap client. Error = %d \n " , error ) ;
return error ;
}
2006-03-20 13:44:23 -05:00
error = rpc_call_sync ( pmap_clnt , & msg , 0 ) ;
2005-04-16 15:20:36 -07:00
if ( error < 0 ) {
printk ( KERN_WARNING
" RPC: failed to contact portmap (errno %d). \n " ,
error ) ;
}
dprintk ( " RPC: registration status %d/%d \n " , error , * okay ) ;
/* Client deleted automatically because cl_oneshot == 1 */
return error ;
}
2006-08-22 20:06:16 -04:00
static struct rpc_clnt * pmap_create ( char * hostname , struct sockaddr_in * srvaddr , int proto , int privileged )
2005-04-16 15:20:36 -07:00
{
2006-08-22 20:06:21 -04:00
struct rpc_create_args args = {
. protocol = proto ,
. address = ( struct sockaddr * ) srvaddr ,
. addrsize = sizeof ( * srvaddr ) ,
. servername = hostname ,
. program = & pmap_program ,
. version = RPC_PMAP_VERSION ,
. authflavor = RPC_AUTH_UNIX ,
. flags = ( RPC_CLNT_CREATE_ONESHOT |
RPC_CLNT_CREATE_NOPING ) ,
} ;
srvaddr - > sin_port = htons ( RPC_PMAP_PORT ) ;
2005-09-22 21:24:59 -04:00
if ( ! privileged )
2006-08-22 20:06:21 -04:00
args . flags | = RPC_CLNT_CREATE_NONPRIVPORT ;
return rpc_create ( & args ) ;
2005-04-16 15:20:36 -07:00
}
/*
* XDR encode / decode functions for PMAP
*/
2006-09-26 22:29:38 -07:00
static int xdr_encode_mapping ( struct rpc_rqst * req , __be32 * p , struct portmap_args * map )
2005-04-16 15:20:36 -07:00
{
2006-08-22 20:06:16 -04:00
dprintk ( " RPC: xdr_encode_mapping(%u, %u, %u, %u) \n " ,
2005-04-16 15:20:36 -07:00
map - > pm_prog , map - > pm_vers , map - > pm_prot , map - > pm_port ) ;
* p + + = htonl ( map - > pm_prog ) ;
* p + + = htonl ( map - > pm_vers ) ;
* p + + = htonl ( map - > pm_prot ) ;
* p + + = htonl ( map - > pm_port ) ;
req - > rq_slen = xdr_adjust_iovec ( req - > rq_svec , p ) ;
return 0 ;
}
2006-09-26 22:29:38 -07:00
static int xdr_decode_port ( struct rpc_rqst * req , __be32 * p , unsigned short * portp )
2005-04-16 15:20:36 -07:00
{
* portp = ( unsigned short ) ntohl ( * p + + ) ;
return 0 ;
}
2006-09-26 22:29:38 -07:00
static int xdr_decode_bool ( struct rpc_rqst * req , __be32 * p , unsigned int * boolp )
2005-04-16 15:20:36 -07:00
{
* boolp = ( unsigned int ) ntohl ( * p + + ) ;
return 0 ;
}
static struct rpc_procinfo pmap_procedures [ ] = {
[ PMAP_SET ] = {
. p_proc = PMAP_SET ,
. p_encode = ( kxdrproc_t ) xdr_encode_mapping ,
. p_decode = ( kxdrproc_t ) xdr_decode_bool ,
. p_bufsiz = 4 ,
. p_count = 1 ,
2006-03-20 13:44:22 -05:00
. p_statidx = PMAP_SET ,
. p_name = " SET " ,
2005-04-16 15:20:36 -07:00
} ,
[ PMAP_UNSET ] = {
. p_proc = PMAP_UNSET ,
. p_encode = ( kxdrproc_t ) xdr_encode_mapping ,
. p_decode = ( kxdrproc_t ) xdr_decode_bool ,
. p_bufsiz = 4 ,
. p_count = 1 ,
2006-03-20 13:44:22 -05:00
. p_statidx = PMAP_UNSET ,
. p_name = " UNSET " ,
2005-04-16 15:20:36 -07:00
} ,
[ PMAP_GETPORT ] = {
. p_proc = PMAP_GETPORT ,
. p_encode = ( kxdrproc_t ) xdr_encode_mapping ,
. p_decode = ( kxdrproc_t ) xdr_decode_port ,
. p_bufsiz = 4 ,
. p_count = 1 ,
2006-03-20 13:44:22 -05:00
. p_statidx = PMAP_GETPORT ,
. p_name = " GETPORT " ,
2005-04-16 15:20:36 -07:00
} ,
} ;
static struct rpc_version pmap_version2 = {
. number = 2 ,
. nrprocs = 4 ,
. procs = pmap_procedures
} ;
static struct rpc_version * pmap_version [ ] = {
NULL ,
NULL ,
& pmap_version2
} ;
static struct rpc_stat pmap_stats ;
static struct rpc_program pmap_program = {
. name = " portmap " ,
. number = RPC_PMAP_PROGRAM ,
. nrvers = ARRAY_SIZE ( pmap_version ) ,
. version = pmap_version ,
. stats = & pmap_stats ,
} ;