Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489/* * PROJECT: ReactOS nVidia nForce Ethernet Controller Driver * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Miniport information callbacks * COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com> */
/* INCLUDES *******************************************************************/
#include "nvnet.h"
#define NDEBUG#include "debug.h"
/* GLOBALS ********************************************************************/
static const NDIS_OID NvpSupportedOidList[] ={ OID_GEN_SUPPORTED_LIST, OID_GEN_CURRENT_PACKET_FILTER, OID_GEN_HARDWARE_STATUS, OID_GEN_MEDIA_SUPPORTED, OID_GEN_MEDIA_IN_USE, OID_GEN_MAXIMUM_LOOKAHEAD, OID_GEN_MAXIMUM_FRAME_SIZE, OID_GEN_MAXIMUM_SEND_PACKETS, OID_GEN_LINK_SPEED, OID_GEN_TRANSMIT_BUFFER_SPACE, OID_GEN_RECEIVE_BUFFER_SPACE, OID_GEN_RECEIVE_BLOCK_SIZE, OID_GEN_TRANSMIT_BLOCK_SIZE, OID_GEN_VENDOR_ID, OID_GEN_VENDOR_DESCRIPTION, OID_GEN_VENDOR_DRIVER_VERSION, OID_GEN_CURRENT_LOOKAHEAD, OID_GEN_DRIVER_VERSION, OID_GEN_MAXIMUM_TOTAL_SIZE, OID_GEN_MAC_OPTIONS, OID_GEN_MEDIA_CONNECT_STATUS, OID_GEN_VLAN_ID, OID_802_3_PERMANENT_ADDRESS, OID_802_3_CURRENT_ADDRESS, OID_802_3_MULTICAST_LIST, OID_802_3_MAXIMUM_LIST_SIZE, OID_GEN_PHYSICAL_MEDIUM,
/* Statistics */ OID_GEN_XMIT_OK, OID_GEN_RCV_OK, OID_GEN_XMIT_ERROR, OID_GEN_RCV_ERROR, OID_GEN_RCV_NO_BUFFER, OID_GEN_DIRECTED_FRAMES_RCV, OID_GEN_RCV_CRC_ERROR, OID_GEN_TRANSMIT_QUEUE_LENGTH, OID_802_3_RCV_ERROR_ALIGNMENT, OID_802_3_XMIT_ONE_COLLISION, OID_802_3_XMIT_MORE_COLLISIONS, OID_802_3_XMIT_DEFERRED, OID_802_3_XMIT_MAX_COLLISIONS, OID_802_3_RCV_OVERRUN, OID_802_3_XMIT_UNDERRUN, OID_802_3_XMIT_HEARTBEAT_FAILURE, OID_802_3_XMIT_TIMES_CRS_LOST, OID_802_3_XMIT_LATE_COLLISIONS,
/* Offload */ OID_TCP_TASK_OFFLOAD,
/* Power management */ OID_PNP_CAPABILITIES, OID_PNP_SET_POWER, OID_PNP_QUERY_POWER, OID_PNP_ADD_WAKE_UP_PATTERN, OID_PNP_REMOVE_WAKE_UP_PATTERN, OID_PNP_ENABLE_WAKE_UP};
/* FUNCTIONS ******************************************************************/
staticULONGNvNetGetLinkSpeed( _In_ PNVNET_ADAPTER Adapter){ ULONG LinkSpeedMbps;
switch (Adapter->LinkSpeed) { case NVREG_LINKSPEED_10: LinkSpeedMbps = 10; break; case NVREG_LINKSPEED_100: LinkSpeedMbps = 100; break; case NVREG_LINKSPEED_1000: LinkSpeedMbps = 1000; break;
default: UNREACHABLE; break; }
return LinkSpeedMbps;}
staticULONGPacketFilterToMask( _In_ ULONG PacketFilter){ ULONG FilterMask = NVREG_PFF_ALWAYS | NVREG_PFF_MYADDR | NVREG_PFF_PROMISC;
if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) { FilterMask &= ~NVREG_PFF_MYADDR; }
if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST) { FilterMask &= ~NVREG_PFF_PROMISC; }
return FilterMask;}
staticDECLSPEC_NOINLINE /* Called from pageable code */VOIDNvNetApplyPacketFilter( _In_ PNVNET_ADAPTER Adapter){ UCHAR Address[ETH_LENGTH_OF_ADDRESS]; UCHAR Mask[ETH_LENGTH_OF_ADDRESS]; ULONG FilterMask; BOOLEAN RestartReceiver;
if (Adapter->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) { NdisZeroMemory(Address, sizeof(Address)); NdisZeroMemory(Mask, sizeof(Mask));
Address[0] |= NVREG_MCASTADDRA_FORCE; Mask[0] |= NVREG_MCASTADDRA_FORCE; } else if (Adapter->PacketFilter & NDIS_PACKET_TYPE_MULTICAST) { if (Adapter->MulticastListSize > 0) { ULONG i, j;
NdisFillMemory(Address, sizeof(Address), 0xFF); NdisFillMemory(Mask, sizeof(Mask), 0xFF);
for (i = 0; i < Adapter->MulticastListSize; ++i) { PUCHAR MacAddress = Adapter->MulticastList[i].MacAddress;
for (j = 0; j < ETH_LENGTH_OF_ADDRESS; ++j) { Address[j] &= MacAddress[j]; Mask[j] &= ~MacAddress[j]; } }
for (j = 0; j < ETH_LENGTH_OF_ADDRESS; ++j) { Mask[j] |= Address[j]; } } else { NdisZeroMemory(Address, sizeof(Address)); NdisZeroMemory(Mask, sizeof(Mask)); } } else { NdisZeroMemory(Address, sizeof(Address)); NdisFillMemory(Mask, sizeof(Mask), 0xFF); }
FilterMask = NV_READ(Adapter, NvRegPacketFilterFlags) & NVREG_PFF_PAUSE_RX; FilterMask |= PacketFilterToMask(Adapter->PacketFilter);
NdisAcquireSpinLock(&Adapter->Receive.Lock);
RestartReceiver = !!(NV_READ(Adapter, NvRegReceiverControl) & NVREG_RCVCTL_START); if (RestartReceiver) { NvNetStopReceiver(Adapter); }
NV_WRITE(Adapter, NvRegMulticastAddrA, Address[3] << 24 | Address[2] << 16 | Address[1] << 8 | Address[0]); NV_WRITE(Adapter, NvRegMulticastAddrB, Address[5] << 8 | Address[4]); NV_WRITE(Adapter, NvRegMulticastMaskA, Mask[3] << 24 | Mask[2] << 16 | Mask[1] << 8 | Mask[0]); NV_WRITE(Adapter, NvRegMulticastMaskB, Mask[5] << 8 | Mask[4]);
NV_WRITE(Adapter, NvRegPacketFilterFlags, FilterMask);
if (RestartReceiver) { NvNetStartReceiver(Adapter); }
NdisReleaseSpinLock(&Adapter->Receive.Lock);}
staticVOIDNvNetReadStatistics( _In_ PNVNET_ADAPTER Adapter){ Adapter->Statistics.HwTxCnt += NV_READ(Adapter, NvRegTxCnt); Adapter->Statistics.HwTxZeroReXmt += NV_READ(Adapter, NvRegTxZeroReXmt); Adapter->Statistics.HwTxOneReXmt += NV_READ(Adapter, NvRegTxOneReXmt); Adapter->Statistics.HwTxManyReXmt += NV_READ(Adapter, NvRegTxManyReXmt); Adapter->Statistics.HwTxLateCol += NV_READ(Adapter, NvRegTxLateCol); Adapter->Statistics.HwTxUnderflow += NV_READ(Adapter, NvRegTxUnderflow); Adapter->Statistics.HwTxLossCarrier += NV_READ(Adapter, NvRegTxLossCarrier); Adapter->Statistics.HwTxExcessDef += NV_READ(Adapter, NvRegTxExcessDef); Adapter->Statistics.HwTxRetryErr += NV_READ(Adapter, NvRegTxRetryErr); Adapter->Statistics.HwRxFrameErr += NV_READ(Adapter, NvRegRxFrameErr); Adapter->Statistics.HwRxExtraByte += NV_READ(Adapter, NvRegRxExtraByte); Adapter->Statistics.HwRxLateCol += NV_READ(Adapter, NvRegRxLateCol); Adapter->Statistics.HwRxRunt += NV_READ(Adapter, NvRegRxRunt); Adapter->Statistics.HwRxFrameTooLong += NV_READ(Adapter, NvRegRxFrameTooLong); Adapter->Statistics.HwRxOverflow += NV_READ(Adapter, NvRegRxOverflow); Adapter->Statistics.HwRxFCSErr += NV_READ(Adapter, NvRegRxFCSErr); Adapter->Statistics.HwRxFrameAlignErr += NV_READ(Adapter, NvRegRxFrameAlignErr); Adapter->Statistics.HwRxLenErr += NV_READ(Adapter, NvRegRxLenErr); Adapter->Statistics.HwRxUnicast += NV_READ(Adapter, NvRegRxUnicast); Adapter->Statistics.HwRxMulticast += NV_READ(Adapter, NvRegRxMulticast); Adapter->Statistics.HwRxBroadcast += NV_READ(Adapter, NvRegRxBroadcast);
if (Adapter->Features & DEV_HAS_STATISTICS_V2) { Adapter->Statistics.HwTxDef += NV_READ(Adapter, NvRegTxDef); Adapter->Statistics.HwTxFrame += NV_READ(Adapter, NvRegTxFrame); Adapter->Statistics.HwRxCnt += NV_READ(Adapter, NvRegRxCnt); Adapter->Statistics.HwTxPause += NV_READ(Adapter, NvRegTxPause); Adapter->Statistics.HwRxPause += NV_READ(Adapter, NvRegRxPause); Adapter->Statistics.HwRxDropFrame += NV_READ(Adapter, NvRegRxDropFrame); }
if (Adapter->Features & DEV_HAS_STATISTICS_V3) { Adapter->Statistics.HwTxUnicast += NV_READ(Adapter, NvRegTxUnicast); Adapter->Statistics.HwTxMulticast += NV_READ(Adapter, NvRegTxMulticast); Adapter->Statistics.HwTxBroadcast += NV_READ(Adapter, NvRegTxBroadcast); }}
staticVOIDNvNetQueryHwCounter( _In_ PNVNET_ADAPTER Adapter, _In_ NDIS_OID Oid, _Out_ PULONG64 Counter){ switch (Oid) { case OID_GEN_XMIT_OK: *Counter = (Adapter->Features & DEV_HAS_STATISTICS_V2) ? Adapter->Statistics.HwTxFrame : (Adapter->Statistics.HwTxZeroReXmt + Adapter->Statistics.HwTxOneReXmt + Adapter->Statistics.HwTxManyReXmt); break; case OID_GEN_RCV_OK: *Counter = (Adapter->Statistics.HwRxUnicast + Adapter->Statistics.HwRxMulticast + Adapter->Statistics.HwRxBroadcast); break; case OID_GEN_XMIT_ERROR: *Counter = (Adapter->Statistics.HwTxRetryErr + Adapter->Statistics.HwTxLateCol + Adapter->Statistics.HwTxUnderflow + Adapter->Statistics.HwTxLossCarrier + Adapter->Statistics.HwTxExcessDef); break; case OID_GEN_RCV_ERROR: *Counter = (Adapter->Statistics.HwRxFrameAlignErr + Adapter->Statistics.HwRxLenErr + Adapter->Statistics.HwRxRunt + Adapter->Statistics.HwRxFrameTooLong + Adapter->Statistics.HwRxFCSErr + Adapter->Statistics.HwRxFrameErr + Adapter->Statistics.HwRxExtraByte + Adapter->Statistics.HwRxLateCol); break; case OID_GEN_RCV_NO_BUFFER: *Counter = (Adapter->Statistics.HwRxDropFrame + Adapter->Statistics.HwRxOverflow + Adapter->Statistics.ReceiveIrqNoBuffers); break; case OID_GEN_DIRECTED_FRAMES_RCV: *Counter = Adapter->Statistics.HwRxUnicast; break; case OID_GEN_RCV_CRC_ERROR: *Counter = Adapter->Statistics.HwRxFCSErr; break; case OID_802_3_RCV_ERROR_ALIGNMENT: *Counter = Adapter->Statistics.HwRxFrameErr; break; case OID_802_3_XMIT_ONE_COLLISION: *Counter = Adapter->Statistics.HwTxOneReXmt; break; case OID_802_3_XMIT_MORE_COLLISIONS: *Counter = Adapter->Statistics.HwTxManyReXmt; break; case OID_802_3_XMIT_DEFERRED: *Counter = Adapter->Statistics.HwTxDef; break; case OID_802_3_XMIT_MAX_COLLISIONS: *Counter = Adapter->Statistics.HwTxRetryErr; break; case OID_802_3_RCV_OVERRUN: *Counter = Adapter->Statistics.HwRxOverflow; break; case OID_802_3_XMIT_UNDERRUN: *Counter = Adapter->Statistics.HwTxUnderflow; break; case OID_802_3_XMIT_HEARTBEAT_FAILURE: *Counter = Adapter->Statistics.HwTxZeroReXmt; break; case OID_802_3_XMIT_TIMES_CRS_LOST: *Counter = Adapter->Statistics.HwTxLossCarrier; break; case OID_802_3_XMIT_LATE_COLLISIONS: *Counter = Adapter->Statistics.HwTxLateCol; break;
default: UNREACHABLE; break; }}
staticVOIDNvNetQuerySoftwareCounter( _In_ PNVNET_ADAPTER Adapter, _In_ NDIS_OID Oid, _Out_ PULONG64 Counter){ switch (Oid) { case OID_GEN_XMIT_OK: *Counter = Adapter->Statistics.TransmitOk; break; case OID_GEN_RCV_OK: *Counter = Adapter->Statistics.ReceiveOk; break; case OID_GEN_XMIT_ERROR: *Counter = Adapter->Statistics.TransmitErrors; break; case OID_GEN_RCV_ERROR: *Counter = Adapter->Statistics.ReceiveErrors; break; case OID_GEN_RCV_NO_BUFFER: *Counter = Adapter->Statistics.ReceiveNoBuffers; break; case OID_GEN_DIRECTED_FRAMES_RCV: *Counter = 0; break; case OID_GEN_RCV_CRC_ERROR: *Counter = Adapter->Statistics.ReceiveCrcErrors; break; case OID_802_3_RCV_ERROR_ALIGNMENT: *Counter = Adapter->Statistics.ReceiveAlignmentErrors; break; case OID_802_3_XMIT_ONE_COLLISION: *Counter = Adapter->Statistics.TransmitOneRetry; break; case OID_802_3_XMIT_MORE_COLLISIONS: *Counter = (Adapter->Statistics.TransmitOk - Adapter->Statistics.TransmitOneRetry - Adapter->Statistics.TransmitZeroRetry); break; case OID_802_3_XMIT_DEFERRED: *Counter = Adapter->Statistics.TransmitDeferred; break; case OID_802_3_XMIT_MAX_COLLISIONS: *Counter = Adapter->Statistics.TransmitExcessiveCollisions; break; case OID_802_3_RCV_OVERRUN: *Counter = Adapter->Statistics.ReceiveOverrunErrors; break; case OID_802_3_XMIT_UNDERRUN: *Counter = Adapter->Statistics.TransmitUnderrunErrors; break; case OID_802_3_XMIT_HEARTBEAT_FAILURE: *Counter = Adapter->Statistics.TransmitZeroRetry; break; case OID_802_3_XMIT_TIMES_CRS_LOST: *Counter = Adapter->Statistics.TransmitLostCarrierSense; break; case OID_802_3_XMIT_LATE_COLLISIONS: *Counter = Adapter->Statistics.TransmitLateCollisions; break;
default: UNREACHABLE; break; }}
staticNDIS_STATUSNvNetFillPowerManagementCapabilities( _In_ PNVNET_ADAPTER Adapter, _Out_ PNDIS_PNP_CAPABILITIES Capabilities){ Capabilities->WakeUpCapabilities.MinMagicPacketWakeUp = Capabilities->WakeUpCapabilities.MinPatternWakeUp = Capabilities->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateD3;
/* All hardware is PM-aware */ return NDIS_STATUS_SUCCESS;}
staticULONGBuildFrameSignature( _In_ PNVNET_WAKE_FRAME WakeFrame){ ULONG i, j, Crc;
Crc = 0xFFFFFFFF; for (i = 0; i < sizeof(WakeFrame->WakeUpPattern); ++i) { if (WakeFrame->PatternMask.AsUCHAR[i / 8] & (1 << (i % 8))) { Crc ^= WakeFrame->WakeUpPattern[i]; for (j = 8; j > 0; --j) { Crc = (Crc >> 1) ^ (-(LONG)(Crc & 1) & 0xEDB88320); } } }
return ~Crc;}
staticVOIDWriteWakeFrame( _In_ PNVNET_ADAPTER Adapter, _In_ PNVNET_WAKE_FRAME WakeFrame, _In_ ULONG FrameNumber){ ULONG Offset = FrameNumber * 5 * sizeof(ULONG);
if (FrameNumber >= NV_WAKEUPPATTERNS) { Offset += NV_PATTERN_V2_OFFSET; }
NV_WRITE(Adapter, NvRegPatternCrc + Offset, BuildFrameSignature(WakeFrame)); NV_WRITE(Adapter, NvRegPatternMask0 + Offset, WakeFrame->PatternMask.AsULONG[0]); NV_WRITE(Adapter, NvRegPatternMask1 + Offset, WakeFrame->PatternMask.AsULONG[1]); NV_WRITE(Adapter, NvRegPatternMask2 + Offset, WakeFrame->PatternMask.AsULONG[2]); NV_WRITE(Adapter, NvRegPatternMask3 + Offset, WakeFrame->PatternMask.AsULONG[3]);}
staticULONGFrameNumberToWakeUpMask( _In_ ULONG FrameNumber){ if (FrameNumber < 5) return 0x10000 << FrameNumber; else return 0;}
staticULONGFrameNumberToPowerMask( _In_ ULONG FrameNumber){ switch (FrameNumber) { case 5: return NVREG_POWERSTATE2_WAKEUPPAT_5; case 6: return NVREG_POWERSTATE2_WAKEUPPAT_6; case 7: return NVREG_POWERSTATE2_WAKEUPPAT_7;
default: return 0; }}
VOIDNvNetSetPowerState( _In_ PNVNET_ADAPTER Adapter, _In_ NDIS_DEVICE_POWER_STATE NewPowerState, _In_ ULONG WakeFlags){ ULONG i, PowerState, PowerState2, WakeUpFlags;
NV_READ(Adapter, NvRegPowerCap);
WakeUpFlags = 0; PowerState2 = 0; if (Adapter->Features & DEV_HAS_POWER_CNTRL) { PowerState2 = NV_READ(Adapter, NvRegPowerState2); PowerState2 &= ~(NVREG_POWERSTATE2_WAKEUPPAT_5 | NVREG_POWERSTATE2_WAKEUPPAT_6 | NVREG_POWERSTATE2_WAKEUPPAT_7); }
if (NewPowerState != NdisDeviceStateD0) { ULONG FramesEnabled = 0;
if (WakeFlags & NDIS_PNP_WAKE_UP_PATTERN_MATCH) WakeUpFlags |= NVREG_WAKEUPFLAGS_ENABLE_MAGPAT; if (WakeFlags & NDIS_PNP_WAKE_UP_LINK_CHANGE) WakeUpFlags |= NVREG_WAKEUPFLAGS_ENABLE_LINKCHANGE; if (WakeFlags & NDIS_PNP_WAKE_UP_MAGIC_PACKET) { WakeUpFlags |= NVREG_WAKEUPFLAGS_ENABLE_WAKEUPPAT;
for (i = 0; i < RTL_NUMBER_OF(Adapter->WakeFrames); ++i) { PNVNET_WAKE_FRAME WakeFrame = Adapter->WakeFrames[i];
if (!WakeFrame) continue;
WriteWakeFrame(Adapter, WakeFrame, i);
PowerState2 |= FrameNumberToPowerMask(i); WakeUpFlags |= FrameNumberToWakeUpMask(i);
++FramesEnabled; } }
if (WakeUpFlags) { if (!(Adapter->Flags & NV_MAC_IN_USE)) { PowerState2 &= ~NVREG_POWERSTATE2_GATE_CLOCKS; PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCK_3;
if (!FramesEnabled && (WakeUpFlags & NVREG_WAKEUPFLAGS_ENABLE_LINKCHANGE)) PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCK_1; if (FramesEnabled < NV_WAKEUPMASKENTRIES) PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCK_2; }
NvNetStartReceiver(Adapter); } else { if (!(Adapter->Flags & NV_MAC_IN_USE)) PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCKS; } }
NdisStallExecution(NV_POWER_STALL);
NV_WRITE(Adapter, NvRegWakeUpFlags, WakeUpFlags); if (Adapter->Features & DEV_HAS_POWER_CNTRL) { NV_WRITE(Adapter, NvRegPowerState2, PowerState2); }
NV_WRITE(Adapter, NvRegPowerState, NV_READ(Adapter, NvRegPowerState) | NVREG_POWERSTATE_POWEREDUP); for (i = 0; i < NV_POWER_ATTEMPTS; ++i) { ULONG State = NV_READ(Adapter, NvRegPowerState);
if (!(State & NVREG_POWERSTATE_POWEREDUP)) break;
NV_WRITE(Adapter, NvRegPowerState, State | NVREG_POWERSTATE_POWEREDUP);
NdisStallExecution(NV_POWER_DELAY); }
PowerState = NewPowerState - 1; if (WakeUpFlags) { PowerState |= NVREG_POWERSTATE_VALID; } NV_WRITE(Adapter, NvRegPowerState, PowerState);}
staticCODE_SEG("PAGE")VOIDNTAPINvNetPowerWorker( _In_ PNDIS_WORK_ITEM WorkItem, _In_opt_ PVOID Context){ PNVNET_ADAPTER Adapter = Context;
UNREFERENCED_PARAMETER(WorkItem);
PAGED_CODE();
if (Adapter->PowerStatePending == NdisDeviceStateD0) { NvNetSetPowerState(Adapter, NdisDeviceStateD0, 0);
NT_VERIFY(NvNetInitNIC(Adapter, TRUE) == NDIS_STATUS_SUCCESS);
NvNetStartAdapter(Adapter);
NvNetApplyPacketFilter(Adapter); } else { NvNetPauseProcessing(Adapter);
NvNetStopAdapter(Adapter);
NvNetIdleTransmitter(Adapter, FALSE); NvNetStopTransmitter(Adapter); NvNetStopReceiver(Adapter); NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET); NdisStallExecution(NV_TXRX_RESET_DELAY);
NvNetFlushTransmitQueue(Adapter, NDIS_STATUS_FAILURE);
NvNetSetPowerState(Adapter, Adapter->PowerStatePending, Adapter->WakeFlags); }
NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS);}
staticNDIS_STATUSNvNetSetPower( _In_ PNVNET_ADAPTER Adapter, _In_ NDIS_DEVICE_POWER_STATE NewPowerState){ Adapter->PowerStatePending = NewPowerState;
NdisInitializeWorkItem(&Adapter->PowerWorkItem, NvNetPowerWorker, Adapter); NdisScheduleWorkItem(&Adapter->PowerWorkItem);
return NDIS_STATUS_PENDING;}
staticNDIS_STATUSNvNetAddWakeUpPattern( _In_ PNVNET_ADAPTER Adapter, _In_ PNDIS_PM_PACKET_PATTERN Pattern){ ULONG FrameNumber; NDIS_STATUS Status; PNVNET_WAKE_FRAME WakeFrame;
if (!_BitScanForward(&FrameNumber, Adapter->WakeFrameBitmap)) { return NDIS_STATUS_RESOURCES; }
Status = NdisAllocateMemoryWithTag((PVOID*)&WakeFrame, sizeof(*WakeFrame), NVNET_TAG); if (Status != NDIS_STATUS_SUCCESS) { return NDIS_STATUS_RESOURCES; }
Adapter->WakeFrameBitmap &= ~(1 << FrameNumber);
NdisZeroMemory(WakeFrame, sizeof(*WakeFrame)); NdisMoveMemory(&WakeFrame->PatternMask, (PUCHAR)Pattern + sizeof(NDIS_PM_PACKET_PATTERN), min(Pattern->MaskSize, 16)); NdisMoveMemory(&WakeFrame->WakeUpPattern, (PUCHAR)Pattern + Pattern->PatternOffset, min(Pattern->PatternSize, 128)); Adapter->WakeFrames[FrameNumber] = WakeFrame;
/* TODO: VLAN frame translation */
return NDIS_STATUS_SUCCESS;}
staticNDIS_STATUSNvNetRemoveWakeUpPattern( _In_ PNVNET_ADAPTER Adapter, _In_ PNDIS_PM_PACKET_PATTERN Pattern){ ULONG i;
for (i = 0; i < RTL_NUMBER_OF(Adapter->WakeFrames); ++i) { PNVNET_WAKE_FRAME WakeFrame = Adapter->WakeFrames[i];
if (!WakeFrame) continue;
if (!NdisEqualMemory(&WakeFrame->PatternMask, (PUCHAR)Pattern + sizeof(NDIS_PM_PACKET_PATTERN), min(Pattern->MaskSize, 16))) { continue; }
if (!NdisEqualMemory(&WakeFrame->WakeUpPattern, (PUCHAR)Pattern + Pattern->PatternOffset, min(Pattern->PatternSize, 128))) { continue; }
NdisFreeMemory(WakeFrame, sizeof(*WakeFrame), 0);
Adapter->WakeFrameBitmap |= (1 << i); Adapter->WakeFrames[i] = NULL;
return NDIS_STATUS_SUCCESS; }
return NDIS_STATUS_INVALID_DATA;}
staticULONGNvNetGetWakeUp( _In_ PNVNET_ADAPTER Adapter){ return Adapter->WakeFlags & (NDIS_PNP_WAKE_UP_MAGIC_PACKET | NDIS_PNP_WAKE_UP_PATTERN_MATCH | NDIS_PNP_WAKE_UP_LINK_CHANGE);}
staticVOIDNvNetEnableWakeUp( _In_ PNVNET_ADAPTER Adapter, _In_ ULONG Flags){ Adapter->WakeFlags = Flags;}
staticNDIS_STATUSNvNetGetTcpTaskOffload( _In_ PNVNET_ADAPTER Adapter, _In_ PNDIS_TASK_OFFLOAD_HEADER TaskOffloadHeader, _In_ ULONG InformationBufferLength, _Out_ PULONG BytesWritten, _Out_ PULONG BytesNeeded){ ULONG InfoLength; PNDIS_TASK_OFFLOAD TaskOffload;
if (!(Adapter->Flags & (NV_SEND_CHECKSUM | NV_SEND_LARGE_SEND))) { *BytesWritten = 0; *BytesNeeded = 0; return NDIS_STATUS_NOT_SUPPORTED; }
InfoLength = sizeof(NDIS_TASK_OFFLOAD_HEADER); if (Adapter->Flags & NV_SEND_CHECKSUM) { InfoLength += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) + sizeof(NDIS_TASK_TCP_IP_CHECKSUM); } if (Adapter->Flags & NV_SEND_LARGE_SEND) { InfoLength += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) + sizeof(NDIS_TASK_TCP_LARGE_SEND); }
if (InformationBufferLength < InfoLength) { *BytesWritten = 0; *BytesNeeded = InfoLength; return NDIS_STATUS_BUFFER_TOO_SHORT; }
if ((TaskOffloadHeader->EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation) && (TaskOffloadHeader->EncapsulationFormat.Encapsulation != UNSPECIFIED_Encapsulation || TaskOffloadHeader->EncapsulationFormat.EncapsulationHeaderSize != sizeof(ETH_HEADER))) { *BytesWritten = 0; *BytesNeeded = 0; return NDIS_STATUS_NOT_SUPPORTED; } if (TaskOffloadHeader->Version != NDIS_TASK_OFFLOAD_VERSION) { *BytesWritten = 0; *BytesNeeded = 0; return NDIS_STATUS_NOT_SUPPORTED; }
TaskOffloadHeader->OffsetFirstTask = sizeof(NDIS_TASK_OFFLOAD_HEADER); TaskOffload = (PNDIS_TASK_OFFLOAD)(TaskOffloadHeader + 1); if (Adapter->Flags & NV_SEND_CHECKSUM) { PNDIS_TASK_TCP_IP_CHECKSUM ChecksumTask;
TaskOffload->Size = sizeof(NDIS_TASK_OFFLOAD); TaskOffload->Version = NDIS_TASK_OFFLOAD_VERSION; TaskOffload->Task = TcpIpChecksumNdisTask; TaskOffload->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM); TaskOffload->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) + sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
ChecksumTask = (PNDIS_TASK_TCP_IP_CHECKSUM)TaskOffload->TaskBuffer; NdisZeroMemory(ChecksumTask, sizeof(*ChecksumTask));
ChecksumTask->V4Transmit.IpOptionsSupported = 1; ChecksumTask->V4Transmit.TcpOptionsSupported = 1; ChecksumTask->V4Transmit.TcpChecksum = 1; ChecksumTask->V4Transmit.UdpChecksum = 1; ChecksumTask->V4Transmit.IpChecksum = 1;
ChecksumTask->V4Receive.IpOptionsSupported = 1; ChecksumTask->V4Receive.TcpOptionsSupported = 1; ChecksumTask->V4Receive.TcpChecksum = 1; ChecksumTask->V4Receive.UdpChecksum = 1; ChecksumTask->V4Receive.IpChecksum = 1;
TaskOffload = (PNDIS_TASK_OFFLOAD)(ChecksumTask + 1); } if (Adapter->Flags & NV_SEND_LARGE_SEND) { PNDIS_TASK_TCP_LARGE_SEND LargeSendTask;
TaskOffload->Size = sizeof(NDIS_TASK_OFFLOAD); TaskOffload->Version = NDIS_TASK_OFFLOAD_VERSION; TaskOffload->Task = TcpLargeSendNdisTask; TaskOffload->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND); TaskOffload->OffsetNextTask = 0;
LargeSendTask = (PNDIS_TASK_TCP_LARGE_SEND)TaskOffload->TaskBuffer; LargeSendTask->Version = NDIS_TASK_TCP_LARGE_SEND_V0; LargeSendTask->MinSegmentCount = NVNET_MINIMUM_LSO_SEGMENT_COUNT; LargeSendTask->MaxOffLoadSize = NVNET_MAXIMUM_LSO_FRAME_SIZE; LargeSendTask->IpOptions = TRUE; LargeSendTask->TcpOptions = TRUE; } TaskOffload->OffsetNextTask = 0;
*BytesWritten = InfoLength; *BytesNeeded = 0;
return NDIS_STATUS_SUCCESS;}
staticNDIS_STATUSNvNetSetTcpTaskOffload( _Inout_ PNVNET_ADAPTER Adapter, _In_ PNDIS_TASK_OFFLOAD_HEADER TaskOffloadHeader, _In_ PULONG BytesRead){ ULONG Offset; PNDIS_TASK_OFFLOAD TaskOffload;
if (TaskOffloadHeader->Version != NDIS_TASK_OFFLOAD_VERSION) { return NDIS_STATUS_NOT_SUPPORTED; }
Adapter->IpHeaderOffset = TaskOffloadHeader->EncapsulationFormat.EncapsulationHeaderSize;
TaskOffload = (PNDIS_TASK_OFFLOAD)TaskOffloadHeader; Offset = TaskOffloadHeader->OffsetFirstTask;
while (Offset) { *BytesRead += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer);
TaskOffload = (PNDIS_TASK_OFFLOAD)((PUCHAR)TaskOffload + Offset); switch (TaskOffload->Task) { case TcpIpChecksumNdisTask: { PNDIS_TASK_TCP_IP_CHECKSUM Task;
*BytesRead += sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
if (!(Adapter->Flags & NV_SEND_CHECKSUM)) { return NDIS_STATUS_NOT_SUPPORTED; }
Task = (PNDIS_TASK_TCP_IP_CHECKSUM)TaskOffload->TaskBuffer;
Adapter->Offload.SendTcpChecksum = Task->V4Transmit.TcpChecksum; Adapter->Offload.SendUdpChecksum = Task->V4Transmit.UdpChecksum; Adapter->Offload.SendIpChecksum = Task->V4Transmit.IpChecksum;
Adapter->Offload.ReceiveTcpChecksum = Task->V4Receive.TcpChecksum; Adapter->Offload.ReceiveUdpChecksum = Task->V4Receive.UdpChecksum; Adapter->Offload.ReceiveIpChecksum = Task->V4Receive.IpChecksum; break; }
case TcpLargeSendNdisTask: { PNDIS_TASK_TCP_LARGE_SEND Task;
if (!(Adapter->Flags & NV_SEND_LARGE_SEND)) { return NDIS_STATUS_NOT_SUPPORTED; }
if ((TaskOffloadHeader-> EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation) && (TaskOffloadHeader-> EncapsulationFormat.Encapsulation != UNSPECIFIED_Encapsulation || TaskOffloadHeader-> EncapsulationFormat.EncapsulationHeaderSize != sizeof(ETH_HEADER))) { return NDIS_STATUS_NOT_SUPPORTED; }
*BytesRead += sizeof(NDIS_TASK_TCP_LARGE_SEND);
Task = (PNDIS_TASK_TCP_LARGE_SEND)TaskOffload->TaskBuffer;
if (Task->MinSegmentCount != NVNET_MINIMUM_LSO_SEGMENT_COUNT) return NDIS_STATUS_NOT_SUPPORTED;
if (Task->MaxOffLoadSize > NVNET_MAXIMUM_LSO_FRAME_SIZE) return NDIS_STATUS_NOT_SUPPORTED;
/* Nothing to do */ break; }
default: break; }
Offset = TaskOffload->OffsetNextTask; }
NdisAcquireSpinLock(&Adapter->Send.Lock);
if (Adapter->Offload.ReceiveTcpChecksum || Adapter->Offload.ReceiveUdpChecksum || Adapter->Offload.ReceiveIpChecksum) { Adapter->TxRxControl |= NVREG_TXRXCTL_RXCHECK; } else { Adapter->TxRxControl &= ~NVREG_TXRXCTL_RXCHECK; } NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl);
NdisReleaseSpinLock(&Adapter->Send.Lock);
return NDIS_STATUS_SUCCESS;}
NDIS_STATUSNTAPIMiniportQueryInformation( _In_ NDIS_HANDLE MiniportAdapterContext, _In_ NDIS_OID Oid, _In_ PVOID InformationBuffer, _In_ ULONG InformationBufferLength, _Out_ PULONG BytesWritten, _Out_ PULONG BytesNeeded){ PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ULONG InfoLength; PVOID InfoPtr; union _GENERIC_INFORMATION { USHORT Ushort; ULONG Ulong; ULONG64 Ulong64; NDIS_MEDIUM Medium; NDIS_HARDWARE_STATUS Status; NDIS_DEVICE_POWER_STATE PowerState; } GenericInfo;
InfoLength = sizeof(ULONG); InfoPtr = &GenericInfo;
switch (Oid) { case OID_GEN_SUPPORTED_LIST: InfoPtr = (PVOID)&NvpSupportedOidList; InfoLength = sizeof(NvpSupportedOidList); break;
case OID_GEN_HARDWARE_STATUS: InfoLength = sizeof(NDIS_HARDWARE_STATUS); GenericInfo.Status = NdisHardwareStatusReady; break;
case OID_GEN_MEDIA_SUPPORTED: case OID_GEN_MEDIA_IN_USE: { InfoLength = sizeof(NDIS_MEDIUM); GenericInfo.Medium = NdisMedium802_3; break; }
case OID_GEN_CURRENT_LOOKAHEAD: case OID_GEN_MAXIMUM_LOOKAHEAD: { GenericInfo.Ulong = Adapter->MaximumFrameSize - sizeof(ETH_HEADER); break; }
case OID_GEN_MAXIMUM_FRAME_SIZE: { GenericInfo.Ulong = Adapter->MaximumFrameSize; break; }
case OID_GEN_LINK_SPEED: { GenericInfo.Ulong = NvNetGetLinkSpeed(Adapter) * 10000; break; }
case OID_GEN_TRANSMIT_BUFFER_SPACE: { /* TODO: Change this later, once the driver can handle multipacket sends */ GenericInfo.Ulong = Adapter->MaximumFrameSize; break; }
case OID_GEN_RECEIVE_BUFFER_SPACE: { GenericInfo.Ulong = Adapter->MaximumFrameSize * NVNET_RECEIVE_DESCRIPTORS; }
case OID_GEN_MAXIMUM_TOTAL_SIZE: case OID_GEN_TRANSMIT_BLOCK_SIZE: case OID_GEN_RECEIVE_BLOCK_SIZE: { GenericInfo.Ulong = Adapter->MaximumFrameSize; break; }
case OID_GEN_VENDOR_ID: { GenericInfo.Ulong = 0; GenericInfo.Ulong |= (Adapter->PermanentMacAddress[0] << 16); GenericInfo.Ulong |= (Adapter->PermanentMacAddress[1] << 8); GenericInfo.Ulong |= (Adapter->PermanentMacAddress[2] & 0xFF); break; }
case OID_GEN_DRIVER_VERSION: { InfoLength = sizeof(USHORT); GenericInfo.Ushort = (NDIS_MINIPORT_MAJOR_VERSION << 8) | NDIS_MINIPORT_MINOR_VERSION; break; }
case OID_GEN_VENDOR_DESCRIPTION: { static const CHAR VendorDesc[] = "nVidia nForce Ethernet Controller"; InfoPtr = (PVOID)&VendorDesc; InfoLength = sizeof(VendorDesc); break; }
case OID_GEN_CURRENT_PACKET_FILTER: { GenericInfo.Ulong = Adapter->PacketFilter; break; }
case OID_GEN_MAC_OPTIONS: { GenericInfo.Ulong = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_NO_LOOPBACK;
if (Adapter->Flags & NV_PACKET_PRIORITY) GenericInfo.Ulong |= NDIS_MAC_OPTION_8021P_PRIORITY; if (Adapter->Flags & NV_VLAN_TAGGING) GenericInfo.Ulong |= NDIS_MAC_OPTION_8021Q_VLAN; break; }
case OID_GEN_MEDIA_CONNECT_STATUS: { GenericInfo.Ulong = Adapter->Connected ? NdisMediaStateConnected : NdisMediaStateDisconnected; break; }
case OID_GEN_MAXIMUM_SEND_PACKETS: { /* TODO: Multipacket sends */ GenericInfo.Ulong = 1; break; }
case OID_GEN_VENDOR_DRIVER_VERSION: { /* 1.0.0 */ GenericInfo.Ulong = 0x100; break; }
case OID_GEN_XMIT_OK: case OID_GEN_RCV_OK: case OID_GEN_XMIT_ERROR: case OID_GEN_RCV_ERROR: case OID_GEN_RCV_NO_BUFFER: case OID_GEN_DIRECTED_FRAMES_RCV: case OID_GEN_RCV_CRC_ERROR: case OID_802_3_RCV_ERROR_ALIGNMENT: case OID_802_3_XMIT_ONE_COLLISION: case OID_802_3_XMIT_MORE_COLLISIONS: case OID_802_3_XMIT_DEFERRED: case OID_802_3_XMIT_MAX_COLLISIONS: case OID_802_3_RCV_OVERRUN: case OID_802_3_XMIT_UNDERRUN: case OID_802_3_XMIT_HEARTBEAT_FAILURE: case OID_802_3_XMIT_TIMES_CRS_LOST: case OID_802_3_XMIT_LATE_COLLISIONS: { if (Adapter->Features & DEV_HAS_STATISTICS_COUNTERS) { NvNetReadStatistics(Adapter); NvNetQueryHwCounter(Adapter, Oid, &GenericInfo.Ulong64); } else { NvNetQuerySoftwareCounter(Adapter, Oid, &GenericInfo.Ulong64); }
*BytesNeeded = sizeof(ULONG64); if (InformationBufferLength < sizeof(ULONG)) { *BytesWritten = 0; return NDIS_STATUS_BUFFER_TOO_SHORT; } if (InformationBufferLength >= sizeof(ULONG64)) { *BytesWritten = sizeof(ULONG64); NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG64)); } else { *BytesWritten = sizeof(ULONG); NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG)); }
return NDIS_STATUS_SUCCESS; }
case OID_GEN_TRANSMIT_QUEUE_LENGTH: { GenericInfo.Ulong = NVNET_TRANSMIT_BLOCKS - Adapter->Send.TcbSlots; break; }
case OID_802_3_PERMANENT_ADDRESS: { InfoPtr = Adapter->PermanentMacAddress; InfoLength = ETH_LENGTH_OF_ADDRESS; break; }
case OID_802_3_CURRENT_ADDRESS: { InfoPtr = Adapter->CurrentMacAddress; InfoLength = ETH_LENGTH_OF_ADDRESS; break; }
case OID_802_3_MULTICAST_LIST: { InfoPtr = Adapter->MulticastList; InfoLength = Adapter->MulticastListSize * ETH_LENGTH_OF_ADDRESS; break; }
case OID_802_3_MAXIMUM_LIST_SIZE: { GenericInfo.Ulong = NVNET_MULTICAST_LIST_SIZE; break; }
case OID_GEN_PHYSICAL_MEDIUM: { GenericInfo.Ulong = NdisPhysicalMedium802_3; break; }
case OID_TCP_TASK_OFFLOAD: { return NvNetGetTcpTaskOffload(Adapter, InformationBuffer, InformationBufferLength, BytesWritten, BytesWritten); }
case OID_PNP_ENABLE_WAKE_UP: { GenericInfo.Ulong = NvNetGetWakeUp(Adapter); break; }
case OID_PNP_CAPABILITIES: { InfoLength = sizeof(NDIS_PNP_CAPABILITIES);
if (InformationBufferLength < InfoLength) { *BytesWritten = 0; *BytesNeeded = InfoLength; return NDIS_STATUS_BUFFER_TOO_SHORT; }
*BytesWritten = InfoLength; *BytesNeeded = 0; return NvNetFillPowerManagementCapabilities(Adapter, InformationBuffer); }
case OID_PNP_QUERY_POWER: { return NDIS_STATUS_SUCCESS; }
case OID_GEN_VLAN_ID: { /* TODO: Implement software VLAN support */ if (!(Adapter->Flags & NV_VLAN_TAGGING)) { Status = NDIS_STATUS_NOT_SUPPORTED; break; }
GenericInfo.Ulong = Adapter->VlanId; break; }
default: Status = NDIS_STATUS_INVALID_OID; break; }
if (Status == NDIS_STATUS_SUCCESS) { if (InfoLength > InformationBufferLength) { *BytesWritten = 0; *BytesNeeded = InfoLength; Status = NDIS_STATUS_BUFFER_TOO_SHORT; } else { NdisMoveMemory(InformationBuffer, InfoPtr, InfoLength); *BytesWritten = InfoLength; *BytesNeeded = 0; } } else { *BytesWritten = 0; *BytesNeeded = 0; }
return Status;}
NDIS_STATUSNTAPIMiniportSetInformation( _In_ NDIS_HANDLE MiniportAdapterContext, _In_ NDIS_OID Oid, _In_ PVOID InformationBuffer, _In_ ULONG InformationBufferLength, _Out_ PULONG BytesRead, _Out_ PULONG BytesNeeded){ PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ULONG GenericUlong;
*BytesRead = 0; *BytesNeeded = 0;
switch (Oid) { case OID_802_3_MULTICAST_LIST: { if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS) { *BytesNeeded = (InformationBufferLength / ETH_LENGTH_OF_ADDRESS) * ETH_LENGTH_OF_ADDRESS; Status = NDIS_STATUS_INVALID_LENGTH; break; }
if (InformationBufferLength > sizeof(Adapter->MulticastList)) { *BytesNeeded = sizeof(Adapter->MulticastList); Status = NDIS_STATUS_MULTICAST_FULL; break; }
*BytesRead = InformationBufferLength; NdisMoveMemory(Adapter->MulticastList, InformationBuffer, InformationBufferLength);
Adapter->MulticastListSize = InformationBufferLength / ETH_LENGTH_OF_ADDRESS;
NvNetApplyPacketFilter(Adapter); break; }
case OID_GEN_CURRENT_PACKET_FILTER: { if (InformationBufferLength < sizeof(ULONG)) { *BytesNeeded = sizeof(ULONG); Status = NDIS_STATUS_INVALID_LENGTH; break; }
*BytesRead = sizeof(ULONG); NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
if (GenericUlong & ~NVNET_PACKET_FILTERS) { Status = NDIS_STATUS_NOT_SUPPORTED; break; }
/* Do not check to see if the filter is the same filter */ Adapter->PacketFilter = GenericUlong;
NvNetApplyPacketFilter(Adapter); break; }
case OID_GEN_CURRENT_LOOKAHEAD: { if (InformationBufferLength < sizeof(ULONG)) { *BytesNeeded = sizeof(ULONG); Status = NDIS_STATUS_INVALID_LENGTH; break; }
/* Nothing to do */ *BytesRead = sizeof(ULONG); break; }
case OID_GEN_VLAN_ID: { if (InformationBufferLength < sizeof(ULONG)) { *BytesNeeded = sizeof(ULONG); Status = NDIS_STATUS_INVALID_LENGTH; break; }
if (!(Adapter->Flags & NV_VLAN_TAGGING)) { Status = NDIS_STATUS_NOT_SUPPORTED; break; }
*BytesRead = sizeof(ULONG); NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
if (GenericUlong > NVNET_MAXIMUM_VLAN_ID) { Status = NDIS_STATUS_FAILURE; break; }
Adapter->VlanId = GenericUlong; break; }
case OID_TCP_TASK_OFFLOAD: { if (InformationBufferLength < sizeof(NDIS_TASK_OFFLOAD_HEADER)) { *BytesNeeded = sizeof(NDIS_TASK_OFFLOAD_HEADER); Status = NDIS_STATUS_INVALID_LENGTH; break; }
*BytesRead = InformationBufferLength;
Status = NvNetSetTcpTaskOffload(Adapter, InformationBuffer, BytesRead); break; }
case OID_PNP_ADD_WAKE_UP_PATTERN: { if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN)) { *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN); Status = NDIS_STATUS_INVALID_LENGTH; break; }
*BytesRead = sizeof(NDIS_PM_PACKET_PATTERN);
Status = NvNetAddWakeUpPattern(Adapter, InformationBuffer); break; }
case OID_PNP_REMOVE_WAKE_UP_PATTERN: { if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN)) { *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN); Status = NDIS_STATUS_INVALID_LENGTH; break; }
*BytesRead = sizeof(NDIS_PM_PACKET_PATTERN);
Status = NvNetRemoveWakeUpPattern(Adapter, InformationBuffer); break; }
case OID_PNP_ENABLE_WAKE_UP: { if (InformationBufferLength < sizeof(ULONG)) { *BytesNeeded = sizeof(ULONG); Status = NDIS_STATUS_INVALID_LENGTH; break; }
*BytesRead = sizeof(ULONG); NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
NvNetEnableWakeUp(Adapter, GenericUlong); break; }
case OID_PNP_SET_POWER: { if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE)) { *BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE); Status = NDIS_STATUS_INVALID_LENGTH; break; }
*BytesRead = sizeof(ULONG); NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
if (GenericUlong < NdisDeviceStateD0 || GenericUlong > NdisDeviceStateD3) { Status = NDIS_STATUS_INVALID_DATA; break; }
Status = NvNetSetPower(Adapter, GenericUlong); break; }
default: Status = NDIS_STATUS_NOT_SUPPORTED; break; }
return Status;}