xref: /reactos/drivers/network/dd/nvnet/requests.c (revision 2ea56af2)
1 /*
2  * PROJECT:     ReactOS nVidia nForce Ethernet Controller Driver
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Miniport information callbacks
5  * COPYRIGHT:   Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
6  */
7 
8 /* INCLUDES *******************************************************************/
9 
10 #include "nvnet.h"
11 
12 #define NDEBUG
13 #include "debug.h"
14 
15 /* GLOBALS ********************************************************************/
16 
17 static const NDIS_OID NvpSupportedOidList[] =
18 {
19     OID_GEN_SUPPORTED_LIST,
20     OID_GEN_CURRENT_PACKET_FILTER,
21     OID_GEN_HARDWARE_STATUS,
22     OID_GEN_MEDIA_SUPPORTED,
23     OID_GEN_MEDIA_IN_USE,
24     OID_GEN_MAXIMUM_LOOKAHEAD,
25     OID_GEN_MAXIMUM_FRAME_SIZE,
26     OID_GEN_MAXIMUM_SEND_PACKETS,
27     OID_GEN_LINK_SPEED,
28     OID_GEN_TRANSMIT_BUFFER_SPACE,
29     OID_GEN_RECEIVE_BUFFER_SPACE,
30     OID_GEN_RECEIVE_BLOCK_SIZE,
31     OID_GEN_TRANSMIT_BLOCK_SIZE,
32     OID_GEN_VENDOR_ID,
33     OID_GEN_VENDOR_DESCRIPTION,
34     OID_GEN_VENDOR_DRIVER_VERSION,
35     OID_GEN_CURRENT_LOOKAHEAD,
36     OID_GEN_DRIVER_VERSION,
37     OID_GEN_MAXIMUM_TOTAL_SIZE,
38     OID_GEN_MAC_OPTIONS,
39     OID_GEN_MEDIA_CONNECT_STATUS,
40     OID_GEN_VLAN_ID,
41     OID_802_3_PERMANENT_ADDRESS,
42     OID_802_3_CURRENT_ADDRESS,
43     OID_802_3_MULTICAST_LIST,
44     OID_802_3_MAXIMUM_LIST_SIZE,
45 
46     /* Statistics */
47     OID_GEN_XMIT_OK,
48     OID_GEN_RCV_OK,
49     OID_GEN_XMIT_ERROR,
50     OID_GEN_RCV_ERROR,
51     OID_GEN_RCV_NO_BUFFER,
52     OID_GEN_DIRECTED_FRAMES_RCV,
53     OID_GEN_RCV_CRC_ERROR,
54     OID_GEN_TRANSMIT_QUEUE_LENGTH,
55     OID_802_3_RCV_ERROR_ALIGNMENT,
56     OID_802_3_XMIT_ONE_COLLISION,
57     OID_802_3_XMIT_MORE_COLLISIONS,
58     OID_802_3_XMIT_DEFERRED,
59     OID_802_3_XMIT_MAX_COLLISIONS,
60     OID_802_3_RCV_OVERRUN,
61     OID_802_3_XMIT_UNDERRUN,
62     OID_802_3_XMIT_HEARTBEAT_FAILURE,
63     OID_802_3_XMIT_TIMES_CRS_LOST,
64     OID_802_3_XMIT_LATE_COLLISIONS,
65 
66     /* Offload */
67     OID_TCP_TASK_OFFLOAD,
68 
69     /* Power management */
70     OID_PNP_CAPABILITIES,
71     OID_PNP_SET_POWER,
72     OID_PNP_QUERY_POWER,
73     OID_PNP_ADD_WAKE_UP_PATTERN,
74     OID_PNP_REMOVE_WAKE_UP_PATTERN,
75     OID_PNP_ENABLE_WAKE_UP
76 };
77 
78 /* FUNCTIONS ******************************************************************/
79 
80 static
81 ULONG
82 NvNetGetLinkSpeed(
83     _In_ PNVNET_ADAPTER Adapter)
84 {
85     ULONG LinkSpeedMbps;
86 
87     switch (Adapter->LinkSpeed)
88     {
89         case NVREG_LINKSPEED_10:
90             LinkSpeedMbps = 10;
91             break;
92         case NVREG_LINKSPEED_100:
93             LinkSpeedMbps = 100;
94             break;
95         case NVREG_LINKSPEED_1000:
96             LinkSpeedMbps = 1000;
97             break;
98 
99         default:
100             UNREACHABLE;
101             break;
102     }
103 
104     return LinkSpeedMbps;
105 }
106 
107 static
108 ULONG
109 PacketFilterToMask(
110     _In_ ULONG PacketFilter)
111 {
112     ULONG FilterMask = NVREG_PFF_ALWAYS | NVREG_PFF_MYADDR | NVREG_PFF_PROMISC;
113 
114     if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
115     {
116         FilterMask &= ~NVREG_PFF_MYADDR;
117     }
118 
119     if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
120     {
121         FilterMask &= ~NVREG_PFF_PROMISC;
122     }
123 
124     return FilterMask;
125 }
126 
127 static
128 DECLSPEC_NOINLINE /* Called from pageable code */
129 VOID
130 NvNetApplyPacketFilter(
131     _In_ PNVNET_ADAPTER Adapter)
132 {
133     UCHAR Address[ETH_LENGTH_OF_ADDRESS];
134     UCHAR Mask[ETH_LENGTH_OF_ADDRESS];
135     ULONG FilterMask;
136     BOOLEAN RestartReceiver;
137 
138     if (Adapter->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
139     {
140         NdisZeroMemory(Address, sizeof(Address));
141         NdisZeroMemory(Mask, sizeof(Mask));
142 
143         Address[0] |= NVREG_MCASTADDRA_FORCE;
144         Mask[0] |= NVREG_MCASTADDRA_FORCE;
145     }
146     else if (Adapter->PacketFilter & NDIS_PACKET_TYPE_MULTICAST)
147     {
148         if (Adapter->MulticastListSize > 0)
149         {
150             ULONG i, j;
151 
152             NdisFillMemory(Address, sizeof(Address), 0xFF);
153             NdisFillMemory(Mask, sizeof(Mask), 0xFF);
154 
155             for (i = 0; i < Adapter->MulticastListSize; ++i)
156             {
157                 PUCHAR MacAddress = Adapter->MulticastList[i].MacAddress;
158 
159                 for (j = 0; j < ETH_LENGTH_OF_ADDRESS; ++j)
160                 {
161                     Address[j] &= MacAddress[j];
162                     Mask[j] &= ~MacAddress[j];
163                 }
164             }
165 
166             for (j = 0; j < ETH_LENGTH_OF_ADDRESS; ++j)
167             {
168                 Mask[j] |= Address[j];
169             }
170         }
171         else
172         {
173             NdisZeroMemory(Address, sizeof(Address));
174             NdisZeroMemory(Mask, sizeof(Mask));
175         }
176     }
177     else
178     {
179         NdisZeroMemory(Address, sizeof(Address));
180         NdisFillMemory(Mask, sizeof(Mask), 0xFF);
181     }
182 
183     FilterMask = NV_READ(Adapter, NvRegPacketFilterFlags) & NVREG_PFF_PAUSE_RX;
184     FilterMask |= PacketFilterToMask(Adapter->PacketFilter);
185 
186     NdisAcquireSpinLock(&Adapter->Receive.Lock);
187 
188     RestartReceiver = !!(NV_READ(Adapter, NvRegReceiverControl) & NVREG_RCVCTL_START);
189     if (RestartReceiver)
190     {
191         NvNetStopReceiver(Adapter);
192     }
193 
194     NV_WRITE(Adapter, NvRegMulticastAddrA,
195              Address[3] << 24 | Address[2] << 16 | Address[1] << 8 | Address[0]);
196     NV_WRITE(Adapter, NvRegMulticastAddrB, Address[5] << 8 | Address[4]);
197     NV_WRITE(Adapter, NvRegMulticastMaskA,
198              Mask[3] << 24 | Mask[2] << 16 | Mask[1] << 8 | Mask[0]);
199     NV_WRITE(Adapter, NvRegMulticastMaskB, Mask[5] << 8 | Mask[4]);
200 
201     NV_WRITE(Adapter, NvRegPacketFilterFlags, FilterMask);
202 
203     if (RestartReceiver)
204     {
205         NvNetStartReceiver(Adapter);
206     }
207 
208     NdisReleaseSpinLock(&Adapter->Receive.Lock);
209 }
210 
211 static
212 VOID
213 NvNetReadStatistics(
214     _In_ PNVNET_ADAPTER Adapter)
215 {
216     Adapter->Statistics.HwTxCnt += NV_READ(Adapter, NvRegTxCnt);
217     Adapter->Statistics.HwTxZeroReXmt += NV_READ(Adapter, NvRegTxZeroReXmt);
218     Adapter->Statistics.HwTxOneReXmt += NV_READ(Adapter, NvRegTxOneReXmt);
219     Adapter->Statistics.HwTxManyReXmt += NV_READ(Adapter, NvRegTxManyReXmt);
220     Adapter->Statistics.HwTxLateCol += NV_READ(Adapter, NvRegTxLateCol);
221     Adapter->Statistics.HwTxUnderflow += NV_READ(Adapter, NvRegTxUnderflow);
222     Adapter->Statistics.HwTxLossCarrier += NV_READ(Adapter, NvRegTxLossCarrier);
223     Adapter->Statistics.HwTxExcessDef += NV_READ(Adapter, NvRegTxExcessDef);
224     Adapter->Statistics.HwTxRetryErr += NV_READ(Adapter, NvRegTxRetryErr);
225     Adapter->Statistics.HwRxFrameErr += NV_READ(Adapter, NvRegRxFrameErr);
226     Adapter->Statistics.HwRxExtraByte += NV_READ(Adapter, NvRegRxExtraByte);
227     Adapter->Statistics.HwRxLateCol += NV_READ(Adapter, NvRegRxLateCol);
228     Adapter->Statistics.HwRxRunt += NV_READ(Adapter, NvRegRxRunt);
229     Adapter->Statistics.HwRxFrameTooLong += NV_READ(Adapter, NvRegRxFrameTooLong);
230     Adapter->Statistics.HwRxOverflow += NV_READ(Adapter, NvRegRxOverflow);
231     Adapter->Statistics.HwRxFCSErr += NV_READ(Adapter, NvRegRxFCSErr);
232     Adapter->Statistics.HwRxFrameAlignErr += NV_READ(Adapter, NvRegRxFrameAlignErr);
233     Adapter->Statistics.HwRxLenErr += NV_READ(Adapter, NvRegRxLenErr);
234     Adapter->Statistics.HwRxUnicast += NV_READ(Adapter, NvRegRxUnicast);
235     Adapter->Statistics.HwRxMulticast += NV_READ(Adapter, NvRegRxMulticast);
236     Adapter->Statistics.HwRxBroadcast += NV_READ(Adapter, NvRegRxBroadcast);
237 
238     if (Adapter->Features & DEV_HAS_STATISTICS_V2)
239     {
240         Adapter->Statistics.HwTxDef += NV_READ(Adapter, NvRegTxDef);
241         Adapter->Statistics.HwTxFrame += NV_READ(Adapter, NvRegTxFrame);
242         Adapter->Statistics.HwRxCnt += NV_READ(Adapter, NvRegRxCnt);
243         Adapter->Statistics.HwTxPause += NV_READ(Adapter, NvRegTxPause);
244         Adapter->Statistics.HwRxPause += NV_READ(Adapter, NvRegRxPause);
245         Adapter->Statistics.HwRxDropFrame += NV_READ(Adapter, NvRegRxDropFrame);
246     }
247 
248     if (Adapter->Features & DEV_HAS_STATISTICS_V3)
249     {
250         Adapter->Statistics.HwTxUnicast += NV_READ(Adapter, NvRegTxUnicast);
251         Adapter->Statistics.HwTxMulticast += NV_READ(Adapter, NvRegTxMulticast);
252         Adapter->Statistics.HwTxBroadcast += NV_READ(Adapter, NvRegTxBroadcast);
253     }
254 }
255 
256 static
257 VOID
258 NvNetQueryHwCounter(
259     _In_ PNVNET_ADAPTER Adapter,
260     _In_ NDIS_OID Oid,
261     _Out_ PULONG64 Counter)
262 {
263     switch (Oid)
264     {
265         case OID_GEN_XMIT_OK:
266             *Counter = (Adapter->Features & DEV_HAS_STATISTICS_V2)
267                        ? Adapter->Statistics.HwTxFrame
268                        : (Adapter->Statistics.HwTxZeroReXmt +
269                           Adapter->Statistics.HwTxOneReXmt +
270                           Adapter->Statistics.HwTxManyReXmt);
271             break;
272         case OID_GEN_RCV_OK:
273             *Counter = (Adapter->Statistics.HwRxUnicast +
274                         Adapter->Statistics.HwRxMulticast +
275                         Adapter->Statistics.HwRxBroadcast);
276             break;
277         case OID_GEN_XMIT_ERROR:
278             *Counter = (Adapter->Statistics.HwTxRetryErr +
279                         Adapter->Statistics.HwTxLateCol +
280                         Adapter->Statistics.HwTxUnderflow +
281                         Adapter->Statistics.HwTxLossCarrier +
282                         Adapter->Statistics.HwTxExcessDef);
283             break;
284         case OID_GEN_RCV_ERROR:
285             *Counter = (Adapter->Statistics.HwRxFrameAlignErr +
286                         Adapter->Statistics.HwRxLenErr +
287                         Adapter->Statistics.HwRxRunt +
288                         Adapter->Statistics.HwRxFrameTooLong +
289                         Adapter->Statistics.HwRxFCSErr +
290                         Adapter->Statistics.HwRxFrameErr +
291                         Adapter->Statistics.HwRxExtraByte +
292                         Adapter->Statistics.HwRxLateCol);
293             break;
294         case OID_GEN_RCV_NO_BUFFER:
295             *Counter = (Adapter->Statistics.HwRxDropFrame +
296                         Adapter->Statistics.HwRxOverflow +
297                         Adapter->Statistics.ReceiveIrqNoBuffers);
298             break;
299         case OID_GEN_DIRECTED_FRAMES_RCV:
300             *Counter = Adapter->Statistics.HwRxUnicast;
301             break;
302         case OID_GEN_RCV_CRC_ERROR:
303             *Counter = Adapter->Statistics.HwRxFCSErr;
304             break;
305         case OID_802_3_RCV_ERROR_ALIGNMENT:
306             *Counter = Adapter->Statistics.HwRxFrameErr;
307             break;
308         case OID_802_3_XMIT_ONE_COLLISION:
309             *Counter = Adapter->Statistics.HwTxOneReXmt;
310             break;
311         case OID_802_3_XMIT_MORE_COLLISIONS:
312             *Counter = Adapter->Statistics.HwTxManyReXmt;
313             break;
314         case OID_802_3_XMIT_DEFERRED:
315             *Counter = Adapter->Statistics.HwTxDef;
316             break;
317         case OID_802_3_XMIT_MAX_COLLISIONS:
318             *Counter = Adapter->Statistics.HwTxRetryErr;
319             break;
320         case OID_802_3_RCV_OVERRUN:
321             *Counter = Adapter->Statistics.HwRxOverflow;
322             break;
323         case OID_802_3_XMIT_UNDERRUN:
324             *Counter = Adapter->Statistics.HwTxUnderflow;
325             break;
326         case OID_802_3_XMIT_HEARTBEAT_FAILURE:
327             *Counter = Adapter->Statistics.HwTxZeroReXmt;
328             break;
329         case OID_802_3_XMIT_TIMES_CRS_LOST:
330             *Counter = Adapter->Statistics.HwTxLossCarrier;
331             break;
332         case OID_802_3_XMIT_LATE_COLLISIONS:
333             *Counter = Adapter->Statistics.HwTxLateCol;
334             break;
335 
336         default:
337             UNREACHABLE;
338             break;
339     }
340 }
341 
342 static
343 VOID
344 NvNetQuerySoftwareCounter(
345     _In_ PNVNET_ADAPTER Adapter,
346     _In_ NDIS_OID Oid,
347     _Out_ PULONG64 Counter)
348 {
349     switch (Oid)
350     {
351         case OID_GEN_XMIT_OK:
352             *Counter = Adapter->Statistics.TransmitOk;
353             break;
354         case OID_GEN_RCV_OK:
355             *Counter = Adapter->Statistics.ReceiveOk;
356             break;
357         case OID_GEN_XMIT_ERROR:
358             *Counter = Adapter->Statistics.TransmitErrors;
359             break;
360         case OID_GEN_RCV_ERROR:
361             *Counter = Adapter->Statistics.ReceiveErrors;
362             break;
363         case OID_GEN_RCV_NO_BUFFER:
364             *Counter = Adapter->Statistics.ReceiveNoBuffers;
365             break;
366         case OID_GEN_DIRECTED_FRAMES_RCV:
367             *Counter = 0;
368             break;
369         case OID_GEN_RCV_CRC_ERROR:
370             *Counter = Adapter->Statistics.ReceiveCrcErrors;
371             break;
372         case OID_802_3_RCV_ERROR_ALIGNMENT:
373             *Counter = Adapter->Statistics.ReceiveAlignmentErrors;
374             break;
375         case OID_802_3_XMIT_ONE_COLLISION:
376             *Counter = Adapter->Statistics.TransmitOneRetry;
377             break;
378         case OID_802_3_XMIT_MORE_COLLISIONS:
379             *Counter = (Adapter->Statistics.TransmitOk -
380                         Adapter->Statistics.TransmitOneRetry -
381                         Adapter->Statistics.TransmitZeroRetry);
382             break;
383         case OID_802_3_XMIT_DEFERRED:
384             *Counter = Adapter->Statistics.TransmitDeferred;
385             break;
386         case OID_802_3_XMIT_MAX_COLLISIONS:
387             *Counter = Adapter->Statistics.TransmitExcessiveCollisions;
388             break;
389         case OID_802_3_RCV_OVERRUN:
390             *Counter = Adapter->Statistics.ReceiveOverrunErrors;
391             break;
392         case OID_802_3_XMIT_UNDERRUN:
393             *Counter = Adapter->Statistics.TransmitUnderrunErrors;
394             break;
395         case OID_802_3_XMIT_HEARTBEAT_FAILURE:
396             *Counter = Adapter->Statistics.TransmitZeroRetry;
397             break;
398         case OID_802_3_XMIT_TIMES_CRS_LOST:
399             *Counter = Adapter->Statistics.TransmitLostCarrierSense;
400             break;
401         case OID_802_3_XMIT_LATE_COLLISIONS:
402             *Counter = Adapter->Statistics.TransmitLateCollisions;
403             break;
404 
405         default:
406             UNREACHABLE;
407             break;
408     }
409 }
410 
411 static
412 NDIS_STATUS
413 NvNetFillPowerManagementCapabilities(
414     _In_ PNVNET_ADAPTER Adapter,
415     _Out_ PNDIS_PNP_CAPABILITIES Capabilities)
416 {
417     Capabilities->WakeUpCapabilities.MinMagicPacketWakeUp =
418     Capabilities->WakeUpCapabilities.MinPatternWakeUp =
419     Capabilities->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateD3;
420 
421     /* All hardware is PM-aware */
422     return NDIS_STATUS_SUCCESS;
423 }
424 
425 static
426 ULONG
427 BuildFrameSignature(
428     _In_ PNVNET_WAKE_FRAME WakeFrame)
429 {
430     ULONG i, j, Crc;
431 
432     Crc = 0xFFFFFFFF;
433     for (i = 0; i < sizeof(WakeFrame->WakeUpPattern); ++i)
434     {
435         if (WakeFrame->PatternMask.AsUCHAR[i / 8] & (1 << (i % 8)))
436         {
437             Crc ^= WakeFrame->WakeUpPattern[i];
438             for (j = 8; j > 0; --j)
439             {
440                 Crc = (Crc >> 1) ^ (-(LONG)(Crc & 1) & 0xEDB88320);
441             }
442         }
443     }
444 
445     return ~Crc;
446 }
447 
448 static
449 VOID
450 WriteWakeFrame(
451     _In_ PNVNET_ADAPTER Adapter,
452     _In_ PNVNET_WAKE_FRAME WakeFrame,
453     _In_ ULONG FrameNumber)
454 {
455     ULONG Offset = FrameNumber * 5 * sizeof(ULONG);
456 
457     if (FrameNumber >= NV_WAKEUPPATTERNS)
458     {
459         Offset += NV_PATTERN_V2_OFFSET;
460     }
461 
462     NV_WRITE(Adapter, NvRegPatternCrc + Offset, BuildFrameSignature(WakeFrame));
463     NV_WRITE(Adapter, NvRegPatternMask0 + Offset, WakeFrame->PatternMask.AsULONG[0]);
464     NV_WRITE(Adapter, NvRegPatternMask1 + Offset, WakeFrame->PatternMask.AsULONG[1]);
465     NV_WRITE(Adapter, NvRegPatternMask2 + Offset, WakeFrame->PatternMask.AsULONG[2]);
466     NV_WRITE(Adapter, NvRegPatternMask3 + Offset, WakeFrame->PatternMask.AsULONG[3]);
467 }
468 
469 static
470 ULONG
471 FrameNumberToWakeUpMask(
472     _In_ ULONG FrameNumber)
473 {
474     if (FrameNumber < 5)
475         return 0x10000 << FrameNumber;
476     else
477         return 0;
478 }
479 
480 static
481 ULONG
482 FrameNumberToPowerMask(
483     _In_ ULONG FrameNumber)
484 {
485     switch (FrameNumber)
486     {
487         case 5:
488             return NVREG_POWERSTATE2_WAKEUPPAT_5;
489         case 6:
490             return NVREG_POWERSTATE2_WAKEUPPAT_6;
491         case 7:
492             return NVREG_POWERSTATE2_WAKEUPPAT_7;
493 
494         default:
495             return 0;
496     }
497 }
498 
499 VOID
500 NvNetSetPowerState(
501     _In_ PNVNET_ADAPTER Adapter,
502     _In_ NDIS_DEVICE_POWER_STATE NewPowerState,
503     _In_ ULONG WakeFlags)
504 {
505     ULONG i, PowerState, PowerState2, WakeUpFlags;
506 
507     NV_READ(Adapter, NvRegPowerCap);
508 
509     WakeUpFlags = 0;
510     PowerState2 = 0;
511     if (Adapter->Features & DEV_HAS_POWER_CNTRL)
512     {
513         PowerState2 = NV_READ(Adapter, NvRegPowerState2);
514         PowerState2 &= ~(NVREG_POWERSTATE2_WAKEUPPAT_5 |
515                          NVREG_POWERSTATE2_WAKEUPPAT_6 |
516                          NVREG_POWERSTATE2_WAKEUPPAT_7);
517     }
518 
519     if (NewPowerState != NdisDeviceStateD0)
520     {
521         ULONG FramesEnabled = 0;
522 
523         if (WakeFlags & NDIS_PNP_WAKE_UP_PATTERN_MATCH)
524             WakeUpFlags |= NVREG_WAKEUPFLAGS_ENABLE_MAGPAT;
525         if (WakeFlags & NDIS_PNP_WAKE_UP_LINK_CHANGE)
526             WakeUpFlags |= NVREG_WAKEUPFLAGS_ENABLE_LINKCHANGE;
527         if (WakeFlags & NDIS_PNP_WAKE_UP_MAGIC_PACKET)
528         {
529             WakeUpFlags |= NVREG_WAKEUPFLAGS_ENABLE_WAKEUPPAT;
530 
531             for (i = 0; i < RTL_NUMBER_OF(Adapter->WakeFrames); ++i)
532             {
533                 PNVNET_WAKE_FRAME WakeFrame = Adapter->WakeFrames[i];
534 
535                 if (!WakeFrame)
536                     continue;
537 
538                 WriteWakeFrame(Adapter, WakeFrame, i);
539 
540                 PowerState2 |= FrameNumberToPowerMask(i);
541                 WakeUpFlags |= FrameNumberToWakeUpMask(i);
542 
543                 ++FramesEnabled;
544             }
545         }
546 
547         if (WakeUpFlags)
548         {
549             if (!(Adapter->Flags & NV_MAC_IN_USE))
550             {
551                 PowerState2 &= ~NVREG_POWERSTATE2_GATE_CLOCKS;
552                 PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCK_3;
553 
554                 if (!FramesEnabled && (WakeUpFlags & NVREG_WAKEUPFLAGS_ENABLE_LINKCHANGE))
555                     PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCK_1;
556                 if (FramesEnabled < NV_WAKEUPMASKENTRIES)
557                     PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCK_2;
558             }
559 
560             NvNetStartReceiver(Adapter);
561         }
562         else
563         {
564             if (!(Adapter->Flags & NV_MAC_IN_USE))
565                 PowerState2 |= NVREG_POWERSTATE2_GATE_CLOCKS;
566         }
567     }
568 
569     NdisStallExecution(NV_POWER_STALL);
570 
571     NV_WRITE(Adapter, NvRegWakeUpFlags, WakeUpFlags);
572     if (Adapter->Features & DEV_HAS_POWER_CNTRL)
573     {
574         NV_WRITE(Adapter, NvRegPowerState2, PowerState2);
575     }
576 
577     NV_WRITE(Adapter, NvRegPowerState,
578              NV_READ(Adapter, NvRegPowerState) | NVREG_POWERSTATE_POWEREDUP);
579     for (i = 0; i < NV_POWER_ATTEMPTS; ++i)
580     {
581         ULONG State = NV_READ(Adapter, NvRegPowerState);
582 
583         if (!(State & NVREG_POWERSTATE_POWEREDUP))
584             break;
585 
586         NV_WRITE(Adapter, NvRegPowerState, State | NVREG_POWERSTATE_POWEREDUP);
587 
588         NdisStallExecution(NV_POWER_DELAY);
589     }
590 
591     PowerState = NewPowerState - 1;
592     if (WakeUpFlags)
593     {
594         PowerState |= NVREG_POWERSTATE_VALID;
595     }
596     NV_WRITE(Adapter, NvRegPowerState, PowerState);
597 }
598 
599 static
600 CODE_SEG("PAGE")
601 VOID
602 NTAPI
603 NvNetPowerWorker(
604     _In_ PNDIS_WORK_ITEM WorkItem,
605     _In_opt_ PVOID Context)
606 {
607     PNVNET_ADAPTER Adapter = Context;
608 
609     UNREFERENCED_PARAMETER(WorkItem);
610 
611     PAGED_CODE();
612 
613     if (Adapter->PowerStatePending == NdisDeviceStateD0)
614     {
615         NvNetSetPowerState(Adapter, NdisDeviceStateD0, 0);
616 
617         NT_VERIFY(NvNetInitNIC(Adapter, TRUE) == NDIS_STATUS_SUCCESS);
618 
619         NvNetStartAdapter(Adapter);
620 
621         NvNetApplyPacketFilter(Adapter);
622     }
623     else
624     {
625         NvNetPauseProcessing(Adapter);
626 
627         NvNetStopAdapter(Adapter);
628 
629         NvNetIdleTransmitter(Adapter, FALSE);
630         NvNetStopTransmitter(Adapter);
631         NvNetStopReceiver(Adapter);
632         NV_WRITE(Adapter, NvRegTxRxControl,
633                  Adapter->TxRxControl | NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET);
634         NdisStallExecution(NV_TXRX_RESET_DELAY);
635 
636         NvNetFlushTransmitQueue(Adapter, NDIS_STATUS_FAILURE);
637 
638         NvNetSetPowerState(Adapter, Adapter->PowerStatePending, Adapter->WakeFlags);
639     }
640 
641     NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS);
642 }
643 
644 static
645 NDIS_STATUS
646 NvNetSetPower(
647     _In_ PNVNET_ADAPTER Adapter,
648     _In_ NDIS_DEVICE_POWER_STATE NewPowerState)
649 {
650     Adapter->PowerStatePending = NewPowerState;
651 
652     NdisInitializeWorkItem(&Adapter->PowerWorkItem, NvNetPowerWorker, Adapter);
653     NdisScheduleWorkItem(&Adapter->PowerWorkItem);
654 
655     return NDIS_STATUS_PENDING;
656 }
657 
658 static
659 NDIS_STATUS
660 NvNetAddWakeUpPattern(
661     _In_ PNVNET_ADAPTER Adapter,
662     _In_ PNDIS_PM_PACKET_PATTERN Pattern)
663 {
664     ULONG FrameNumber;
665     NDIS_STATUS Status;
666     PNVNET_WAKE_FRAME WakeFrame;
667 
668     if (!_BitScanForward(&FrameNumber, Adapter->WakeFrameBitmap))
669     {
670         return NDIS_STATUS_RESOURCES;
671     }
672 
673     Status = NdisAllocateMemoryWithTag((PVOID*)&WakeFrame, sizeof(*WakeFrame), NVNET_TAG);
674     if (Status != NDIS_STATUS_SUCCESS)
675     {
676         return NDIS_STATUS_RESOURCES;
677     }
678 
679     Adapter->WakeFrameBitmap &= ~(1 << FrameNumber);
680 
681     NdisZeroMemory(WakeFrame, sizeof(*WakeFrame));
682     NdisMoveMemory(&WakeFrame->PatternMask,
683                    (PUCHAR)Pattern + sizeof(NDIS_PM_PACKET_PATTERN),
684                    min(Pattern->MaskSize, 16));
685     NdisMoveMemory(&WakeFrame->WakeUpPattern,
686                    (PUCHAR)Pattern + Pattern->PatternOffset,
687                    min(Pattern->PatternSize, 128));
688     Adapter->WakeFrames[FrameNumber] = WakeFrame;
689 
690     /* TODO: VLAN frame translation */
691 
692     return NDIS_STATUS_SUCCESS;
693 }
694 
695 static
696 BOOLEAN
697 NvEqualMemory(
698     _In_reads_bytes_(Length) PVOID Destination,
699     _In_reads_bytes_(Length) PVOID Source,
700     _In_ ULONG Length)
701 {
702     ULONG i;
703     PUCHAR Src, Dest;
704 
705     Src = Source;
706     Dest = Destination;
707     for (i = 0; i < Length; ++i)
708     {
709         if (Src[i] != Dest[i])
710             return FALSE;
711     }
712 
713     return TRUE;
714 }
715 /* 'memcmp' is unavailable for some reason */
716 #undef NdisEqualMemory
717 #define NdisEqualMemory NvEqualMemory
718 
719 static
720 NDIS_STATUS
721 NvNetRemoveWakeUpPattern(
722     _In_ PNVNET_ADAPTER Adapter,
723     _In_ PNDIS_PM_PACKET_PATTERN Pattern)
724 {
725     ULONG i;
726 
727     for (i = 0; i < RTL_NUMBER_OF(Adapter->WakeFrames); ++i)
728     {
729         PNVNET_WAKE_FRAME WakeFrame = Adapter->WakeFrames[i];
730 
731         if (!WakeFrame)
732             continue;
733 
734         if (!NdisEqualMemory(&WakeFrame->PatternMask,
735                              (PUCHAR)Pattern + sizeof(NDIS_PM_PACKET_PATTERN),
736                              min(Pattern->MaskSize, 16)))
737         {
738             continue;
739         }
740 
741         if (!NdisEqualMemory(&WakeFrame->WakeUpPattern,
742                              (PUCHAR)Pattern + Pattern->PatternOffset,
743                              min(Pattern->PatternSize, 128)))
744         {
745             continue;
746         }
747 
748         NdisFreeMemory(WakeFrame, sizeof(*WakeFrame), 0);
749 
750         Adapter->WakeFrameBitmap |= (1 << i);
751         Adapter->WakeFrames[i] = NULL;
752 
753         return NDIS_STATUS_SUCCESS;
754     }
755 
756     return NDIS_STATUS_INVALID_DATA;
757 }
758 
759 static
760 ULONG
761 NvNetGetWakeUp(
762     _In_ PNVNET_ADAPTER Adapter)
763 {
764     return Adapter->WakeFlags & (NDIS_PNP_WAKE_UP_MAGIC_PACKET |
765                                  NDIS_PNP_WAKE_UP_PATTERN_MATCH |
766                                  NDIS_PNP_WAKE_UP_LINK_CHANGE);
767 }
768 
769 static
770 VOID
771 NvNetEnableWakeUp(
772     _In_ PNVNET_ADAPTER Adapter,
773     _In_ ULONG Flags)
774 {
775     Adapter->WakeFlags = Flags;
776 }
777 
778 static
779 NDIS_STATUS
780 NvNetGetTcpTaskOffload(
781     _In_ PNVNET_ADAPTER Adapter,
782     _In_ PNDIS_TASK_OFFLOAD_HEADER TaskOffloadHeader,
783     _In_ ULONG InformationBufferLength,
784     _Out_ PULONG BytesWritten,
785     _Out_ PULONG BytesNeeded)
786 {
787     ULONG InfoLength;
788     PNDIS_TASK_OFFLOAD TaskOffload;
789 
790     if (!(Adapter->Flags & (NV_SEND_CHECKSUM | NV_SEND_LARGE_SEND)))
791     {
792         *BytesWritten = 0;
793         *BytesNeeded = 0;
794         return NDIS_STATUS_NOT_SUPPORTED;
795     }
796 
797     InfoLength = sizeof(NDIS_TASK_OFFLOAD_HEADER);
798     if (Adapter->Flags & NV_SEND_CHECKSUM)
799     {
800         InfoLength += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) +
801                       sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
802     }
803     if (Adapter->Flags & NV_SEND_LARGE_SEND)
804     {
805         InfoLength += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) +
806                       sizeof(NDIS_TASK_TCP_LARGE_SEND);
807     }
808 
809     if (InformationBufferLength < InfoLength)
810     {
811         *BytesWritten = 0;
812         *BytesNeeded = InfoLength;
813         return NDIS_STATUS_BUFFER_TOO_SHORT;
814     }
815 
816     if ((TaskOffloadHeader->EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation) &&
817         (TaskOffloadHeader->EncapsulationFormat.Encapsulation != UNSPECIFIED_Encapsulation ||
818          TaskOffloadHeader->EncapsulationFormat.EncapsulationHeaderSize != sizeof(ETH_HEADER)))
819     {
820         *BytesWritten = 0;
821         *BytesNeeded = 0;
822         return NDIS_STATUS_NOT_SUPPORTED;
823     }
824     if (TaskOffloadHeader->Version != NDIS_TASK_OFFLOAD_VERSION)
825     {
826         *BytesWritten = 0;
827         *BytesNeeded = 0;
828         return NDIS_STATUS_NOT_SUPPORTED;
829     }
830 
831     TaskOffloadHeader->OffsetFirstTask = sizeof(NDIS_TASK_OFFLOAD_HEADER);
832     TaskOffload = (PNDIS_TASK_OFFLOAD)(TaskOffloadHeader + 1);
833     if (Adapter->Flags & NV_SEND_CHECKSUM)
834     {
835         PNDIS_TASK_TCP_IP_CHECKSUM ChecksumTask;
836 
837         TaskOffload->Size = sizeof(NDIS_TASK_OFFLOAD);
838         TaskOffload->Version = NDIS_TASK_OFFLOAD_VERSION;
839         TaskOffload->Task = TcpIpChecksumNdisTask;
840         TaskOffload->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
841         TaskOffload->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) +
842                                       sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
843 
844         ChecksumTask = (PNDIS_TASK_TCP_IP_CHECKSUM)TaskOffload->TaskBuffer;
845         NdisZeroMemory(ChecksumTask, sizeof(*ChecksumTask));
846 
847         ChecksumTask->V4Transmit.IpOptionsSupported = 1;
848         ChecksumTask->V4Transmit.TcpOptionsSupported = 1;
849         ChecksumTask->V4Transmit.TcpChecksum = 1;
850         ChecksumTask->V4Transmit.UdpChecksum = 1;
851         ChecksumTask->V4Transmit.IpChecksum = 1;
852 
853         ChecksumTask->V4Receive.IpOptionsSupported = 1;
854         ChecksumTask->V4Receive.TcpOptionsSupported = 1;
855         ChecksumTask->V4Receive.TcpChecksum = 1;
856         ChecksumTask->V4Receive.UdpChecksum = 1;
857         ChecksumTask->V4Receive.IpChecksum = 1;
858 
859         TaskOffload = (PNDIS_TASK_OFFLOAD)(ChecksumTask + 1);
860     }
861     if (Adapter->Flags & NV_SEND_LARGE_SEND)
862     {
863         PNDIS_TASK_TCP_LARGE_SEND LargeSendTask;
864 
865         TaskOffload->Size = sizeof(NDIS_TASK_OFFLOAD);
866         TaskOffload->Version = NDIS_TASK_OFFLOAD_VERSION;
867         TaskOffload->Task = TcpLargeSendNdisTask;
868         TaskOffload->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND);
869         TaskOffload->OffsetNextTask = 0;
870 
871         LargeSendTask = (PNDIS_TASK_TCP_LARGE_SEND)TaskOffload->TaskBuffer;
872         LargeSendTask->Version = NDIS_TASK_TCP_LARGE_SEND_V0;
873         LargeSendTask->MinSegmentCount = NVNET_MINIMUM_LSO_SEGMENT_COUNT;
874         LargeSendTask->MaxOffLoadSize = NVNET_MAXIMUM_LSO_FRAME_SIZE;
875         LargeSendTask->IpOptions = TRUE;
876         LargeSendTask->TcpOptions = TRUE;
877     }
878     TaskOffload->OffsetNextTask = 0;
879 
880     *BytesWritten = InfoLength;
881     *BytesNeeded = 0;
882 
883     return NDIS_STATUS_SUCCESS;
884 }
885 
886 static
887 NDIS_STATUS
888 NvNetSetTcpTaskOffload(
889     _Inout_ PNVNET_ADAPTER Adapter,
890     _In_ PNDIS_TASK_OFFLOAD_HEADER TaskOffloadHeader,
891     _In_ PULONG BytesRead)
892 {
893     ULONG Offset;
894     PNDIS_TASK_OFFLOAD TaskOffload;
895 
896     if (TaskOffloadHeader->Version != NDIS_TASK_OFFLOAD_VERSION)
897     {
898         return NDIS_STATUS_NOT_SUPPORTED;
899     }
900 
901     Adapter->IpHeaderOffset = TaskOffloadHeader->EncapsulationFormat.EncapsulationHeaderSize;
902 
903     TaskOffload = (PNDIS_TASK_OFFLOAD)TaskOffloadHeader;
904     Offset = TaskOffloadHeader->OffsetFirstTask;
905 
906     while (Offset)
907     {
908         *BytesRead += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer);
909 
910         TaskOffload = (PNDIS_TASK_OFFLOAD)((PUCHAR)TaskOffload + Offset);
911         switch (TaskOffload->Task)
912         {
913             case TcpIpChecksumNdisTask:
914             {
915                 PNDIS_TASK_TCP_IP_CHECKSUM Task;
916 
917                 *BytesRead += sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
918 
919                 if (!(Adapter->Flags & NV_SEND_CHECKSUM))
920                 {
921                     return NDIS_STATUS_NOT_SUPPORTED;
922                 }
923 
924                 Task = (PNDIS_TASK_TCP_IP_CHECKSUM)TaskOffload->TaskBuffer;
925 
926                 Adapter->Offload.SendTcpChecksum = Task->V4Transmit.TcpChecksum;
927                 Adapter->Offload.SendUdpChecksum = Task->V4Transmit.UdpChecksum;
928                 Adapter->Offload.SendIpChecksum = Task->V4Transmit.IpChecksum;
929 
930                 Adapter->Offload.ReceiveTcpChecksum = Task->V4Receive.TcpChecksum;
931                 Adapter->Offload.ReceiveUdpChecksum = Task->V4Receive.UdpChecksum;
932                 Adapter->Offload.ReceiveIpChecksum = Task->V4Receive.IpChecksum;
933                 break;
934             }
935 
936             case TcpLargeSendNdisTask:
937             {
938                 PNDIS_TASK_TCP_LARGE_SEND Task;
939 
940                 if (!(Adapter->Flags & NV_SEND_LARGE_SEND))
941                 {
942                     return NDIS_STATUS_NOT_SUPPORTED;
943                 }
944 
945                 if ((TaskOffloadHeader->
946                      EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation) &&
947                     (TaskOffloadHeader->
948                      EncapsulationFormat.Encapsulation != UNSPECIFIED_Encapsulation ||
949                      TaskOffloadHeader->
950                      EncapsulationFormat.EncapsulationHeaderSize != sizeof(ETH_HEADER)))
951                 {
952                     return NDIS_STATUS_NOT_SUPPORTED;
953                 }
954 
955                 *BytesRead += sizeof(NDIS_TASK_TCP_LARGE_SEND);
956 
957                 Task = (PNDIS_TASK_TCP_LARGE_SEND)TaskOffload->TaskBuffer;
958 
959                 if (Task->MinSegmentCount != NVNET_MINIMUM_LSO_SEGMENT_COUNT)
960                     return NDIS_STATUS_NOT_SUPPORTED;
961 
962                 if (Task->MaxOffLoadSize > NVNET_MAXIMUM_LSO_FRAME_SIZE)
963                     return NDIS_STATUS_NOT_SUPPORTED;
964 
965                 /* Nothing to do */
966                 break;
967             }
968 
969             default:
970                 break;
971         }
972 
973         Offset = TaskOffload->OffsetNextTask;
974     }
975 
976     NdisAcquireSpinLock(&Adapter->Send.Lock);
977 
978     if (Adapter->Offload.ReceiveTcpChecksum ||
979         Adapter->Offload.ReceiveUdpChecksum ||
980         Adapter->Offload.ReceiveIpChecksum)
981     {
982         Adapter->TxRxControl |= NVREG_TXRXCTL_RXCHECK;
983     }
984     else
985     {
986         Adapter->TxRxControl &= ~NVREG_TXRXCTL_RXCHECK;
987     }
988     NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl);
989 
990     NdisReleaseSpinLock(&Adapter->Send.Lock);
991 
992     return NDIS_STATUS_SUCCESS;
993 }
994 
995 NDIS_STATUS
996 NTAPI
997 MiniportQueryInformation(
998     _In_ NDIS_HANDLE MiniportAdapterContext,
999     _In_ NDIS_OID Oid,
1000     _In_ PVOID InformationBuffer,
1001     _In_ ULONG InformationBufferLength,
1002     _Out_ PULONG BytesWritten,
1003     _Out_ PULONG BytesNeeded)
1004 {
1005     PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
1006     NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1007     ULONG InfoLength;
1008     PVOID InfoPtr;
1009     union _GENERIC_INFORMATION
1010     {
1011         USHORT Ushort;
1012         ULONG Ulong;
1013         ULONG64 Ulong64;
1014         NDIS_MEDIUM Medium;
1015         NDIS_HARDWARE_STATUS Status;
1016         NDIS_DEVICE_POWER_STATE PowerState;
1017     } GenericInfo;
1018 
1019     InfoLength = sizeof(ULONG);
1020     InfoPtr = &GenericInfo;
1021 
1022     switch (Oid)
1023     {
1024         case OID_GEN_SUPPORTED_LIST:
1025             InfoPtr = (PVOID)&NvpSupportedOidList;
1026             InfoLength = sizeof(NvpSupportedOidList);
1027             break;
1028 
1029         case OID_GEN_HARDWARE_STATUS:
1030             InfoLength = sizeof(NDIS_HARDWARE_STATUS);
1031             GenericInfo.Status = NdisHardwareStatusReady;
1032             break;
1033 
1034         case OID_GEN_MEDIA_SUPPORTED:
1035         case OID_GEN_MEDIA_IN_USE:
1036         {
1037             InfoLength = sizeof(NDIS_MEDIUM);
1038             GenericInfo.Medium = NdisMedium802_3;
1039             break;
1040         }
1041 
1042         case OID_GEN_CURRENT_LOOKAHEAD:
1043         case OID_GEN_MAXIMUM_LOOKAHEAD:
1044         {
1045             GenericInfo.Ulong = Adapter->MaximumFrameSize - sizeof(ETH_HEADER);
1046             break;
1047         }
1048 
1049         case OID_GEN_MAXIMUM_FRAME_SIZE:
1050         {
1051             GenericInfo.Ulong = Adapter->MaximumFrameSize;
1052             break;
1053         }
1054 
1055         case OID_GEN_LINK_SPEED:
1056         {
1057             GenericInfo.Ulong = NvNetGetLinkSpeed(Adapter) * 10000;
1058             break;
1059         }
1060 
1061         case OID_GEN_TRANSMIT_BUFFER_SPACE:
1062         {
1063             /* TODO: Change this later, once the driver can handle multipacket sends */
1064             GenericInfo.Ulong = Adapter->MaximumFrameSize;
1065             break;
1066         }
1067 
1068         case OID_GEN_RECEIVE_BUFFER_SPACE:
1069         {
1070             GenericInfo.Ulong = Adapter->MaximumFrameSize * NVNET_RECEIVE_DESCRIPTORS;
1071         }
1072 
1073         case OID_GEN_MAXIMUM_TOTAL_SIZE:
1074         case OID_GEN_TRANSMIT_BLOCK_SIZE:
1075         case OID_GEN_RECEIVE_BLOCK_SIZE:
1076         {
1077             GenericInfo.Ulong = Adapter->MaximumFrameSize;
1078             break;
1079         }
1080 
1081         case OID_GEN_VENDOR_ID:
1082         {
1083             GenericInfo.Ulong = 0;
1084             GenericInfo.Ulong |= (Adapter->PermanentMacAddress[0] << 16);
1085             GenericInfo.Ulong |= (Adapter->PermanentMacAddress[1] << 8);
1086             GenericInfo.Ulong |= (Adapter->PermanentMacAddress[2] & 0xFF);
1087             break;
1088         }
1089 
1090         case OID_GEN_DRIVER_VERSION:
1091         {
1092             InfoLength = sizeof(USHORT);
1093             GenericInfo.Ushort = (NDIS_MINIPORT_MAJOR_VERSION << 8) | NDIS_MINIPORT_MINOR_VERSION;
1094             break;
1095         }
1096 
1097         case OID_GEN_VENDOR_DESCRIPTION:
1098         {
1099             static const CHAR VendorDesc[] = "nVidia nForce Ethernet Controller";
1100             InfoPtr = (PVOID)&VendorDesc;
1101             InfoLength = sizeof(VendorDesc);
1102             break;
1103         }
1104 
1105         case OID_GEN_CURRENT_PACKET_FILTER:
1106         {
1107             GenericInfo.Ulong = Adapter->PacketFilter;
1108             break;
1109         }
1110 
1111         case OID_GEN_MAC_OPTIONS:
1112         {
1113             GenericInfo.Ulong = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
1114                                 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
1115                                 NDIS_MAC_OPTION_NO_LOOPBACK;
1116 
1117             if (Adapter->Flags & NV_PACKET_PRIORITY)
1118                 GenericInfo.Ulong |= NDIS_MAC_OPTION_8021P_PRIORITY;
1119             if (Adapter->Flags & NV_VLAN_TAGGING)
1120                 GenericInfo.Ulong |= NDIS_MAC_OPTION_8021Q_VLAN;
1121             break;
1122         }
1123 
1124         case OID_GEN_MEDIA_CONNECT_STATUS:
1125         {
1126             GenericInfo.Ulong = Adapter->Connected ? NdisMediaStateConnected
1127                                                    : NdisMediaStateDisconnected;
1128             break;
1129         }
1130 
1131         case OID_GEN_MAXIMUM_SEND_PACKETS:
1132         {
1133             /* TODO: Multipacket sends */
1134             GenericInfo.Ulong = 1;
1135             break;
1136         }
1137 
1138         case OID_GEN_VENDOR_DRIVER_VERSION:
1139         {
1140             /* 1.0.0 */
1141             GenericInfo.Ulong = 0x100;
1142             break;
1143         }
1144 
1145         case OID_GEN_XMIT_OK:
1146         case OID_GEN_RCV_OK:
1147         case OID_GEN_XMIT_ERROR:
1148         case OID_GEN_RCV_ERROR:
1149         case OID_GEN_RCV_NO_BUFFER:
1150         case OID_GEN_DIRECTED_FRAMES_RCV:
1151         case OID_GEN_RCV_CRC_ERROR:
1152         case OID_802_3_RCV_ERROR_ALIGNMENT:
1153         case OID_802_3_XMIT_ONE_COLLISION:
1154         case OID_802_3_XMIT_MORE_COLLISIONS:
1155         case OID_802_3_XMIT_DEFERRED:
1156         case OID_802_3_XMIT_MAX_COLLISIONS:
1157         case OID_802_3_RCV_OVERRUN:
1158         case OID_802_3_XMIT_UNDERRUN:
1159         case OID_802_3_XMIT_HEARTBEAT_FAILURE:
1160         case OID_802_3_XMIT_TIMES_CRS_LOST:
1161         case OID_802_3_XMIT_LATE_COLLISIONS:
1162         {
1163             if (Adapter->Features & DEV_HAS_STATISTICS_COUNTERS)
1164             {
1165                 NvNetReadStatistics(Adapter);
1166                 NvNetQueryHwCounter(Adapter, Oid, &GenericInfo.Ulong64);
1167             }
1168             else
1169             {
1170                 NvNetQuerySoftwareCounter(Adapter, Oid, &GenericInfo.Ulong64);
1171             }
1172 
1173             *BytesNeeded = sizeof(ULONG64);
1174             if (InformationBufferLength < sizeof(ULONG))
1175             {
1176                 *BytesWritten = 0;
1177                 return NDIS_STATUS_BUFFER_TOO_SHORT;
1178             }
1179             if (InformationBufferLength >= sizeof(ULONG64))
1180             {
1181                 *BytesWritten = sizeof(ULONG64);
1182                 NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG64));
1183             }
1184             else
1185             {
1186                 *BytesWritten = sizeof(ULONG);
1187                 NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG));
1188             }
1189 
1190             return NDIS_STATUS_SUCCESS;
1191         }
1192 
1193         case OID_GEN_TRANSMIT_QUEUE_LENGTH:
1194         {
1195             GenericInfo.Ulong = NVNET_TRANSMIT_BLOCKS - Adapter->Send.TcbSlots;
1196             break;
1197         }
1198 
1199         case OID_802_3_PERMANENT_ADDRESS:
1200         {
1201             InfoPtr = Adapter->PermanentMacAddress;
1202             InfoLength = ETH_LENGTH_OF_ADDRESS;
1203             break;
1204         }
1205 
1206         case OID_802_3_CURRENT_ADDRESS:
1207         {
1208             InfoPtr = Adapter->CurrentMacAddress;
1209             InfoLength = ETH_LENGTH_OF_ADDRESS;
1210             break;
1211         }
1212 
1213         case OID_802_3_MULTICAST_LIST:
1214         {
1215             InfoPtr = Adapter->MulticastList;
1216             InfoLength = Adapter->MulticastListSize * ETH_LENGTH_OF_ADDRESS;
1217             break;
1218         }
1219 
1220         case OID_802_3_MAXIMUM_LIST_SIZE:
1221         {
1222             GenericInfo.Ulong = NVNET_MULTICAST_LIST_SIZE;
1223             break;
1224         }
1225 
1226         case OID_TCP_TASK_OFFLOAD:
1227         {
1228             return NvNetGetTcpTaskOffload(Adapter,
1229                                           InformationBuffer,
1230                                           InformationBufferLength,
1231                                           BytesWritten,
1232                                           BytesWritten);
1233         }
1234 
1235         case OID_PNP_ENABLE_WAKE_UP:
1236         {
1237             GenericInfo.Ulong = NvNetGetWakeUp(Adapter);
1238             break;
1239         }
1240 
1241         case OID_PNP_CAPABILITIES:
1242         {
1243             InfoLength = sizeof(NDIS_PNP_CAPABILITIES);
1244 
1245             if (InformationBufferLength < InfoLength)
1246             {
1247                 *BytesWritten = 0;
1248                 *BytesNeeded = InfoLength;
1249                 return NDIS_STATUS_BUFFER_TOO_SHORT;
1250             }
1251 
1252             *BytesWritten = InfoLength;
1253             *BytesNeeded = 0;
1254             return NvNetFillPowerManagementCapabilities(Adapter, InformationBuffer);
1255         }
1256 
1257         case OID_PNP_QUERY_POWER:
1258         {
1259             return NDIS_STATUS_SUCCESS;
1260         }
1261 
1262         case OID_GEN_VLAN_ID:
1263         {
1264             /* TODO: Implement software VLAN support */
1265             if (!(Adapter->Flags & NV_VLAN_TAGGING))
1266             {
1267                 Status = NDIS_STATUS_NOT_SUPPORTED;
1268                 break;
1269             }
1270 
1271             GenericInfo.Ulong = Adapter->VlanId;
1272             break;
1273         }
1274 
1275         default:
1276             Status = NDIS_STATUS_INVALID_OID;
1277             break;
1278     }
1279 
1280     if (Status == NDIS_STATUS_SUCCESS)
1281     {
1282         if (InfoLength > InformationBufferLength)
1283         {
1284             *BytesWritten = 0;
1285             *BytesNeeded = InfoLength;
1286             Status = NDIS_STATUS_BUFFER_TOO_SHORT;
1287         }
1288         else
1289         {
1290             NdisMoveMemory(InformationBuffer, InfoPtr, InfoLength);
1291             *BytesWritten = InfoLength;
1292             *BytesNeeded = 0;
1293         }
1294     }
1295     else
1296     {
1297         *BytesWritten = 0;
1298         *BytesNeeded = 0;
1299     }
1300 
1301     return Status;
1302 }
1303 
1304 NDIS_STATUS
1305 NTAPI
1306 MiniportSetInformation(
1307     _In_ NDIS_HANDLE MiniportAdapterContext,
1308     _In_ NDIS_OID Oid,
1309     _In_ PVOID InformationBuffer,
1310     _In_ ULONG InformationBufferLength,
1311     _Out_ PULONG BytesRead,
1312     _Out_ PULONG BytesNeeded)
1313 {
1314     PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
1315     NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1316     ULONG GenericUlong;
1317 
1318     *BytesRead = 0;
1319     *BytesNeeded = 0;
1320 
1321     switch (Oid)
1322     {
1323         case OID_802_3_MULTICAST_LIST:
1324         {
1325             if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS)
1326             {
1327                 *BytesNeeded = (InformationBufferLength / ETH_LENGTH_OF_ADDRESS) *
1328                                ETH_LENGTH_OF_ADDRESS;
1329                 Status = NDIS_STATUS_INVALID_LENGTH;
1330                 break;
1331             }
1332 
1333             if (InformationBufferLength > sizeof(Adapter->MulticastList))
1334             {
1335                 *BytesNeeded = sizeof(Adapter->MulticastList);
1336                 Status = NDIS_STATUS_MULTICAST_FULL;
1337                 break;
1338             }
1339 
1340             *BytesRead = InformationBufferLength;
1341             NdisMoveMemory(Adapter->MulticastList, InformationBuffer, InformationBufferLength);
1342 
1343             Adapter->MulticastListSize = InformationBufferLength / ETH_LENGTH_OF_ADDRESS;
1344 
1345             NvNetApplyPacketFilter(Adapter);
1346             break;
1347         }
1348 
1349         case OID_GEN_CURRENT_PACKET_FILTER:
1350         {
1351             if (InformationBufferLength < sizeof(ULONG))
1352             {
1353                 *BytesNeeded = sizeof(ULONG);
1354                 Status = NDIS_STATUS_INVALID_LENGTH;
1355                 break;
1356             }
1357 
1358             *BytesRead = sizeof(ULONG);
1359             NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
1360 
1361             if (GenericUlong & ~NVNET_PACKET_FILTERS)
1362             {
1363                 Status = NDIS_STATUS_NOT_SUPPORTED;
1364                 break;
1365             }
1366 
1367             /* Do not check to see if the filter is the same filter */
1368             Adapter->PacketFilter = GenericUlong;
1369 
1370             NvNetApplyPacketFilter(Adapter);
1371             break;
1372         }
1373 
1374         case OID_GEN_CURRENT_LOOKAHEAD:
1375         {
1376             if (InformationBufferLength < sizeof(ULONG))
1377             {
1378                 *BytesNeeded = sizeof(ULONG);
1379                 Status = NDIS_STATUS_INVALID_LENGTH;
1380                 break;
1381             }
1382 
1383             /* Nothing to do */
1384             *BytesRead = sizeof(ULONG);
1385             break;
1386         }
1387 
1388         case OID_GEN_VLAN_ID:
1389         {
1390             if (InformationBufferLength < sizeof(ULONG))
1391             {
1392                 *BytesNeeded = sizeof(ULONG);
1393                 Status = NDIS_STATUS_INVALID_LENGTH;
1394                 break;
1395             }
1396 
1397             if (!(Adapter->Flags & NV_VLAN_TAGGING))
1398             {
1399                 Status = NDIS_STATUS_NOT_SUPPORTED;
1400                 break;
1401             }
1402 
1403             *BytesRead = sizeof(ULONG);
1404             NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
1405 
1406             if (GenericUlong > NVNET_MAXIMUM_VLAN_ID)
1407             {
1408                 Status = NDIS_STATUS_FAILURE;
1409                 break;
1410             }
1411 
1412             Adapter->VlanId = GenericUlong;
1413             break;
1414         }
1415 
1416         case OID_TCP_TASK_OFFLOAD:
1417         {
1418             if (InformationBufferLength < sizeof(NDIS_TASK_OFFLOAD_HEADER))
1419             {
1420                 *BytesNeeded = sizeof(NDIS_TASK_OFFLOAD_HEADER);
1421                 Status = NDIS_STATUS_INVALID_LENGTH;
1422                 break;
1423             }
1424 
1425             *BytesRead = InformationBufferLength;
1426 
1427             Status = NvNetSetTcpTaskOffload(Adapter, InformationBuffer, BytesRead);
1428             break;
1429         }
1430 
1431         case OID_PNP_ADD_WAKE_UP_PATTERN:
1432         {
1433             if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
1434             {
1435                 *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
1436                 Status = NDIS_STATUS_INVALID_LENGTH;
1437                 break;
1438             }
1439 
1440             *BytesRead = sizeof(NDIS_PM_PACKET_PATTERN);
1441 
1442             Status = NvNetAddWakeUpPattern(Adapter, InformationBuffer);
1443             break;
1444         }
1445 
1446         case OID_PNP_REMOVE_WAKE_UP_PATTERN:
1447         {
1448             if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
1449             {
1450                 *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
1451                 Status = NDIS_STATUS_INVALID_LENGTH;
1452                 break;
1453             }
1454 
1455             *BytesRead = sizeof(NDIS_PM_PACKET_PATTERN);
1456 
1457             Status = NvNetRemoveWakeUpPattern(Adapter, InformationBuffer);
1458             break;
1459         }
1460 
1461         case OID_PNP_ENABLE_WAKE_UP:
1462         {
1463             if (InformationBufferLength < sizeof(ULONG))
1464             {
1465                 *BytesNeeded = sizeof(ULONG);
1466                 Status = NDIS_STATUS_INVALID_LENGTH;
1467                 break;
1468             }
1469 
1470             *BytesRead = sizeof(ULONG);
1471             NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
1472 
1473             NvNetEnableWakeUp(Adapter, GenericUlong);
1474             break;
1475         }
1476 
1477         case OID_PNP_SET_POWER:
1478         {
1479             if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
1480             {
1481                 *BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE);
1482                 Status = NDIS_STATUS_INVALID_LENGTH;
1483                 break;
1484             }
1485 
1486             *BytesRead = sizeof(ULONG);
1487             NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
1488 
1489             if (GenericUlong < NdisDeviceStateD0 || GenericUlong > NdisDeviceStateD3)
1490             {
1491                 Status = NDIS_STATUS_INVALID_DATA;
1492                 break;
1493             }
1494 
1495             Status = NvNetSetPower(Adapter, GenericUlong);
1496             break;
1497         }
1498 
1499         default:
1500             Status = NDIS_STATUS_NOT_SUPPORTED;
1501             break;
1502     }
1503 
1504     return Status;
1505 }
1506