/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* This file contains a simple implementation of RPC. Standard XDR is
* used.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <errno.h>
#include "socket_inet.h"
#include "ipv4.h"
#include <rpc/auth_sys.h>
#include <netdb.h>
#include "clnt.h"
#include "brpc.h"
#include "auth_inet.h"
#include "pmap.h"
#include "nfs_inet.h"
#include <rpcsvc/nfs_prot.h>
#include <rpc/auth_unix.h>
#include "mac.h"
#include <sys/bootdebug.h>
void
{
case RPC_CANTENCODEARGS:
printf("RPC: Can't encode arguments.\n");
break;
case RPC_CANTDECODERES:
printf("RPC: Can't decode result.\n");
break;
case RPC_CANTSEND:
printf("RPC: Unable to send (%s).\n",
break;
case RPC_CANTRECV:
printf("RPC: Unable to receive (%s).\n",
break;
case RPC_TIMEDOUT:
printf("RPC: Timed out.\n");
break;
case RPC_VERSMISMATCH:
printf("RPC: Incompatible versions of RPC.\n");
break;
case RPC_AUTHERROR:
printf("RPC: Authentication error:\n");
case AUTH_BADCRED:
printf("remote: bogus credentials "
"(seal broken).\n");
break;
case AUTH_REJECTEDCRED:
printf("remote: client should begin new "
"session.\n");
break;
case AUTH_BADVERF:
printf("remote: bogus verifier "
"(seal broken).\n");
break;
case AUTH_REJECTEDVERF:
printf("remote: verifier expired or was "
"replayed.\n");
break;
case AUTH_TOOWEAK:
printf("remote: rejected due to security "
"reasons.\n");
break;
case AUTH_INVALIDRESP:
printf("local: bogus response verifier.\n");
break;
case AUTH_FAILED:
/* FALLTHRU */
default:
printf("local: unknown error.\n");
break;
}
break;
case RPC_PROGUNAVAIL:
printf("RPC: Program unavailable.\n");
break;
case RPC_PROGVERSMISMATCH:
break;
case RPC_PROCUNAVAIL:
printf("RPC: Procedure unavailable.\n");
break;
case RPC_CANTDECODEARGS:
printf("RPC: Server can't decode arguments.\n");
break;
case RPC_SYSTEMERROR:
printf("RPC: Remote system error.\n");
break;
case RPC_UNKNOWNHOST:
printf("RPC: Unknown host.\n");
break;
case RPC_UNKNOWNPROTO:
printf("RPC: Unknown protocol.\n");
break;
case RPC_PMAPFAILURE:
printf("RPC: Port mapper failure.\n");
break;
case RPC_PROGNOTREGISTERED:
printf("RPC: Program not registered.\n");
break;
case RPC_FAILED:
printf("RPC: Failed (unspecified error).\n");
break;
default:
printf("RPC: (unknown error code).\n");
break;
}
}
}
/*
* rpc_hdr: sets the fields in the rpc msg header.
*
* Returns: TRUE on success, FALSE if failure.
*/
/*ARGSUSED*/
static bool_t
{
/* setup header */
/* xdr the header. */
return (FALSE);
else
return (TRUE);
}
/*
* our version of brpc_call(). We cache in portnumber in to->sin_port for
* your convenience. to and from addresses are taken and received in network
* order.
*/
enum clnt_stat
int rexmit, /* retransmission interval (secs) */
int wait_time, /* how long (secs) to wait (resp) */
{
int s;
trm_len = mac_get_mtu();
goto gt_error;
}
goto gt_error;
}
if (dontroute) {
}
&optlen);
} else {
}
/* Bind our endpoint. */
goto gt_error;
}
/* initialize reply's rpc_msg struct, so we can decode later. */
/* snag the udp port we need. */
goto gt_error;
}
/* generate xid - increment */
if (xid == 0)
else
xid++;
/* set up outgoing pkt as xdr modified. */
/* setup rpc header */
dprintf("brpc_call: cannot setup rpc header.\n");
goto gt_error;
}
/* setup authentication */
switch (auth) {
case AUTH_NONE:
xmit_auth = authnone_create();
break;
case AUTH_UNIX:
/*
* Assumes we've configured the stack and thus know our
* IP address/hostname, either by using DHCP or rarp/bootparams.
*/
break;
default:
dprintf("brpc_call: Unsupported authentication type: %d\n",
auth);
goto gt_error;
/*NOTREACHED*/
}
/*
* rpc_hdr puts everything in the xmit buffer for the header
* EXCEPT the proc. Put it, and our authentication info into
* it now, serializing as we go. We will be at the place where
* we left off.
*/
goto gt_error;
} else
/*
* Right now the outgoing packet should be all serialized and
* ready to go... Set up timers.
*/
sizeof (xdelay));
wait_time += prom_gettime();
/*
* send out the request. The first item in the receive buffer will
* be the xid. Check if it is correct.
*/
errors = 0;
do {
sizeof (struct sockaddr_in)) < 0) {
/*
* If errno is set to ETIMEDOUT, return
* with RPC status as RPC_TIMEDOUT. Calling
* funciton will take care of this error by
* retrying the RPC call.
*/
} else {
}
goto gt_error;
}
from_len = sizeof (struct sockaddr_in);
if (rcv_len < 0) {
if (errno == EWOULDBLOCK ||
break; /* timeout */
}
goto gt_error;
}
dprintf("brpc_call: xid: 0x%x != 0x%x\n",
continue;
}
/*
* Let's deserialize the data into our 'ret' buffer.
*/
goto gt_error;
}
case RPC_SUCCESS:
/*
* XXX - validate for unix and none
* always return true.
*/
if (AUTH_VALIDATE(xmit_auth,
errors++;
}
0) {
(void) xdr_opaque_auth(
}
break;
case RPC_AUTHERROR:
/*
* Let's see if our credentials need
* refreshing
*/
nrefreshes--;
}
errors++;
break;
case RPC_PROCUNAVAIL:
/*
* Might be a silly portmapper implementation
* erroneously responding to our rpc broadcast
* indirect portmapper call. For this
* particular case, we don't increment the
* error counter because we want to keep
* sifting for successful replies...
*/
errors++;
break;
case RPC_PROGVERSMISMATCH:
/*
* Successfully talked to server, but they
* don't speak our lingo.
*/
goto gt_error;
default:
/* Just keep trying till there's no data... */
errors++;
break;
}
dprintf("brpc_call: from: %s, error: ",
} else
break;
}
/*
* If we're having trouble reassembling datagrams, let the
* application know ASAP so that it can take the appropriate
* actions.
*/
prom_gettime() < wait_time);
/*
* socket calls reset errno. Since we want to hold onto the errno
* value if it is ETIMEDOUT to communicate to our caller that this
* RPC_TIMEDOUT situation is due to a stack problem (we're getting
* a reply, but the stack simply can't assemble it.), we need to
* preserve errno's value over the socket_close().
*/
(void) socket_close(s);
}