700 lines
16 KiB
C
700 lines
16 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
sh_irp.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This source file contains the functions that convert between NT IRPs
|
|||
|
and STREAMS messages.
|
|||
|
|
|||
|
Most functions in this module are based on identically named routines
|
|||
|
in the SpiderStreams emulator source, stremul/msgrtns.c.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Eric Chin (ericc) August 16, 1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
#include "sh_inc.h"
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Local (Private) Functions
|
|||
|
*/
|
|||
|
STATIC void
|
|||
|
mp_buf_free(
|
|||
|
IN char *p
|
|||
|
);
|
|||
|
|
|||
|
STATIC int
|
|||
|
mptoirp(
|
|||
|
IN mblk_t *mp,
|
|||
|
IN PIRP irp
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SHpGenReply(
|
|||
|
IN PIRP irp,
|
|||
|
IN int retval,
|
|||
|
IN int MyErrno
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called to complete IRPs that convey generic STREAMS
|
|||
|
API's: ioctl(I_FDINSERT), ioctl(I_STR), putmsg(), ....
|
|||
|
|
|||
|
By generic, we mean it returns a return value and possible an errno.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
irp - irp to complete
|
|||
|
retval - return value of the ioctl(,I_FDINSERT,) or putmsg()
|
|||
|
errno - POSIX error value, if any
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PSTRM_ARGS_OUT outptr;
|
|||
|
PIO_STACK_LOCATION pIrpSp;
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: SHpGenReply(irp = %lx, %lx, %lx) entered\n",
|
|||
|
irp, retval, MyErrno));
|
|||
|
}
|
|||
|
|
|||
|
pIrpSp = IoGetCurrentIrpStackLocation(irp);
|
|||
|
|
|||
|
// Check size of output buffer.
|
|||
|
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STRM_ARGS_OUT))
|
|||
|
{
|
|||
|
shortreply(irp, STATUS_BUFFER_TOO_SMALL, 0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// have IopCompleteRequest() copy the following back to the user's
|
|||
|
// output buffer, laid out as:
|
|||
|
//
|
|||
|
// typedef struct _STRM_ARGS_OUT_ { // generic return parameters
|
|||
|
// int a_retval; // return value
|
|||
|
// int a_errno; // errno if retval == -1
|
|||
|
//
|
|||
|
// } STRM_ARGS_OUT, *PSTRM_ARGS_OUT;
|
|||
|
//
|
|||
|
outptr = (PSTRM_ARGS_OUT) irp->AssociatedIrp.SystemBuffer;
|
|||
|
outptr->a_retval = retval;
|
|||
|
outptr->a_errno = MyErrno;
|
|||
|
|
|||
|
shortreply(irp, STATUS_SUCCESS, sizeof(STRM_ARGS_OUT));
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: SHpGenReply(irp = %lx) done\n", irp));
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
} // SHpGenReply
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
iocreply(
|
|||
|
IN mblk_t *mp,
|
|||
|
IN PIRP irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function sends the reply to an M_IOCTL message back to the user,
|
|||
|
reverting a STREAMS message into an NT irp. It is loosely based on the
|
|||
|
SpiderStreams functions, iocreply() and mptomsg(), in stremul/msgrtns.c.
|
|||
|
|
|||
|
It should be called after the appropriate routine has taken the message
|
|||
|
off the queue. If it fails to send a message, it returns a negative
|
|||
|
value.
|
|||
|
|
|||
|
Acquire the lock of ms->e_strm before calling, and release it afterwards !!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
mp - pointer to the message to reply to
|
|||
|
irp - pointer to the IRP
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
-1 - no message is ready to be sent to the user
|
|||
|
-2 - failed to send a message to the user
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
mblk_t *tmp;
|
|||
|
int length;
|
|||
|
char *outbuf;
|
|||
|
int *pretval;
|
|||
|
int nbytes = 0;
|
|||
|
struct iocblk *iocp;
|
|||
|
struct strioctl *striop;
|
|||
|
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: iocreply(mp = %lx, irp = %lx) entered\n", mp, irp));
|
|||
|
}
|
|||
|
|
|||
|
if (!mp) {
|
|||
|
return(-1);
|
|||
|
}
|
|||
|
outbuf = irp->AssociatedIrp.SystemBuffer;
|
|||
|
pretval = (int *) outbuf;
|
|||
|
*pretval = 0;
|
|||
|
|
|||
|
switch (mp->b_datap->db_type) {
|
|||
|
|
|||
|
/*
|
|||
|
* for ioctl(I_STR), arrange the return parameters contiguously in outbuf
|
|||
|
* in the format:
|
|||
|
*
|
|||
|
* int return value (required)
|
|||
|
* union {
|
|||
|
* int errno; (required)
|
|||
|
* struct strioctl; (ic_cmd is not valid !!)
|
|||
|
* }
|
|||
|
* int (required)
|
|||
|
* int (required)
|
|||
|
* ic_dp buffer (optional)
|
|||
|
*/
|
|||
|
case M_IOCACK:
|
|||
|
iocp = (struct iocblk *) mp->b_rptr;
|
|||
|
*pretval = iocp->ioc_rval;
|
|||
|
striop = (struct strioctl *) ((int *) outbuf + 1);
|
|||
|
striop->ic_len = 0;
|
|||
|
outbuf = (char *) (striop + 1) + 2 * sizeof(int);
|
|||
|
|
|||
|
for (tmp = mp->b_cont; tmp; tmp = tmp->b_cont) {
|
|||
|
ASSERT(tmp->b_datap->db_type == M_DATA);
|
|||
|
length = (int)(tmp->b_wptr - tmp->b_rptr);
|
|||
|
|
|||
|
ASSERT(length >= 0);
|
|||
|
striop->ic_len += length;
|
|||
|
|
|||
|
RtlCopyMemory(outbuf, tmp->b_rptr, length);
|
|||
|
outbuf += length;
|
|||
|
}
|
|||
|
nbytes = (int) ( outbuf - (char *) irp->AssociatedIrp.SystemBuffer );
|
|||
|
break;
|
|||
|
|
|||
|
case M_IOCNAK:
|
|||
|
iocp = (struct iocblk *) mp->b_rptr;
|
|||
|
*pretval = -1;
|
|||
|
*(pretval + 1) = iocp->ioc_error;
|
|||
|
nbytes = 2 * sizeof(int);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
ASSERT(0); /* shouldn't come here */
|
|||
|
}
|
|||
|
shortreply(irp, STATUS_SUCCESS, nbytes);
|
|||
|
freemsg(mp);
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: iocreply(irp = %lx) nbytes = %lx, completed ok\n",
|
|||
|
irp, nbytes));
|
|||
|
}
|
|||
|
return(0);
|
|||
|
|
|||
|
} // iocreply
|
|||
|
|
|||
|
|
|||
|
|
|||
|
mblk_t *
|
|||
|
irptomp(
|
|||
|
IN PIRP irp,
|
|||
|
IN int pri,
|
|||
|
IN int ctlsize,
|
|||
|
IN int datasize,
|
|||
|
IN char *mbuf
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function converts the buffers associated with an NT irp into a
|
|||
|
STREAMS message. It is based on the SpiderSTREAMS routine, msgtomp().
|
|||
|
|
|||
|
The first block of the message created is either an M_PROTO or M_DATA
|
|||
|
block. To make it M_PCPROTO, M_IOCTL, ..., set it yourself after
|
|||
|
this function returns !!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
irp - pointer to the IRP.
|
|||
|
pri - buffer allocation priority. BPRI_LO, BPRI_MED or BPRI_HI.
|
|||
|
ctlsize - length of control part message
|
|||
|
datasize - length of data part of message
|
|||
|
mbuf - pointer to a contiguous chunk containing first the control
|
|||
|
part of the message, if any, and then the data part.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
pointer to the resulting STREAMS message, or NULL if unsuccessful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
unsigned char *extra;
|
|||
|
mblk_t *mp = (mblk_t *) NULL;
|
|||
|
mblk_t *cmp = (mblk_t *) NULL;
|
|||
|
frtn_t fr_rtn;
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: irptomp(clen, dlen, mbuf = %lx, %lx, %lx) entered\n",
|
|||
|
ctlsize, datasize, mbuf));
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* special case for constructing a zero length message.
|
|||
|
*/
|
|||
|
if ((max(ctlsize, 0) + max(datasize, 0)) == 0) {
|
|||
|
|
|||
|
mp = allocb(0, pri);
|
|||
|
|
|||
|
if (!mp) {
|
|||
|
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: irptomp(), allocb of 0 failed\n"));
|
|||
|
}
|
|||
|
|
|||
|
return((mblk_t *) NULL);
|
|||
|
}
|
|||
|
ASSERT(mp->b_datap->db_type == M_DATA);
|
|||
|
|
|||
|
if (ctlsize != -1) {
|
|||
|
mp->b_datap->db_type = M_PROTO;
|
|||
|
}
|
|||
|
ASSERT(mp->b_wptr == mp->b_rptr);
|
|||
|
return(mp);
|
|||
|
}
|
|||
|
fr_rtn.free_func = mp_buf_free;
|
|||
|
|
|||
|
if (ctlsize >= 0) {
|
|||
|
|
|||
|
if (ctlsize) {
|
|||
|
|
|||
|
extra = ExAllocatePool(NonPagedPool, ctlsize);
|
|||
|
|
|||
|
if (!extra) {
|
|||
|
return((mblk_t *) NULL);
|
|||
|
}
|
|||
|
RtlCopyMemory(extra, mbuf, ctlsize);
|
|||
|
|
|||
|
fr_rtn.free_arg = (char *) extra;
|
|||
|
cmp = esballoc(extra, ctlsize, pri, &fr_rtn);
|
|||
|
}
|
|||
|
else {
|
|||
|
cmp = allocb(0, pri);
|
|||
|
}
|
|||
|
if (!cmp) {
|
|||
|
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: irptomp(), esballoc %x failed\n", ctlsize));
|
|||
|
}
|
|||
|
|
|||
|
return((mblk_t *) NULL);
|
|||
|
}
|
|||
|
ASSERT(cmp->b_datap->db_type == M_DATA);
|
|||
|
cmp->b_datap->db_type = M_PROTO;
|
|||
|
|
|||
|
ASSERT(cmp->b_wptr == cmp->b_rptr);
|
|||
|
cmp->b_wptr += ctlsize;
|
|||
|
}
|
|||
|
|
|||
|
if (datasize >= 0) {
|
|||
|
|
|||
|
if (datasize) {
|
|||
|
extra = ExAllocatePool(NonPagedPool, datasize);
|
|||
|
|
|||
|
if (!extra) {
|
|||
|
if (cmp) {
|
|||
|
freemsg(cmp);
|
|||
|
}
|
|||
|
return((mblk_t *) NULL);
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory(extra,
|
|||
|
(ctlsize <= 0) ? mbuf : mbuf + ctlsize, datasize);
|
|||
|
|
|||
|
fr_rtn.free_arg = (char *) extra;
|
|||
|
|
|||
|
mp = esballoc(extra, datasize, pri, &fr_rtn);
|
|||
|
}
|
|||
|
else {
|
|||
|
mp = allocb(0, pri);
|
|||
|
}
|
|||
|
if (!mp) {
|
|||
|
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: irptomp(), esballoc %x failed\n", ctlsize));
|
|||
|
}
|
|||
|
|
|||
|
if (cmp) {
|
|||
|
freemsg(cmp);
|
|||
|
}
|
|||
|
return((mblk_t *) NULL);
|
|||
|
}
|
|||
|
ASSERT(mp->b_datap->db_type == M_DATA);
|
|||
|
ASSERT(mp->b_wptr == mp->b_rptr);
|
|||
|
mp->b_wptr += datasize;
|
|||
|
}
|
|||
|
if (cmp) {
|
|||
|
cmp->b_cont = mp;
|
|||
|
mp = cmp;
|
|||
|
}
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: irptomp(mbuf = %lx) returns, mp = %lx\n", mbuf, mp));
|
|||
|
}
|
|||
|
return(mp);
|
|||
|
|
|||
|
} // irptomp
|
|||
|
|
|||
|
|
|||
|
|
|||
|
STATIC void
|
|||
|
mp_buf_free(
|
|||
|
IN char *p
|
|||
|
)
|
|||
|
{
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: mp_buf_free(%lx) entered\n", p));
|
|||
|
}
|
|||
|
if (p) {
|
|||
|
ExFreePool(p);
|
|||
|
}
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: mp_buf_free(%lx) completed\n", p));
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
} // mp_buf_free
|
|||
|
|
|||
|
|
|||
|
|
|||
|
STATIC int
|
|||
|
mptoirp(
|
|||
|
IN mblk_t *mp,
|
|||
|
IN PIRP irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function converts a STREAMS message into an NT irp. It is based
|
|||
|
on the SpiderStreams routine, mptomsg(), in stremul/msgrtns.c.
|
|||
|
|
|||
|
It should be called after the appropriate routine has taken the message
|
|||
|
off the queue. If it fails to send a message, it returns a negative
|
|||
|
value.
|
|||
|
|
|||
|
The caller must free the STREAMS message, mp. This function doesn't !!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
mp
|
|||
|
irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
number of bytes copied back to user space, or a negative value if
|
|||
|
unsuccessful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
char *outbuf;
|
|||
|
int *pretval;
|
|||
|
int length, nbytes;
|
|||
|
struct strbuf *strbufp;
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: mptoirp(mp = %lx, irp = %lx) entered\n", mp, irp));
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* for getmsg(), arrange the return parameters contiguously in outbuf
|
|||
|
* in the format:
|
|||
|
*
|
|||
|
* int return value (required)
|
|||
|
* flags / errno (required)
|
|||
|
* struct strbuf ctrlbuf (required)
|
|||
|
* struct strbuf databuf (required)
|
|||
|
* ctrl buffer (optional)
|
|||
|
* data buffer (optional)
|
|||
|
*/
|
|||
|
outbuf = irp->AssociatedIrp.SystemBuffer;
|
|||
|
pretval = (int *) outbuf;
|
|||
|
strbufp = (struct strbuf *) (pretval + 2); /* struct strbuf ctrlbuf */
|
|||
|
outbuf = (char *) (strbufp + 2); /* ctrl buffer */
|
|||
|
|
|||
|
/*
|
|||
|
* ensure that the return value is copied back to the user-level runtime.
|
|||
|
* It was zeroed in ShDispGetmsg(), and the MORECTL, MOREDATA bits may
|
|||
|
* have set by st_getmsg().
|
|||
|
*/
|
|||
|
nbytes = 2 * sizeof(int);
|
|||
|
|
|||
|
switch (mp->b_datap->db_type) {
|
|||
|
|
|||
|
case M_PCPROTO:
|
|||
|
*(pretval + 1) = RS_HIPRI; /* flags */
|
|||
|
goto doproto;
|
|||
|
|
|||
|
case M_PROTO:
|
|||
|
*(pretval + 1) = 0; /* flags */
|
|||
|
|
|||
|
doproto:
|
|||
|
length = (int)(mp->b_wptr - mp->b_rptr);
|
|||
|
|
|||
|
if (strbufp->maxlen < length) {
|
|||
|
length = strbufp->maxlen;
|
|||
|
*pretval |= MORECTL;
|
|||
|
}
|
|||
|
strbufp->len = length;
|
|||
|
RtlCopyMemory(outbuf, mp->b_rptr, strbufp->len);
|
|||
|
|
|||
|
mp = mp->b_cont;
|
|||
|
goto dodata;
|
|||
|
|
|||
|
case M_DATA:
|
|||
|
*(pretval + 1) = 0; /* flags */
|
|||
|
strbufp->len = 0; /* ctrlbuf->len */
|
|||
|
|
|||
|
dodata:
|
|||
|
outbuf += strbufp->len;
|
|||
|
|
|||
|
(++strbufp)->len = 0;
|
|||
|
|
|||
|
for (; mp; mp = mp->b_cont) {
|
|||
|
ASSERT(mp->b_datap->db_type == M_DATA);
|
|||
|
length = (int)(mp->b_wptr - mp->b_rptr);
|
|||
|
|
|||
|
ASSERT(length >= 0);
|
|||
|
|
|||
|
if (strbufp->maxlen < length) {
|
|||
|
length = strbufp->maxlen;
|
|||
|
*pretval |= MOREDATA;
|
|||
|
}
|
|||
|
RtlCopyMemory(outbuf, mp->b_rptr, length);
|
|||
|
outbuf += length;
|
|||
|
strbufp->len += length;
|
|||
|
|
|||
|
if ((strbufp->maxlen -= length) == 0) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
nbytes = (int)( outbuf - (char *) irp->AssociatedIrp.SystemBuffer );
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: mptoirp(), unexpected db_type = %x\n",
|
|||
|
mp->b_datap->db_type));
|
|||
|
}
|
|||
|
ASSERT(0); /* shouldn't come here */
|
|||
|
KeBugCheck(STREAMS_INTERNAL_ERROR);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* no matter what, we always pass back the return value and the flags
|
|||
|
* to the user-level runtime.
|
|||
|
*/
|
|||
|
ASSERT(nbytes >= 2 * sizeof(int));
|
|||
|
shortreply(irp, STATUS_SUCCESS, nbytes);
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: mptoirp(irp = %lx), %lx, completed\n", irp, nbytes));
|
|||
|
}
|
|||
|
return(nbytes);
|
|||
|
|
|||
|
} // mptoirp
|
|||
|
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
msgreply(
|
|||
|
IN STREAM_ENDPOINT *ms,
|
|||
|
IN PIRP irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function gets a STREAMS message to complete an IRP representing
|
|||
|
a getmsg(). It is based on the SpiderStreams emulator function of the
|
|||
|
same name.
|
|||
|
|
|||
|
Lock the stream, ms->e_strm, before calling this function, and unlock
|
|||
|
it after this function returns !!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ms - stream endpoint from whose read queue to get the message from
|
|||
|
irp - IRP to complete
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
0 - successful completion
|
|||
|
-1 - no message is ready to be sent to the user
|
|||
|
-2 - failed to send a message to the user
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
int ret;
|
|||
|
mblk_t *mp;
|
|||
|
int more = 0;
|
|||
|
struct strbuf *strbufp;
|
|||
|
int ctlsize, datasize, flags, *pretval, remains;
|
|||
|
|
|||
|
/*
|
|||
|
* the arguments are marshalled in one contiguous chunk, laid out as:
|
|||
|
*
|
|||
|
* an unused int (required)
|
|||
|
* flags (required)
|
|||
|
* struct strbuf ctrlbuf (required)
|
|||
|
* struct strbuf databuf (required)
|
|||
|
*/
|
|||
|
pretval = (int *) irp->AssociatedIrp.SystemBuffer;
|
|||
|
flags = * (pretval + 1);
|
|||
|
strbufp = (struct strbuf *) (pretval + 2);
|
|||
|
ctlsize = strbufp->maxlen;
|
|||
|
datasize = (++strbufp)->maxlen;
|
|||
|
|
|||
|
/*
|
|||
|
* st_getmsg() may set MORECTL and/or MOREDATA in *pretval; we must
|
|||
|
* return it to the user-level runtime !!
|
|||
|
*/
|
|||
|
ret = st_getmsg(ms->e_strm, ctlsize, datasize, &flags, pretval,
|
|||
|
&mp, &remains);
|
|||
|
if (ret) {
|
|||
|
ASSERT(0);
|
|||
|
shortreply(irp, STATUS_SUCCESS, 0);
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
if (!mp) {
|
|||
|
return(-1);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Unlike SpiderSTREAMS, our mptoirp() function never fails !! Hence
|
|||
|
// the assertion.
|
|||
|
//
|
|||
|
if (mptoirp(mp, irp) < 0) {
|
|||
|
ASSERT(0);
|
|||
|
st_putback(ms->e_strm, mp, remains);
|
|||
|
return(-2);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Spider frees mp by chasing mp->b_next. Why ?
|
|||
|
*/
|
|||
|
ASSERT(!(mp->b_next));
|
|||
|
|
|||
|
freemsg(mp);
|
|||
|
return(0);
|
|||
|
|
|||
|
} // msgreply
|
|||
|
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
shortreply(
|
|||
|
IN PIRP irp,
|
|||
|
IN int status,
|
|||
|
IN int nbytes
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function completes an IRP, and arranges for return parameters,
|
|||
|
if any, to be copied.
|
|||
|
|
|||
|
Although somewhat a misnomer, this function is named after a similar
|
|||
|
function in the SpiderSTREAMS emulator.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
irp - pointer to the IRP to complete
|
|||
|
status - completion status of the IRP
|
|||
|
nbytes - number of bytes to return
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
number of bytes copied back to the user.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
CCHAR priboost;
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE((
|
|||
|
"SHEAD: shortreply(irp, status, nbytes = %lx, %lx, %lx) entered\n",
|
|||
|
irp, status, nbytes));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// set the irp's cancel routine to NULL, or the system may bugcheck
|
|||
|
// with the bugcode, CANCEL_STATE_IN_COMPLETED_IRP !!
|
|||
|
//
|
|||
|
// ref: IoCancelIrp(), ...\ntos\io\iosubs.c.
|
|||
|
//
|
|||
|
//
|
|||
|
IoAcquireCancelSpinLock(&irp->CancelIrql);
|
|||
|
IoSetCancelRoutine(irp, NULL);
|
|||
|
IoReleaseCancelSpinLock(irp->CancelIrql);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// irp->IoStatus.Information is meaningful only for STATUS_SUCCESS
|
|||
|
//
|
|||
|
ASSERT(!nbytes || (status == STATUS_SUCCESS));
|
|||
|
|
|||
|
irp->IoStatus.Information = nbytes;
|
|||
|
irp->IoStatus.Status = status;
|
|||
|
|
|||
|
priboost = (CCHAR) ((status == STATUS_SUCCESS) ?
|
|||
|
IO_NETWORK_INCREMENT : IO_NO_INCREMENT);
|
|||
|
|
|||
|
IoCompleteRequest(irp, priboost);
|
|||
|
|
|||
|
return(nbytes);
|
|||
|
|
|||
|
} // shortreply
|