190 lines
4.4 KiB
C
190 lines
4.4 KiB
C
|
/****************************************************************************
|
||
|
* (c) Copyright 1993 Micro Computer Systems, Inc. All rights reserved.
|
||
|
*****************************************************************************
|
||
|
*
|
||
|
* Title: IPX/SPX WinSock Helper DLL for Windows NT
|
||
|
*
|
||
|
* Module: ipx/sockhelp/wshutil.c
|
||
|
*
|
||
|
* Version: 1.00.00
|
||
|
*
|
||
|
* Date: 04-08-93
|
||
|
*
|
||
|
* Author: Brian Walker
|
||
|
*
|
||
|
*****************************************************************************
|
||
|
*
|
||
|
* Change Log:
|
||
|
*
|
||
|
* Date DevSFC Comment
|
||
|
* -------- ------ -------------------------------------------------------
|
||
|
*
|
||
|
*****************************************************************************
|
||
|
*
|
||
|
* Functional Description:
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
#include <nt.h>
|
||
|
#include <ntrtl.h>
|
||
|
#include <nturtl.h>
|
||
|
|
||
|
#include <windef.h>
|
||
|
#include <winbase.h>
|
||
|
#include <tdi.h>
|
||
|
|
||
|
#include <winsock.h>
|
||
|
#include <wsahelp.h>
|
||
|
|
||
|
#include <isnkrnl.h>
|
||
|
|
||
|
/*page*******************************************************
|
||
|
d o _ t d i _ a c t i o n
|
||
|
|
||
|
Generate a TDI_ACTION down to the streams
|
||
|
driver.
|
||
|
|
||
|
Arguments - fd = Handle to send on
|
||
|
cmd = Command to send down
|
||
|
optbuf = Ptr to options buffer
|
||
|
optlen = Ptr to options length
|
||
|
addrflag = TRUE = This is for DG/STREAM socket on addr handle
|
||
|
FALSE = This is for conn handle
|
||
|
|
||
|
Returns - A WinSock error code (NO_ERROR = OK)
|
||
|
************************************************************/
|
||
|
INT do_tdi_action(HANDLE fd, ULONG cmd, PUCHAR optbuf, INT optlen, BOOLEAN addrflag, PHANDLE eventhandle OPTIONAL)
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
PSTREAMS_TDI_ACTION tdibuf;
|
||
|
ULONG tdilen;
|
||
|
IO_STATUS_BLOCK iostat;
|
||
|
HANDLE event;
|
||
|
|
||
|
|
||
|
/** If the eventhandle is passed, it also means that the **/
|
||
|
/** NWLINK_ACTION header is pre-allocated in the buffer, **/
|
||
|
/** although we still have to fill the header in here. **/
|
||
|
|
||
|
if (eventhandle == NULL) {
|
||
|
|
||
|
/** Get the length of the buffer we need to allocate **/
|
||
|
|
||
|
tdilen = FIELD_OFFSET(STREAMS_TDI_ACTION,Buffer) + sizeof(ULONG) + optlen;
|
||
|
|
||
|
/** Allocate a buffer to use for the action **/
|
||
|
|
||
|
tdibuf = RtlAllocateHeap(RtlProcessHeap(), 0, tdilen);
|
||
|
if (tdibuf == NULL) {
|
||
|
return WSAENOBUFS;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
tdilen = optlen;
|
||
|
tdibuf = (PSTREAMS_TDI_ACTION)optbuf;
|
||
|
|
||
|
}
|
||
|
|
||
|
/** Set the datagram option **/
|
||
|
|
||
|
RtlMoveMemory(&tdibuf->Header.TransportId, "MISN", 4);
|
||
|
tdibuf->DatagramOption = addrflag;
|
||
|
|
||
|
/**
|
||
|
Fill out the buffer, the buffer looks like this:
|
||
|
|
||
|
ULONG cmd
|
||
|
data passed.
|
||
|
**/
|
||
|
|
||
|
memcpy(tdibuf->Buffer, &cmd, sizeof(ULONG));
|
||
|
|
||
|
if (eventhandle == NULL) {
|
||
|
|
||
|
tdibuf->BufferLength = sizeof(ULONG) + optlen;
|
||
|
|
||
|
RtlMoveMemory(tdibuf->Buffer + sizeof(ULONG), optbuf, optlen);
|
||
|
|
||
|
/** Create an event to wait on **/
|
||
|
|
||
|
status = NtCreateEvent(
|
||
|
&event,
|
||
|
EVENT_ALL_ACCESS,
|
||
|
NULL,
|
||
|
SynchronizationEvent,
|
||
|
FALSE);
|
||
|
|
||
|
/** If no event - then return error **/
|
||
|
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
RtlFreeHeap(RtlProcessHeap(), 0, tdibuf);
|
||
|
return WSAENOBUFS;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
tdibuf->BufferLength = sizeof(ULONG) + optlen - FIELD_OFFSET (NWLINK_ACTION, Data[0]);
|
||
|
|
||
|
/** Use the event handle passed in **/
|
||
|
|
||
|
event = *eventhandle;
|
||
|
|
||
|
}
|
||
|
|
||
|
/** **/
|
||
|
|
||
|
status = NtDeviceIoControlFile(
|
||
|
fd,
|
||
|
event,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&iostat,
|
||
|
IOCTL_TDI_ACTION,
|
||
|
NULL,
|
||
|
0,
|
||
|
tdibuf,
|
||
|
tdilen);
|
||
|
|
||
|
|
||
|
if (eventhandle == NULL) {
|
||
|
|
||
|
/** If pending - wait for it to finish **/
|
||
|
|
||
|
if (status == STATUS_PENDING) {
|
||
|
status = NtWaitForSingleObject(event, FALSE, NULL);
|
||
|
ASSERT(status == 0);
|
||
|
status = iostat.Status;
|
||
|
}
|
||
|
|
||
|
/** Close the event **/
|
||
|
|
||
|
NtClose(event);
|
||
|
|
||
|
}
|
||
|
|
||
|
/** If we get an error - return it **/
|
||
|
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
if (eventhandle == NULL) {
|
||
|
RtlFreeHeap(RtlProcessHeap(), 0, tdibuf);
|
||
|
}
|
||
|
return WSAEINVAL;
|
||
|
}
|
||
|
|
||
|
if (eventhandle == NULL) {
|
||
|
|
||
|
/** Copy the returned back to optbuf if needed */
|
||
|
|
||
|
if (optlen) {
|
||
|
RtlMoveMemory (optbuf, tdibuf->Buffer + sizeof(ULONG), optlen);
|
||
|
}
|
||
|
|
||
|
RtlFreeHeap(RtlProcessHeap(), 0, tdibuf);
|
||
|
|
||
|
}
|
||
|
|
||
|
/** Return OK **/
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|