696 lines
22 KiB
C
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);
|
|
}
|
|
|