Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1249 lines
32 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. recv.c
  5. Abstract:
  6. NDIS protocol entry points and utility routines to handle receiving
  7. data.
  8. Environment:
  9. Kernel mode only.
  10. Revision History:
  11. arvindm 4/6/2000 Created
  12. --*/
  13. #include "precomp.h"
  14. #define __FILENUMBER 'VCER'
  15. NTSTATUS
  16. NdisuioRead(
  17. IN PDEVICE_OBJECT pDeviceObject,
  18. IN PIRP pIrp
  19. )
  20. /*++
  21. Routine Description:
  22. Dispatch routine to handle IRP_MJ_READ.
  23. Arguments:
  24. pDeviceObject - pointer to our device object
  25. pIrp - Pointer to request packet
  26. Return Value:
  27. NT status code.
  28. --*/
  29. {
  30. PIO_STACK_LOCATION pIrpSp;
  31. ULONG FunctionCode;
  32. NTSTATUS NtStatus;
  33. PNDISUIO_OPEN_CONTEXT pOpenContext;
  34. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  35. pOpenContext = pIrpSp->FileObject->FsContext;
  36. do
  37. {
  38. //
  39. // Validate!
  40. //
  41. if (pOpenContext == NULL)
  42. {
  43. DEBUGP(DL_FATAL, ("Read: NULL FsContext on FileObject %p\n",
  44. pIrpSp->FileObject));
  45. NtStatus = STATUS_INVALID_HANDLE;
  46. break;
  47. }
  48. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  49. if (pIrp->MdlAddress == NULL)
  50. {
  51. DEBUGP(DL_FATAL, ("Read: NULL MDL address on IRP %p\n", pIrp));
  52. NtStatus = STATUS_INVALID_PARAMETER;
  53. break;
  54. }
  55. //
  56. // Try to get a virtual address for the MDL.
  57. //
  58. #ifndef WIN9X
  59. if (MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority) == NULL)
  60. {
  61. DEBUGP(DL_FATAL, ("Read: MmGetSystemAddr failed for IRP %p, MDL %p\n",
  62. pIrp, pIrp->MdlAddress));
  63. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  64. break;
  65. }
  66. #endif
  67. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  68. if (!NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
  69. {
  70. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  71. NtStatus = STATUS_INVALID_HANDLE;
  72. break;
  73. }
  74. //
  75. // Add this IRP to the list of pended Read IRPs
  76. //
  77. NUIO_INSERT_TAIL_LIST(&pOpenContext->PendedReads, &pIrp->Tail.Overlay.ListEntry);
  78. NUIO_REF_OPEN(pOpenContext); // pended read IRP
  79. pOpenContext->PendedReadCount++;
  80. //
  81. // Set up the IRP for possible cancellation.
  82. //
  83. pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
  84. IoMarkIrpPending(pIrp);
  85. IoSetCancelRoutine(pIrp, NdisuioCancelRead);
  86. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  87. NtStatus = STATUS_PENDING;
  88. //
  89. // Run the service routine for reads.
  90. //
  91. ndisuioServiceReads(pOpenContext);
  92. break;
  93. }
  94. while (FALSE);
  95. if (NtStatus != STATUS_PENDING)
  96. {
  97. NUIO_ASSERT(NtStatus != STATUS_SUCCESS);
  98. pIrp->IoStatus.Information = 0;
  99. pIrp->IoStatus.Status = NtStatus;
  100. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  101. }
  102. return (NtStatus);
  103. }
  104. VOID
  105. NdisuioCancelRead(
  106. IN PDEVICE_OBJECT pDeviceObject,
  107. IN PIRP pIrp
  108. )
  109. /*++
  110. Routine Description:
  111. Cancel a pending read IRP. We unlink the IRP from the open context
  112. queue and complete it.
  113. Arguments:
  114. pDeviceObject - pointer to our device object
  115. pIrp - IRP to be cancelled
  116. Return Value:
  117. None
  118. --*/
  119. {
  120. PNDISUIO_OPEN_CONTEXT pOpenContext;
  121. PLIST_ENTRY pEnt;
  122. PLIST_ENTRY pIrpEntry;
  123. BOOLEAN Found;
  124. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  125. Found = FALSE;
  126. pOpenContext = (PNDISUIO_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
  127. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  128. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  129. //
  130. // Locate the IRP in the pended read queue and remove it if found.
  131. //
  132. for (pIrpEntry = pOpenContext->PendedReads.Flink;
  133. pIrpEntry != &pOpenContext->PendedReads;
  134. pIrpEntry = pIrpEntry->Flink)
  135. {
  136. if (pIrp == CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry))
  137. {
  138. NUIO_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);
  139. pOpenContext->PendedReadCount--;
  140. Found = TRUE;
  141. break;
  142. }
  143. }
  144. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  145. if (Found)
  146. {
  147. DEBUGP(DL_INFO, ("CancelRead: Open %p, IRP %p\n", pOpenContext, pIrp));
  148. pIrp->IoStatus.Status = STATUS_CANCELLED;
  149. pIrp->IoStatus.Information = 0;
  150. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  151. NUIO_DEREF_OPEN(pOpenContext); // Cancel removed pended Read
  152. }
  153. }
  154. VOID
  155. ndisuioServiceReads(
  156. IN PNDISUIO_OPEN_CONTEXT pOpenContext
  157. )
  158. /*++
  159. Routine Description:
  160. Utility routine to copy received data into user buffers and
  161. complete READ IRPs.
  162. Arguments:
  163. pOpenContext - pointer to open context
  164. Return Value:
  165. None
  166. --*/
  167. {
  168. PIRP pIrp;
  169. PLIST_ENTRY pIrpEntry;
  170. PNDIS_PACKET pRcvPacket;
  171. PLIST_ENTRY pRcvPacketEntry;
  172. PUCHAR pSrc, pDst;
  173. ULONG BytesRemaining; // at pDst
  174. PNDIS_BUFFER pNdisBuffer;
  175. ULONG BytesAvailable;
  176. DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n",
  177. pOpenContext, pOpenContext->Flags));
  178. NUIO_REF_OPEN(pOpenContext); // temp ref - service reads
  179. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  180. while (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads) &&
  181. !NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue))
  182. {
  183. //
  184. // Get the first pended Read IRP
  185. //
  186. pIrpEntry = pOpenContext->PendedReads.Flink;
  187. pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);
  188. //
  189. // Check to see if it is being cancelled.
  190. //
  191. if (IoSetCancelRoutine(pIrp, NULL))
  192. {
  193. //
  194. // It isn't being cancelled, and can't be cancelled henceforth.
  195. //
  196. NUIO_REMOVE_ENTRY_LIST(pIrpEntry);
  197. //
  198. // NOTE: we decrement PendedReadCount way below in the
  199. // while loop, to avoid letting through a thread trying
  200. // to unbind.
  201. //
  202. }
  203. else
  204. {
  205. //
  206. // The IRP is being cancelled; let the cancel routine handle it.
  207. //
  208. DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %p\n",
  209. pOpenContext, pIrp));
  210. continue;
  211. }
  212. //
  213. // Get the first queued receive packet
  214. //
  215. pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink;
  216. NUIO_REMOVE_ENTRY_LIST(pRcvPacketEntry);
  217. pOpenContext->RecvPktCount --;
  218. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  219. NUIO_DEREF_OPEN(pOpenContext); // Service: dequeue rcv packet
  220. pRcvPacket = NUIO_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry);
  221. //
  222. // Copy as much data as possible from the receive packet to
  223. // the IRP MDL.
  224. //
  225. #ifndef WIN9X
  226. pDst = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
  227. NUIO_ASSERT(pDst != NULL); // since it was already mapped
  228. #else
  229. pDst = MmGetSystemAddressForMdl(pIrp->MdlAddress); // Win9x
  230. #endif
  231. BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress);
  232. pNdisBuffer = pRcvPacket->Private.Head;
  233. while (BytesRemaining && (pNdisBuffer != NULL))
  234. {
  235. #ifndef WIN9X
  236. NdisQueryBufferSafe(pNdisBuffer, &pSrc, &BytesAvailable, NormalPagePriority);
  237. if (pSrc == NULL)
  238. {
  239. DEBUGP(DL_FATAL,
  240. ("ServiceReads: Open %p, QueryBuffer failed for buffer %p\n",
  241. pOpenContext, pNdisBuffer));
  242. break;
  243. }
  244. #else
  245. NdisQueryBuffer(pNdisBuffer, &pSrc, &BytesAvailable);
  246. #endif
  247. if (BytesAvailable)
  248. {
  249. ULONG BytesToCopy = MIN(BytesAvailable, BytesRemaining);
  250. NUIO_COPY_MEM(pDst, pSrc, BytesToCopy);
  251. BytesRemaining -= BytesToCopy;
  252. pDst += BytesToCopy;
  253. }
  254. NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
  255. }
  256. //
  257. // Complete the IRP.
  258. //
  259. pIrp->IoStatus.Status = STATUS_SUCCESS;
  260. pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining;
  261. DEBUGP(DL_INFO, ("ServiceReads: Open %p, IRP %p completed with %d bytes\n",
  262. pOpenContext, pIrp, pIrp->IoStatus.Information));
  263. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  264. //
  265. // Free up the receive packet - back to the miniport if it
  266. // belongs to it, else reclaim it (local copy).
  267. //
  268. if (NdisGetPoolFromPacket(pRcvPacket) != pOpenContext->RecvPacketPool)
  269. {
  270. NdisReturnPackets(&pRcvPacket, 1);
  271. }
  272. else
  273. {
  274. ndisuioFreeReceivePacket(pOpenContext, pRcvPacket);
  275. }
  276. NUIO_DEREF_OPEN(pOpenContext); // took out pended Read
  277. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  278. pOpenContext->PendedReadCount--;
  279. }
  280. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  281. NUIO_DEREF_OPEN(pOpenContext); // temp ref - service reads
  282. }
  283. NDIS_STATUS
  284. NdisuioReceive(
  285. IN NDIS_HANDLE ProtocolBindingContext,
  286. IN NDIS_HANDLE MacReceiveContext,
  287. IN PVOID pHeaderBuffer,
  288. IN UINT HeaderBufferSize,
  289. IN PVOID pLookaheadBuffer,
  290. IN UINT LookaheadBufferSize,
  291. IN UINT PacketSize
  292. )
  293. /*++
  294. Routine Description:
  295. Our protocol receive handler called by NDIS, typically if we have
  296. a miniport below that doesn't indicate packets.
  297. We make a local packet/buffer copy of this data, queue it up, and
  298. kick off the read service routine.
  299. Arguments:
  300. ProtocolBindingContext - pointer to open context
  301. MacReceiveContext - for use in NdisTransferData
  302. pHeaderBuffer - pointer to data header
  303. HeaderBufferSize - size of the above
  304. pLookaheadBuffer - pointer to buffer containing lookahead data
  305. LookaheadBufferSize - size of the above
  306. PacketSize - size of the entire packet, minus header size.
  307. Return Value:
  308. NDIS_STATUS_NOT_ACCEPTED - if this packet is uninteresting
  309. NDIS_STATUS_SUCCESS - if we processed this successfully
  310. --*/
  311. {
  312. PNDISUIO_OPEN_CONTEXT pOpenContext;
  313. NDIS_STATUS Status;
  314. PNDISUIO_ETH_HEADER pEthHeader;
  315. PNDIS_PACKET pRcvPacket;
  316. PUCHAR pRcvData;
  317. UINT BytesTransferred;
  318. PNDIS_BUFFER pOriginalNdisBuffer, pPartialNdisBuffer;
  319. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  320. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  321. pRcvPacket = NULL;
  322. pRcvData = NULL;
  323. Status = NDIS_STATUS_SUCCESS;
  324. do
  325. {
  326. if (HeaderBufferSize != sizeof(NDISUIO_ETH_HEADER))
  327. {
  328. Status = NDIS_STATUS_NOT_ACCEPTED;
  329. break;
  330. }
  331. pEthHeader = (PNDISUIO_ETH_HEADER)pHeaderBuffer;
  332. //
  333. // Check the EtherType. If the Ether type indicates presence of
  334. // a tag, then the "real" Ether type is 4 bytes further down.
  335. //
  336. if (pEthHeader->EthType == NUIO_8021P_TAG_TYPE)
  337. {
  338. USHORT UNALIGNED *pEthType;
  339. pEthType = (USHORT UNALIGNED *)((PUCHAR)&pEthHeader->EthType + 4);
  340. if (*pEthType != Globals.EthType)
  341. {
  342. Status = NDIS_STATUS_NOT_ACCEPTED;
  343. break;
  344. }
  345. }
  346. else if (pEthHeader->EthType != Globals.EthType)
  347. {
  348. Status = NDIS_STATUS_NOT_ACCEPTED;
  349. break;
  350. }
  351. //
  352. // Allocate resources for queueing this up.
  353. //
  354. pRcvPacket = ndisuioAllocateReceivePacket(
  355. pOpenContext,
  356. PacketSize + HeaderBufferSize,
  357. &pRcvData
  358. );
  359. if (pRcvPacket == NULL)
  360. {
  361. Status = NDIS_STATUS_NOT_ACCEPTED;
  362. break;
  363. }
  364. NdisMoveMappedMemory(pRcvData, pHeaderBuffer, HeaderBufferSize);
  365. //
  366. // Check if the entire packet is within the lookahead.
  367. //
  368. if (PacketSize == LookaheadBufferSize)
  369. {
  370. NdisCopyLookaheadData(pRcvData+HeaderBufferSize,
  371. pLookaheadBuffer,
  372. LookaheadBufferSize,
  373. pOpenContext->MacOptions);
  374. //
  375. // Queue this up for receive processing, and
  376. // try to complete some read IRPs.
  377. //
  378. ndisuioQueueReceivePacket(pOpenContext, pRcvPacket);
  379. }
  380. else
  381. {
  382. //
  383. // Allocate an NDIS buffer to map the receive area
  384. // at an offset "HeaderBufferSize" from the current
  385. // start. This is so that NdisTransferData can copy
  386. // in at the right point in the destination buffer.
  387. //
  388. NdisAllocateBuffer(
  389. &Status,
  390. &pPartialNdisBuffer,
  391. pOpenContext->RecvBufferPool,
  392. pRcvData + HeaderBufferSize,
  393. PacketSize);
  394. if (Status == NDIS_STATUS_SUCCESS)
  395. {
  396. //
  397. // Unlink and save away the original NDIS Buffer
  398. // that maps the full receive buffer.
  399. //
  400. NdisUnchainBufferAtFront(pRcvPacket, &pOriginalNdisBuffer);
  401. NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pOriginalNdisBuffer;
  402. //
  403. // Link in the partial buffer for NdisTransferData to
  404. // operate on.
  405. //
  406. NdisChainBufferAtBack(pRcvPacket, pPartialNdisBuffer);
  407. DEBUGP(DL_LOUD, ("Receive: setting up for TransferData:"
  408. " Pkt %p, OriginalBuf %p, PartialBuf %p\n",
  409. pRcvPacket, pOriginalNdisBuffer, pPartialNdisBuffer));
  410. NdisTransferData(
  411. &Status,
  412. pOpenContext->BindingHandle,
  413. MacReceiveContext,
  414. 0, // ByteOffset
  415. PacketSize,
  416. pRcvPacket,
  417. &BytesTransferred);
  418. }
  419. else
  420. {
  421. //
  422. // Failure handled below in TransferDataComplete.
  423. //
  424. BytesTransferred = 0;
  425. }
  426. if (Status != NDIS_STATUS_PENDING)
  427. {
  428. NdisuioTransferDataComplete(
  429. (NDIS_HANDLE)pOpenContext,
  430. pRcvPacket,
  431. Status,
  432. BytesTransferred);
  433. }
  434. }
  435. break;
  436. }
  437. while (FALSE);
  438. return Status;
  439. DEBUGP(DL_LOUD, ("Receive: Open %p, Pkt %p, Size %d\n",
  440. pOpenContext, pRcvPacket, PacketSize));
  441. }
  442. VOID
  443. NdisuioTransferDataComplete(
  444. IN NDIS_HANDLE ProtocolBindingContext,
  445. IN PNDIS_PACKET pNdisPacket,
  446. IN NDIS_STATUS TransferStatus,
  447. IN UINT BytesTransferred
  448. )
  449. /*++
  450. Routine Description:
  451. NDIS entry point called to signal completion of a call to
  452. NdisTransferData that had pended.
  453. Arguments:
  454. ProtocolBindingContext - pointer to open context
  455. pNdisPacket - our receive packet into which data is transferred
  456. TransferStatus - status of the transfer
  457. BytesTransferred - bytes copied into the packet.
  458. Return Value:
  459. None
  460. --*/
  461. {
  462. PNDISUIO_OPEN_CONTEXT pOpenContext;
  463. PNDIS_BUFFER pOriginalBuffer, pPartialBuffer;
  464. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  465. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  466. //
  467. // Check if an NDIS_BUFFER was created to map part of the receive buffer;
  468. // if so, free it and link back the original NDIS_BUFFER that maps
  469. // the full receive buffer to the packet.
  470. //
  471. pOriginalBuffer = NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pNdisPacket);
  472. if (pOriginalBuffer != NULL)
  473. {
  474. //
  475. // We had stashed off the NDIS_BUFFER for the full receive
  476. // buffer in the packet reserved area. Unlink the partial
  477. // buffer and link in the full buffer.
  478. //
  479. NdisUnchainBufferAtFront(pNdisPacket, &pPartialBuffer);
  480. NdisChainBufferAtBack(pNdisPacket, pOriginalBuffer);
  481. DEBUGP(DL_LOUD, ("TransferComp: Pkt %p, OrigBuf %p, PartialBuf %p\n",
  482. pNdisPacket, pOriginalBuffer, pPartialBuffer));
  483. //
  484. // Free up the partial buffer.
  485. //
  486. NdisFreeBuffer(pPartialBuffer);
  487. }
  488. if (TransferStatus == NDIS_STATUS_SUCCESS)
  489. {
  490. //
  491. // Queue this up for receive processing, and
  492. // try to complete some read IRPs.
  493. //
  494. ndisuioQueueReceivePacket(pOpenContext, pNdisPacket);
  495. }
  496. else
  497. {
  498. ndisuioFreeReceivePacket(pOpenContext, pNdisPacket);
  499. }
  500. }
  501. VOID
  502. NdisuioReceiveComplete(
  503. IN NDIS_HANDLE ProtocolBindingContext
  504. )
  505. /*++
  506. Routine Description:
  507. Protocol entry point called by NDIS when the miniport
  508. has finished indicating up a batch of receives.
  509. We ignore this.
  510. Arguments:
  511. ProtocolBindingContext - pointer to open context
  512. Return Value:
  513. None
  514. --*/
  515. {
  516. PNDISUIO_OPEN_CONTEXT pOpenContext;
  517. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  518. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  519. return;
  520. }
  521. INT
  522. NdisuioReceivePacket(
  523. IN NDIS_HANDLE ProtocolBindingContext,
  524. IN PNDIS_PACKET pNdisPacket
  525. )
  526. /*++
  527. Routine Description:
  528. Protocol entry point called by NDIS if the driver below
  529. uses NDIS 4 style receive packet indications.
  530. If the miniport allows us to hold on to this packet, we
  531. use it as is, otherwise we make a copy.
  532. Arguments:
  533. ProtocolBindingContext - pointer to open context
  534. pNdisPacket - the packet being indicated up.
  535. Return Value:
  536. None
  537. --*/
  538. {
  539. PNDISUIO_OPEN_CONTEXT pOpenContext;
  540. PNDIS_BUFFER pNdisBuffer;
  541. UINT BufferLength;
  542. PNDISUIO_ETH_HEADER pEthHeader;
  543. PNDIS_PACKET pCopyPacket;
  544. PUCHAR pCopyBuf;
  545. UINT TotalPacketLength;
  546. UINT BytesCopied;
  547. INT RefCount = 0;
  548. NDIS_STATUS Status;
  549. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  550. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  551. #ifdef NDIS51
  552. NdisGetFirstBufferFromPacketSafe(
  553. pNdisPacket,
  554. &pNdisBuffer,
  555. &pEthHeader,
  556. &BufferLength,
  557. &TotalPacketLength,
  558. NormalPagePriority);
  559. if (pEthHeader == NULL)
  560. {
  561. //
  562. // The system is low on resources. Set up to handle failure
  563. // below.
  564. //
  565. BufferLength = 0;
  566. }
  567. #else
  568. NdisGetFirstBufferFromPacket(
  569. pNdisPacket,
  570. &pNdisBuffer,
  571. &pEthHeader,
  572. &BufferLength,
  573. &TotalPacketLength);
  574. #endif
  575. do
  576. {
  577. if (BufferLength < sizeof(NDISUIO_ETH_HEADER))
  578. {
  579. DEBUGP(DL_WARN,
  580. ("ReceivePacket: Open %p, runt pkt %p, first buffer length %d\n",
  581. pOpenContext, pNdisPacket, BufferLength));
  582. Status = NDIS_STATUS_NOT_ACCEPTED;
  583. break;
  584. }
  585. //
  586. // Check the EtherType. If the Ether type indicates presence of
  587. // a tag, then the "real" Ether type is 4 bytes further down.
  588. //
  589. if (pEthHeader->EthType == NUIO_8021P_TAG_TYPE)
  590. {
  591. USHORT UNALIGNED *pEthType;
  592. pEthType = (USHORT UNALIGNED *)((PUCHAR)&pEthHeader->EthType + 4);
  593. if (*pEthType != Globals.EthType)
  594. {
  595. Status = NDIS_STATUS_NOT_ACCEPTED;
  596. break;
  597. }
  598. }
  599. else if (pEthHeader->EthType != Globals.EthType)
  600. {
  601. Status = NDIS_STATUS_NOT_ACCEPTED;
  602. break;
  603. }
  604. DEBUGP(DL_LOUD, ("ReceivePacket: Open %p, interesting pkt %p\n",
  605. pOpenContext, pNdisPacket));
  606. //
  607. // If the miniport is out of resources, we can't queue
  608. // this packet - make a copy if this is so.
  609. //
  610. if ((NDIS_GET_PACKET_STATUS(pNdisPacket) == NDIS_STATUS_RESOURCES) ||
  611. pOpenContext->bRunningOnWin9x)
  612. {
  613. pCopyPacket = ndisuioAllocateReceivePacket(
  614. pOpenContext,
  615. TotalPacketLength,
  616. &pCopyBuf
  617. );
  618. if (pCopyPacket == NULL)
  619. {
  620. DEBUGP(DL_FATAL, ("ReceivePacket: Open %p, failed to"
  621. " alloc copy, %d bytes\n", pOpenContext, TotalPacketLength));
  622. break;
  623. }
  624. NdisCopyFromPacketToPacket(
  625. pCopyPacket,
  626. 0,
  627. TotalPacketLength,
  628. pNdisPacket,
  629. 0,
  630. &BytesCopied);
  631. NUIO_ASSERT(BytesCopied == TotalPacketLength);
  632. pNdisPacket = pCopyPacket;
  633. }
  634. else
  635. {
  636. //
  637. // We can queue the original packet - return
  638. // a packet reference count indicating that
  639. // we will call NdisReturnPackets when we are
  640. // done with this packet.
  641. //
  642. RefCount = 1;
  643. }
  644. //
  645. // Queue this up and service any pending Read IRPs.
  646. //
  647. ndisuioQueueReceivePacket(pOpenContext, pNdisPacket);
  648. break;
  649. }
  650. while (FALSE);
  651. return (RefCount);
  652. }
  653. VOID
  654. ndisuioQueueReceivePacket(
  655. IN PNDISUIO_OPEN_CONTEXT pOpenContext,
  656. IN PNDIS_PACKET pRcvPacket
  657. )
  658. /*++
  659. Routine Description:
  660. Queue up a received packet on the open context structure.
  661. If the queue size goes beyond a water mark, discard a packet
  662. at the head of the queue.
  663. Finally, run the queue service routine.
  664. Arguments:
  665. pOpenContext - pointer to open context
  666. pRcvPacket - the received packet
  667. Return Value:
  668. None
  669. --*/
  670. {
  671. PLIST_ENTRY pEnt;
  672. PLIST_ENTRY pDiscardEnt;
  673. PNDIS_PACKET pDiscardPkt;
  674. do
  675. {
  676. pEnt = NUIO_RCV_PKT_TO_LIST_ENTRY(pRcvPacket);
  677. NUIO_REF_OPEN(pOpenContext); // queued rcv packet
  678. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  679. //
  680. // Check if the binding is in the proper state to receive
  681. // this packet.
  682. //
  683. if (NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE) &&
  684. (pOpenContext->PowerState == NetDeviceStateD0))
  685. {
  686. NUIO_INSERT_TAIL_LIST(&pOpenContext->RecvPktQueue, pEnt);
  687. pOpenContext->RecvPktCount++;
  688. DEBUGP(DL_VERY_LOUD, ("QueueReceivePacket: open %p,"
  689. " queued pkt %p, queue size %d\n",
  690. pOpenContext, pRcvPacket, pOpenContext->RecvPktCount));
  691. }
  692. else
  693. {
  694. //
  695. // Received this packet when the binding is going away.
  696. // Drop this.
  697. //
  698. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  699. ndisuioFreeReceivePacket(pOpenContext, pRcvPacket);
  700. NUIO_DEREF_OPEN(pOpenContext); // dropped rcv packet - bad state
  701. break;
  702. }
  703. //
  704. // Trim the queue if it has grown too big.
  705. //
  706. if (pOpenContext->RecvPktCount > MAX_RECV_QUEUE_SIZE)
  707. {
  708. //
  709. // Remove the head of the queue.
  710. //
  711. pDiscardEnt = pOpenContext->RecvPktQueue.Flink;
  712. NUIO_REMOVE_ENTRY_LIST(pDiscardEnt);
  713. pOpenContext->RecvPktCount --;
  714. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  715. pDiscardPkt = NUIO_LIST_ENTRY_TO_RCV_PKT(pDiscardEnt);
  716. ndisuioFreeReceivePacket(pOpenContext, pDiscardPkt);
  717. NUIO_DEREF_OPEN(pOpenContext); // dropped rcv packet - queue too long
  718. DEBUGP(DL_INFO, ("QueueReceivePacket: open %p queue"
  719. " too long, discarded pkt %p\n",
  720. pOpenContext, pDiscardPkt));
  721. }
  722. else
  723. {
  724. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  725. }
  726. //
  727. // Run the receive queue service routine now.
  728. //
  729. ndisuioServiceReads(pOpenContext);
  730. }
  731. while (FALSE);
  732. }
  733. PNDIS_PACKET
  734. ndisuioAllocateReceivePacket(
  735. IN PNDISUIO_OPEN_CONTEXT pOpenContext,
  736. IN UINT DataLength,
  737. OUT PUCHAR * ppDataBuffer
  738. )
  739. /*++
  740. Routine Description:
  741. Allocate resources to copy and queue a received packet.
  742. Arguments:
  743. pOpenContext - pointer to open context for received packet
  744. DataLength - total length in bytes of the packet
  745. ppDataBuffer - place to return pointer to allocated buffer
  746. Return Value:
  747. Pointer to NDIS packet if successful, else NULL.
  748. --*/
  749. {
  750. PNDIS_PACKET pNdisPacket;
  751. PNDIS_BUFFER pNdisBuffer;
  752. PUCHAR pDataBuffer;
  753. NDIS_STATUS Status;
  754. pNdisPacket = NULL;
  755. pNdisBuffer = NULL;
  756. pDataBuffer = NULL;
  757. do
  758. {
  759. NUIO_ALLOC_MEM(pDataBuffer, DataLength);
  760. if (pDataBuffer == NULL)
  761. {
  762. DEBUGP(DL_FATAL, ("AllocRcvPkt: open %p, failed to alloc"
  763. " data buffer %d bytes\n", pOpenContext, DataLength));
  764. break;
  765. }
  766. //
  767. // Make this an NDIS buffer.
  768. //
  769. NdisAllocateBuffer(
  770. &Status,
  771. &pNdisBuffer,
  772. pOpenContext->RecvBufferPool,
  773. pDataBuffer,
  774. DataLength);
  775. if (Status != NDIS_STATUS_SUCCESS)
  776. {
  777. DEBUGP(DL_FATAL, ("AllocateRcvPkt: open %p, failed to alloc"
  778. " NDIS buffer, %d bytes\n", pOpenContext, DataLength));
  779. break;
  780. }
  781. NdisAllocatePacket(&Status, &pNdisPacket, pOpenContext->RecvPacketPool);
  782. if (Status != NDIS_STATUS_SUCCESS)
  783. {
  784. DEBUGP(DL_FATAL, ("AllocateRcvPkt: open %p, failed to alloc"
  785. " NDIS packet, %d bytes\n", pOpenContext, DataLength));
  786. break;
  787. }
  788. NDIS_SET_PACKET_STATUS(pNdisPacket, 0);
  789. NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pNdisPacket) = NULL;
  790. NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
  791. *ppDataBuffer = pDataBuffer;
  792. break;
  793. }
  794. while (FALSE);
  795. if (pNdisPacket == NULL)
  796. {
  797. //
  798. // Clean up
  799. //
  800. if (pNdisBuffer != NULL)
  801. {
  802. NdisFreeBuffer(pNdisBuffer);
  803. }
  804. if (pDataBuffer != NULL)
  805. {
  806. NUIO_FREE_MEM(pDataBuffer);
  807. }
  808. }
  809. return (pNdisPacket);
  810. }
  811. VOID
  812. ndisuioFreeReceivePacket(
  813. IN PNDISUIO_OPEN_CONTEXT pOpenContext,
  814. IN PNDIS_PACKET pNdisPacket
  815. )
  816. /*++
  817. Routine Description:
  818. Free up all resources associated with a received packet. If this
  819. is a local copy, free the packet to our receive pool, else return
  820. this to the miniport.
  821. Arguments:
  822. pOpenContext - pointer to open context
  823. pNdisPacket - pointer to packet to be freed.
  824. Return Value:
  825. None
  826. --*/
  827. {
  828. PNDIS_BUFFER pNdisBuffer;
  829. UINT TotalLength;
  830. UINT BufferLength;
  831. PUCHAR pCopyData;
  832. if (NdisGetPoolFromPacket(pNdisPacket) == pOpenContext->RecvPacketPool)
  833. {
  834. //
  835. // This is a local copy.
  836. //
  837. #ifdef NDIS51
  838. NdisGetFirstBufferFromPacketSafe(
  839. pNdisPacket,
  840. &pNdisBuffer,
  841. (PVOID *)&pCopyData,
  842. &BufferLength,
  843. &TotalLength,
  844. NormalPagePriority);
  845. #else
  846. NdisGetFirstBufferFromPacket(
  847. pNdisPacket,
  848. &pNdisBuffer,
  849. (PVOID *)&pCopyData,
  850. &BufferLength,
  851. &TotalLength);
  852. #endif
  853. NUIO_ASSERT(BufferLength == TotalLength);
  854. NUIO_ASSERT(pNdisBuffer != NULL);
  855. NUIO_ASSERT(pCopyData != NULL); // we would have allocated non-paged pool
  856. NdisFreePacket(pNdisPacket);
  857. NdisFreeBuffer(pNdisBuffer);
  858. NUIO_FREE_MEM(pCopyData);
  859. }
  860. else
  861. {
  862. NdisReturnPackets(&pNdisPacket, 1);
  863. }
  864. }
  865. VOID
  866. ndisuioCancelPendingReads(
  867. IN PNDISUIO_OPEN_CONTEXT pOpenContext
  868. )
  869. /*++
  870. Routine Description:
  871. Cancel any pending read IRPs queued on the given open.
  872. Arguments:
  873. pOpenContext - pointer to open context
  874. Return Value:
  875. None
  876. --*/
  877. {
  878. PIRP pIrp;
  879. PLIST_ENTRY pIrpEntry;
  880. NUIO_REF_OPEN(pOpenContext); // temp ref - cancel reads
  881. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  882. while (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads))
  883. {
  884. //
  885. // Get the first pended Read IRP
  886. //
  887. pIrpEntry = pOpenContext->PendedReads.Flink;
  888. pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);
  889. //
  890. // Check to see if it is being cancelled.
  891. //
  892. if (IoSetCancelRoutine(pIrp, NULL))
  893. {
  894. //
  895. // It isn't being cancelled, and can't be cancelled henceforth.
  896. //
  897. NUIO_REMOVE_ENTRY_LIST(pIrpEntry);
  898. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  899. //
  900. // Complete the IRP.
  901. //
  902. pIrp->IoStatus.Status = STATUS_CANCELLED;
  903. pIrp->IoStatus.Information = 0;
  904. DEBUGP(DL_INFO, ("CancelPendingReads: Open %p, IRP %p cancelled\n",
  905. pOpenContext, pIrp));
  906. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  907. NUIO_DEREF_OPEN(pOpenContext); // took out pended Read for cancelling
  908. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  909. pOpenContext->PendedReadCount--;
  910. }
  911. else
  912. {
  913. //
  914. // It is being cancelled, let the cancel routine handle it.
  915. //
  916. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  917. //
  918. // Give the cancel routine some breathing space, otherwise
  919. // we might end up examining the same (cancelled) IRP over
  920. // and over again.
  921. //
  922. NUIO_SLEEP(1);
  923. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  924. }
  925. }
  926. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  927. NUIO_DEREF_OPEN(pOpenContext); // temp ref - cancel reads
  928. }
  929. VOID
  930. ndisuioFlushReceiveQueue(
  931. IN PNDISUIO_OPEN_CONTEXT pOpenContext
  932. )
  933. /*++
  934. Routine Description:
  935. Free any receive packets queued up on the specified open
  936. Arguments:
  937. pOpenContext - pointer to open context
  938. Return Value:
  939. None
  940. --*/
  941. {
  942. PLIST_ENTRY pRcvPacketEntry;
  943. PNDIS_PACKET pRcvPacket;
  944. NUIO_REF_OPEN(pOpenContext); // temp ref - flushRcvQueue
  945. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  946. while (!NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue))
  947. {
  948. //
  949. // Get the first queued receive packet
  950. //
  951. pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink;
  952. NUIO_REMOVE_ENTRY_LIST(pRcvPacketEntry);
  953. pOpenContext->RecvPktCount --;
  954. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  955. pRcvPacket = NUIO_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry);
  956. DEBUGP(DL_LOUD, ("FlushReceiveQueue: open %p, pkt %p\n",
  957. pOpenContext, pRcvPacket));
  958. ndisuioFreeReceivePacket(pOpenContext, pRcvPacket);
  959. NUIO_DEREF_OPEN(pOpenContext); // took out pended Read
  960. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  961. }
  962. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  963. NUIO_DEREF_OPEN(pOpenContext); // temp ref - flushRcvQueue
  964. }