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