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) { /* * Response comes from some other * destination: * ignore it since it's not related to the * request we just sent out. */ (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( /* LINTED pointer alignment */ *(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; /* now read up to 4 bytes from the TIME server */ 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; /* * The outer loop iterates until we reach the * end of the mblk chain. */ while (mp2 != NULL) { /* * The inner loop iterates until * we've gotten 4 bytes or until * the mblk is exhausted. */ while (i < sizeof (dummy) && mp2->b_rptr < mp2->b_wptr) { i++; /* * We avoid big-endian/little-endian * issues by serializing the result * one byte at a time. */ 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: /* * We talk to rpcbind. */ 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); }
/* * Send rpc reply. * Serialize the reply packet into the output buffer then * call t_ksndudata to send it. */ static bool_t svc_clts_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg) { /* LINTED pointer alignment */ struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf; XDR *xdrs = &clone_xprt->xp_xdrout; int stat = FALSE; mblk_t *mp; int msgsz; struct T_unitdata_req *udreq; xdrproc_t xdr_results; caddr_t xdr_location; bool_t has_args; TRACE_0(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_START, "svc_clts_ksend_start:"); ASSERT(ud->ud_resp != NULL); /* * If there is a result procedure specified in the reply message, * it will be processed in the xdr_replymsg and SVCAUTH_WRAP. * We need to make sure it won't be processed twice, so we null * it for xdr_replymsg here. */ has_args = FALSE; if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { if ((xdr_results = msg->acpted_rply.ar_results.proc) != NULL) { has_args = TRUE; xdr_location = msg->acpted_rply.ar_results.where; msg->acpted_rply.ar_results.proc = xdr_void; msg->acpted_rply.ar_results.where = NULL; } } if (ud->ud_resp->b_cont == NULL) { /* * Allocate an initial mblk for the response data. */ while ((mp = allocb(UD_INITSIZE, BPRI_LO)) == NULL) { if (strwaitbuf(UD_INITSIZE, BPRI_LO)) { TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_END, "svc_clts_ksend_end:(%S)", "strwaitbuf"); return (FALSE); } } /* * Initialize the XDR decode stream. Additional mblks * will be allocated if necessary. They will be UD_MAXSIZE * sized. */ xdrmblk_init(xdrs, mp, XDR_ENCODE, UD_MAXSIZE); /* * Leave some space for protocol headers. */ (void) XDR_SETPOS(xdrs, 512); mp->b_rptr += 512; msg->rm_xid = clone_xprt->xp_xid; ud->ud_resp->b_cont = mp; TRACE_0(TR_FAC_KRPC, TR_XDR_REPLYMSG_START, "xdr_replymsg_start:"); if (!(xdr_replymsg(xdrs, msg) && (!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs, xdr_results, xdr_location)))) { TRACE_1(TR_FAC_KRPC, TR_XDR_REPLYMSG_END, "xdr_replymsg_end:(%S)", "bad"); RPCLOG0(1, "xdr_replymsg/SVCAUTH_WRAP failed\n"); goto out; } TRACE_1(TR_FAC_KRPC, TR_XDR_REPLYMSG_END, "xdr_replymsg_end:(%S)", "good"); } else if (!(xdr_replymsg_body(xdrs, msg) && (!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs, xdr_results, xdr_location)))) { RPCLOG0(1, "xdr_replymsg_body/SVCAUTH_WRAP failed\n"); goto out; } msgsz = (int)xmsgsize(ud->ud_resp->b_cont); if (msgsz <= 0 || (clone_xprt->xp_msg_size != -1 && msgsz > clone_xprt->xp_msg_size)) { #ifdef DEBUG cmn_err(CE_NOTE, "KRPC: server response message of %d bytes; transport limits are [0, %d]", msgsz, clone_xprt->xp_msg_size); #endif goto out; } /* * Construct the T_unitdata_req. We take advantage * of the fact that T_unitdata_ind looks just like * T_unitdata_req, except for the primitive type. */ udreq = (struct T_unitdata_req *)ud->ud_resp->b_rptr; udreq->PRIM_type = T_UNITDATA_REQ; put(clone_xprt->xp_wq, ud->ud_resp); stat = TRUE; ud->ud_resp = NULL; out: if (stat == FALSE) { freemsg(ud->ud_resp); ud->ud_resp = NULL; } /* * This is completely disgusting. If public is set it is * a pointer to a structure whose first field is the address * of the function to free that structure and any related * stuff. (see rrokfree in nfs_xdr.c). */ if (xdrs->x_public) { /* LINTED pointer alignment */ (**((int (**)())xdrs->x_public))(xdrs->x_public); } TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_END, "svc_clts_ksend_end:(%S)", "done"); return (stat); }