Leaked source code of windows server 2003
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.

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