Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1090 lines
26 KiB

#include <ndis.h>
#include <e100_equ.h>
#include <e100_557.h>
#include <e100_def.h>
#include <mp_def.h>
#include <mp_cmn.h>
#include <mp.h>
#include <mp_nic.h>
#include <mp_dbg.h>
#include <e100_sup.h>
// Things to note:
// PME_ena bit should be active before the 82558 is set into low power mode
// Default for WOL should generate wake up event after a HW Reset
// Fixed Packet Filtering
// Need to verify that the micro code is loaded and Micro Machine is active
// Clock signal is active on PCI clock
// Address Matching
// Need to enable IAMatch_Wake_En bit and the MCMatch_Wake_En bit is set
// ARP Wakeup
// Need to set BRCST DISABL bet to 0 (broadcast enable)
// To handle VLAN set the VLAN_ARP bit
// IP address needs to be configured with 16 least significant bits
// Set the IP Address in the IP_Address configuration word.
// Fixed WakeUp Filters:
// There are 3ight different fixed WakeUp Filters
// ( Unicast, Multicast, Arp. etc).
// Link Status Event
// Set Link_Status_Wakeup Enable bit.
// Flexible filtering:
// Supports: ARP packets, Directed, Magic Packet and Link Event
// Flexible Filtering Overview:
// driver should program micro-code before setting card into low power
// Incoming packets are compared against the loadable microcode. If PME is
// is enabled then, the system is woken up.
// Segments are defined in book - but not implemented here.
// WakeUp Packet -that causes the machine to wake up will be stored
// in the Micro Machine temporary storage area so that the driver can read it.
// Software Work:
// Power Down:
// OS requests the driver to go to a low power state
// Software Pends request
// SW sets CU and RU to idle by issuing a Selective Reset to the device
// 3rd portion .- Wake Up Segments defintion
// The above three segments are loaded as on chain. The last CB must have
// its EL bit set.
// Device can now be powered down.
// Software driver completes OS request
// OS then physically switches the Device to low power state
//
// Power Up:
// OS powers up the Device
// OS tells the SW that it is now in D0
// driver should NOT initialize the Device. It should NOT issue a Self Test
// Driver Initiates a PORT DUMP command
// Device dumps its internal registers including the wakeup frame storage area
// SW reads the PME register
// SW reads the WakeUp Frame Data, analyzes it and acts accordingly
// SW restores its cvonfiguration and and resumes normal operation.
//
//
// Power Management definitions from the Intel Handbook
//
//
// Definitions from Table 4.2, Pg 4.9
// of the 10/100 Mbit Ethernet Family Software Technical
// Reference Manual
//
#define PMC_Offset 0xDE
#define E100_PMC_WAKE_FROM_D0 0x1
#define E100_PMC_WAKE_FROM_D1 0x2
#define E100_PMC_WAKE_FROM_D2 0x4
#define E100_PMC_WAKE_FROM_D3HOT 0x8
#define E100_PMC_WAKE_FROM_D3_AUX 0x10
//
// Load Programmable filter definintions.
// Taken from C-19 from the Software Reference Manual.
// It has examples too. The opcode used for load is 0x80000
//
#define BIT_15_13 0xA000
#define CB_LOAD_PROG_FILTER BIT_3
#define CU_LOAD_PROG_FILTER_EL BIT_7
#define CU_SUCCEED_LOAD_PROG_FILTER BIT_15_13
#define CB_FILTER_EL BIT_7
#define CB_FILTER_PREDEFINED_FIX BIT_6
#define CB_FILTER_ARP_WAKEUP BIT_3
#define CB_FILTER_IA_WAKEUP BIT_1
#define CU_SCB_NULL ((UINT)-1)
#pragma pack( push, enter_include1, 1 )
//
// Define the PM Capabilities register in the device
// portion of the PCI config space
//
typedef struct _MP_PM_CAP_REG {
USHORT UnInteresting:11;
USHORT PME_Support:5;
} MP_PM_CAP_REG;
//
// Define the PM Control/Status Register
//
typedef struct _MP_PMCSR {
USHORT PowerState:2; // Power State;
USHORT Res:2; // reserved
USHORT DynData:1; // Ignored
USHORT Res1:3; // Reserved
USHORT PME_En:1; // Enable device to set the PME Event;
USHORT DataSel:4; // Unused
USHORT DataScale:2; // Data Scale - Unused
USHORT PME_Status:1; // PME Status - Sticky bit;
} MP_PMCSR ;
typedef struct _MP_PM_PCI_SPACE {
UCHAR Stuff[PMC_Offset];
// PM capabilites
MP_PM_CAP_REG PMCaps;
// PM Control Status Register
MP_PMCSR PMCSR;
} MP_PM_PCI_SPACE , *PMP_PM_PCI_SPACE ;
//
// This is the Programmable Filter Command Structure
//
typedef struct _MP_PROG_FILTER_COMM_STRUCT
{
// CB Status Word
USHORT CBStatus;
// CB Command Word
USHORT CBCommand;
//Next CB PTR == ffff ffff
ULONG NextCBPTR;
//Programmable Filters
ULONG FilterData[16];
} MP_PROG_FILTER_COMM_STRUCT,*PMP_PROG_FILTER_COMM_STRUCT;
typedef struct _MP_PMDR
{
// Status of the PME bit
UCHAR PMEStatus:1;
// Is the TCO busy
UCHAR TCORequest:1;
// Force TCO indication
UCHAR TCOForce:1;
// Is the TCO Ready
UCHAR TCOReady:1;
// Reserved
UCHAR Reserved:1;
// Has an InterestingPacket been received
UCHAR InterestingPacket:1;
// Has a Magic Packet been received
UCHAR MagicPacket:1;
// Has the Link Status been changed
UCHAR LinkStatus:1;
} MP_PMDR , *PMP_PMDR;
//-------------------------------------------------------------------------
// Structure used to set up a programmable filter.
// This is overlayed over the Control/Status Register (CSR)
//-------------------------------------------------------------------------
typedef struct _CSR_FILTER_STRUC {
// Status- used to verify if the load prog filter command
// has been accepted .set to 0xa000
USHORT ScbStatus; // SCB Status register
// Set to an opcode of 0x8
//
UCHAR ScbCommandLow; // SCB Command register (low byte)
// 80. Low + High gives the required opcode 0x80080000
UCHAR ScbCommandHigh; // SCB Command register (high byte)
// Set to NULL ff ff ff ff
ULONG NextPointer; // SCB General pointer
// Set to a hardcoded filter, Arp + IA Match, + IP address
union
{
ULONG u32;
struct {
UCHAR IPAddress[2];
UCHAR Reserved;
UCHAR Set;
}PreDefined;
}Programmable; // Wake UP Filter union
} CSR_FILTER_STRUC, *PCSR_FILTER_STRUC;
#pragma pack( pop, enter_include1 )
#define MP_CLEAR_PMDR(pPMDR) (*pPMDR) = ((*pPMDR) | 0xe0); // clear the 3 uppermost bits in the PMDR
//-------------------------------------------------------------------------
// L O C A L P R O T O T Y P E S
//-------------------------------------------------------------------------
__inline
NDIS_STATUS
MPIssueScbPoMgmtCommand(
IN PMP_ADAPTER Adapter,
IN PCSR_FILTER_STRUC pFilter,
IN BOOLEAN WaitForScb
);
VOID
MPCreateProgrammableFilter (
IN PMP_WAKE_PATTERN pMpWakePattern ,
IN PUCHAR pFilter,
IN OUT PULONG pNext
);
//
// Macros used to walk a doubly linked list. Only macros that are not defined in ndis.h
// The List Next macro will work on Single and Doubly linked list as Flink is a common
// field name in both
//
/*
PLIST_ENTRY
ListNext (
IN PLIST_ENTRY
);
PSINGLE_LIST_ENTRY
ListNext (
IN PSINGLE_LIST_ENTRY
);
*/
#define ListNext(_pL) (_pL)->Flink
/*
PLIST_ENTRY
ListPrev (
IN LIST_ENTRY *
);
*/
#define ListPrev(_pL) (_pL)->Blink
//-------------------------------------------------------------------------
// P O W E R M G M T F U N C T I O N S
//-------------------------------------------------------------------------
PUCHAR
HwReadPowerPMDR(
IN PMP_ADAPTER Adapter
)
/*++
Routine Description:
This routine will Hardware's PM registers
Arguments:
Adapter Pointer to our adapter
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_HARD_ERRORS
--*/
{
UCHAR PMDR =0;
PUCHAR pPMDR = NULL;
#define CSR_SIZE sizeof (*Adapter->CSRAddress)
ASSERT (CSR_SIZE == 0x18);
pPMDR = 0x18 + (PUCHAR)Adapter->CSRAddress ;
PMDR = *pPMDR;
return pPMDR;
}
NDIS_STATUS
MPWritePciSlotInfo(
PMP_ADAPTER pAdapter,
ULONG Offset,
PVOID pValue,
ULONG SizeofValue
)
{
ULONG ulResult;
NDIS_STATUS Status;
ulResult = NdisWritePciSlotInformation(
pAdapter->AdapterHandle,
0,
Offset,
pValue,
SizeofValue);
ASSERT (ulResult == SizeofValue);
// What do we do in case of failure;
//
if (ulResult == SizeofValue)
{
Status = NDIS_STATUS_SUCCESS;
}
else
{
Status = NDIS_STATUS_FAILURE;
}
return Status;
}
NDIS_STATUS
MPReadPciSlotInfo(
PMP_ADAPTER pAdapter,
ULONG Offset,
PVOID pValue,
ULONG SizeofValue
)
{
ULONG ulResult;
NDIS_STATUS Status;
ulResult = NdisReadPciSlotInformation(
pAdapter->AdapterHandle,
0,
Offset,
pValue,
SizeofValue);
ASSERT (ulResult == SizeofValue);
// What do we do in case of failure;
//
if (ulResult == SizeofValue)
{
Status = NDIS_STATUS_SUCCESS;
}
else
{
Status = NDIS_STATUS_FAILURE;
}
return Status;
}
NDIS_STATUS
MpClearPME_En (
IN PMP_ADAPTER pAdapter,
IN MP_PMCSR PMCSR
)
{
NDIS_STATUS Status;
UINT ulResult;
PMCSR.PME_En = 0;
Status = MPWritePciSlotInfo( pAdapter,
FIELD_OFFSET(MP_PM_PCI_SPACE, PMCSR),
(PVOID)&PMCSR,
sizeof(PMCSR));
return Status;
}
VOID MpExtractPMInfoFromPciSpace(
PMP_ADAPTER pAdapter,
PUCHAR pPciConfig
)
/*++
Routine Description:
Looks at the PM information in the
device specific section of the PCI Config space.
Interprets the register values and stores it
in the adapter structure
Definitions from Table 4.2 & 4.3, Pg 4-9 & 4-10
of the 10/100 Mbit Ethernet Family Software Technical
Reference Manual
Arguments:
Adapter Pointer to our adapter
pPciConfig Pointer to Common Pci Space
Return Value:
--*/
{
PMP_PM_PCI_SPACE pPmPciConfig = (PMP_PM_PCI_SPACE )pPciConfig;
PMP_POWER_MGMT pPoMgmt = &pAdapter->PoMgmt;
MP_PMCSR PMCSR;
//
// First interpret the PM Capabities register
//
{
MP_PM_CAP_REG PmCaps;
PmCaps = pPmPciConfig->PMCaps;
if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D0)
{
pAdapter->PoMgmt.bWakeFromD0 = TRUE;
}
if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D1)
{
pAdapter->PoMgmt.bWakeFromD1 = TRUE;
}
if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D2)
{
pAdapter->PoMgmt.bWakeFromD2 = TRUE;
}
if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D3HOT)
{
pAdapter->PoMgmt.bWakeFromD3Hot = TRUE;
}
if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D3_AUX)
{
pAdapter->PoMgmt.bWakeFromD3Aux = TRUE;
}
}
//
// Interpret the PM Control/Status Register
//
{
PMCSR = pPmPciConfig->PMCSR;
if (PMCSR.PME_En == 1)
{
//
// PME is enabled. Clear the PME_En bit.
// So that it is not asserted
//
MpClearPME_En (pAdapter,PMCSR);
}
//pPoMgmt->PowerState = PMCSR.PowerState;
}
}
VOID
MPSetPowerLowPrivate(
PMP_ADAPTER pAdapter
)
/*++
Routine Description:
The section follows the steps mentioned in
Section C.2.6.2 of the Reference Manual.
Arguments:
Adapter Pointer to our adapter
Return Value:
--*/
{
CSR_FILTER_STRUC Filter;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
USHORT IntStatus;
MP_PMCSR PMCSR;
NdisZeroMemory (&Filter, sizeof (Filter));
do
{
//
// Before issue the command to low power state, we should disable the
// interrup and ack all the pending interrupts, then set the adapter's power to
// low state.
//
NICDisableInterrupt(pAdapter);
NIC_ACK_INTERRUPT(pAdapter, IntStatus);
pAdapter->CurrentPowerState = pAdapter->NextPowerState;
//
// If the driver should wake up the machine
//
if (pAdapter->WakeUpEnable != 0)
{
//
// Send the WakeUp Patter to the nic
MPIssueScbPoMgmtCommand(pAdapter, &Filter, TRUE);
//
// Section C.2.6.2 - The driver needs to wait for the CU to idle
// The above function already waits for the CU to idle
//
ASSERT ((pAdapter->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_IDLE);
}
else
{
MPReadPciSlotInfo(pAdapter,
FIELD_OFFSET(MP_PM_PCI_SPACE, PMCSR),
(PVOID)&PMCSR,
sizeof(PMCSR));
if (PMCSR.PME_En == 1)
{
//
// PME is enabled. Clear the PME_En bit.
// So that it is not asserted
//
MpClearPME_En (pAdapter,PMCSR);
}
//
// Set the driver to lower power state by OS
//
}
} while (FALSE);
}
NDIS_STATUS
MPSetPowerD0Private (
IN MP_ADAPTER* pAdapter
)
{
PUCHAR pPMDR;
NDIS_STATUS Status;
do
{
// Dump the packet if necessary
//Cause of Wake Up
pPMDR = HwReadPowerPMDR(pAdapter);
NICInitializeAdapter(pAdapter);
// Clear the PMDR
MP_CLEAR_PMDR(pPMDR);
NICIssueSelectiveReset(pAdapter);
} while (FALSE);
return NDIS_STATUS_SUCCESS;
}
VOID
MPSetPowerWorkItem(
IN PNDIS_WORK_ITEM pWorkItem,
IN PVOID pContext
)
{
//
// Call the appropriate function
//
//
// Complete the original request
//
}
VOID
HwSetWakeUpConfigure(
IN PMP_ADAPTER pAdapter,
PUCHAR pPoMgmtConfigType,
UINT WakeUpParameter
)
{
if (MPIsPoMgmtSupported( pAdapter) == TRUE)
{
(*pPoMgmtConfigType)= ((*pPoMgmtConfigType)| CB_WAKE_ON_LINK_BYTE9 |CB_WAKE_ON_ARP_PKT_BYTE9 );
}
}
NDIS_STATUS
MPSetUpFilterCB(
IN PMP_ADAPTER pAdapter
)
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PCB_HEADER_STRUC NonTxCmdBlockHdr = (PCB_HEADER_STRUC)pAdapter->NonTxCmdBlock;
PFILTER_CB_STRUC pFilterCb = (PFILTER_CB_STRUC)NonTxCmdBlockHdr;
ULONG Curr = 0;
ULONG Next = 0;
PLIST_ENTRY pPatternEntry = ListNext(&pAdapter->PoMgmt.PatternList) ;
DBGPRINT(MP_TRACE, ("--> HwSetupIAAddress\n"));
NdisZeroMemory (pFilterCb, sizeof(*pFilterCb));
// Individual Address Setup
NonTxCmdBlockHdr->CbStatus = 0;
NonTxCmdBlockHdr->CbCommand = CB_EL_BIT | CB_LOAD_PROG_FILTER;
NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL;
// go through each filter in the list.
while (pPatternEntry != (&pAdapter->PoMgmt.PatternList))
{
PMP_WAKE_PATTERN pWakeUpPattern = NULL;
PNDIS_PM_PACKET_PATTERN pCurrPattern = NULL;;
// initialize local variables
pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN, linkListEntry);
// increment the iterator
pPatternEntry = ListNext (pPatternEntry);
// Update the Curr Array Pointer
Curr = Next;
// Create the Programmable filter for this device.
MPCreateProgrammableFilter (pWakeUpPattern , (PUCHAR)&pFilterCb->Pattern[Curr], &Next);
if (Next >=16)
{
break;
}
}
{
// Set the EL bit on the last pattern
PUCHAR pLastPattern = (PUCHAR) &pFilterCb->Pattern[Curr];
// Get to bit 31
pLastPattern[3] |= CB_FILTER_EL ;
}
ASSERT(pAdapter->CSRAddress->ScbCommandLow == 0)
// Wait for the CU to Idle before giving it this command
if(!WaitScb(pAdapter))
{
Status = NDIS_STATUS_HARD_ERRORS;
}
return Status;
}
NDIS_STATUS
MPIssueScbPoMgmtCommand(
IN PMP_ADAPTER pAdapter,
IN PCSR_FILTER_STRUC pNewFilter,
IN BOOLEAN WaitForScb
)
{
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
do
{
// Set up SCB to issue this command
Status = MPSetUpFilterCB(pAdapter);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
// Submit the configure command to the chip, and wait for it to complete.
pAdapter->CSRAddress->ScbGeneralPointer = pAdapter->NonTxCmdBlockPhys;
Status = D100SubmitCommandBlockAndWait(pAdapter);
if(Status != NDIS_STATUS_SUCCESS)
{
Status = NDIS_STATUS_NOT_ACCEPTED;
break;
}
} while (FALSE);
return Status;
}
NDIS_STATUS
MPCalculateE100PatternForFilter (
IN PUCHAR pFrame,
IN ULONG FrameLength,
IN PUCHAR pMask,
IN ULONG MaskLength,
OUT PULONG pSignature
)
/*++
Routine Description:
This function outputs the E100 specific Pattern Signature
used to wake up the machine.
Section C.2.4 - CRC word calculation of a Flexible Filer
Arguments:
pFrame - Pattern Set by the protocols
FrameLength - Length of the Pattern
pMask - Mask set by the Protocols
MaskLength - Length of the Mask
pSignature - caller allocated return structure
Return Value:
Returns Success
Failure - if the Pattern is greater than 129 bytes
--*/
{
const ULONG Coefficients = 0x04c11db7;
ULONG Signature = 0;
ULONG n = 0;
ULONG i= 0;
PUCHAR pCurrentMaskByte = pMask - 1; // init to -1
ULONG MaskOffset = 0;
ULONG BitOffsetInMask = 0;
ULONG MaskBit = 0;
BOOLEAN fIgnoreCurrentByte = FALSE;
ULONG ShiftBy = 0;
UCHAR FrameByte = 0;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
*pSignature = 0;
do
{
if (FrameLength > 128)
{
Status = NDIS_STATUS_FAILURE;
break;
}
// The E100 driver can only accept 3 DWORDS of Mask in a single pattern
if (MaskLength > (3*sizeof(ULONG)))
{
Status = NDIS_STATUS_FAILURE;
break;
}
for (n=i=0;(n<128) && (n < FrameLength); ++n)
{
// The first half deals with the question -
// Is the nth Frame byte to be included in the Filter
//
BitOffsetInMask = (n % 8);
if (BitOffsetInMask == 0)
{
//
// We need to move to a new byte.
// [0] for 0th byte, [1] for 8th byte, [2] for 16th byte, etc.
//
MaskOffset = n/8; // This is the new byte we need to go
//
//
if (MaskOffset == MaskLength)
{
break;
}
pCurrentMaskByte ++;
ASSERT (*pCurrentMaskByte == pMask[n/8]);
}
// Now look at the actual bit in the mask
MaskBit = 1 << BitOffsetInMask ;
// If the current Mask Bit is set in the Mask then
// we need to use it in the CRC calculation, otherwise we ignore it
fIgnoreCurrentByte = ! (MaskBit & pCurrentMaskByte[0]);
if (fIgnoreCurrentByte)
{
continue;
}
// We are suppossed to take in the current byte as part of the CRC calculation
// Initialize the variables
FrameByte = pFrame[n];
ShiftBy = (i % 3 ) * 8;
ASSERT (ShiftBy!= 24); // Bit 24 is never used
if (Signature & 0x80000000)
{
Signature = ((Signature << 1) ^ ( FrameByte << ShiftBy) ^ Coefficients);
}
else
{
Signature = ((Signature << 1 ) ^ (FrameByte << ShiftBy));
}
++i;
}
// Clear bits 22-31
Signature &= 0x00ffffff;
// Update the result
*pSignature = Signature;
// We have succeeded
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
return Status;
}
VOID
MPCreateProgrammableFilter (
IN PMP_WAKE_PATTERN pMpWakePattern ,
IN PUCHAR pFilter,
IN OUT PULONG pNext
)
/*++
Routine Description:
This function outputs the E100 specific Pattern Signature
used to wake up the machine.
Section C.2.4 - Load Programmable Filter page C.20
Arguments:
pMpWakePattern - Filter will be created for this pattern,
pFilter - Filter will be stored here,
pNext - Used for validation . This Ulong will also be incremented by the size
of the filter (in ulongs)
Return Value:
--*/
{
PUCHAR pCurrentByte = pFilter;
ULONG NumBytesWritten = 0;
PULONG pCurrentUlong = (PULONG)pFilter;
PNDIS_PM_PACKET_PATTERN pNdisPattern = (PNDIS_PM_PACKET_PATTERN)(&pMpWakePattern->Pattern[0]);
ULONG LengthOfFilter = 0;
// Is there enough room for this pattern
//
{
// Length in DWORDS
LengthOfFilter = pNdisPattern->MaskSize /4;
if (pNdisPattern->MaskSize % 4 != 0)
{
LengthOfFilter++;
}
// Increment LengthOfFilter to account for the 1st DWORD
LengthOfFilter++;
// We are only allowed 16 DWORDS in a filter
if (*pNext + LengthOfFilter >= 16)
{
// Failure - early exit
return;
}
}
// Clear the Predefined bit; already cleared in the previous function.
// first , initialize -
*pCurrentUlong = 0;
// Mask Length goes into Bits 27-29 of the 1st DWORD. MaskSize is measured in DWORDs
{
ULONG dwMaskSize = pNdisPattern->MaskSize /4;
ULONG dwMLen = 0;
// If there is a remainder a remainder then increment
if (pNdisPattern->MaskSize % 4 != 0)
{
dwMaskSize++;
}
//
// If we fail this assertion, it means our
// MaskSize is greater than 16 bytes.
// This filter should have been failed upfront at the time of the request
//
ASSERT (0 < dwMaskSize <5);
//
// In the Spec, 0 - Single DWORD maske, 001 - 2 DWORD mask,
// 011 - 3 DWORD mask, 111 - 4 Dword Mask.
//
if (dwMaskSize == 1) dwMLen = 0;
if (dwMaskSize == 2) dwMLen = 1;
if (dwMaskSize == 3) dwMLen = 3;
if (dwMaskSize == 4) dwMLen = 7;
// Adjust the Mlen, so it is in the correct position
dwMLen = (dwMLen << 3);
if (dwMLen != 0)
{
ASSERT (dwMLen <= 0x38 && dwMLen >= 0x08);
}
// These go into bits 27,28,29 (bits 3,4 and 5 of the 4th byte)
pCurrentByte[3] |= dwMLen ;
}
// Add the signature to bits 0-23 of the 1st DWORD
{
PUCHAR pSignature = (PUCHAR)&pMpWakePattern->Signature;
// Bits 0-23 are also the 1st three bytes of the DWORD
pCurrentByte[0] = pSignature[0];
pCurrentByte[1] = pSignature[1];
pCurrentByte[2] = pSignature[2];
}
// Lets move to the next DWORD. Init variables
pCurrentByte += 4 ;
NumBytesWritten = 4;
pCurrentUlong = (PULONG)pCurrentByte;
// We Copy in the Mask over here
{
// The Mask is at the end of the pattern
PUCHAR pMask = (PUCHAR)pNdisPattern + sizeof(*pNdisPattern);
Dump (pMask,pNdisPattern->MaskSize, 0,1);
NdisMoveMemory (pCurrentByte, pMask, pNdisPattern->MaskSize);
NumBytesWritten += pNdisPattern->MaskSize;
}
// Update the output value
{
ULONG NumUlongs = (NumBytesWritten /4);
if ((NumBytesWritten %4) != 0)
{
NumUlongs ++;
}
ASSERT (NumUlongs == LengthOfFilter);
*pNext = *pNext + NumUlongs;
}
return;
}