PageRenderTime 60ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/kernel/win/recv.c

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