1 /* 2 * This file contains driver-related part of NDIS5.X adapter driver. 3 * 4 * Copyright (c) 2008-2017 Red Hat, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met : 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and / or other materials provided with the distribution. 14 * 3. Neither the names of the copyright holders nor the names of their contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 #include "ParaNdis5.h" 30 31 //#define NO_XP_POWER_MANAGEMENT 32 33 #ifdef WPP_EVENT_TRACING 34 #include "ParaNdis5-Driver.tmh" 35 #endif 36 37 static NDIS_HANDLE DriverHandle; 38 static ULONG gID = 0; 39 40 /****************************************************** 41 Unload handler, only responsibility is cleanup WPP 42 *******************************************************/ 43 static VOID NTAPI ParaVirtualNICUnload(IN PDRIVER_OBJECT pDriverObject) 44 { 45 DEBUG_ENTRY(0); 46 ParaNdis_DebugCleanup(pDriverObject); 47 } 48 49 /************************************************************* 50 Required NDIS function 51 Responsible to put the adapter to known (initial) hardware state 52 53 Do not call any NDIS functions 54 *************************************************************/ 55 static VOID NTAPI ParaNdis5_Shutdown(IN NDIS_HANDLE MiniportAdapterContext) 56 { 57 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; 58 ParaNdis_OnShutdown(pContext); 59 } 60 61 /****************************************************** 62 Required NDIS procedure 63 Allocates and initializes adapter context 64 Finally sets send and receive to Enabled state and reports connect 65 Returns: 66 NDIS_STATUS SUCCESS or some error code 67 *******************************************************/ 68 static NDIS_STATUS NTAPI ParaNdis5_Initialize(OUT PNDIS_STATUS OpenErrorStatus, 69 OUT PUINT SelectedMediumIndex, 70 IN PNDIS_MEDIUM MediumArray, 71 IN UINT MediumArraySize, 72 IN NDIS_HANDLE MiniportAdapterHandle, 73 IN NDIS_HANDLE WrapperConfigurationContext) 74 { 75 NDIS_STATUS status = NDIS_STATUS_UNSUPPORTED_MEDIA; 76 PARANDIS_ADAPTER *pContext = NULL; 77 UINT i; 78 for(i = 0; i < MediumArraySize; ++i) 79 { 80 if(MediumArray[i] == NdisMedium802_3) 81 { 82 *SelectedMediumIndex = i; 83 status = NDIS_STATUS_SUCCESS; 84 break; 85 } 86 } 87 88 if (status == NDIS_STATUS_SUCCESS) 89 { 90 pContext = 91 (PARANDIS_ADAPTER *)ParaNdis_AllocateMemory(NULL, sizeof(PARANDIS_ADAPTER)); 92 if (!pContext) 93 { 94 status = NDIS_STATUS_RESOURCES; 95 } 96 } 97 98 if (status == NDIS_STATUS_SUCCESS) 99 { 100 PVOID pResourceList = &status; 101 UINT uSize = 0; 102 NdisZeroMemory(pContext, sizeof(PARANDIS_ADAPTER)); 103 pContext->ulUniqueID = NdisInterlockedIncrement(&gID); 104 pContext->DriverHandle = DriverHandle; 105 pContext->MiniportHandle = MiniportAdapterHandle; 106 pContext->WrapperConfigurationHandle = WrapperConfigurationContext; 107 NdisMQueryAdapterResources(&status, WrapperConfigurationContext, pResourceList, &uSize); 108 if (uSize > 0) 109 pResourceList = ParaNdis_AllocateMemory(MiniportAdapterHandle, uSize); 110 else 111 pResourceList = NULL; 112 if (!pResourceList) 113 status = uSize > 0 ? NDIS_STATUS_RESOURCES : NDIS_STATUS_FAILURE; 114 else 115 { 116 ULONG attributes; 117 attributes = NDIS_ATTRIBUTE_DESERIALIZE | NDIS_ATTRIBUTE_BUS_MASTER; 118 // in XP SP2, if this flag is NOT set, the NDIS halts miniport 119 // upon transition to S1..S4. 120 // it seems that XP SP3 ignores it and always sends SET_POWER to D3 121 #ifndef NO_XP_POWER_MANAGEMENT 122 attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; 123 #endif 124 NdisMSetAttributesEx( 125 MiniportAdapterHandle, 126 pContext, 127 0, 128 attributes, 129 NdisInterfacePci); 130 NdisMQueryAdapterResources(&status, WrapperConfigurationContext, pResourceList, &uSize); 131 status = ParaNdis_InitializeContext(pContext, (PNDIS_RESOURCE_LIST)pResourceList); 132 NdisFreeMemory(pResourceList, 0, 0); 133 } 134 } 135 136 if (status == NDIS_STATUS_SUCCESS) 137 { 138 status = ParaNdis_FinishInitialization(pContext); 139 if (status == NDIS_STATUS_SUCCESS) 140 { 141 ParaNdis_DebugRegisterMiniport(pContext, TRUE); 142 ParaNdis_IndicateConnect(pContext, FALSE, TRUE); 143 ParaNdis5_StopSend(pContext, FALSE, NULL); 144 ParaNdis5_StopReceive(pContext, FALSE, NULL); 145 if (!pContext->ulMilliesToConnect) 146 { 147 ParaNdis_ReportLinkStatus(pContext, FALSE); 148 } 149 else 150 { 151 NdisSetTimer(&pContext->ConnectTimer, pContext->ulMilliesToConnect); 152 } 153 } 154 else 155 { 156 ParaNdis_CleanupContext(pContext); 157 } 158 } 159 160 if (status != NDIS_STATUS_SUCCESS && pContext) 161 { 162 NdisFreeMemory(pContext, 0, 0); 163 } 164 165 DEBUG_EXIT_STATUS(0, status); 166 return status; 167 } 168 169 170 /************************************************************* 171 Callback of delayed receive pause procedure upon reset request 172 *************************************************************/ 173 static void OnReceiveStoppedOnReset(VOID *p) 174 { 175 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p; 176 DEBUG_ENTRY(0); 177 NdisSetEvent(&pContext->ResetEvent); 178 } 179 180 /************************************************************* 181 Callback of delayed send pause procedure upon reset request 182 *************************************************************/ 183 static void OnSendStoppedOnReset(VOID *p) 184 { 185 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p; 186 DEBUG_ENTRY(0); 187 NdisSetEvent(&pContext->ResetEvent); 188 } 189 190 VOID ParaNdis_Suspend(PARANDIS_ADAPTER *pContext) 191 { 192 DEBUG_ENTRY(0); 193 NdisResetEvent(&pContext->ResetEvent); 194 if (NDIS_STATUS_PENDING != ParaNdis5_StopSend(pContext, TRUE, OnSendStoppedOnReset)) 195 { 196 NdisSetEvent(&pContext->ResetEvent); 197 } 198 NdisWaitEvent(&pContext->ResetEvent, 0); 199 NdisResetEvent(&pContext->ResetEvent); 200 if (NDIS_STATUS_PENDING != ParaNdis5_StopReceive(pContext, TRUE, OnReceiveStoppedOnReset)) 201 { 202 NdisSetEvent(&pContext->ResetEvent); 203 } 204 NdisWaitEvent(&pContext->ResetEvent, 0); 205 NdisResetEvent(&pContext->ResetEvent); 206 DEBUG_EXIT_STATUS(0, 0); 207 } 208 209 VOID ParaNdis_Resume(PARANDIS_ADAPTER *pContext) 210 { 211 ParaNdis5_StopSend(pContext, FALSE, NULL); 212 ParaNdis5_StopReceive(pContext, FALSE, NULL); 213 DEBUG_EXIT_STATUS(0, 0); 214 } 215 216 static void NTAPI OnResetWorkItem(NDIS_WORK_ITEM * pWorkItem, PVOID Context) 217 { 218 tGeneralWorkItem *pwi = (tGeneralWorkItem *)pWorkItem; 219 PARANDIS_ADAPTER *pContext = pwi->pContext; 220 DEBUG_ENTRY(0); 221 222 pContext->bResetInProgress = TRUE; 223 ParaNdis_IndicateConnect(pContext, FALSE, FALSE); 224 ParaNdis_Suspend(pContext); 225 ParaNdis_Resume(pContext); 226 pContext->bResetInProgress = FALSE; 227 ParaNdis_ReportLinkStatus(pContext, FALSE); 228 229 NdisFreeMemory(pwi, 0, 0); 230 ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 0, NDIS_STATUS_SUCCESS, 0); 231 NdisMResetComplete(pContext->MiniportHandle, NDIS_STATUS_SUCCESS, TRUE); 232 } 233 234 235 /************************************************************* 236 Required NDIS procedure 237 Called when some procedure (like OID handler) returns PENDING and 238 does not complete or when CheckForHang return TRUE 239 *************************************************************/ 240 static NDIS_STATUS NTAPI ParaNdis5_Reset( 241 OUT PBOOLEAN AddressingReset, 242 IN NDIS_HANDLE MiniportAdapterContext) 243 { 244 NDIS_STATUS status; 245 tGeneralWorkItem *pwi; 246 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; 247 DEBUG_ENTRY(0); 248 ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 1, 0, 0); 249 status = NDIS_STATUS_FAILURE; 250 pwi = ParaNdis_AllocateMemory(pContext, sizeof(tGeneralWorkItem)); 251 if (pwi) 252 { 253 pwi->pContext = pContext; 254 NdisInitializeWorkItem(&pwi->wi, OnResetWorkItem, pwi); 255 if (NdisScheduleWorkItem(&pwi->wi) == NDIS_STATUS_SUCCESS) 256 { 257 status = NDIS_STATUS_PENDING; 258 } 259 else 260 { 261 NdisFreeMemory(pwi, 0, 0); 262 } 263 } 264 if (status != NDIS_STATUS_PENDING) 265 { 266 ParaNdis_DebugHistory(pContext, hopSysReset, NULL, 0, status, 0); 267 } 268 return status; 269 } 270 271 /************************************************************* 272 Callback of delayed receive pause procedure 273 *************************************************************/ 274 static VOID OnReceiveStopped(VOID *p) 275 { 276 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p; 277 DEBUG_ENTRY(0); 278 NdisSetEvent(&pContext->HaltEvent); 279 } 280 281 /************************************************************* 282 Callback of delayed send pause procedure 283 *************************************************************/ 284 static VOID OnSendStopped(VOID *p) 285 { 286 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)p; 287 DEBUG_ENTRY(0); 288 NdisSetEvent(&pContext->HaltEvent); 289 } 290 291 static void WaitHaltEvent(PARANDIS_ADAPTER *pContext, const char *Reason) 292 { 293 UINT ms = 5000; 294 if (!NdisWaitEvent(&pContext->HaltEvent, 1)) 295 { 296 while (!NdisWaitEvent(&pContext->HaltEvent, ms)) 297 { 298 DPrintf(0, ("[%s]", __FUNCTION__)); 299 } 300 } 301 } 302 303 /************************************************************* 304 Required NDIS procedure 305 Stops TX and RX path and finished the function of adapter 306 *************************************************************/ 307 static VOID NTAPI ParaNdis5_Halt( 308 IN NDIS_HANDLE MiniportAdapterContext) 309 { 310 NDIS_STATUS status = NDIS_STATUS_SUCCESS; 311 BOOLEAN bUnused; 312 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; 313 DEBUG_ENTRY(0); 314 315 ParaNdis_DebugHistory(pContext, hopHalt, NULL, 1, 0, 0); 316 317 NdisCancelTimer(&pContext->ConnectTimer, &bUnused); 318 NdisResetEvent(&pContext->HaltEvent); 319 if (NDIS_STATUS_PENDING != ParaNdis5_StopSend(pContext, TRUE, OnSendStopped)) 320 NdisSetEvent(&pContext->HaltEvent); 321 WaitHaltEvent(pContext, "Send"); 322 NdisResetEvent(&pContext->HaltEvent); 323 if (NDIS_STATUS_PENDING != ParaNdis5_StopReceive(pContext, TRUE, OnReceiveStopped)) 324 NdisSetEvent(&pContext->HaltEvent); 325 WaitHaltEvent(pContext, "Receive"); 326 ParaNdis_CleanupContext(pContext); 327 NdisCancelTimer(&pContext->DPCPostProcessTimer, &bUnused); 328 ParaNdis_DebugHistory(pContext, hopHalt, NULL, 0, 0, 0); 329 ParaNdis_DebugRegisterMiniport(pContext, FALSE); 330 NdisFreeMemory(pContext, 0, 0); 331 DEBUG_EXIT_STATUS(0, status); 332 } 333 334 335 /************************************************************* 336 Called periodically (usually each 2 seconds) 337 *************************************************************/ 338 static BOOLEAN NTAPI ParaNdis5_CheckForHang(IN NDIS_HANDLE MiniportAdapterContext) 339 { 340 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; 341 DEBUG_ENTRY(8); 342 return ParaNdis_CheckForHang(pContext); 343 } 344 345 /************************************************************* 346 Required NDIS procedure 347 Responsible for hardware interrupt handling 348 *************************************************************/ 349 static VOID NTAPI ParaNdis5_MiniportISR(OUT PBOOLEAN InterruptRecognized, 350 OUT PBOOLEAN QueueMiniportHandleInterrupt, 351 IN NDIS_HANDLE MiniportAdapterContext) 352 { 353 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; 354 BOOLEAN b; 355 *QueueMiniportHandleInterrupt = FALSE; 356 b = ParaNdis_OnLegacyInterrupt(pContext, QueueMiniportHandleInterrupt); 357 *InterruptRecognized = b; 358 DEBUG_EXIT_STATUS(7, (ULONG)b); 359 } 360 361 /************************************************************* 362 Parameters: 363 364 Return value: 365 366 *************************************************************/ 367 VOID NTAPI ParaNdis5_PnPEventNotify(IN NDIS_HANDLE MiniportAdapterContext, 368 IN NDIS_DEVICE_PNP_EVENT PnPEvent, 369 IN PVOID InformationBuffer, 370 IN ULONG InformationBufferLength) 371 { 372 PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)MiniportAdapterContext; 373 ParaNdis_OnPnPEvent(pContext, PnPEvent, InformationBuffer, InformationBufferLength); 374 } 375 376 /************************************************************* 377 Driver's entry point 378 Parameters: 379 as usual 380 Return value: 381 SUCCESS or error code 382 *************************************************************/ 383 NDIS_STATUS NTAPI DriverEntry(PVOID DriverObject,PVOID RegistryPath) 384 { 385 NDIS_STATUS status; 386 NDIS_MINIPORT_CHARACTERISTICS chars; 387 ParaNdis_DebugInitialize(DriverObject, RegistryPath); 388 389 status = NDIS_STATUS_FAILURE; 390 391 DEBUG_ENTRY(0); 392 _LogOutString(0, __DATE__ " " __TIME__); 393 394 NdisMInitializeWrapper(&DriverHandle, 395 DriverObject, 396 RegistryPath, 397 NULL 398 ); 399 400 if (DriverHandle) 401 { 402 NdisZeroMemory(&chars, sizeof(chars)); 403 //NDIS version of the miniport 404 chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION; 405 chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION; 406 //Init and destruction 407 chars.InitializeHandler = ParaNdis5_Initialize; 408 chars.HaltHandler = ParaNdis5_Halt; 409 410 //Interrupt and DPC handling 411 chars.HandleInterruptHandler = ParaNdis5_HandleDPC; 412 chars.ISRHandler = ParaNdis5_MiniportISR; 413 414 //Packet transfer - send path and notification on the send packet 415 chars.SendPacketsHandler = ParaNdis5_SendPackets; 416 chars.ReturnPacketHandler = ParaNdis5_ReturnPacket; 417 418 //OID set\get 419 chars.SetInformationHandler = ParaNdis5_SetOID; 420 chars.QueryInformationHandler = ParaNdis5_QueryOID; 421 422 //Reset 423 chars.ResetHandler = ParaNdis5_Reset; 424 chars.CheckForHangHandler = ParaNdis5_CheckForHang; //optional 425 426 chars.CancelSendPacketsHandler = ParaNdis5_CancelSendPackets; 427 chars.PnPEventNotifyHandler = ParaNdis5_PnPEventNotify; 428 chars.AdapterShutdownHandler = ParaNdis5_Shutdown; 429 430 status = NdisMRegisterMiniport( 431 DriverHandle, 432 &chars, 433 sizeof(chars)); 434 } 435 436 if (status == NDIS_STATUS_SUCCESS) 437 { 438 NdisMRegisterUnloadHandler(DriverHandle, ParaVirtualNICUnload); 439 } 440 else if (DriverHandle) 441 { 442 DPrintf(0, ("NdisMRegisterMiniport failed")); 443 NdisTerminateWrapper(DriverHandle, NULL); 444 } 445 else 446 { 447 DPrintf(0, ("NdisMInitializeWrapper failed")); 448 } 449 450 DEBUG_EXIT_STATUS(status ? 0 : 4, status); 451 return status; 452 } 453