windows-nt/Source/XPSP1/NT/net/ndis/lib/ndisapi.c
2020-09-26 16:20:57 +08:00

696 lines
22 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
ndisapi.c
Abstract:
NDIS User-Mode apis to support PnP from the network UI
Author:
JameelH
Environment:
Kernel mode, FSD
Revision History:
Aug 1997 JameelH Initial version
--*/
#include <windows.h>
#include <wtypes.h>
#include <ntddndis.h>
#include <ndisprv.h>
#include <devioctl.h>
#ifndef UNICODE_STRING
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
#endif
#include <ndispnp.h>
#include <ndisprv.h>
#define MAC_ADDRESS_SIZE 6
#define VENDOR_ID_SIZE 3
extern
VOID
InitUnicodeString(
IN PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
);
extern
LONG
AppendUnicodeStringToString(
IN PUNICODE_STRING Destination,
IN PUNICODE_STRING Source
);
extern
HANDLE
OpenDevice(
IN PUNICODE_STRING DeviceName
);
//
// UNICODE_STRING_SIZE calculates the size of the buffer needed to
// store a given UNICODE_STRING including an appended null-terminator.
//
// ULONG
// UNICODE_STRING_SIZE(
// PUNICODE_STRING String
// );
//
#define UNICODE_STRING_SIZE(x) \
((((x) == NULL) ? 0 : (x)->Length) + sizeof(WCHAR))
VOID
NdispUnicodeStringToVar(
IN PVOID Base,
IN PUNICODE_STRING String,
IN OUT PNDIS_VAR_DATA_DESC NdisVar
)
/*++
Routine Description:
This function copies the contents of a UNICODE_STRING to an
NDIS_VAR_DATA structure. NdisVar->Offset is treated as an input parameter
and represents the offset into Base that the string characters should be
copied to.
Arguments:
Base - Specifies the base address of the IOCTL buffer.
String - Supplies a pointer to the UNICODE_STRING that should be copied.
NdisVar - Supplies a pointer to the target NDIS_VAR_DATA_DESC. Its Offset
field is taken as input, and its Length and MaximumLength fields
are treated as output.
Return Value:
None.
--*/
{
PWCHAR destination;
//
// NdisVar->Offset is assumed to be filled in and is treated
// as an input parameter.
//
destination = (PWCHAR)(((PCHAR)Base) + NdisVar->Offset);
//
// Copy over the UNICODE_STRING, if any, and set NdisVar->Length
//
if ((String != NULL) && (String->Length > 0)) {
NdisVar->Length = String->Length;
memcpy(destination, String->Buffer, NdisVar->Length );
} else {
NdisVar->Length = 0;
}
//
// Null-terminate, fill in MaxiumLength and we're done.
//
*(destination + NdisVar->Length / sizeof(WCHAR)) = L'\0';
NdisVar->MaximumLength = NdisVar->Length + sizeof(WCHAR);
}
UINT
NdisHandlePnPEvent(
IN UINT Layer,
IN UINT Operation,
IN PUNICODE_STRING LowerComponent OPTIONAL,
IN PUNICODE_STRING UpperComponent OPTIONAL,
IN PUNICODE_STRING BindList OPTIONAL,
IN PVOID ReConfigBuffer OPTIONAL,
IN UINT ReConfigBufferSize OPTIONAL
)
{
PNDIS_PNP_OPERATION Op;
NDIS_PNP_OPERATION tempOp;
HANDLE hDevice;
BOOL fResult = FALSE;
UINT cb, Size;
DWORD Error;
ULONG padding;
do
{
//
// Validate Layer & Operation
//
if (((Layer != NDIS) && (Layer != TDI)) ||
((Operation != BIND) && (Operation != UNBIND) && (Operation != RECONFIGURE) &&
(Operation != UNLOAD) && (Operation != REMOVE_DEVICE) &&
(Operation != ADD_IGNORE_BINDING) &&
(Operation != DEL_IGNORE_BINDING) &&
(Operation != BIND_LIST)))
{
Error = ERROR_INVALID_PARAMETER;
break;
}
//
// Allocate and initialize memory for the block to be passed down. The buffer
// will look like this:
//
//
// +=================================+
// | NDIS_PNP_OPERATION |
// | ReConfigBufferOff | ----+
// +--- | LowerComponent.Offset | |
// | | UpperComponent.Offset | --+ |
// +-|--- | BindList.Offset | | |
// | +--> +---------------------------------+ | |
// | | LowerComponentStringBuffer | | |
// | +---------------------------------+ <-+ |
// | | UpperComponentStringBuffer | |
// +----> +---------------------------------+ |
// | BindListStringBuffer | |
// +---------------------------------+ |
// | Padding to ensure ULONG_PTR | |
// | alignment of ReConfigBuffer | |
// +---------------------------------+ <---+
// | ReConfigBuffer |
// +=================================+
//
// tempOp is a temporary structure into which we will store offsets as
// they are calculated. This temporary structure will be moved to
// the head of the real buffer once its size is known and it is
// allocated.
//
Size = sizeof(NDIS_PNP_OPERATION);
tempOp.LowerComponent.Offset = Size;
Size += UNICODE_STRING_SIZE(LowerComponent);
tempOp.UpperComponent.Offset = Size;
Size += UNICODE_STRING_SIZE(UpperComponent);
tempOp.BindList.Offset = Size;
Size += UNICODE_STRING_SIZE(BindList);
padding = (sizeof(ULONG_PTR) - (Size & (sizeof(ULONG_PTR) - 1))) &
(sizeof(ULONG_PTR) - 1);
Size += padding;
tempOp.ReConfigBufferOff = Size;
Size += ReConfigBufferSize + 1;
Op = (PNDIS_PNP_OPERATION)LocalAlloc(LPTR, Size);
if (Op == NULL)
{
Error = ERROR_NOT_ENOUGH_MEMORY;
break;
}
//
// We have a buffer of the necessary size. Copy in the partially-
// filled in tempOp, then fill in the remaining fields and copy the
// data into the buffer.
//
*Op = tempOp;
Op->Layer = Layer;
Op->Operation = Operation;
//
// Copy over the three unicode strings
//
NdispUnicodeStringToVar( Op, LowerComponent, &Op->LowerComponent );
NdispUnicodeStringToVar( Op, UpperComponent, &Op->UpperComponent );
NdispUnicodeStringToVar( Op, BindList, &Op->BindList );
//
// Finally, copy over the ReConfigBuffer
//
Op->ReConfigBufferSize = ReConfigBufferSize;
if (ReConfigBufferSize > 0)
{
memcpy((PUCHAR)Op + Op->ReConfigBufferOff,
ReConfigBuffer,
ReConfigBufferSize);
}
*((PUCHAR)Op + Op->ReConfigBufferOff + ReConfigBufferSize) = 0;
hDevice = CreateFile(L"\\\\.\\NDIS",
GENERIC_READ | GENERIC_WRITE,
0, // sharing mode - not significant
NULL, // security attributes
OPEN_EXISTING,
0, // file attributes and flags
NULL); // handle to template file
if (hDevice != INVALID_HANDLE_VALUE)
{
fResult = DeviceIoControl(hDevice,
IOCTL_NDIS_DO_PNP_OPERATION,
Op, // input buffer
Size, // input buffer size
NULL, // output buffer
0, // output buffer size
&cb, // bytes returned
NULL); // OVERLAPPED structure
Error = GetLastError();
CloseHandle(hDevice);
}
else
{
Error = GetLastError();
}
LocalFree(Op);
} while (FALSE);
SetLastError(Error);
return(fResult);
}
NDIS_OID StatsOidList[] =
{
OID_GEN_LINK_SPEED,
OID_GEN_MEDIA_IN_USE | NDIS_OID_PRIVATE,
OID_GEN_MEDIA_CONNECT_STATUS | NDIS_OID_PRIVATE,
OID_GEN_XMIT_OK,
OID_GEN_RCV_OK,
OID_GEN_XMIT_ERROR,
OID_GEN_RCV_ERROR,
OID_GEN_DIRECTED_FRAMES_RCV | NDIS_OID_PRIVATE,
OID_GEN_DIRECTED_BYTES_XMIT | NDIS_OID_PRIVATE,
OID_GEN_DIRECTED_BYTES_RCV | NDIS_OID_PRIVATE,
OID_GEN_ELAPSED_TIME | NDIS_OID_PRIVATE,
OID_GEN_INIT_TIME_MS | NDIS_OID_PRIVATE,
OID_GEN_RESET_COUNTS | NDIS_OID_PRIVATE,
OID_GEN_MEDIA_SENSE_COUNTS | NDIS_OID_PRIVATE,
OID_GEN_PHYSICAL_MEDIUM | NDIS_OID_PRIVATE
};
UINT NumOidsInList = sizeof(StatsOidList)/sizeof(NDIS_OID);
UINT
NdisQueryStatistics(
IN PUNICODE_STRING Device,
OUT PNIC_STATISTICS Statistics
)
{
NDIS_STATISTICS_VALUE StatsBuf[4*sizeof(StatsOidList)/sizeof(NDIS_OID)];
PNDIS_STATISTICS_VALUE pStatsBuf;
HANDLE hDevice;
BOOL fResult = FALSE;
UINT cb, Size, Index;
DWORD Error;
if (Statistics->Size != sizeof(NIC_STATISTICS))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return(FALSE);
}
memset(Statistics, 0, sizeof(NIC_STATISTICS));
Statistics->DeviceState = DEVICE_STATE_DISCONNECTED;
Statistics->MediaState = MEDIA_STATE_UNKNOWN;
hDevice = OpenDevice(Device);
if (hDevice != NULL)
{
Statistics->MediaState = MEDIA_STATE_CONNECTED; // default, if the device does not support
Statistics->DeviceState = DEVICE_STATE_CONNECTED;
fResult = DeviceIoControl(hDevice,
IOCTL_NDIS_QUERY_SELECTED_STATS,
StatsOidList, // input buffer
sizeof(StatsOidList), // input buffer size
StatsBuf, // output buffer
sizeof(StatsBuf), // output buffer size
&cb, // bytes returned
NULL); // OVERLAPPED structure
Error = GetLastError();
CloseHandle(hDevice);
if (fResult)
{
Error = NO_ERROR;
for (Index = Size = 0, pStatsBuf = StatsBuf; Size < cb; Index++)
{
LARGE_INTEGER Value;
NDIS_OID Oid;
Value.QuadPart = 0;
if (pStatsBuf->DataLength == sizeof(LARGE_INTEGER))
{
// Use memcpy rather than assignment to avoid unalignment
// faults on ia64.
//
memcpy(&Value.QuadPart, &pStatsBuf->Data[0], pStatsBuf->DataLength);
}
else
{
Value.LowPart = *(PULONG)(&pStatsBuf->Data[0]);
}
Size += (pStatsBuf->DataLength + FIELD_OFFSET(NDIS_STATISTICS_VALUE, Data));
Oid = pStatsBuf->Oid;
pStatsBuf = (PNDIS_STATISTICS_VALUE)((PUCHAR)pStatsBuf +
FIELD_OFFSET(NDIS_STATISTICS_VALUE, Data) +
pStatsBuf->DataLength);
switch (Oid & ~NDIS_OID_PRIVATE)
{
case OID_GEN_LINK_SPEED:
Statistics->LinkSpeed = Value.LowPart;
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
Statistics->MediaState = (Value.LowPart == NdisMediaStateConnected) ?
MEDIA_STATE_CONNECTED : MEDIA_STATE_DISCONNECTED;
break;
case OID_GEN_MEDIA_IN_USE:
Statistics->MediaType = Value.LowPart;
break;
case OID_GEN_XMIT_OK:
Statistics->PacketsSent = Value.QuadPart;
break;
case OID_GEN_RCV_OK:
Statistics->PacketsReceived = Value.QuadPart;
break;
case OID_GEN_XMIT_ERROR:
Statistics->PacketsSendErrors = Value.LowPart;
break;
case OID_GEN_RCV_ERROR:
Statistics->PacketsReceiveErrors = Value.LowPart;
break;
case OID_GEN_DIRECTED_BYTES_XMIT:
Statistics->BytesSent += Value.QuadPart;
break;
case OID_GEN_MULTICAST_BYTES_XMIT:
Statistics->BytesSent += Value.QuadPart;
break;
case OID_GEN_BROADCAST_BYTES_XMIT:
Statistics->BytesSent += Value.QuadPart;
break;
case OID_GEN_DIRECTED_BYTES_RCV:
Statistics->BytesReceived += Value.QuadPart;
Statistics->DirectedBytesReceived = Value.QuadPart;
break;
case OID_GEN_DIRECTED_FRAMES_RCV:
Statistics->DirectedPacketsReceived = Value.QuadPart;
break;
case OID_GEN_MULTICAST_BYTES_RCV:
Statistics->BytesReceived += Value.QuadPart;
break;
case OID_GEN_BROADCAST_BYTES_RCV:
Statistics->BytesReceived += Value.QuadPart;
break;
case OID_GEN_ELAPSED_TIME:
Statistics->ConnectTime = Value.LowPart;
break;
case OID_GEN_INIT_TIME_MS:
Statistics->InitTime = Value.LowPart;
break;
case OID_GEN_RESET_COUNTS:
Statistics->ResetCount = Value.LowPart;
break;
case OID_GEN_MEDIA_SENSE_COUNTS:
Statistics->MediaSenseConnectCount = Value.LowPart >> 16;
Statistics->MediaSenseDisconnectCount = Value.LowPart & 0xFFFF;
break;
case OID_GEN_PHYSICAL_MEDIUM:
Statistics->PhysicalMediaType = Value.LowPart;
break;
default:
// ASSERT(0);
break;
}
}
}
else
{
Error = GetLastError();
}
}
else
{
Error = GetLastError();
}
SetLastError(Error);
return(fResult);
}
UINT
NdisEnumerateInterfaces(
IN PNDIS_ENUM_INTF Interfaces,
IN UINT Size
)
{
HANDLE hDevice;
BOOL fResult = FALSE;
UINT cb;
DWORD Error = NO_ERROR;
do
{
hDevice = CreateFile(L"\\\\.\\NDIS",
GENERIC_READ | GENERIC_WRITE,
0, // sharing mode - not significant
NULL, // security attributes
OPEN_EXISTING,
0, // file attributes and flags
NULL); // handle to template file
if (hDevice != INVALID_HANDLE_VALUE)
{
fResult = DeviceIoControl(hDevice,
IOCTL_NDIS_ENUMERATE_INTERFACES,
NULL, // input buffer
0, // input buffer size
Interfaces, // output buffer
Size, // output buffer size
&cb, // bytes returned
NULL); // OVERLAPPED structure
Error = GetLastError();
CloseHandle(hDevice);
if (Error == NO_ERROR)
{
UINT i;
//
// Fix-up pointers
//
for (i = 0; i < Interfaces->TotalInterfaces; i++)
{
OFFSET_TO_POINTER(Interfaces->Interface[i].DeviceName.Buffer, Interfaces);
OFFSET_TO_POINTER(Interfaces->Interface[i].DeviceDescription.Buffer, Interfaces);
}
}
}
else
{
Error = GetLastError();
}
} while (FALSE);
SetLastError(Error);
return(fResult);
}
#if 0
UINT
NdisQueryDeviceBundle(
IN PUNICODE_STRING Device,
OUT PDEVICE_BUNDLE BundleBuffer,
IN UINT BufferSize
)
{
HANDLE hDevice;
BOOL fResult = FALSE;
UINT cb;
DWORD Error = NO_ERROR;
do
{
if (BufferSize < (sizeof(DEVICE_BUNDLE) + Device->MaximumLength))
{
Error = ERROR_INSUFFICIENT_BUFFER;
break;
}
hDevice = OpenDevice(Device);
if (hDevice != NULL)
{
fResult = DeviceIoControl(hDevice,
IOCTL_NDIS_GET_DEVICE_BUNDLE,
NULL, // input buffer
0, // input buffer size
BundleBuffer, // output buffer
BufferSize, // output buffer size
&cb, // bytes returned
NULL); // OVERLAPPED structure
Error = GetLastError();
CloseHandle(hDevice);
if (Error == NO_ERROR)
{
UINT i;
//
// Fix-up pointers
//
for (i = 0; i < BundleBuffer->TotalEntries; i++)
{
OFFSET_TO_POINTER(BundleBuffer->Entries[i].Name.Buffer, BundleBuffer);
}
}
}
else
{
Error = ERROR_FILE_NOT_FOUND;
}
} while (FALSE);
SetLastError(Error);
return(fResult);
}
#endif
UINT
NdisQueryHwAddress(
IN PUNICODE_STRING Device,
OUT PUCHAR CurrentAddress,
OUT PUCHAR PermanentAddress,
OUT PUCHAR VendorId
)
{
UCHAR Buf[3*sizeof(NDIS_STATISTICS_VALUE) + 48];
PNDIS_STATISTICS_VALUE pBuf;
NDIS_OID Oids[] = { OID_802_3_CURRENT_ADDRESS, OID_802_3_PERMANENT_ADDRESS, OID_GEN_VENDOR_ID };
HANDLE hDevice;
BOOL fResult = FALSE;
UINT cb;
DWORD Error;
memset(CurrentAddress, 0, MAC_ADDRESS_SIZE);
memset(PermanentAddress, 0, MAC_ADDRESS_SIZE);
memset(VendorId, 0, VENDOR_ID_SIZE);
hDevice = OpenDevice(Device);
if (hDevice != NULL)
{
fResult = DeviceIoControl(hDevice,
IOCTL_NDIS_QUERY_SELECTED_STATS,
&Oids, // input buffer
sizeof(Oids), // input buffer size
Buf, // output buffer
sizeof(Buf), // output buffer size
&cb, // bytes returned
NULL); // OVERLAPPED structure
Error = GetLastError();
CloseHandle(hDevice);
if (fResult)
{
UINT Size, tmp;
Error = NO_ERROR;
pBuf = (PNDIS_STATISTICS_VALUE)Buf;
for (Size = 0; Size < cb; )
{
tmp = (pBuf->DataLength + FIELD_OFFSET(NDIS_STATISTICS_VALUE, Data));
Size += tmp;
switch (pBuf->Oid)
{
case OID_802_3_CURRENT_ADDRESS:
memcpy(CurrentAddress, pBuf->Data, MAC_ADDRESS_SIZE);
break;
case OID_802_3_PERMANENT_ADDRESS:
memcpy(PermanentAddress, pBuf->Data, MAC_ADDRESS_SIZE);
break;
case OID_GEN_VENDOR_ID:
memcpy(VendorId, pBuf->Data, VENDOR_ID_SIZE);
}
pBuf = (PNDIS_STATISTICS_VALUE)((PUCHAR)pBuf + tmp);
}
}
else
{
Error = GetLastError();
}
}
else
{
Error = ERROR_FILE_NOT_FOUND;
}
SetLastError(Error);
return(fResult);
}
VOID
XSetLastError(
IN ULONG Error
)
{
SetLastError(Error);
}