#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/socket.h>
#include <sys/sysmacros.h>
#include <netinet/in.h>
#include <rpc/rpc.h>
#include <sys/stream.h>
#include <sys/strsubr.h>
#include <sys/cred.h>
#include <sys/utsname.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/systeminfo.h>
#include <rpc/rpcb_prot.h>
#include <sys/cmn_err.h>
#define TOFFSET ((uint32_t)86400 * (365 * 70 + (70 / 4)))
#define WRITTEN ((uint32_t)86400 * (365 * 86 + (86 / 4)))
#define NC_INET "inet"
int
rtime(struct knetconfig *synconfig, struct netbuf *addrp, int calltype,
struct timeval *timep, struct timeval *wait)
{
int error;
int timo;
time_t thetime;
int32_t srvtime;
uint32_t dummy;
struct t_kunitdata *unitdata;
struct t_call *server;
TIUSER *tiptr;
int type;
int uderr;
int i;
int retries;
mblk_t *mp;
mblk_t *mp2;
retries = 5;
if (calltype == 0) {
again:
RPCLOG0(8, "rtime: using old method\n");
if ((error = t_kopen(NULL, synconfig->knc_rdev,
FREAD|FWRITE, &tiptr, CRED())) != 0) {
RPCLOG(1, "rtime: t_kopen %d\n", error);
return (-1);
}
if ((error = t_kbind(tiptr, NULL, NULL)) != 0) {
(void) t_kclose(tiptr, 1);
RPCLOG(1, "rtime: t_kbind %d\n", error);
return (-1);
}
if (synconfig->knc_semantics == NC_TPI_CLTS) {
if ((error = t_kalloc(tiptr, T_UNITDATA,
T_UDATA|T_ADDR, (char **)&unitdata)) != 0) {
RPCLOG(1, "rtime: t_kalloc %d\n", error);
(void) t_kclose(tiptr, 1);
return (-1);
}
unitdata->addr.len = addrp->len;
bcopy(addrp->buf, unitdata->addr.buf,
unitdata->addr.len);
dummy = 0;
unitdata->udata.buf = (caddr_t)&dummy;
unitdata->udata.len = sizeof (dummy);
if ((error = t_ksndudata(tiptr, unitdata, NULL)) !=
0) {
RPCLOG(1, "rtime: t_ksndudata %d\n", error);
(void) t_kfree(tiptr, (char *)unitdata,
T_UNITDATA);
(void) t_kclose(tiptr, 1);
return (-1);
}
timo = TIMEVAL_TO_TICK(wait);
RPCLOG(8, "rtime: timo %x\n", timo);
if ((error = t_kspoll(tiptr, timo, READWAIT,
&type)) != 0) {
RPCLOG(1, "rtime: t_kspoll %d\n", error);
(void) t_kfree(tiptr, (char *)unitdata,
T_UNITDATA);
(void) t_kclose(tiptr, 1);
return (-1);
}
if (type == 0) {
RPCLOG0(1, "rtime: t_kspoll timed out\n");
(void) t_kfree(tiptr, (char *)unitdata,
T_UNITDATA);
(void) t_kclose(tiptr, 1);
return (-1);
}
error = t_krcvudata(tiptr, unitdata, &type, &uderr);
if (error != 0) {
RPCLOG(1, "rtime: t_krcvudata %d\n", error);
(void) t_kfree(tiptr, (char *)unitdata,
T_UNITDATA);
(void) t_kclose(tiptr, 1);
if (error == EBADMSG && retries-- > 0)
goto again;
return (-1);
}
if (type == T_UDERR) {
if (bcmp(addrp->buf, unitdata->addr.buf,
unitdata->addr.len) != 0) {
(void) t_kfree(tiptr, (char *)unitdata,
T_UNITDATA);
(void) t_kclose(tiptr, 1);
goto again;
}
}
if (type != T_DATA) {
RPCLOG(1,
"rtime: t_krcvudata returned type %d\n",
type);
(void) t_kfree(tiptr, (char *)unitdata,
T_UNITDATA);
(void) t_kclose(tiptr, 1);
if (retries-- == 0)
return (-1);
goto again;
}
if (unitdata->udata.len < sizeof (uint32_t)) {
RPCLOG(1, "rtime: bad rcvd length %d\n",
unitdata->udata.len);
(void) t_kfree(tiptr, (char *)unitdata,
T_UNITDATA);
(void) t_kclose(tiptr, 1);
if (retries-- == 0)
return (-1);
goto again;
}
thetime = (time_t)ntohl(
*(uint32_t *)unitdata->udata.buf);
(void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
} else {
if ((error = t_kalloc(tiptr, T_CALL, T_ADDR,
(char **)&server)) != 0) {
RPCLOG(1, "rtime: t_kalloc %d\n", error);
(void) t_kclose(tiptr, 1);
return (-1);
}
server->addr.len = addrp->len;
bcopy(addrp->buf, server->addr.buf, server->addr.len);
if ((error = t_kconnect(tiptr, server, NULL)) != 0) {
RPCLOG(1, "rtime: t_kconnect %d\n", error);
(void) t_kfree(tiptr, (char *)server, T_CALL);
(void) t_kclose(tiptr, 1);
return (-1);
}
(void) t_kfree(tiptr, (char *)server, T_CALL);
timo = TIMEVAL_TO_TICK(wait);
RPCLOG(8, "rtime: timo %x\n", timo);
i = 0;
dummy = 0;
while (i < sizeof (dummy)) {
error = t_kspoll(tiptr, timo, READWAIT, &type);
if (error != 0) {
RPCLOG(1, "rtime: t_kspoll %d\n",
error);
(void) t_kclose(tiptr, 1);
return (-1);
}
if (type == 0) {
RPCLOG0(1,
"rtime: t_kspoll timed out\n");
(void) t_kclose(tiptr, 1);
return (-1);
}
error = tli_recv(tiptr, &mp,
tiptr->fp->f_flag);
if (error != 0) {
RPCLOG(1, "rtime: tli_recv %d\n",
error);
(void) t_kclose(tiptr, 1);
return (-1);
}
if (mp->b_datap->db_type != M_DATA) {
RPCLOG(1, "rtime: wrong msg type %d\n",
mp->b_datap->db_type);
RPCLOG(1,
"rtime: wrong msg type: read %d"
" bytes\n", i);
(void) t_kclose(tiptr, 1);
freemsg(mp);
return (-1);
}
mp2 = mp;
while (mp2 != NULL) {
while (i < sizeof (dummy) &&
mp2->b_rptr < mp2->b_wptr) {
i++;
dummy <<= 8;
dummy += ((*mp2->b_rptr) &
0xFF);
mp2->b_rptr++;
}
mp2 = mp2->b_cont;
}
freemsg(mp);
}
thetime = (time_t)dummy;
}
(void) t_kclose(tiptr, 1);
} else {
CLIENT *client;
struct timeval timout;
RPCLOG0(8, "rtime: using new method\n");
new_again:
error = clnt_tli_kcreate(synconfig, addrp, (rpcprog_t)RPCBPROG,
(rpcvers_t)RPCBVERS, 0, retries, CRED(), &client);
if (error != 0) {
RPCLOG(1,
"rtime: clnt_tli_kcreate returned %d\n", error);
return (-1);
}
timout.tv_sec = 60;
timout.tv_usec = 0;
error = clnt_call(client, RPCBPROC_GETTIME, (xdrproc_t)xdr_void,
NULL, (xdrproc_t)xdr_u_int,
(caddr_t)&srvtime, timout);
thetime = srvtime;
auth_destroy(client->cl_auth);
clnt_destroy(client);
if (error == RPC_UDERROR) {
if (retries-- > 0)
goto new_again;
}
if (error != RPC_SUCCESS) {
RPCLOG(1, "rtime: time sync clnt_call returned %d\n",
error);
error = EIO;
return (-1);
}
}
if (calltype != 0)
thetime += TOFFSET;
RPCLOG(8, "rtime: thetime = %lx\n", thetime);
if (thetime < WRITTEN) {
RPCLOG(1, "rtime: time returned is too far in past %lx",
thetime);
RPCLOG(1, "rtime: WRITTEN %x", WRITTEN);
return (-1);
}
thetime -= TOFFSET;
timep->tv_sec = thetime;
RPCLOG(8, "rtime: timep->tv_sec = %lx\n", timep->tv_sec);
RPCLOG(8, "rtime: machine time = %lx\n", gethrestime_sec());
timep->tv_usec = 0;
RPCLOG0(8, "rtime: returning success\n");
return (0);
}
enum clnt_stat
kgetnetname(char *netname)
{
return (key_getnetname(netname, CRED()));
}