/* * Given the information in the callback info struct, create a client * handle that can be used by the server for its callback path. */ static CLIENT * rfs4_cbch_init(rfs4_cbinfo_t *cbp) { struct knetconfig knc; vnode_t *vp; struct sockaddr_in addr4; struct sockaddr_in6 addr6; void *addr, *taddr; in_port_t *pp; int af; char *devnam; struct netbuf nb; int size; CLIENT *ch = NULL; int useresvport = 0; mutex_enter(cbp->cb_lock); if (cbp->cb_callback.cb_location.r_netid == NULL || cbp->cb_callback.cb_location.r_addr == NULL) { goto cb_init_out; } if (strcmp(cbp->cb_callback.cb_location.r_netid, "tcp") == 0) { knc.knc_semantics = NC_TPI_COTS; knc.knc_protofmly = "inet"; knc.knc_proto = "tcp"; devnam = "/dev/tcp"; af = AF_INET; } else if (strcmp(cbp->cb_callback.cb_location.r_netid, "udp") == 0) { knc.knc_semantics = NC_TPI_CLTS; knc.knc_protofmly = "inet"; knc.knc_proto = "udp"; devnam = "/dev/udp"; af = AF_INET; } else if (strcmp(cbp->cb_callback.cb_location.r_netid, "tcp6") == 0) { knc.knc_semantics = NC_TPI_COTS; knc.knc_protofmly = "inet6"; knc.knc_proto = "tcp"; devnam = "/dev/tcp6"; af = AF_INET6; } else if (strcmp(cbp->cb_callback.cb_location.r_netid, "udp6") == 0) { knc.knc_semantics = NC_TPI_CLTS; knc.knc_protofmly = "inet6"; knc.knc_proto = "udp"; devnam = "/dev/udp6"; af = AF_INET6; } else { goto cb_init_out; } if (lookupname(devnam, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp) != 0) { goto cb_init_out; } if (vp->v_type != VCHR) { VN_RELE(vp); goto cb_init_out; } knc.knc_rdev = vp->v_rdev; VN_RELE(vp); if (af == AF_INET) { size = sizeof (addr4); bzero(&addr4, size); addr4.sin_family = (sa_family_t)af; addr = &addr4.sin_addr; pp = &addr4.sin_port; taddr = &addr4; } else /* AF_INET6 */ { size = sizeof (addr6); bzero(&addr6, size); addr6.sin6_family = (sa_family_t)af; addr = &addr6.sin6_addr; pp = &addr6.sin6_port; taddr = &addr6; } if (uaddr2sockaddr(af, cbp->cb_callback.cb_location.r_addr, addr, pp)) { goto cb_init_out; } nb.maxlen = nb.len = size; nb.buf = (char *)taddr; if (clnt_tli_kcreate(&knc, &nb, cbp->cb_callback.cb_program, NFS_CB, 0, 0, curthread->t_cred, &ch)) { ch = NULL; } /* turn off reserved port usage */ (void) CLNT_CONTROL(ch, CLSET_BINDRESVPORT, (char *)&useresvport); cb_init_out: mutex_exit(cbp->cb_lock); return (ch); }
enum clnt_stat rpcbind_getaddr(struct knetconfig *config, rpcprog_t prog, rpcvers_t vers, struct netbuf *addr) { char *ua = NULL; enum clnt_stat status; RPCB parms; struct timeval tmo; CLIENT *client = NULL; k_sigset_t oldmask; k_sigset_t newmask; ushort_t port; int iptype; /* * Call rpcbind (local or remote) to get an address we can use * in an RPC client handle. */ tmo.tv_sec = RPC_PMAP_TIMEOUT; tmo.tv_usec = 0; parms.r_prog = prog; parms.r_vers = vers; parms.r_addr = parms.r_owner = ""; if (strcmp(config->knc_protofmly, NC_INET) == 0) { if (strcmp(config->knc_proto, NC_TCP) == 0) parms.r_netid = "tcp"; else parms.r_netid = "udp"; put_inet_port(addr, htons(PMAPPORT)); } else if (strcmp(config->knc_protofmly, NC_INET6) == 0) { if (strcmp(config->knc_proto, NC_TCP) == 0) parms.r_netid = "tcp6"; else parms.r_netid = "udp6"; put_inet6_port(addr, htons(PMAPPORT)); } else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) { ASSERT(strnrchr(addr->buf, '.', addr->len) != NULL); if (config->knc_semantics == NC_TPI_COTS_ORD) parms.r_netid = "ticotsord"; else if (config->knc_semantics == NC_TPI_COTS) parms.r_netid = "ticots"; else parms.r_netid = "ticlts"; put_loopback_port(addr, "rpc"); } else { status = RPC_UNKNOWNPROTO; goto out; } /* * Mask signals for the duration of the handle creation and * RPC calls. This allows relatively normal operation with a * signal already posted to our thread (e.g., when we are * sending an NLM_CANCEL in response to catching a signal). * * Any further exit paths from this routine must restore * the original signal mask. */ sigfillset(&newmask); sigreplace(&newmask, &oldmask); if (clnt_tli_kcreate(config, addr, RPCBPROG, RPCBVERS, 0, 0, CRED(), &client)) { status = RPC_TLIERROR; sigreplace(&oldmask, (k_sigset_t *)NULL); goto out; } client->cl_nosignal = 1; if ((status = CLNT_CALL(client, RPCBPROC_GETADDR, xdr_rpcb, (char *)&parms, xdr_wrapstring, (char *)&ua, tmo)) != RPC_SUCCESS) { sigreplace(&oldmask, (k_sigset_t *)NULL); goto out; } sigreplace(&oldmask, (k_sigset_t *)NULL); if (ua == NULL || *ua == NULL) { status = RPC_PROGNOTREGISTERED; goto out; } /* * Convert the universal address to the transport address. * Theoretically, we should call the local rpcbind to translate * from the universal address to the transport address, but it gets * complicated (e.g., there's no direct way to tell rpcbind that we * want an IP address instead of a loopback address). Note that * the transport address is potentially host-specific, so we can't * just ask the remote rpcbind, because it might give us the wrong * answer. */ if (strcmp(config->knc_protofmly, NC_INET) == 0) { /* make sure that the ip address is the correct type */ if (rpc_iptype(ua, &iptype) != 0) { status = RPC_UNKNOWNADDR; goto out; } port = rpc_uaddr2port(iptype, ua); put_inet_port(addr, ntohs(port)); } else if (strcmp(config->knc_protofmly, NC_INET6) == 0) { /* make sure that the ip address is the correct type */ if (rpc_iptype(ua, &iptype) != 0) { status = RPC_UNKNOWNADDR; goto out; } port = rpc_uaddr2port(iptype, ua); put_inet6_port(addr, ntohs(port)); } else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) { loopb_u2t(ua, addr); } else { /* "can't happen" - should have been checked for above */ cmn_err(CE_PANIC, "rpcbind_getaddr: bad protocol family"); } out: if (client != NULL) { auth_destroy(client->cl_auth); clnt_destroy(client); } if (ua != NULL) xdr_free(xdr_wrapstring, (char *)&ua); return (status); }
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); }