static int32_t * svc_clts_kgetres(SVCXPRT *clone_xprt, int size) { /* LINTED pointer alignment */ struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf; XDR *xdrs = &clone_xprt->xp_xdrout; mblk_t *mp; int32_t *buf; struct rpc_msg rply; /* * Allocate an initial mblk for the response data. */ while ((mp = allocb(UD_INITSIZE, BPRI_LO)) == NULL) { if (strwaitbuf(UD_INITSIZE, BPRI_LO)) { return (FALSE); } } mp->b_cont = NULL; /* * 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; /* * Assume a successful RPC since most of them are. */ rply.rm_xid = clone_xprt->xp_xid; rply.rm_direction = REPLY; rply.rm_reply.rp_stat = MSG_ACCEPTED; rply.acpted_rply.ar_verf = clone_xprt->xp_verf; rply.acpted_rply.ar_stat = SUCCESS; if (!xdr_replymsg_hdr(xdrs, &rply)) { freeb(mp); return (NULL); } buf = XDR_INLINE(xdrs, size); if (buf == NULL) freeb(mp); else ud->ud_resp->b_cont = mp; return (buf); }
static int nd_get_reply(TIUSER *tiptr, XDR *xdrp, uint32_t call_xid, int *badmsg) { static struct rpc_msg reply_msg; static struct rpc_err rpc_err; static struct nfsattrstat na; static struct WRITE3res wres; static struct t_kunitdata rudata; int uderr; int type; int error; *badmsg = 0; rudata.addr.maxlen = 0; rudata.opt.maxlen = 0; rudata.udata.udata_mp = (mblk_t *)NULL; nd_log("nfs_dump: calling t_krcvudata\n"); if (error = t_krcvudata(tiptr, &rudata, &type, &uderr)) { if (error == EBADMSG) { cmn_err(CE_WARN, "\tnfs_dump: received EBADMSG"); *badmsg = 1; return (0); } nfs_perror(error, "\nnfs_dump: t_krcvudata failed: %m\n"); return (EIO); } if (type != T_DATA) { cmn_err(CE_WARN, "\tnfs_dump: received type %d", type); *badmsg = 1; return (0); } if (!rudata.udata.udata_mp) { cmn_err(CE_WARN, "\tnfs_dump: null receive"); *badmsg = 1; return (0); } /* * Decode results. */ xdrmblk_init(xdrp, rudata.udata.udata_mp, XDR_DECODE, 0); reply_msg.acpted_rply.ar_verf = _null_auth; switch (nfsdump_version) { case NFS_VERSION: reply_msg.acpted_rply.ar_results.where = (caddr_t)&na; reply_msg.acpted_rply.ar_results.proc = xdr_attrstat; break; case NFS_V3: reply_msg.acpted_rply.ar_results.where = (caddr_t)&wres; reply_msg.acpted_rply.ar_results.proc = xdr_WRITE3res; break; default: XDR_DESTROY(xdrp); return (EIO); } if (!xdr_replymsg(xdrp, &reply_msg)) { XDR_DESTROY(xdrp); cmn_err(CE_WARN, "\tnfs_dump: xdr_replymsg failed"); return (EIO); } if (reply_msg.rm_xid != call_xid) { XDR_DESTROY(xdrp); *badmsg = 1; return (0); } _seterr_reply(&reply_msg, &rpc_err); if (rpc_err.re_status != RPC_SUCCESS) { XDR_DESTROY(xdrp); cmn_err(CE_WARN, "\tnfs_dump: RPC error %d (%s)", rpc_err.re_status, clnt_sperrno(rpc_err.re_status)); return (EIO); } switch (nfsdump_version) { case NFS_VERSION: if (na.ns_status) { XDR_DESTROY(xdrp); cmn_err(CE_WARN, "\tnfs_dump: status %d", na.ns_status); return (EIO); } break; case NFS_V3: if (wres.status != NFS3_OK) { XDR_DESTROY(xdrp); cmn_err(CE_WARN, "\tnfs_dump: status %d", wres.status); return (EIO); } break; default: XDR_DESTROY(xdrp); return (EIO); } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { /* free auth handle */ xdrp->x_op = XDR_FREE; (void) xdr_opaque_auth(xdrp, &(reply_msg.acpted_rply.ar_verf)); } XDR_DESTROY(xdrp); freemsg(rudata.udata.udata_mp); 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); }
/* * Receive rpc requests. * Pulls a request in off the socket, checks if the packet is intact, * and deserializes the call packet. */ static bool_t svc_clts_krecv(SVCXPRT *clone_xprt, mblk_t *mp, struct rpc_msg *msg) { /* LINTED pointer alignment */ struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf; XDR *xdrs = &clone_xprt->xp_xdrin; struct rpc_clts_server *stats = CLONE2STATS(clone_xprt); union T_primitives *pptr; int hdrsz; TRACE_0(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_START, "svc_clts_krecv_start:"); RSSTAT_INCR(stats, rscalls); /* * The incoming request should start with an M_PROTO message. */ if (mp->b_datap->db_type != M_PROTO) { goto bad; } /* * The incoming request should be an T_UNITDTA_IND. There * might be other messages coming up the stream, but we can * ignore them. */ pptr = (union T_primitives *)mp->b_rptr; if (pptr->type != T_UNITDATA_IND) { goto bad; } /* * Do some checking to make sure that the header at least looks okay. */ hdrsz = (int)(mp->b_wptr - mp->b_rptr); if (hdrsz < TUNITDATAINDSZ || hdrsz < (pptr->unitdata_ind.OPT_offset + pptr->unitdata_ind.OPT_length) || hdrsz < (pptr->unitdata_ind.SRC_offset + pptr->unitdata_ind.SRC_length)) { goto bad; } /* * Make sure that the transport provided a usable address. */ if (pptr->unitdata_ind.SRC_length <= 0) { goto bad; } /* * Point the remote transport address in the service_transport * handle at the address in the request. */ clone_xprt->xp_rtaddr.buf = (char *)mp->b_rptr + pptr->unitdata_ind.SRC_offset; clone_xprt->xp_rtaddr.len = pptr->unitdata_ind.SRC_length; /* * Save the first mblk which contains the T_unidata_ind in * ud_resp. It will be used to generate the T_unitdata_req * during the reply. */ if (ud->ud_resp) { if (ud->ud_resp->b_cont != NULL) { cmn_err(CE_WARN, "svc_clts_krecv: ud_resp %p, " "b_cont %p", (void *)ud->ud_resp, (void *)ud->ud_resp->b_cont); } freeb(ud->ud_resp); } ud->ud_resp = mp; mp = mp->b_cont; ud->ud_resp->b_cont = NULL; xdrmblk_init(xdrs, mp, XDR_DECODE, 0); TRACE_0(TR_FAC_KRPC, TR_XDR_CALLMSG_START, "xdr_callmsg_start:"); if (! xdr_callmsg(xdrs, msg)) { TRACE_1(TR_FAC_KRPC, TR_XDR_CALLMSG_END, "xdr_callmsg_end:(%S)", "bad"); RSSTAT_INCR(stats, rsxdrcall); goto bad; } TRACE_1(TR_FAC_KRPC, TR_XDR_CALLMSG_END, "xdr_callmsg_end:(%S)", "good"); clone_xprt->xp_xid = msg->rm_xid; ud->ud_inmp = mp; TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_END, "svc_clts_krecv_end:(%S)", "good"); return (TRUE); bad: if (mp) freemsg(mp); if (ud->ud_resp) { /* * There should not be any left over results buffer. */ ASSERT(ud->ud_resp->b_cont == NULL); freeb(ud->ud_resp); ud->ud_resp = NULL; } RSSTAT_INCR(stats, rsbadcalls); TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_END, "svc_clts_krecv_end:(%S)", "bad"); return (FALSE); }