xref: /reactos/drivers/network/dd/nvnet/requests.c (revision 0af84ce1)
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
NvNetGetLinkSpeed(_In_ PNVNET_ADAPTER Adapter)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
PacketFilterToMask(_In_ ULONG PacketFilter)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
NvNetApplyPacketFilter(_In_ PNVNET_ADAPTER Adapter)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
NvNetReadStatistics(_In_ PNVNET_ADAPTER Adapter)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
NvNetQueryHwCounter(_In_ PNVNET_ADAPTER Adapter,_In_ NDIS_OID Oid,_Out_ PULONG64 Counter)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
NvNetQuerySoftwareCounter(_In_ PNVNET_ADAPTER Adapter,_In_ NDIS_OID Oid,_Out_ PULONG64 Counter)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
NvNetFillPowerManagementCapabilities(_In_ PNVNET_ADAPTER Adapter,_Out_ PNDIS_PNP_CAPABILITIES Capabilities)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
BuildFrameSignature(_In_ PNVNET_WAKE_FRAME WakeFrame)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
WriteWakeFrame(_In_ PNVNET_ADAPTER Adapter,_In_ PNVNET_WAKE_FRAME WakeFrame,_In_ ULONG FrameNumber)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
FrameNumberToWakeUpMask(_In_ ULONG FrameNumber)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
FrameNumberToPowerMask(_In_ ULONG FrameNumber)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
NvNetSetPowerState(_In_ PNVNET_ADAPTER Adapter,_In_ NDIS_DEVICE_POWER_STATE NewPowerState,_In_ ULONG WakeFlags)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
NvNetPowerWorker(_In_ PNDIS_WORK_ITEM WorkItem,_In_opt_ PVOID Context)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
NvNetSetPower(_In_ PNVNET_ADAPTER Adapter,_In_ NDIS_DEVICE_POWER_STATE NewPowerState)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
NvNetAddWakeUpPattern(_In_ PNVNET_ADAPTER Adapter,_In_ PNDIS_PM_PACKET_PATTERN Pattern)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 NDIS_STATUS
NvNetRemoveWakeUpPattern(_In_ PNVNET_ADAPTER Adapter,_In_ PNDIS_PM_PACKET_PATTERN Pattern)697 NvNetRemoveWakeUpPattern(
698     _In_ PNVNET_ADAPTER Adapter,
699     _In_ PNDIS_PM_PACKET_PATTERN Pattern)
700 {
701     ULONG i;
702 
703     for (i = 0; i < RTL_NUMBER_OF(Adapter->WakeFrames); ++i)
704     {
705         PNVNET_WAKE_FRAME WakeFrame = Adapter->WakeFrames[i];
706 
707         if (!WakeFrame)
708             continue;
709 
710         if (!NdisEqualMemory(&WakeFrame->PatternMask,
711                              (PUCHAR)Pattern + sizeof(NDIS_PM_PACKET_PATTERN),
712                              min(Pattern->MaskSize, 16)))
713         {
714             continue;
715         }
716 
717         if (!NdisEqualMemory(&WakeFrame->WakeUpPattern,
718                              (PUCHAR)Pattern + Pattern->PatternOffset,
719                              min(Pattern->PatternSize, 128)))
720         {
721             continue;
722         }
723 
724         NdisFreeMemory(WakeFrame, sizeof(*WakeFrame), 0);
725 
726         Adapter->WakeFrameBitmap |= (1 << i);
727         Adapter->WakeFrames[i] = NULL;
728 
729         return NDIS_STATUS_SUCCESS;
730     }
731 
732     return NDIS_STATUS_INVALID_DATA;
733 }
734 
735 static
736 ULONG
NvNetGetWakeUp(_In_ PNVNET_ADAPTER Adapter)737 NvNetGetWakeUp(
738     _In_ PNVNET_ADAPTER Adapter)
739 {
740     return Adapter->WakeFlags & (NDIS_PNP_WAKE_UP_MAGIC_PACKET |
741                                  NDIS_PNP_WAKE_UP_PATTERN_MATCH |
742                                  NDIS_PNP_WAKE_UP_LINK_CHANGE);
743 }
744 
745 static
746 VOID
NvNetEnableWakeUp(_In_ PNVNET_ADAPTER Adapter,_In_ ULONG Flags)747 NvNetEnableWakeUp(
748     _In_ PNVNET_ADAPTER Adapter,
749     _In_ ULONG Flags)
750 {
751     Adapter->WakeFlags = Flags;
752 }
753 
754 static
755 NDIS_STATUS
NvNetGetTcpTaskOffload(_In_ PNVNET_ADAPTER Adapter,_In_ PNDIS_TASK_OFFLOAD_HEADER TaskOffloadHeader,_In_ ULONG InformationBufferLength,_Out_ PULONG BytesWritten,_Out_ PULONG BytesNeeded)756 NvNetGetTcpTaskOffload(
757     _In_ PNVNET_ADAPTER Adapter,
758     _In_ PNDIS_TASK_OFFLOAD_HEADER TaskOffloadHeader,
759     _In_ ULONG InformationBufferLength,
760     _Out_ PULONG BytesWritten,
761     _Out_ PULONG BytesNeeded)
762 {
763     ULONG InfoLength;
764     PNDIS_TASK_OFFLOAD TaskOffload;
765 
766     if (!(Adapter->Flags & (NV_SEND_CHECKSUM | NV_SEND_LARGE_SEND)))
767     {
768         *BytesWritten = 0;
769         *BytesNeeded = 0;
770         return NDIS_STATUS_NOT_SUPPORTED;
771     }
772 
773     InfoLength = sizeof(NDIS_TASK_OFFLOAD_HEADER);
774     if (Adapter->Flags & NV_SEND_CHECKSUM)
775     {
776         InfoLength += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) +
777                       sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
778     }
779     if (Adapter->Flags & NV_SEND_LARGE_SEND)
780     {
781         InfoLength += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) +
782                       sizeof(NDIS_TASK_TCP_LARGE_SEND);
783     }
784 
785     if (InformationBufferLength < InfoLength)
786     {
787         *BytesWritten = 0;
788         *BytesNeeded = InfoLength;
789         return NDIS_STATUS_BUFFER_TOO_SHORT;
790     }
791 
792     if ((TaskOffloadHeader->EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation) &&
793         (TaskOffloadHeader->EncapsulationFormat.Encapsulation != UNSPECIFIED_Encapsulation ||
794          TaskOffloadHeader->EncapsulationFormat.EncapsulationHeaderSize != sizeof(ETH_HEADER)))
795     {
796         *BytesWritten = 0;
797         *BytesNeeded = 0;
798         return NDIS_STATUS_NOT_SUPPORTED;
799     }
800     if (TaskOffloadHeader->Version != NDIS_TASK_OFFLOAD_VERSION)
801     {
802         *BytesWritten = 0;
803         *BytesNeeded = 0;
804         return NDIS_STATUS_NOT_SUPPORTED;
805     }
806 
807     TaskOffloadHeader->OffsetFirstTask = sizeof(NDIS_TASK_OFFLOAD_HEADER);
808     TaskOffload = (PNDIS_TASK_OFFLOAD)(TaskOffloadHeader + 1);
809     if (Adapter->Flags & NV_SEND_CHECKSUM)
810     {
811         PNDIS_TASK_TCP_IP_CHECKSUM ChecksumTask;
812 
813         TaskOffload->Size = sizeof(NDIS_TASK_OFFLOAD);
814         TaskOffload->Version = NDIS_TASK_OFFLOAD_VERSION;
815         TaskOffload->Task = TcpIpChecksumNdisTask;
816         TaskOffload->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
817         TaskOffload->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer) +
818                                       sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
819 
820         ChecksumTask = (PNDIS_TASK_TCP_IP_CHECKSUM)TaskOffload->TaskBuffer;
821         NdisZeroMemory(ChecksumTask, sizeof(*ChecksumTask));
822 
823         ChecksumTask->V4Transmit.IpOptionsSupported = 1;
824         ChecksumTask->V4Transmit.TcpOptionsSupported = 1;
825         ChecksumTask->V4Transmit.TcpChecksum = 1;
826         ChecksumTask->V4Transmit.UdpChecksum = 1;
827         ChecksumTask->V4Transmit.IpChecksum = 1;
828 
829         ChecksumTask->V4Receive.IpOptionsSupported = 1;
830         ChecksumTask->V4Receive.TcpOptionsSupported = 1;
831         ChecksumTask->V4Receive.TcpChecksum = 1;
832         ChecksumTask->V4Receive.UdpChecksum = 1;
833         ChecksumTask->V4Receive.IpChecksum = 1;
834 
835         TaskOffload = (PNDIS_TASK_OFFLOAD)(ChecksumTask + 1);
836     }
837     if (Adapter->Flags & NV_SEND_LARGE_SEND)
838     {
839         PNDIS_TASK_TCP_LARGE_SEND LargeSendTask;
840 
841         TaskOffload->Size = sizeof(NDIS_TASK_OFFLOAD);
842         TaskOffload->Version = NDIS_TASK_OFFLOAD_VERSION;
843         TaskOffload->Task = TcpLargeSendNdisTask;
844         TaskOffload->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND);
845         TaskOffload->OffsetNextTask = 0;
846 
847         LargeSendTask = (PNDIS_TASK_TCP_LARGE_SEND)TaskOffload->TaskBuffer;
848         LargeSendTask->Version = NDIS_TASK_TCP_LARGE_SEND_V0;
849         LargeSendTask->MinSegmentCount = NVNET_MINIMUM_LSO_SEGMENT_COUNT;
850         LargeSendTask->MaxOffLoadSize = NVNET_MAXIMUM_LSO_FRAME_SIZE;
851         LargeSendTask->IpOptions = TRUE;
852         LargeSendTask->TcpOptions = TRUE;
853     }
854     TaskOffload->OffsetNextTask = 0;
855 
856     *BytesWritten = InfoLength;
857     *BytesNeeded = 0;
858 
859     return NDIS_STATUS_SUCCESS;
860 }
861 
862 static
863 NDIS_STATUS
NvNetSetTcpTaskOffload(_Inout_ PNVNET_ADAPTER Adapter,_In_ PNDIS_TASK_OFFLOAD_HEADER TaskOffloadHeader,_In_ PULONG BytesRead)864 NvNetSetTcpTaskOffload(
865     _Inout_ PNVNET_ADAPTER Adapter,
866     _In_ PNDIS_TASK_OFFLOAD_HEADER TaskOffloadHeader,
867     _In_ PULONG BytesRead)
868 {
869     ULONG Offset;
870     PNDIS_TASK_OFFLOAD TaskOffload;
871 
872     if (TaskOffloadHeader->Version != NDIS_TASK_OFFLOAD_VERSION)
873     {
874         return NDIS_STATUS_NOT_SUPPORTED;
875     }
876 
877     Adapter->IpHeaderOffset = TaskOffloadHeader->EncapsulationFormat.EncapsulationHeaderSize;
878 
879     TaskOffload = (PNDIS_TASK_OFFLOAD)TaskOffloadHeader;
880     Offset = TaskOffloadHeader->OffsetFirstTask;
881 
882     while (Offset)
883     {
884         *BytesRead += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer);
885 
886         TaskOffload = (PNDIS_TASK_OFFLOAD)((PUCHAR)TaskOffload + Offset);
887         switch (TaskOffload->Task)
888         {
889             case TcpIpChecksumNdisTask:
890             {
891                 PNDIS_TASK_TCP_IP_CHECKSUM Task;
892 
893                 *BytesRead += sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
894 
895                 if (!(Adapter->Flags & NV_SEND_CHECKSUM))
896                 {
897                     return NDIS_STATUS_NOT_SUPPORTED;
898                 }
899 
900                 Task = (PNDIS_TASK_TCP_IP_CHECKSUM)TaskOffload->TaskBuffer;
901 
902                 Adapter->Offload.SendTcpChecksum = Task->V4Transmit.TcpChecksum;
903                 Adapter->Offload.SendUdpChecksum = Task->V4Transmit.UdpChecksum;
904                 Adapter->Offload.SendIpChecksum = Task->V4Transmit.IpChecksum;
905 
906                 Adapter->Offload.ReceiveTcpChecksum = Task->V4Receive.TcpChecksum;
907                 Adapter->Offload.ReceiveUdpChecksum = Task->V4Receive.UdpChecksum;
908                 Adapter->Offload.ReceiveIpChecksum = Task->V4Receive.IpChecksum;
909                 break;
910             }
911 
912             case TcpLargeSendNdisTask:
913             {
914                 PNDIS_TASK_TCP_LARGE_SEND Task;
915 
916                 if (!(Adapter->Flags & NV_SEND_LARGE_SEND))
917                 {
918                     return NDIS_STATUS_NOT_SUPPORTED;
919                 }
920 
921                 if ((TaskOffloadHeader->
922                      EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation) &&
923                     (TaskOffloadHeader->
924                      EncapsulationFormat.Encapsulation != UNSPECIFIED_Encapsulation ||
925                      TaskOffloadHeader->
926                      EncapsulationFormat.EncapsulationHeaderSize != sizeof(ETH_HEADER)))
927                 {
928                     return NDIS_STATUS_NOT_SUPPORTED;
929                 }
930 
931                 *BytesRead += sizeof(NDIS_TASK_TCP_LARGE_SEND);
932 
933                 Task = (PNDIS_TASK_TCP_LARGE_SEND)TaskOffload->TaskBuffer;
934 
935                 if (Task->MinSegmentCount != NVNET_MINIMUM_LSO_SEGMENT_COUNT)
936                     return NDIS_STATUS_NOT_SUPPORTED;
937 
938                 if (Task->MaxOffLoadSize > NVNET_MAXIMUM_LSO_FRAME_SIZE)
939                     return NDIS_STATUS_NOT_SUPPORTED;
940 
941                 /* Nothing to do */
942                 break;
943             }
944 
945             default:
946                 break;
947         }
948 
949         Offset = TaskOffload->OffsetNextTask;
950     }
951 
952     NdisAcquireSpinLock(&Adapter->Send.Lock);
953 
954     if (Adapter->Offload.ReceiveTcpChecksum ||
955         Adapter->Offload.ReceiveUdpChecksum ||
956         Adapter->Offload.ReceiveIpChecksum)
957     {
958         Adapter->TxRxControl |= NVREG_TXRXCTL_RXCHECK;
959     }
960     else
961     {
962         Adapter->TxRxControl &= ~NVREG_TXRXCTL_RXCHECK;
963     }
964     NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl);
965 
966     NdisReleaseSpinLock(&Adapter->Send.Lock);
967 
968     return NDIS_STATUS_SUCCESS;
969 }
970 
971 NDIS_STATUS
972 NTAPI
MiniportQueryInformation(_In_ NDIS_HANDLE MiniportAdapterContext,_In_ NDIS_OID Oid,_In_ PVOID InformationBuffer,_In_ ULONG InformationBufferLength,_Out_ PULONG BytesWritten,_Out_ PULONG BytesNeeded)973 MiniportQueryInformation(
974     _In_ NDIS_HANDLE MiniportAdapterContext,
975     _In_ NDIS_OID Oid,
976     _In_ PVOID InformationBuffer,
977     _In_ ULONG InformationBufferLength,
978     _Out_ PULONG BytesWritten,
979     _Out_ PULONG BytesNeeded)
980 {
981     PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
982     NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
983     ULONG InfoLength;
984     PVOID InfoPtr;
985     union _GENERIC_INFORMATION
986     {
987         USHORT Ushort;
988         ULONG Ulong;
989         ULONG64 Ulong64;
990         NDIS_MEDIUM Medium;
991         NDIS_HARDWARE_STATUS Status;
992         NDIS_DEVICE_POWER_STATE PowerState;
993     } GenericInfo;
994 
995     InfoLength = sizeof(ULONG);
996     InfoPtr = &GenericInfo;
997 
998     switch (Oid)
999     {
1000         case OID_GEN_SUPPORTED_LIST:
1001             InfoPtr = (PVOID)&NvpSupportedOidList;
1002             InfoLength = sizeof(NvpSupportedOidList);
1003             break;
1004 
1005         case OID_GEN_HARDWARE_STATUS:
1006             InfoLength = sizeof(NDIS_HARDWARE_STATUS);
1007             GenericInfo.Status = NdisHardwareStatusReady;
1008             break;
1009 
1010         case OID_GEN_MEDIA_SUPPORTED:
1011         case OID_GEN_MEDIA_IN_USE:
1012         {
1013             InfoLength = sizeof(NDIS_MEDIUM);
1014             GenericInfo.Medium = NdisMedium802_3;
1015             break;
1016         }
1017 
1018         case OID_GEN_CURRENT_LOOKAHEAD:
1019         case OID_GEN_MAXIMUM_LOOKAHEAD:
1020         {
1021             GenericInfo.Ulong = Adapter->MaximumFrameSize - sizeof(ETH_HEADER);
1022             break;
1023         }
1024 
1025         case OID_GEN_MAXIMUM_FRAME_SIZE:
1026         {
1027             GenericInfo.Ulong = Adapter->MaximumFrameSize;
1028             break;
1029         }
1030 
1031         case OID_GEN_LINK_SPEED:
1032         {
1033             GenericInfo.Ulong = NvNetGetLinkSpeed(Adapter) * 10000;
1034             break;
1035         }
1036 
1037         case OID_GEN_TRANSMIT_BUFFER_SPACE:
1038         {
1039             /* TODO: Change this later, once the driver can handle multipacket sends */
1040             GenericInfo.Ulong = Adapter->MaximumFrameSize;
1041             break;
1042         }
1043 
1044         case OID_GEN_RECEIVE_BUFFER_SPACE:
1045         {
1046             GenericInfo.Ulong = Adapter->MaximumFrameSize * NVNET_RECEIVE_DESCRIPTORS;
1047         }
1048 
1049         case OID_GEN_MAXIMUM_TOTAL_SIZE:
1050         case OID_GEN_TRANSMIT_BLOCK_SIZE:
1051         case OID_GEN_RECEIVE_BLOCK_SIZE:
1052         {
1053             GenericInfo.Ulong = Adapter->MaximumFrameSize;
1054             break;
1055         }
1056 
1057         case OID_GEN_VENDOR_ID:
1058         {
1059             GenericInfo.Ulong = 0;
1060             GenericInfo.Ulong |= (Adapter->PermanentMacAddress[0] << 16);
1061             GenericInfo.Ulong |= (Adapter->PermanentMacAddress[1] << 8);
1062             GenericInfo.Ulong |= (Adapter->PermanentMacAddress[2] & 0xFF);
1063             break;
1064         }
1065 
1066         case OID_GEN_DRIVER_VERSION:
1067         {
1068             InfoLength = sizeof(USHORT);
1069             GenericInfo.Ushort = (NDIS_MINIPORT_MAJOR_VERSION << 8) | NDIS_MINIPORT_MINOR_VERSION;
1070             break;
1071         }
1072 
1073         case OID_GEN_VENDOR_DESCRIPTION:
1074         {
1075             static const CHAR VendorDesc[] = "nVidia nForce Ethernet Controller";
1076             InfoPtr = (PVOID)&VendorDesc;
1077             InfoLength = sizeof(VendorDesc);
1078             break;
1079         }
1080 
1081         case OID_GEN_CURRENT_PACKET_FILTER:
1082         {
1083             GenericInfo.Ulong = Adapter->PacketFilter;
1084             break;
1085         }
1086 
1087         case OID_GEN_MAC_OPTIONS:
1088         {
1089             GenericInfo.Ulong = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
1090                                 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
1091                                 NDIS_MAC_OPTION_NO_LOOPBACK;
1092 
1093             if (Adapter->Flags & NV_PACKET_PRIORITY)
1094                 GenericInfo.Ulong |= NDIS_MAC_OPTION_8021P_PRIORITY;
1095             if (Adapter->Flags & NV_VLAN_TAGGING)
1096                 GenericInfo.Ulong |= NDIS_MAC_OPTION_8021Q_VLAN;
1097             break;
1098         }
1099 
1100         case OID_GEN_MEDIA_CONNECT_STATUS:
1101         {
1102             GenericInfo.Ulong = Adapter->Connected ? NdisMediaStateConnected
1103                                                    : NdisMediaStateDisconnected;
1104             break;
1105         }
1106 
1107         case OID_GEN_MAXIMUM_SEND_PACKETS:
1108         {
1109             /* TODO: Multipacket sends */
1110             GenericInfo.Ulong = 1;
1111             break;
1112         }
1113 
1114         case OID_GEN_VENDOR_DRIVER_VERSION:
1115         {
1116             /* 1.0.0 */
1117             GenericInfo.Ulong = 0x100;
1118             break;
1119         }
1120 
1121         case OID_GEN_XMIT_OK:
1122         case OID_GEN_RCV_OK:
1123         case OID_GEN_XMIT_ERROR:
1124         case OID_GEN_RCV_ERROR:
1125         case OID_GEN_RCV_NO_BUFFER:
1126         case OID_GEN_DIRECTED_FRAMES_RCV:
1127         case OID_GEN_RCV_CRC_ERROR:
1128         case OID_802_3_RCV_ERROR_ALIGNMENT:
1129         case OID_802_3_XMIT_ONE_COLLISION:
1130         case OID_802_3_XMIT_MORE_COLLISIONS:
1131         case OID_802_3_XMIT_DEFERRED:
1132         case OID_802_3_XMIT_MAX_COLLISIONS:
1133         case OID_802_3_RCV_OVERRUN:
1134         case OID_802_3_XMIT_UNDERRUN:
1135         case OID_802_3_XMIT_HEARTBEAT_FAILURE:
1136         case OID_802_3_XMIT_TIMES_CRS_LOST:
1137         case OID_802_3_XMIT_LATE_COLLISIONS:
1138         {
1139             if (Adapter->Features & DEV_HAS_STATISTICS_COUNTERS)
1140             {
1141                 NvNetReadStatistics(Adapter);
1142                 NvNetQueryHwCounter(Adapter, Oid, &GenericInfo.Ulong64);
1143             }
1144             else
1145             {
1146                 NvNetQuerySoftwareCounter(Adapter, Oid, &GenericInfo.Ulong64);
1147             }
1148 
1149             *BytesNeeded = sizeof(ULONG64);
1150             if (InformationBufferLength < sizeof(ULONG))
1151             {
1152                 *BytesWritten = 0;
1153                 return NDIS_STATUS_BUFFER_TOO_SHORT;
1154             }
1155             if (InformationBufferLength >= sizeof(ULONG64))
1156             {
1157                 *BytesWritten = sizeof(ULONG64);
1158                 NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG64));
1159             }
1160             else
1161             {
1162                 *BytesWritten = sizeof(ULONG);
1163                 NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG));
1164             }
1165 
1166             return NDIS_STATUS_SUCCESS;
1167         }
1168 
1169         case OID_GEN_TRANSMIT_QUEUE_LENGTH:
1170         {
1171             GenericInfo.Ulong = NVNET_TRANSMIT_BLOCKS - Adapter->Send.TcbSlots;
1172             break;
1173         }
1174 
1175         case OID_802_3_PERMANENT_ADDRESS:
1176         {
1177             InfoPtr = Adapter->PermanentMacAddress;
1178             InfoLength = ETH_LENGTH_OF_ADDRESS;
1179             break;
1180         }
1181 
1182         case OID_802_3_CURRENT_ADDRESS:
1183         {
1184             InfoPtr = Adapter->CurrentMacAddress;
1185             InfoLength = ETH_LENGTH_OF_ADDRESS;
1186             break;
1187         }
1188 
1189         case OID_802_3_MULTICAST_LIST:
1190         {
1191             InfoPtr = Adapter->MulticastList;
1192             InfoLength = Adapter->MulticastListSize * ETH_LENGTH_OF_ADDRESS;
1193             break;
1194         }
1195 
1196         case OID_802_3_MAXIMUM_LIST_SIZE:
1197         {
1198             GenericInfo.Ulong = NVNET_MULTICAST_LIST_SIZE;
1199             break;
1200         }
1201 
1202         case OID_TCP_TASK_OFFLOAD:
1203         {
1204             return NvNetGetTcpTaskOffload(Adapter,
1205                                           InformationBuffer,
1206                                           InformationBufferLength,
1207                                           BytesWritten,
1208                                           BytesWritten);
1209         }
1210 
1211         case OID_PNP_ENABLE_WAKE_UP:
1212         {
1213             GenericInfo.Ulong = NvNetGetWakeUp(Adapter);
1214             break;
1215         }
1216 
1217         case OID_PNP_CAPABILITIES:
1218         {
1219             InfoLength = sizeof(NDIS_PNP_CAPABILITIES);
1220 
1221             if (InformationBufferLength < InfoLength)
1222             {
1223                 *BytesWritten = 0;
1224                 *BytesNeeded = InfoLength;
1225                 return NDIS_STATUS_BUFFER_TOO_SHORT;
1226             }
1227 
1228             *BytesWritten = InfoLength;
1229             *BytesNeeded = 0;
1230             return NvNetFillPowerManagementCapabilities(Adapter, InformationBuffer);
1231         }
1232 
1233         case OID_PNP_QUERY_POWER:
1234         {
1235             return NDIS_STATUS_SUCCESS;
1236         }
1237 
1238         case OID_GEN_VLAN_ID:
1239         {
1240             /* TODO: Implement software VLAN support */
1241             if (!(Adapter->Flags & NV_VLAN_TAGGING))
1242             {
1243                 Status = NDIS_STATUS_NOT_SUPPORTED;
1244                 break;
1245             }
1246 
1247             GenericInfo.Ulong = Adapter->VlanId;
1248             break;
1249         }
1250 
1251         default:
1252             Status = NDIS_STATUS_INVALID_OID;
1253             break;
1254     }
1255 
1256     if (Status == NDIS_STATUS_SUCCESS)
1257     {
1258         if (InfoLength > InformationBufferLength)
1259         {
1260             *BytesWritten = 0;
1261             *BytesNeeded = InfoLength;
1262             Status = NDIS_STATUS_BUFFER_TOO_SHORT;
1263         }
1264         else
1265         {
1266             NdisMoveMemory(InformationBuffer, InfoPtr, InfoLength);
1267             *BytesWritten = InfoLength;
1268             *BytesNeeded = 0;
1269         }
1270     }
1271     else
1272     {
1273         *BytesWritten = 0;
1274         *BytesNeeded = 0;
1275     }
1276 
1277     return Status;
1278 }
1279 
1280 NDIS_STATUS
1281 NTAPI
MiniportSetInformation(_In_ NDIS_HANDLE MiniportAdapterContext,_In_ NDIS_OID Oid,_In_ PVOID InformationBuffer,_In_ ULONG InformationBufferLength,_Out_ PULONG BytesRead,_Out_ PULONG BytesNeeded)1282 MiniportSetInformation(
1283     _In_ NDIS_HANDLE MiniportAdapterContext,
1284     _In_ NDIS_OID Oid,
1285     _In_ PVOID InformationBuffer,
1286     _In_ ULONG InformationBufferLength,
1287     _Out_ PULONG BytesRead,
1288     _Out_ PULONG BytesNeeded)
1289 {
1290     PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
1291     NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1292     ULONG GenericUlong;
1293 
1294     *BytesRead = 0;
1295     *BytesNeeded = 0;
1296 
1297     switch (Oid)
1298     {
1299         case OID_802_3_MULTICAST_LIST:
1300         {
1301             if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS)
1302             {
1303                 *BytesNeeded = (InformationBufferLength / ETH_LENGTH_OF_ADDRESS) *
1304                                ETH_LENGTH_OF_ADDRESS;
1305                 Status = NDIS_STATUS_INVALID_LENGTH;
1306                 break;
1307             }
1308 
1309             if (InformationBufferLength > sizeof(Adapter->MulticastList))
1310             {
1311                 *BytesNeeded = sizeof(Adapter->MulticastList);
1312                 Status = NDIS_STATUS_MULTICAST_FULL;
1313                 break;
1314             }
1315 
1316             *BytesRead = InformationBufferLength;
1317             NdisMoveMemory(Adapter->MulticastList, InformationBuffer, InformationBufferLength);
1318 
1319             Adapter->MulticastListSize = InformationBufferLength / ETH_LENGTH_OF_ADDRESS;
1320 
1321             NvNetApplyPacketFilter(Adapter);
1322             break;
1323         }
1324 
1325         case OID_GEN_CURRENT_PACKET_FILTER:
1326         {
1327             if (InformationBufferLength < sizeof(ULONG))
1328             {
1329                 *BytesNeeded = sizeof(ULONG);
1330                 Status = NDIS_STATUS_INVALID_LENGTH;
1331                 break;
1332             }
1333 
1334             *BytesRead = sizeof(ULONG);
1335             NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
1336 
1337             if (GenericUlong & ~NVNET_PACKET_FILTERS)
1338             {
1339                 Status = NDIS_STATUS_NOT_SUPPORTED;
1340                 break;
1341             }
1342 
1343             /* Do not check to see if the filter is the same filter */
1344             Adapter->PacketFilter = GenericUlong;
1345 
1346             NvNetApplyPacketFilter(Adapter);
1347             break;
1348         }
1349 
1350         case OID_GEN_CURRENT_LOOKAHEAD:
1351         {
1352             if (InformationBufferLength < sizeof(ULONG))
1353             {
1354                 *BytesNeeded = sizeof(ULONG);
1355                 Status = NDIS_STATUS_INVALID_LENGTH;
1356                 break;
1357             }
1358 
1359             /* Nothing to do */
1360             *BytesRead = sizeof(ULONG);
1361             break;
1362         }
1363 
1364         case OID_GEN_VLAN_ID:
1365         {
1366             if (InformationBufferLength < sizeof(ULONG))
1367             {
1368                 *BytesNeeded = sizeof(ULONG);
1369                 Status = NDIS_STATUS_INVALID_LENGTH;
1370                 break;
1371             }
1372 
1373             if (!(Adapter->Flags & NV_VLAN_TAGGING))
1374             {
1375                 Status = NDIS_STATUS_NOT_SUPPORTED;
1376                 break;
1377             }
1378 
1379             *BytesRead = sizeof(ULONG);
1380             NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
1381 
1382             if (GenericUlong > NVNET_MAXIMUM_VLAN_ID)
1383             {
1384                 Status = NDIS_STATUS_FAILURE;
1385                 break;
1386             }
1387 
1388             Adapter->VlanId = GenericUlong;
1389             break;
1390         }
1391 
1392         case OID_TCP_TASK_OFFLOAD:
1393         {
1394             if (InformationBufferLength < sizeof(NDIS_TASK_OFFLOAD_HEADER))
1395             {
1396                 *BytesNeeded = sizeof(NDIS_TASK_OFFLOAD_HEADER);
1397                 Status = NDIS_STATUS_INVALID_LENGTH;
1398                 break;
1399             }
1400 
1401             *BytesRead = InformationBufferLength;
1402 
1403             Status = NvNetSetTcpTaskOffload(Adapter, InformationBuffer, BytesRead);
1404             break;
1405         }
1406 
1407         case OID_PNP_ADD_WAKE_UP_PATTERN:
1408         {
1409             if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
1410             {
1411                 *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
1412                 Status = NDIS_STATUS_INVALID_LENGTH;
1413                 break;
1414             }
1415 
1416             *BytesRead = sizeof(NDIS_PM_PACKET_PATTERN);
1417 
1418             Status = NvNetAddWakeUpPattern(Adapter, InformationBuffer);
1419             break;
1420         }
1421 
1422         case OID_PNP_REMOVE_WAKE_UP_PATTERN:
1423         {
1424             if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
1425             {
1426                 *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
1427                 Status = NDIS_STATUS_INVALID_LENGTH;
1428                 break;
1429             }
1430 
1431             *BytesRead = sizeof(NDIS_PM_PACKET_PATTERN);
1432 
1433             Status = NvNetRemoveWakeUpPattern(Adapter, InformationBuffer);
1434             break;
1435         }
1436 
1437         case OID_PNP_ENABLE_WAKE_UP:
1438         {
1439             if (InformationBufferLength < sizeof(ULONG))
1440             {
1441                 *BytesNeeded = sizeof(ULONG);
1442                 Status = NDIS_STATUS_INVALID_LENGTH;
1443                 break;
1444             }
1445 
1446             *BytesRead = sizeof(ULONG);
1447             NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
1448 
1449             NvNetEnableWakeUp(Adapter, GenericUlong);
1450             break;
1451         }
1452 
1453         case OID_PNP_SET_POWER:
1454         {
1455             if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
1456             {
1457                 *BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE);
1458                 Status = NDIS_STATUS_INVALID_LENGTH;
1459                 break;
1460             }
1461 
1462             *BytesRead = sizeof(ULONG);
1463             NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG));
1464 
1465             if (GenericUlong < NdisDeviceStateD0 || GenericUlong > NdisDeviceStateD3)
1466             {
1467                 Status = NDIS_STATUS_INVALID_DATA;
1468                 break;
1469             }
1470 
1471             Status = NvNetSetPower(Adapter, GenericUlong);
1472             break;
1473         }
1474 
1475         default:
1476             Status = NDIS_STATUS_NOT_SUPPORTED;
1477             break;
1478     }
1479 
1480     return Status;
1481 }
1482