1 /*
2  * This file contains NDIS5.X implementation of
3  * OID-related adapter driver procedures
4  *
5  * Copyright (c) 2008-2017 Red Hat, Inc.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met :
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and / or other materials provided with the distribution.
15  * 3. Neither the names of the copyright holders nor the names of their contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 #include "ParaNdis5.h"
31 #include "ParaNdis-Oid.h"
32 
33 #ifdef WPP_EVENT_TRACING
34 #include "ParaNdis5-Oid.tmh"
35 #endif
36 
37 #define OIDENTRY(oid, el, xfl, xokl, flags) \
38 { oid, el, xfl, xokl, flags, NULL }
39 #define OIDENTRYPROC(oid, el, xfl, xokl, flags, setproc) \
40 { oid, el, xfl, xokl, flags, setproc }
41 
42 static NDIS_TASK_OFFLOAD_HEADER ReservedHeader =
43 {
44     NDIS_TASK_OFFLOAD_VERSION,
45     sizeof(NDIS_TASK_OFFLOAD_HEADER),
46     0,
47     0,
48     { IEEE_802_3_Encapsulation, { 1, 0 }, 0 }
49 };
50 
51 
52 static NDIS_OID SupportedOids[] = {
53     OID_GEN_SUPPORTED_LIST,
54     OID_GEN_HARDWARE_STATUS,
55     OID_GEN_MEDIA_SUPPORTED,
56     OID_GEN_MEDIA_IN_USE,
57     OID_GEN_MAXIMUM_LOOKAHEAD,
58     OID_GEN_MAXIMUM_FRAME_SIZE,
59     OID_GEN_LINK_SPEED,
60     OID_GEN_TRANSMIT_BUFFER_SPACE,
61     OID_GEN_RECEIVE_BUFFER_SPACE,
62     OID_GEN_TRANSMIT_BLOCK_SIZE,
63     OID_GEN_RECEIVE_BLOCK_SIZE,
64     OID_GEN_VENDOR_ID,
65     OID_GEN_VENDOR_DESCRIPTION,
66     OID_GEN_VENDOR_DRIVER_VERSION,
67     OID_GEN_CURRENT_PACKET_FILTER,
68     OID_GEN_CURRENT_LOOKAHEAD,
69     OID_GEN_DRIVER_VERSION,
70     OID_GEN_MAXIMUM_TOTAL_SIZE,
71     OID_GEN_PROTOCOL_OPTIONS,
72     OID_GEN_MAC_OPTIONS,
73     OID_GEN_MEDIA_CONNECT_STATUS,
74     OID_GEN_MAXIMUM_SEND_PACKETS,
75     OID_GEN_XMIT_OK,
76     OID_GEN_RCV_OK,
77     OID_GEN_VLAN_ID,
78     OID_GEN_XMIT_ERROR,
79     OID_GEN_RCV_ERROR,
80     OID_GEN_RCV_NO_BUFFER,
81     OID_GEN_RCV_CRC_ERROR,
82     OID_GEN_TRANSMIT_QUEUE_LENGTH,
83     OID_802_3_PERMANENT_ADDRESS,
84     OID_802_3_CURRENT_ADDRESS,
85     OID_802_3_MULTICAST_LIST,
86     OID_802_3_MAC_OPTIONS,
87     OID_802_3_MAXIMUM_LIST_SIZE,
88     OID_802_3_RCV_ERROR_ALIGNMENT,
89     OID_802_3_XMIT_ONE_COLLISION,
90     OID_802_3_XMIT_MORE_COLLISIONS,
91     OID_802_3_XMIT_DEFERRED,
92     OID_802_3_XMIT_MAX_COLLISIONS,
93     OID_802_3_RCV_OVERRUN,
94     OID_802_3_XMIT_UNDERRUN,
95     OID_802_3_XMIT_HEARTBEAT_FAILURE,
96     OID_802_3_XMIT_TIMES_CRS_LOST,
97     OID_802_3_XMIT_LATE_COLLISIONS,
98     OID_PNP_CAPABILITIES,
99     OID_PNP_SET_POWER,
100     OID_PNP_QUERY_POWER,
101     OID_PNP_ADD_WAKE_UP_PATTERN,
102     OID_PNP_REMOVE_WAKE_UP_PATTERN,
103     OID_PNP_ENABLE_WAKE_UP,
104     OID_TCP_TASK_OFFLOAD
105 };
106 
107 static NDIS_STATUS OnOidSetNdis5Offload(PARANDIS_ADAPTER *pContext, tOidDesc *pOid);
108 static NDIS_STATUS CreateOffloadInfo5ForQuery(PARANDIS_ADAPTER *pContext, tOidDesc *pOid, PVOID *ppInfo, PULONG pulSize);
109 static NDIS_STATUS CreateOffloadInfo5Internal(PARANDIS_ADAPTER *pContext, PVOID *ppInfo, PULONG pulSize, PCCHAR reason, NDIS_TASK_OFFLOAD_HEADER *pHeader);
110 
111 /**********************************************************
112 Structure defining how to process all the oids
113 ***********************************************************/
114 // oid                                          e f ok flags      set procedure
115 static const tOidWhatToDo OidsDB[] =
116 {
117 OIDENTRY(OID_GEN_SUPPORTED_LIST,                2,2,4, ohfQueryStat     ),
118 OIDENTRY(OID_GEN_HARDWARE_STATUS,               2,0,4, ohfQuery         ),
119 OIDENTRY(OID_GEN_MEDIA_SUPPORTED,               2,0,4, ohfQuery         ),
120 OIDENTRY(OID_GEN_MEDIA_IN_USE,                  2,0,4, ohfQuery         ),
121 OIDENTRY(OID_GEN_MAXIMUM_LOOKAHEAD,             2,0,4, ohfQuery         ),
122 OIDENTRY(OID_GEN_MAXIMUM_FRAME_SIZE,            2,0,4, ohfQuery         ),
123 OIDENTRY(OID_GEN_LINK_SPEED,                    6,0,6, ohfQuery         ),
124 OIDENTRY(OID_GEN_TRANSMIT_BUFFER_SPACE,         2,0,4, ohfQuery         ),
125 OIDENTRY(OID_GEN_RECEIVE_BUFFER_SPACE,          2,0,4, ohfQuery         ),
126 OIDENTRY(OID_GEN_TRANSMIT_BLOCK_SIZE,           2,0,4, ohfQuery         ),
127 OIDENTRY(OID_GEN_RECEIVE_BLOCK_SIZE,            2,0,4, ohfQuery         ),
128 OIDENTRY(OID_GEN_VENDOR_ID,                     2,0,4, ohfQueryStat     ),
129 OIDENTRY(OID_GEN_VENDOR_DESCRIPTION,            2,2,4, ohfQuery         ),
130 OIDENTRYPROC(OID_GEN_CURRENT_PACKET_FILTER,     2,0,4, ohfQuerySet, ParaNdis_OnSetPacketFilter),
131 OIDENTRYPROC(OID_GEN_CURRENT_LOOKAHEAD,         2,0,4, ohfQuerySet, ParaNdis_OnSetLookahead),
132 OIDENTRY(OID_GEN_DRIVER_VERSION,                2,0,4, ohfQuery         ),
133 OIDENTRY(OID_GEN_MAXIMUM_TOTAL_SIZE,            2,0,4, ohfQuery         ),
134 OIDENTRY(OID_GEN_PROTOCOL_OPTIONS,              2,0,4, 0                ),
135 OIDENTRY(OID_GEN_MAC_OPTIONS,                   2,0,4, ohfQuery         ),
136 OIDENTRY(OID_GEN_MEDIA_CONNECT_STATUS,          6,0,6, ohfQuery         ),
137 OIDENTRY(OID_GEN_MAXIMUM_SEND_PACKETS,          2,0,4, ohfQuery         ),
138 OIDENTRY(OID_GEN_VENDOR_DRIVER_VERSION,         2,0,4, ohfQuery         ),
139 OIDENTRY(OID_GEN_SUPPORTED_GUIDS,               2,2,4, 0                ),
140 OIDENTRY(OID_GEN_TRANSPORT_HEADER_OFFSET,       2,4,4, 0                ),
141 OIDENTRY(OID_GEN_MEDIA_CAPABILITIES,            2,4,4, 0                ),
142 OIDENTRY(OID_GEN_PHYSICAL_MEDIUM,               2,4,4, 0                ),
143 OIDENTRY(OID_GEN_XMIT_OK,                       6,0,6, ohfQuery3264     ),
144 OIDENTRY(OID_GEN_RCV_OK,                        6,0,4, ohfQuery3264     ),
145 OIDENTRY(OID_GEN_XMIT_ERROR,                    6,0,6, ohfQuery3264     ),
146 OIDENTRY(OID_GEN_RCV_ERROR,                     6,0,6, ohfQuery3264     ),
147 OIDENTRY(OID_GEN_RCV_NO_BUFFER,                 2,0,4, ohfQuery3264     ),
148 OIDENTRY(OID_GEN_DIRECTED_BYTES_XMIT,           2,4,4, 0                ),
149 OIDENTRY(OID_GEN_DIRECTED_FRAMES_XMIT,          2,4,4, 0                ),
150 OIDENTRY(OID_GEN_MULTICAST_BYTES_XMIT,          2,4,4, 0                ),
151 OIDENTRY(OID_GEN_MULTICAST_FRAMES_XMIT,         2,4,4, 0                ),
152 OIDENTRY(OID_GEN_BROADCAST_BYTES_XMIT,          2,4,4, 0                ),
153 OIDENTRY(OID_GEN_BROADCAST_FRAMES_XMIT,         2,4,4, 0                ),
154 OIDENTRY(OID_GEN_DIRECTED_BYTES_RCV,            2,4,4, 0                ),
155 OIDENTRY(OID_GEN_DIRECTED_FRAMES_RCV,           2,4,4, 0                ),
156 OIDENTRY(OID_GEN_MULTICAST_BYTES_RCV,           2,4,4, 0                ),
157 OIDENTRY(OID_GEN_MULTICAST_FRAMES_RCV,          2,4,4, 0                ),
158 OIDENTRY(OID_GEN_BROADCAST_BYTES_RCV,           2,4,4, 0                ),
159 OIDENTRY(OID_GEN_BROADCAST_FRAMES_RCV,          2,4,4, 0                ),
160 OIDENTRY(OID_GEN_RCV_CRC_ERROR,                 2,0,4, ohfQuery3264     ),
161 OIDENTRY(OID_GEN_TRANSMIT_QUEUE_LENGTH,         2,0,4, ohfQuery         ),
162 OIDENTRY(OID_GEN_GET_TIME_CAPS,                 2,4,4, 0                ),
163 OIDENTRY(OID_GEN_GET_NETCARD_TIME,              2,4,4, 0                ),
164 OIDENTRY(OID_GEN_NETCARD_LOAD,                  2,4,4, 0                ),
165 OIDENTRY(OID_GEN_DEVICE_PROFILE,                2,4,4, 0                ),
166 OIDENTRY(OID_GEN_INIT_TIME_MS,                  2,4,4, 0                ),
167 OIDENTRY(OID_GEN_RESET_COUNTS,                  2,4,4, 0                ),
168 OIDENTRY(OID_GEN_MEDIA_SENSE_COUNTS,            2,4,4, 0                ),
169 OIDENTRY(OID_PNP_CAPABILITIES,                  2,0,4, ohfQuery         ),
170 OIDENTRY(OID_PNP_QUERY_POWER,                   2,0,4, ohfQuery         ),
171 OIDENTRY(OID_802_3_PERMANENT_ADDRESS,           2,0,4, ohfQueryStat     ),
172 OIDENTRY(OID_802_3_CURRENT_ADDRESS,             2,0,4, ohfQueryStat     ),
173 OIDENTRY(OID_802_3_MAXIMUM_LIST_SIZE,           2,0,4, ohfQuery         ),
174 OIDENTRY(OID_802_3_MAC_OPTIONS,                 2,4,4, ohfQuery         ),
175 OIDENTRY(OID_802_3_RCV_ERROR_ALIGNMENT,         2,0,4, ohfQuery3264     ),
176 OIDENTRY(OID_802_3_XMIT_ONE_COLLISION,          2,4,4, ohfQuery3264     ),
177 OIDENTRY(OID_802_3_XMIT_MORE_COLLISIONS,        2,4,4, ohfQuery3264     ),
178 OIDENTRY(OID_802_3_XMIT_DEFERRED,               2,0,4, ohfQuery3264     ),
179 OIDENTRY(OID_802_3_XMIT_MAX_COLLISIONS,         2,0,4, ohfQuery3264     ),
180 OIDENTRY(OID_802_3_RCV_OVERRUN,                 2,0,4, ohfQuery3264     ),
181 OIDENTRY(OID_802_3_XMIT_UNDERRUN,               2,0,4, ohfQuery3264     ),
182 OIDENTRY(OID_802_3_XMIT_HEARTBEAT_FAILURE,      2,0,4, ohfQuery3264     ),
183 OIDENTRY(OID_802_3_XMIT_TIMES_CRS_LOST,         2,0,4, ohfQuery3264     ),
184 OIDENTRY(OID_802_3_XMIT_LATE_COLLISIONS,        2,0,4, ohfQuery3264     ),
185 OIDENTRY(OID_GEN_MACHINE_NAME,                  2,4,4, 0                ),
186 OIDENTRY(OID_IP4_OFFLOAD_STATS,                 4,4,4, 0                ),
187 OIDENTRY(OID_IP6_OFFLOAD_STATS,                 4,4,4, 0                ),
188 OIDENTRY(OID_802_11_CAPABILITY,                 4,4,4, 0                ),
189 OIDENTRYPROC(OID_PNP_ADD_WAKE_UP_PATTERN,       2,0,4, ohfSet,          ParaNdis_OnAddWakeupPattern),
190 OIDENTRYPROC(OID_PNP_REMOVE_WAKE_UP_PATTERN,    2,0,4, ohfSet,          ParaNdis_OnRemoveWakeupPattern),
191 OIDENTRYPROC(OID_PNP_ENABLE_WAKE_UP,            2,0,4, ohfQuerySet,     ParaNdis_OnEnableWakeup),
192 OIDENTRYPROC(OID_PNP_SET_POWER,                 2,0,4, ohfSet | ohfSetMoreOK,   ParaNdis_OnSetPower),
193 OIDENTRYPROC(OID_GEN_CURRENT_LOOKAHEAD,         2,0,4, ohfQuerySet,     ParaNdis_OnSetLookahead),
194 OIDENTRYPROC(OID_GEN_CURRENT_PACKET_FILTER,     2,0,4, ohfQuerySet,     ParaNdis_OnSetPacketFilter),
195 OIDENTRYPROC(OID_802_3_MULTICAST_LIST,          2,0,4, ohfQuerySet,     ParaNdis_OnOidSetMulticastList),
196 OIDENTRY(OID_FFP_SUPPORT,                       2,4,4, 0                ),
197 OIDENTRYPROC(OID_TCP_TASK_OFFLOAD,              0,0,0, ohfQuerySet, OnOidSetNdis5Offload),
198 OIDENTRYPROC(OID_GEN_VLAN_ID,                   0,4,4, ohfQuerySet, ParaNdis_OnSetVlanId),
199 OIDENTRY(0x00010203 /*(OID_GEN_RECEIVE_SCALE_CAPABILITIES)*/, 2,4,4, 0  ),
200 OIDENTRY(0x0001021F /*(OID_GEN_RECEIVE_HASH)*/, 2,4,4, 0                ),
201 OIDENTRY(0,                                     4,4,4, 0),
202 };
203 
204 /**********************************************************
205 Returns to common query processor the array of supported oids
206 ***********************************************************/
ParaNdis_GetSupportedOid(PVOID * pOidsArray,PULONG pLength)207 void ParaNdis_GetSupportedOid(PVOID *pOidsArray, PULONG pLength)
208 {
209     *pOidsArray     = SupportedOids;
210     *pLength        = sizeof(SupportedOids);
211 }
212 
213 
214 /*****************************************************************
215 Handles NDIS5 specific OID, all the rest handled by common handler
216 *****************************************************************/
ParaNdis_OidQuery(PARANDIS_ADAPTER * pContext,tOidDesc * pOid)217 static NDIS_STATUS ParaNdis_OidQuery(PARANDIS_ADAPTER *pContext, tOidDesc *pOid)
218 {
219     NDIS_STATUS status;
220     BOOLEAN bFreeInfo = FALSE;
221     PVOID pInfo = NULL;
222     ULONG ulSize = 0;
223     ULONG ulLinkSpeed = 0;
224 
225     switch(pOid->Oid)
226     {
227         case OID_TCP_TASK_OFFLOAD:
228             status = CreateOffloadInfo5ForQuery(pContext, pOid, &pInfo, &ulSize);
229             bFreeInfo = pInfo != NULL;
230             break;
231         case OID_GEN_LINK_SPEED:
232             {
233                 /* units are 100 bps */
234                 ulLinkSpeed = (ULONG)(PARANDIS_FORMAL_LINK_SPEED / 100);
235                 pInfo = &ulLinkSpeed;
236                 ulSize = sizeof(ulLinkSpeed);
237                 status = NDIS_STATUS_SUCCESS;
238             }
239             break;
240         default:
241             return ParaNdis_OidQueryCommon(pContext, pOid);
242     }
243     if (status == NDIS_STATUS_SUCCESS)
244     {
245         status = ParaNdis_OidQueryCopy(pOid, pInfo, ulSize, bFreeInfo);
246     }
247     else if (bFreeInfo)
248     {
249         NdisFreeMemory(pInfo, 0, 0);
250     }
251     return status;
252 }
253 
254 /**********************************************************
255 NDIS required procedure of OID QUERY
256 Just passes all the supported oids to common query procedure
257 Return value:
258     NDIS_STATUS                 as returned from common code
259     NDIS_STATUS_NOT_SUPPORTED   if suppressed in the table
260 ***********************************************************/
ParaNdis5_QueryOID(IN NDIS_HANDLE MiniportAdapterContext,IN NDIS_OID Oid,IN PVOID InformationBuffer,IN ULONG InformationBufferLength,OUT PULONG BytesWritten,OUT PULONG BytesNeeded)261 NDIS_STATUS NTAPI ParaNdis5_QueryOID(IN NDIS_HANDLE MiniportAdapterContext,
262                                     IN NDIS_OID Oid,
263                                     IN PVOID InformationBuffer,
264                                     IN ULONG InformationBufferLength,
265                                     OUT PULONG BytesWritten,
266                                     OUT PULONG BytesNeeded)
267 {
268     NDIS_STATUS  status = NDIS_STATUS_NOT_SUPPORTED;
269     tOidWhatToDo Rules;
270     PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
271     tOidDesc _oid;
272     ParaNdis_GetOidSupportRules(Oid, &Rules, OidsDB);
273     _oid.ulToDoFlags = Rules.Flags;
274     *BytesWritten = 0;
275     *BytesNeeded  = 0;
276     ParaNdis_DebugHistory(pContext, hopOidRequest, NULL, Oid, 0, 1);
277     DPrintf(Rules.nEntryLevel, ("[%s], id 0x%X(%s) of %d", __FUNCTION__,
278                 Oid,
279                 Rules.name,
280                 InformationBufferLength));
281     _oid.Oid = Oid;
282     _oid.InformationBuffer = InformationBuffer;
283     _oid.InformationBufferLength = InformationBufferLength;
284     _oid.pBytesNeeded = (PUINT)BytesNeeded;
285     _oid.pBytesRead   = (PUINT)BytesWritten;
286     _oid.pBytesWritten = (PUINT)BytesWritten;
287     if (pContext->bSurprizeRemoved) status = NDIS_STATUS_NOT_ACCEPTED;
288     else if (Rules.Flags & ohfQuery) status = ParaNdis_OidQuery(pContext, &_oid);
289 
290 
291     ParaNdis_DebugHistory(pContext, hopOidRequest, NULL, Oid, status, 0);
292     DPrintf((status != NDIS_STATUS_SUCCESS) ? Rules.nExitFailLevel : Rules.nExitOKLevel,
293         ("[%s] , id 0x%X(%s) (%X), written %d, needed %d",
294         __FUNCTION__,
295         Rules.oid,
296         Rules.name,
297         status,
298         *BytesWritten,
299         *BytesNeeded));
300     return status;
301 
302 }
303 
304 /**********************************************************
305 NDIS required procedure of OID SET
306 Just passes all the supported oids to common set procedure
307 Return value:
308     NDIS_STATUS                 as returned from set procedure
309     NDIS_STATUS_NOT_SUPPORTED   if support not defined in the table
310 ***********************************************************/
ParaNdis5_SetOID(IN NDIS_HANDLE MiniportAdapterContext,IN NDIS_OID Oid,IN PVOID InformationBuffer,IN ULONG InformationBufferLength,OUT PULONG BytesRead,OUT PULONG BytesNeeded)311 NDIS_STATUS NTAPI ParaNdis5_SetOID(IN NDIS_HANDLE MiniportAdapterContext,
312                                   IN NDIS_OID Oid,
313                                   IN PVOID InformationBuffer,
314                                   IN ULONG InformationBufferLength,
315                                   OUT PULONG BytesRead,
316                                   OUT PULONG BytesNeeded)
317 {
318     NDIS_STATUS  status = NDIS_STATUS_NOT_SUPPORTED;
319     tOidWhatToDo Rules;
320     PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext;
321     tOidDesc _oid;
322     ParaNdis_GetOidSupportRules(Oid, &Rules, OidsDB);
323     _oid.ulToDoFlags = Rules.Flags;
324     *BytesRead = 0;
325     *BytesNeeded = 0;
326     ParaNdis_DebugHistory(pContext, hopOidRequest, NULL, Oid, 1, 1);
327     DPrintf(Rules.nEntryLevel, ("[%s], id 0x%X(%s) of %d", __FUNCTION__,
328                 Oid,
329                 Rules.name,
330                 InformationBufferLength));
331     _oid.Oid = Oid;
332     _oid.InformationBuffer = InformationBuffer;
333     _oid.InformationBufferLength = InformationBufferLength;
334     _oid.pBytesNeeded = (PUINT)BytesNeeded;
335     _oid.pBytesRead   = (PUINT)BytesRead;
336     _oid.pBytesWritten = (PUINT)BytesRead;
337     if (pContext->bSurprizeRemoved) status = NDIS_STATUS_NOT_ACCEPTED;
338     else if (Rules.Flags & ohfSet)
339     {
340         if (Rules.OidSetProc) status = Rules.OidSetProc(pContext, &_oid);
341         else
342         {
343             DPrintf(0, ("[%s] ERROR in OID redirection table", __FUNCTION__));
344             status = NDIS_STATUS_INVALID_OID;
345         }
346     }
347     ParaNdis_DebugHistory(pContext, hopOidRequest, NULL, Oid, status, 0);
348     if  (status != NDIS_STATUS_PENDING)
349     {
350         DPrintf((status != NDIS_STATUS_SUCCESS) ? Rules.nExitFailLevel : Rules.nExitOKLevel,
351             ("[%s] , id 0x%X(%s) (%X), read %d, needed %d", __FUNCTION__,
352             Rules.oid, Rules.name, status, *BytesRead, *BytesNeeded));
353     }
354     return status;
355 }
356 
OnSetPowerWorkItem(NDIS_WORK_ITEM * pWorkItem,PVOID Context)357 static void NTAPI OnSetPowerWorkItem(NDIS_WORK_ITEM * pWorkItem, PVOID  Context)
358 {
359     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
360     tPowerWorkItem *pwi = (tPowerWorkItem *)pWorkItem;
361     PARANDIS_ADAPTER *pContext = pwi->pContext;
362     if (pwi->state == (NDIS_DEVICE_POWER_STATE)NetDeviceStateD0)
363     {
364         status = ParaNdis_PowerOn(pContext);
365     }
366     else
367     {
368         ParaNdis_PowerOff(pContext);
369     }
370     NdisFreeMemory(pwi, 0, 0);
371     ParaNdis_DebugHistory(pContext, hopOidRequest, NULL, OID_PNP_SET_POWER, 0, 2);
372     NdisMSetInformationComplete(pContext->MiniportHandle, status);
373 }
374 
375 /**********************************************************
376 NDIS5.X handler of power management
377 ***********************************************************/
ParaNdis_OnSetPower(PARANDIS_ADAPTER * pContext,tOidDesc * pOid)378 NDIS_STATUS ParaNdis_OnSetPower(PARANDIS_ADAPTER *pContext, tOidDesc *pOid)
379 {
380     NDIS_STATUS status;
381     NDIS_DEVICE_POWER_STATE newState;
382     DEBUG_ENTRY(0);
383     status = ParaNdis_OidSetCopy(pOid, &newState, sizeof(newState));
384     if (status == NDIS_STATUS_SUCCESS)
385     {
386         tPowerWorkItem *pwi = ParaNdis_AllocateMemory(pContext, sizeof(tPowerWorkItem));
387         status = NDIS_STATUS_FAILURE;
388         if (pwi)
389         {
390             pwi->pContext = pContext;
391             pwi->state    = newState;
392             NdisInitializeWorkItem(&pwi->wi, OnSetPowerWorkItem, pwi);
393             if (NdisScheduleWorkItem(&pwi->wi) == NDIS_STATUS_SUCCESS)
394             {
395                 status = NDIS_STATUS_PENDING;
396             }
397             else
398                 NdisFreeMemory(pwi, 0, 0);
399         }
400     }
401     return status;
402 }
403 
404 /***************************************************
405 check that the incoming NDIS_TASK_TCP_IP_CHECKSUM
406 does not enable options which we do not support
407 ***************************************************/
IsValidPcs(PARANDIS_ADAPTER * pContext,NDIS_TASK_TCP_IP_CHECKSUM * pcs)408 static BOOLEAN IsValidPcs(  PARANDIS_ADAPTER *pContext, NDIS_TASK_TCP_IP_CHECKSUM *pcs)
409 {
410     tOffloadSettingsFlags f;
411     BOOLEAN bInvalid = FALSE;
412     ParaNdis_ResetOffloadSettings(pContext, &f, NULL);
413     bInvalid |= pcs->V4Receive.IpChecksum && !f.fRxIPChecksum;
414     bInvalid |= pcs->V4Receive.IpOptionsSupported && !f.fRxIPOptions;
415     bInvalid |= pcs->V4Receive.TcpChecksum && !f.fRxTCPChecksum;
416     bInvalid |= pcs->V4Receive.TcpOptionsSupported && !f.fRxTCPOptions;
417     bInvalid |= pcs->V4Receive.UdpChecksum && !f.fRxUDPChecksum;
418 
419     bInvalid |= pcs->V4Transmit.IpChecksum && !f.fTxIPChecksum;
420     bInvalid |= pcs->V4Transmit.IpOptionsSupported && !f.fTxIPOptions;
421     bInvalid |= pcs->V4Transmit.TcpChecksum && !f.fTxTCPChecksum;
422     bInvalid |= pcs->V4Transmit.TcpOptionsSupported && !f.fTxTCPOptions;
423     bInvalid |= pcs->V4Transmit.UdpChecksum && !f.fTxUDPChecksum;
424     return !bInvalid;
425 }
426 
427 /***************************************************
428 check that the incoming NDIS_TASK_TCP_LARGE_SEND
429 does not enable options which we do not support
430 ***************************************************/
IsValidPls(PARANDIS_ADAPTER * pContext,NDIS_TASK_TCP_LARGE_SEND * pls)431 static BOOLEAN IsValidPls(  PARANDIS_ADAPTER *pContext, NDIS_TASK_TCP_LARGE_SEND *pls)
432 {
433     tOffloadSettingsFlags f;
434     BOOLEAN bInvalid = FALSE;
435     ParaNdis_ResetOffloadSettings(pContext, &f, NULL);
436     bInvalid |= pls->Version != NDIS_TASK_TCP_LARGE_SEND_V0;
437     bInvalid |= pls->IpOptions && !f.fTxLsoIP;
438     bInvalid |= pls->TcpOptions && !f.fTxLsoTCP;
439     bInvalid |= (pls->IpOptions || pls->TcpOptions || pls->MaxOffLoadSize) && !f.fTxLso;
440     bInvalid |= pls->MinSegmentCount < PARANDIS_MIN_LSO_SEGMENTS;
441     return !bInvalid;
442 }
443 
ParseOffloadTask(PARANDIS_ADAPTER * pContext,BOOLEAN bApply,NDIS_TASK_OFFLOAD * pto,ULONG offset,ULONG maxSize)444 static NDIS_STATUS ParseOffloadTask(
445     PARANDIS_ADAPTER *pContext,
446     BOOLEAN bApply, /* for 'set'*/
447     NDIS_TASK_OFFLOAD *pto,
448     ULONG offset,
449     ULONG maxSize)
450 {
451     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
452     NDIS_TASK_TCP_IP_CHECKSUM *pcs = NULL;
453     NDIS_TASK_TCP_LARGE_SEND  *pls = NULL;
454     NDIS_TASK_IPSEC *pips = NULL;
455     LPCSTR sName = NULL;
456     ULONG TaskBufferSize = 0, tailOffset = 0;
457     switch(pto->Task)
458     {
459     case TcpIpChecksumNdisTask:
460         pcs = (NDIS_TASK_TCP_IP_CHECKSUM *)pto->TaskBuffer;
461         TaskBufferSize = sizeof(*pcs);
462         sName = "TcpIpChecksumNdisTask";
463         break;
464     case TcpLargeSendNdisTask:
465         pls = (NDIS_TASK_TCP_LARGE_SEND *)pto->TaskBuffer;
466         TaskBufferSize = sizeof(*pls);
467         sName = "TcpLargeSendNdisTask";
468         break;
469     case IpSecNdisTask:
470         pips = (NDIS_TASK_IPSEC *)pto->TaskBuffer;
471         TaskBufferSize = sizeof(*pips);
472         sName = "IpSecNdisTask";
473         break;
474     default:
475         break;
476     }
477     tailOffset = offset + RtlPointerToOffset(pto, &pto->TaskBuffer) + TaskBufferSize;
478     if (!TaskBufferSize)
479     {
480         DPrintf(0, ("[%s], unknown offload task %d", __FUNCTION__, pto->Task));
481     }
482     else if (tailOffset > maxSize)
483     {
484         DPrintf(0, ("[%s], can not parse %s at offset %d, tail at %d", __FUNCTION__, sName, offset, tailOffset));
485         status = NDIS_STATUS_BUFFER_TOO_SHORT;
486     }
487     else if (TaskBufferSize > pto->TaskBufferLength)
488     {
489         DPrintf(0, ("[%s], invalid size of %s", __FUNCTION__, sName));
490         status = NDIS_STATUS_BUFFER_TOO_SHORT;
491     }
492     else if (pcs)
493     {
494         DPrintf(0, ("[%s], parsing %s", __FUNCTION__, sName));
495         DPrintf(0, ("Rx4: checksum IP(%d),TCP(%d),UDP(%d), options IP(%d),TCP(%d)",
496             pcs->V4Receive.IpChecksum, pcs->V4Receive.TcpChecksum, pcs->V4Receive.UdpChecksum,
497             pcs->V4Receive.IpOptionsSupported, pcs->V4Receive.TcpOptionsSupported
498             ));
499         DPrintf(0, ("Tx4: checksum IP(%d),TCP(%d),UDP(%d), options IP(%d),TCP(%d)",
500             pcs->V4Transmit.IpChecksum, pcs->V4Transmit.TcpChecksum, pcs->V4Transmit.UdpChecksum,
501             pcs->V4Transmit.IpOptionsSupported, pcs->V4Transmit.TcpOptionsSupported
502             ));
503         if (bApply)
504         {
505             if (IsValidPcs(pContext, pcs))
506             {
507                 tOffloadSettingsFlags *pf = &pContext->Offload.flags;
508                 pf->fTxIPChecksum = !!pcs->V4Transmit.IpChecksum;
509                 pf->fTxTCPChecksum = !!pcs->V4Transmit.TcpChecksum;
510                 pf->fTxUDPChecksum = !!pcs->V4Transmit.UdpChecksum;
511                 pf->fTxTCPOptions = !!pcs->V4Transmit.TcpOptionsSupported;
512                 pf->fTxIPOptions = !!pcs->V4Transmit.IpOptionsSupported;
513                 pf->fRxIPChecksum = !!pcs->V4Receive.IpChecksum;
514                 pf->fRxIPOptions = !!pcs->V4Receive.IpOptionsSupported;
515                 pf->fRxTCPChecksum = !!pcs->V4Receive.TcpChecksum;
516                 pf->fRxTCPOptions = !!pcs->V4Receive.TcpOptionsSupported;
517                 pf->fRxUDPChecksum = !!pcs->V4Receive.UdpChecksum;
518             }
519             else
520                 status = STATUS_NOT_SUPPORTED;
521         }
522     }
523     else if (pls)
524     {
525         DPrintf(0, ("[%s], parsing %s version %d", __FUNCTION__, sName, pls->Version));
526         DPrintf(0, ("options IP(%d),TCP(%d),MaxOffload %d, MinSegments %d",
527             pls->IpOptions, pls->TcpOptions, pls->MaxOffLoadSize, pls->MinSegmentCount));
528         if (bApply)
529         {
530             if (IsValidPls(pContext, pls))
531             {
532                 tOffloadSettingsFlags *pf = &pContext->Offload.flags;
533                 pf->fTxLsoIP = !!pls->IpOptions;
534                 pf->fTxLsoTCP = !!pls->TcpOptions;
535                 pf->fTxLso = 1;
536             }
537             else
538                 status = STATUS_NOT_SUPPORTED;
539         }
540     }
541     else if (pips)
542     {
543         DPrintf(0, ("[%s], parsing %s", __FUNCTION__, sName));
544     }
545     return status;
546 }
547 
ValidateOffloadHeader(NDIS_TASK_OFFLOAD_HEADER * pth)548 static FORCEINLINE BOOLEAN ValidateOffloadHeader(NDIS_TASK_OFFLOAD_HEADER *pth)
549 {
550     return
551         pth->EncapsulationFormat.Encapsulation == IEEE_802_3_Encapsulation &&
552         pth->Version == NDIS_TASK_OFFLOAD_VERSION &&
553         pth->Size == sizeof(*pth);
554 }
555 
ParseOffload(PARANDIS_ADAPTER * pContext,NDIS_TASK_OFFLOAD_HEADER * pth,ULONG size,BOOLEAN bApply,PCCHAR reason,BOOLEAN headerOnly)556 static NDIS_STATUS ParseOffload(
557     PARANDIS_ADAPTER *pContext,
558     NDIS_TASK_OFFLOAD_HEADER *pth,
559     ULONG size,
560     BOOLEAN bApply,
561     PCCHAR reason,
562     BOOLEAN headerOnly)
563 {
564     NDIS_STATUS status = NDIS_STATUS_NOT_SUPPORTED;
565     BOOLEAN bReset = FALSE;
566     ULONG ulNoCapabilities = 0;
567     DPrintf(0, ("[%s](%s), format %d", __FUNCTION__, reason,
568         pth->EncapsulationFormat.Encapsulation));
569     if (ValidateOffloadHeader(pth))
570     {
571         PUCHAR p = (PUCHAR)pth;
572         LONG  offset = (LONG)pth->OffsetFirstTask;
573         status = NDIS_STATUS_SUCCESS;
574         DPrintf(0, ("[%s], header version %d, ip header at %d, fixed %d, first at %d", __FUNCTION__,
575             pth->Version,
576             pth->EncapsulationFormat.EncapsulationHeaderSize,
577             pth->EncapsulationFormat.Flags.FixedHeaderSize,
578             offset));
579         if (!offset && bApply)
580         {
581             /* disable all the capabilities */
582             // according to DDK, 0 at first task offset means disabling all the capabilities
583             DPrintf(0, ("[%s] RESETTING offload capabilities", __FUNCTION__));
584             ParaNdis_ResetOffloadSettings(pContext, NULL, &ulNoCapabilities);
585             bReset = TRUE;
586         }
587         while (!headerOnly && offset > 0 && (offset + sizeof(NDIS_TASK_OFFLOAD)) < size)
588         {
589             NDIS_TASK_OFFLOAD *pto = (NDIS_TASK_OFFLOAD *)(p + offset);
590             if (pto->Version != NDIS_TASK_OFFLOAD_VERSION)
591             {
592                 DPrintf(0, ("[%s], unexpected TO version %d at %d",
593                     __FUNCTION__, pto->Version, offset));
594                 status = NDIS_STATUS_INVALID_DATA;
595                 break;
596             }
597             status = ParseOffloadTask(pContext, bApply, pto, offset, size);
598             if (!pto->OffsetNextTask || status != NDIS_STATUS_SUCCESS)
599                 break;
600             offset += pto->OffsetNextTask;
601         }
602     }
603     if (status == STATUS_SUCCESS && bApply)
604         pContext->Offload.ipHeaderOffset = bReset ? 0: pth->EncapsulationFormat.EncapsulationHeaderSize;
605     return status;
606 }
607 
608 /********************************************************
609 Fill offload query structure according to our capabilities
610 ********************************************************/
GetTcpIpCheckSumCapabilities(PARANDIS_ADAPTER * pContext,NDIS_TASK_TCP_IP_CHECKSUM * pcs)611 static BOOLEAN GetTcpIpCheckSumCapabilities(
612     PARANDIS_ADAPTER *pContext,
613     NDIS_TASK_TCP_IP_CHECKSUM *pcs)
614 {
615     tOffloadSettingsFlags f;
616     NdisZeroMemory(pcs, sizeof(*pcs));
617     ParaNdis_ResetOffloadSettings(pContext, &f, NULL);
618     pcs->V4Transmit.IpChecksum = !!f.fTxIPChecksum;
619     pcs->V4Transmit.TcpChecksum = !!f.fTxTCPChecksum;
620     pcs->V4Transmit.UdpChecksum = !!f.fTxUDPChecksum;
621     pcs->V4Transmit.IpOptionsSupported = !!f.fTxIPOptions;
622     pcs->V4Transmit.TcpOptionsSupported = !!f.fTxTCPOptions;
623     pcs->V4Receive.IpChecksum = !!f.fRxIPChecksum;
624     pcs->V4Receive.IpOptionsSupported = !!f.fRxIPOptions;
625     pcs->V4Receive.TcpChecksum = !!f.fRxTCPChecksum;
626     pcs->V4Receive.TcpOptionsSupported = !!f.fRxTCPOptions;
627     pcs->V4Receive.UdpChecksum = !!f.fRxUDPChecksum;
628 
629     return
630         pcs->V4Transmit.IpChecksum ||
631         pcs->V4Transmit.TcpChecksum ||
632         pcs->V4Transmit.UdpChecksum ||
633         pcs->V4Receive.IpChecksum ||
634         pcs->V4Receive.TcpChecksum ||
635         pcs->V4Receive.UdpChecksum;
636 }
637 
638 /********************************************************
639 Fill offload query structure according to our capabilities
640 ********************************************************/
GetLargeSendCapabilities(PARANDIS_ADAPTER * pContext,NDIS_TASK_TCP_LARGE_SEND * pls)641 static BOOLEAN GetLargeSendCapabilities(
642     PARANDIS_ADAPTER *pContext,
643     NDIS_TASK_TCP_LARGE_SEND  *pls)
644 {
645     tOffloadSettingsFlags f;
646     NdisZeroMemory(pls, sizeof(*pls));
647     ParaNdis_ResetOffloadSettings(pContext, &f, NULL);
648     pls->Version = NDIS_TASK_TCP_LARGE_SEND_V0;
649     pls->IpOptions = !!f.fTxLsoIP;
650     pls->TcpOptions = !!f.fTxLsoTCP;
651     pls->MinSegmentCount = PARANDIS_MIN_LSO_SEGMENTS;
652     pls->MaxOffLoadSize = pContext->Offload.maxPacketSize;
653     return f.fTxLso != 0;
654 }
655 
656 /********************************************************
657 Allocate and fill our capabilities, dependent on registry setting
658 Note than NDIS test of WLK1.2 and 1.3 fail (offloadmisc)
659 if CS capability indicated and passes if only LSO indicated
660 ********************************************************/
CreateOffloadInfo5Internal(PARANDIS_ADAPTER * pContext,PVOID * ppInfo,PULONG pulSize,PCCHAR reason,NDIS_TASK_OFFLOAD_HEADER * pHeader)661 NDIS_STATUS CreateOffloadInfo5Internal(
662     PARANDIS_ADAPTER *pContext,
663     PVOID *ppInfo,
664     PULONG pulSize,
665     PCCHAR reason,
666     NDIS_TASK_OFFLOAD_HEADER *pHeader)
667 {
668     NDIS_STATUS status = NDIS_STATUS_RESOURCES;
669     ULONG size =
670         sizeof(NDIS_TASK_OFFLOAD_HEADER) +
671         sizeof(NDIS_TASK_OFFLOAD) + sizeof(NDIS_TASK_TCP_IP_CHECKSUM) +
672         sizeof(NDIS_TASK_OFFLOAD) + sizeof(NDIS_TASK_TCP_LARGE_SEND);
673     *ppInfo = ParaNdis_AllocateMemory(pContext, size);
674     if (*ppInfo)
675     {
676         ULONG flags = 0;
677         NDIS_TASK_TCP_IP_CHECKSUM cs;
678         NDIS_TASK_TCP_LARGE_SEND lso;
679         flags |= GetTcpIpCheckSumCapabilities(pContext, &cs) ? 2 : 0;
680         flags |= GetLargeSendCapabilities(pContext, &lso) ? 1 : 0;
681         if (flags)
682         {
683             NDIS_TASK_OFFLOAD_HEADER *ph;
684             NDIS_TASK_OFFLOAD *pto;
685             UINT i = 0;
686             ULONG *pOffset;
687             PVOID base;
688             *pulSize = size;
689             NdisZeroMemory(*ppInfo, size);
690             ph = (NDIS_TASK_OFFLOAD_HEADER *)*ppInfo;
691             *ph = *pHeader;
692             pto = (NDIS_TASK_OFFLOAD *)(ph + 1);
693             base = ph;
694             pOffset = &ph->OffsetFirstTask;
695             ph->OffsetFirstTask = 0;
696             do
697             {
698                 if (flags & (1 << i))
699                 {
700                     flags &= ~(1 << i);
701                     pto->Version = NDIS_TASK_OFFLOAD_VERSION;
702                     pto->Size = sizeof(*pto);
703                     *pOffset = RtlPointerToOffset(base, pto);
704                     base = pto;
705                     pOffset = &pto->OffsetNextTask;
706                     switch(i)
707                     {
708                         case 1:
709                         {
710                             NDIS_TASK_TCP_IP_CHECKSUM *pcs = (NDIS_TASK_TCP_IP_CHECKSUM *)pto->TaskBuffer;
711                             pto->Task = TcpIpChecksumNdisTask;
712                             pto->TaskBufferLength = sizeof(*pcs);
713                             NdisMoveMemory(pcs, &cs, sizeof(cs));
714                             pto = (NDIS_TASK_OFFLOAD *)(pcs + 1);
715                             break;
716                         }
717                         case 0:
718                         {
719                             NDIS_TASK_TCP_LARGE_SEND  *pls = (NDIS_TASK_TCP_LARGE_SEND *)pto->TaskBuffer;
720                             pto->Task = TcpLargeSendNdisTask;
721                             pto->TaskBufferLength = sizeof(*pls);
722                             NdisMoveMemory(pls, &lso, sizeof(lso));
723                             pto = (NDIS_TASK_OFFLOAD *)(pls + 1);
724                             break;
725                         }
726                         default:
727                             break;
728                     }
729                 }
730                 ++i;
731             } while (flags);
732             status = ParseOffload(pContext, ph, size, FALSE, reason, FALSE);
733         }
734         else
735         {
736             NdisFreeMemory(*ppInfo, 0, 0);
737             *ppInfo = NULL;
738             status = NDIS_STATUS_NOT_SUPPORTED;
739         }
740     }
741     return status;
742 }
743 
744 
CreateOffloadInfo5ForQuery(PARANDIS_ADAPTER * pContext,tOidDesc * pOid,PVOID * ppInfo,PULONG pulSize)745 NDIS_STATUS CreateOffloadInfo5ForQuery(
746     PARANDIS_ADAPTER *pContext,
747     tOidDesc *pOid,
748     PVOID *ppInfo,
749     PULONG pulSize)
750 {
751     NDIS_TASK_OFFLOAD_HEADER *pth = (NDIS_TASK_OFFLOAD_HEADER *)pOid->InformationBuffer;
752     NDIS_STATUS status;
753     *ppInfo  = NULL;
754     *pulSize = 0;
755     if (pOid->InformationBufferLength < sizeof(*pth)) pth = &ReservedHeader;
756     status = ParseOffload(pContext, pth, pOid->InformationBufferLength, FALSE, "query enter", TRUE);
757     if (status == NDIS_STATUS_SUCCESS)
758     {
759         CreateOffloadInfo5Internal(pContext, ppInfo, pulSize, "QUERY", pth);
760     }
761     return status;
762 }
763 
OnOidSetNdis5Offload(PARANDIS_ADAPTER * pContext,tOidDesc * pOid)764 NDIS_STATUS OnOidSetNdis5Offload(PARANDIS_ADAPTER *pContext, tOidDesc *pOid)
765 {
766     NDIS_STATUS status;
767     status = ParseOffload(pContext, (NDIS_TASK_OFFLOAD_HEADER *)pOid->InformationBuffer,
768         pOid->InformationBufferLength, TRUE, "SET", FALSE);
769     if (status == STATUS_SUCCESS)
770     {
771 #if 0   // only for logging after SET
772         PVOID pInfo = NULL;
773         ULONG dummy = 0;
774         CreateOffloadInfo5Internal(pContext, &pInfo, &dummy, "UPDATED", &ReservedHeader);
775         if (pInfo) NdisFreeMemory(pInfo, 0, 0);
776 #endif
777         *pOid->pBytesRead = pOid->InformationBufferLength;
778     }
779     else
780     {
781         DPrintf(0, ("[%s], restoring after unsuccessful set", __FUNCTION__));
782         pContext->Offload = pContext->Offload;
783     }
784     return status;
785 }
786