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.

1284 lines
50 KiB

  1. /***************************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. RECEIVE.C
  5. Abstract:
  6. Packet and message receive routines
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  11. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  12. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  13. PURPOSE.
  14. Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  15. Revision History:
  16. 5/20/99 : created
  17. Author:
  18. Tom Green
  19. ****************************************************************************/
  20. #include "precomp.h"
  21. //
  22. // Some debug stuff, not critical to operation:
  23. //
  24. ULONG RcvFrameAllocs = 0;
  25. ULONG RcvTimerCount = 0;
  26. ULONG RcvPacketCount = 0;
  27. ULONG RcvMaxPackets = 0;
  28. ULONG RcvIndicateCount = 0;
  29. ULONG RcvReturnCount = 0;
  30. //
  31. // For raw encapsulation test
  32. //
  33. extern ULONG gRawEncap;
  34. /****************************************************************************/
  35. /* RndismpGetReturnedPackets */
  36. /****************************************************************************/
  37. /* */
  38. /* Routine Description: */
  39. /* */
  40. /* This function is called by NDIS to return to our possession a packet */
  41. /* that we had indicated up. */
  42. /* */
  43. /* Arguments: */
  44. /* */
  45. /* MiniportAdapterContext - a context version of our Adapter pointer */
  46. /* pNdisPacket - the packet that is being freed */
  47. /* */
  48. /* Return: */
  49. /* */
  50. /* VOID */
  51. /* */
  52. /****************************************************************************/
  53. VOID
  54. RndismpReturnPacket(IN NDIS_HANDLE MiniportAdapterContext,
  55. IN PNDIS_PACKET pNdisPacket)
  56. {
  57. PRNDISMP_ADAPTER pAdapter;
  58. PRNDISMP_RECV_PKT_RESERVED pRcvResvd;
  59. PRNDISMP_RECV_DATA_FRAME pRcvFrame;
  60. PRNDISMP_VC pVc;
  61. PNDIS_BUFFER pNdisBuffer;
  62. ULONG RefCount;
  63. // get adapter context
  64. pAdapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
  65. CHECK_VALID_ADAPTER(pAdapter);
  66. TRACE2(("RndismpReturnPacket: Adapter %x, Pkt %x\n", pAdapter, pNdisPacket));
  67. // get receive frame context
  68. pRcvResvd = PRNDISMP_RESERVED_FROM_RECV_PACKET(pNdisPacket);
  69. pRcvFrame = pRcvResvd->pRcvFrame;
  70. pVc = pRcvResvd->pVc;
  71. // Free the buffer.
  72. NdisQueryPacket(pNdisPacket,
  73. NULL,
  74. NULL,
  75. &pNdisBuffer,
  76. NULL);
  77. NdisFreeBuffer(pNdisBuffer);
  78. DereferenceRcvFrame(pRcvFrame, pAdapter);
  79. if (pVc != NULL)
  80. {
  81. RNDISMP_DEREF_VC(pVc, &RefCount);
  82. }
  83. NdisFreePacket(pNdisPacket);
  84. RcvReturnCount++;
  85. } // RndismpReturnPacket
  86. /****************************************************************************/
  87. /* DereferenceRcvFrame */
  88. /****************************************************************************/
  89. /* */
  90. /* Routine Description: */
  91. /* */
  92. /* Utility routine to deref a receive frame structure, e.g. when a */
  93. /* received packet is returned to us from higher layers. */
  94. /* */
  95. /* Arguments: */
  96. /* */
  97. /* pRcvFrame - Pointer to receive frame to be deref'ed. */
  98. /* pAdapter - Pointer to adapter structure */
  99. /* */
  100. /* Return: */
  101. /* */
  102. /* VOID */
  103. /* */
  104. /****************************************************************************/
  105. VOID
  106. DereferenceRcvFrame(IN PRNDISMP_RECV_DATA_FRAME pRcvFrame,
  107. IN PRNDISMP_ADAPTER pAdapter)
  108. {
  109. ULONG ReturnsPending;
  110. ReturnsPending = NdisInterlockedDecrement(&pRcvFrame->ReturnsPending);
  111. if (ReturnsPending == 0)
  112. {
  113. TRACE3(("DerefRcvFrame: Adapter %x, Frame %p, uPcontext %x, LocalCopy %d\n",
  114. pAdapter, pRcvFrame, pRcvFrame->MicroportMessageContext, pRcvFrame->bMessageCopy));
  115. if (pRcvFrame->bMessageCopy)
  116. {
  117. FreeRcvMessageCopy(pRcvFrame->pLocalMessageCopy);
  118. }
  119. else
  120. {
  121. TRACE3(("DerefRcvFrame: uP MDL %x, uPContext %x\n",
  122. pRcvFrame->pMicroportMdl,
  123. pRcvFrame->MicroportMessageContext));
  124. RNDISMP_RETURN_TO_MICROPORT(pAdapter,
  125. pRcvFrame->pMicroportMdl,
  126. pRcvFrame->MicroportMessageContext);
  127. }
  128. FreeReceiveFrame(pRcvFrame, pAdapter);
  129. }
  130. } // DereferenceRcvFrame
  131. /****************************************************************************/
  132. /* RndisMIndicateReceive */
  133. /****************************************************************************/
  134. /* */
  135. /* Routine Description: */
  136. /* */
  137. /* Called by microport to indicate receiving RNDIS messages */
  138. /* */
  139. /* Arguments: */
  140. /* */
  141. /* MiniportAdapterContext - a context version of our Adapter pointer */
  142. /* pMdl - pointer to MDL chain describing RNDIS message */
  143. /* MicroportMessageContext - context for message from micorport */
  144. /* ChannelType - channel on which this message arrived (control/data) */
  145. /* ReceiveStatus - used by microport to indicate it is low on resource */
  146. /* */
  147. /* Return: */
  148. /* */
  149. /* VOID */
  150. /* */
  151. /****************************************************************************/
  152. VOID
  153. RndisMIndicateReceive(IN NDIS_HANDLE MiniportAdapterContext,
  154. IN PMDL pMdl,
  155. IN NDIS_HANDLE MicroportMessageContext,
  156. IN RM_CHANNEL_TYPE ChannelType,
  157. IN NDIS_STATUS ReceiveStatus)
  158. {
  159. PRNDISMP_ADAPTER Adapter;
  160. PRNDIS_MESSAGE pMessage;
  161. BOOLEAN bMessageCopied = FALSE;
  162. PRNDISMP_MSG_HANDLER_FUNC pMsgHandlerFunc;
  163. BOOLEAN bReturnToMicroport;
  164. NDIS_STATUS Status;
  165. PRNDISMP_RECV_MSG_CONTEXT pRcvMsg;
  166. PMDL pTmpMdl;
  167. ULONG TotalLength;
  168. Adapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
  169. CHECK_VALID_ADAPTER(Adapter);
  170. TRACE2(("RndisIndicateReceive: Adapter %x, Mdl %x\n", Adapter, pMdl));
  171. RNDISMP_ASSERT_AT_DISPATCH();
  172. bReturnToMicroport = TRUE;
  173. #if DBG
  174. NdisInterlockedIncrement(&Adapter->MicroportReceivesOutstanding);
  175. #endif
  176. do
  177. {
  178. //
  179. // Find the total length first.
  180. //
  181. TotalLength = 0;
  182. for (pTmpMdl = pMdl; pTmpMdl != NULL; pTmpMdl = RNDISMP_GET_MDL_NEXT(pTmpMdl))
  183. {
  184. TotalLength += RNDISMP_GET_MDL_LENGTH(pTmpMdl);
  185. }
  186. //
  187. // Check if the entire message is in a single MDL - if not, make a copy
  188. // TBD -- handle multi-MDL messages without copying.
  189. //
  190. if ((RNDISMP_GET_MDL_NEXT(pMdl) == NULL) &&
  191. (!Adapter->bRunningOnWin9x || (ReceiveStatus != NDIS_STATUS_RESOURCES)))
  192. {
  193. pMessage = RNDISMP_GET_MDL_ADDRESS(pMdl);
  194. if (pMessage == NULL)
  195. {
  196. TRACE0(("RndisMIndicateReceive: Adapter %x: failed to"
  197. " access msg from MDL %x\n", Adapter, pMdl));
  198. break;
  199. }
  200. }
  201. else
  202. {
  203. pMessage = CoalesceMultiMdlMessage(pMdl, TotalLength);
  204. if (pMessage == NULL)
  205. {
  206. break;
  207. }
  208. bMessageCopied = TRUE;
  209. }
  210. TRACEDUMP(("Received msg (%d bytes):\n", TotalLength),
  211. pMessage, TotalLength);
  212. // get timer tick for this message
  213. NdisGetSystemUpTime(&Adapter->LastMessageFromDevice);
  214. if (Adapter->bRunningOnWin9x)
  215. {
  216. Status = MemAlloc(&pRcvMsg, sizeof(RNDISMP_RECV_MSG_CONTEXT));
  217. if (Status != NDIS_STATUS_SUCCESS)
  218. {
  219. bReturnToMicroport = TRUE;
  220. TRACE1(("RndisMIndicateReceive: Adapter %x, failed to alloc rcv msg\n",
  221. Adapter));
  222. break;
  223. }
  224. pRcvMsg->MicroportMessageContext = MicroportMessageContext;
  225. pRcvMsg->pMdl = pMdl;
  226. pRcvMsg->TotalLength = TotalLength;
  227. pRcvMsg->pMessage = pMessage;
  228. pRcvMsg->ReceiveStatus = ReceiveStatus;
  229. pRcvMsg->bMessageCopied = bMessageCopied;
  230. pRcvMsg->ChannelType = ChannelType;
  231. //
  232. // Queue all packets for indicating receives up to protocols.
  233. // We do this rather than indicate packets directly because
  234. // we are in a DPC context, and need to be in a "global event"
  235. // context to make the upper layers happy. One way to be in a
  236. // global event context is to be in the context of an NDIS timer
  237. // callback function.
  238. //
  239. // So, queue this up on the adapter and start a timer
  240. // routine if necessary.
  241. //
  242. bReturnToMicroport = FALSE;
  243. RNDISMP_ACQUIRE_ADAPTER_LOCK(Adapter);
  244. InsertTailList(&Adapter->PendingRcvMessageList, &pRcvMsg->Link);
  245. if (!Adapter->IndicatingReceives)
  246. {
  247. Adapter->IndicatingReceives = TRUE;
  248. NdisSetTimer(&Adapter->IndicateTimer, 0);
  249. }
  250. RNDISMP_RELEASE_ADAPTER_LOCK(Adapter);
  251. }
  252. else
  253. {
  254. //
  255. // Running on NT.
  256. if ((Adapter->DeviceFlags & RNDIS_DF_RAW_DATA) || (gRawEncap))
  257. {
  258. if (ChannelType == RMC_CONTROL)
  259. {
  260. RNDISMP_GET_MSG_HANDLER(pMsgHandlerFunc,pMessage->NdisMessageType);
  261. #if DBG
  262. ASSERT(pMessage->NdisMessageType != REMOTE_NDIS_PACKET_MSG);
  263. #endif
  264. } else
  265. {
  266. pMsgHandlerFunc = ReceivePacketMessageRaw;
  267. }
  268. } else
  269. {
  270. RNDISMP_GET_MSG_HANDLER(pMsgHandlerFunc, pMessage->NdisMessageType);
  271. #if DBG
  272. if (pMessage->NdisMessageType == REMOTE_NDIS_PACKET_MSG)
  273. {
  274. ASSERT(ChannelType == RMC_DATA);
  275. }
  276. else
  277. {
  278. ASSERT(ChannelType == RMC_CONTROL);
  279. }
  280. #endif
  281. }
  282. bReturnToMicroport = (*pMsgHandlerFunc)(
  283. Adapter,
  284. pMessage,
  285. pMdl,
  286. TotalLength,
  287. MicroportMessageContext,
  288. ReceiveStatus,
  289. bMessageCopied);
  290. }
  291. }
  292. while (FALSE);
  293. //
  294. // Are we done with the microport's message?
  295. //
  296. if (bReturnToMicroport || bMessageCopied)
  297. {
  298. RNDISMP_RETURN_TO_MICROPORT(Adapter,
  299. pMdl,
  300. MicroportMessageContext);
  301. }
  302. //
  303. // If we had made a copy of the microport's message, are we done with
  304. // this copy?
  305. //
  306. if (bMessageCopied && bReturnToMicroport)
  307. {
  308. FreeRcvMessageCopy(pMessage);
  309. }
  310. }
  311. /****************************************************************************/
  312. /* CoalesceMultiMdlMessage */
  313. /****************************************************************************/
  314. /* */
  315. /* Routine Description: */
  316. /* */
  317. /* Make a copy of a received message that is in a chain of multiple */
  318. /* MDLs, into one single buffer. */
  319. /* */
  320. /* Arguments: */
  321. /* */
  322. /* pMdl - pointer to MDL that is the head of the chain. */
  323. /* TotalLength - length of data contained in entire chain. */
  324. /* */
  325. /* Return: */
  326. /* */
  327. /* PRNDIS_MESSAGE */
  328. /* */
  329. /****************************************************************************/
  330. PRNDIS_MESSAGE
  331. CoalesceMultiMdlMessage(IN PMDL pMdl,
  332. IN ULONG TotalLength)
  333. {
  334. ULONG MdlLength;
  335. PRNDIS_MESSAGE pMessage;
  336. NDIS_STATUS Status;
  337. PMDL pTmpMdl;
  338. PUCHAR pDest;
  339. TRACE2(("Coalesce: Mdl %x\n", pMdl));
  340. Status = MemAlloc(&pMessage, TotalLength);
  341. if (Status == NDIS_STATUS_SUCCESS)
  342. {
  343. pDest = (PUCHAR)pMessage;
  344. for (pTmpMdl = pMdl; pTmpMdl != NULL; pTmpMdl = RNDISMP_GET_MDL_NEXT(pTmpMdl))
  345. {
  346. MdlLength = RNDISMP_GET_MDL_LENGTH(pTmpMdl);
  347. RNDISMP_MOVE_MEM(pDest,
  348. RNDISMP_GET_MDL_ADDRESS(pTmpMdl),
  349. MdlLength);
  350. pDest = (PUCHAR)pDest + MdlLength;
  351. }
  352. }
  353. else
  354. {
  355. pMessage = NULL;
  356. }
  357. return (pMessage);
  358. }
  359. /****************************************************************************/
  360. /* FreeRcvMessageCopy */
  361. /****************************************************************************/
  362. /* */
  363. /* Routine Description: */
  364. /* */
  365. /* Free the local copy of a received RNDIS message. */
  366. /* */
  367. /* Arguments: */
  368. /* */
  369. /* pMessage - pointer to RNDIS message */
  370. /* */
  371. /* Return: */
  372. /* */
  373. /* VOID */
  374. /* */
  375. /****************************************************************************/
  376. VOID
  377. FreeRcvMessageCopy(IN PRNDIS_MESSAGE pMessage)
  378. {
  379. TRACE3(("FreeRcvMessageCopy: pMessage %x\n", pMessage));
  380. MemFree(pMessage, -1);
  381. }
  382. /****************************************************************************/
  383. /* ReceivePacketMessage */
  384. /****************************************************************************/
  385. /* */
  386. /* Routine Description: */
  387. /* */
  388. /* Got a packet message, so send it to the upper layers */
  389. /* */
  390. /* Arguments: */
  391. /* */
  392. /* pAdapter - pointer to our Adapter structure */
  393. /* pMessage - pointer to RNDIS message */
  394. /* pMdl - pointer to MDL received from microport */
  395. /* TotalLength - length of complete message */
  396. /* MicroportMessageContext - context for message from micorport */
  397. /* ReceiveStatus - used by microport to indicate it is low on resource */
  398. /* bMessageCopied - is this a copy of the original message? */
  399. /* */
  400. /* Return: */
  401. /* */
  402. /* BOOLEAN - should the message be returned to the microport? */
  403. /* */
  404. /****************************************************************************/
  405. BOOLEAN
  406. ReceivePacketMessage(IN PRNDISMP_ADAPTER pAdapter,
  407. IN PRNDIS_MESSAGE pMessage,
  408. IN PMDL pMdl,
  409. IN ULONG TotalLength,
  410. IN NDIS_HANDLE MicroportMessageContext,
  411. IN NDIS_STATUS ReceiveStatus,
  412. IN BOOLEAN bMessageCopied)
  413. {
  414. ULONG LengthRemaining; // in entire message
  415. PMDL pTmpMdl;
  416. PRNDISMP_RECV_DATA_FRAME pRcvFrame;
  417. ULONG NumberOfPackets;
  418. PRNDIS_PACKET pRndisPacket;
  419. ULONG i;
  420. #define MAX_RECV_PACKETS_IN_MSG 40
  421. PNDIS_PACKET PacketArray[MAX_RECV_PACKETS_IN_MSG];
  422. ULONG NumPackets;
  423. PNDIS_PACKET pNdisPacket;
  424. PRNDISMP_RECV_PKT_RESERVED pRcvResvd;
  425. PNDIS_BUFFER pNdisBuffer;
  426. NDIS_STATUS BufferStatus;
  427. NDIS_STATUS Status;
  428. BOOLEAN bDiscardPkt;
  429. PRNDISMP_VC pVc;
  430. bDiscardPkt = FALSE;
  431. pVc = NULL;
  432. do
  433. {
  434. #ifndef BUILD_WIN9X
  435. if (bMessageCopied)
  436. {
  437. ReceiveStatus = NDIS_STATUS_SUCCESS;
  438. }
  439. #else
  440. //
  441. // Rur ReturnPacket handler never gets called on
  442. // Win98 Gold, so we force the status to be able
  443. // to reclaim the indicated packet immediately.
  444. //
  445. ReceiveStatus = NDIS_STATUS_RESOURCES;
  446. #endif
  447. //
  448. // Allocate a receive frame to keep track of this RNDIS packet message.
  449. //
  450. pRcvFrame = AllocateReceiveFrame(pAdapter);
  451. if (pRcvFrame == NULL)
  452. {
  453. bDiscardPkt = TRUE;
  454. break;
  455. }
  456. pRcvFrame->MicroportMessageContext = MicroportMessageContext;
  457. if (bMessageCopied)
  458. {
  459. pRcvFrame->pLocalMessageCopy = pMessage;
  460. pRcvFrame->bMessageCopy = TRUE;
  461. }
  462. else
  463. {
  464. pRcvFrame->pMicroportMdl = pMdl;
  465. pRcvFrame->bMessageCopy = FALSE;
  466. }
  467. NumberOfPackets = 0;
  468. LengthRemaining = TotalLength;
  469. //
  470. // TBD - Check that the received message is well-formed!
  471. //
  472. //
  473. // Temp ref to take care of multiple indications.
  474. //
  475. pRcvFrame->ReturnsPending = 1;
  476. //
  477. // Prepare NDIS packets for indicating up.
  478. //
  479. do
  480. {
  481. pRndisPacket = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage);
  482. //
  483. // Some sanity checks. TBD - do better checks!
  484. //
  485. if ((pMessage->MessageLength > LengthRemaining) ||
  486. (pMessage->NdisMessageType != REMOTE_NDIS_PACKET_MSG) ||
  487. (pMessage->MessageLength < RNDIS_MESSAGE_SIZE(RNDIS_PACKET)))
  488. {
  489. TRACE1(("ReceivePacketMessage: Msg %x: length %d or type %x has a problem\n",
  490. pMessage, pMessage->MessageLength, pMessage->NdisMessageType));
  491. ASSERT(FALSE);
  492. RNDISMP_INCR_STAT(pAdapter, RecvError);
  493. break;
  494. }
  495. if (pRndisPacket->DataLength > pMessage->MessageLength)
  496. {
  497. TRACE1(("ReceivePacketMessage: invalid data length (%d) > Msg length (%d)\n",
  498. pRndisPacket->DataLength, pMessage->MessageLength));
  499. RNDISMP_INCR_STAT(pAdapter, RecvError);
  500. break;
  501. }
  502. if (pRndisPacket->VcHandle != 0)
  503. {
  504. pVc = LookupVcId(pAdapter, pRndisPacket->VcHandle);
  505. if (pVc == NULL)
  506. {
  507. TRACE1(("ReceivePacketMessage: invalid Vc handle %x\n", pRndisPacket->VcHandle));
  508. RNDISMP_INCR_STAT(pAdapter, RecvError);
  509. break;
  510. }
  511. }
  512. //
  513. // Allocate an NDIS packet to do the indication with.
  514. //
  515. NdisAllocatePacket(&Status, &pNdisPacket, pAdapter->ReceivePacketPool);
  516. if (Status != NDIS_STATUS_SUCCESS)
  517. {
  518. pNdisPacket = NULL;
  519. TRACE2(("ReceivePacketMessage: failed to allocate packet, Adapter %X\n",
  520. pAdapter));
  521. RNDISMP_INCR_STAT(pAdapter, RecvNoBuf);
  522. break;
  523. }
  524. NDIS_SET_PACKET_STATUS(pNdisPacket, ReceiveStatus);
  525. switch (pAdapter->Medium)
  526. {
  527. case NdisMedium802_3:
  528. NDIS_SET_PACKET_HEADER_SIZE(pNdisPacket, ETHERNET_HEADER_SIZE);
  529. break;
  530. default:
  531. break;
  532. }
  533. NdisAllocateBuffer(&BufferStatus,
  534. &pNdisBuffer,
  535. pAdapter->ReceiveBufferPool,
  536. GET_PTR_TO_RNDIS_DATA_BUFF(pRndisPacket),
  537. pRndisPacket->DataLength);
  538. if (BufferStatus != NDIS_STATUS_SUCCESS)
  539. {
  540. TRACE1(("ReceivePacketMessage: failed to allocate"
  541. " buffer, Adapter %X\n", pAdapter));
  542. NdisFreePacket(pNdisPacket);
  543. RNDISMP_INCR_STAT(pAdapter, RecvNoBuf);
  544. break;
  545. }
  546. TRACE2(("Rcv: msg Pkt %d bytes\n", pRndisPacket->DataLength));
  547. TRACEDUMP(("Rcv %d bytes\n", pRndisPacket->DataLength),
  548. GET_PTR_TO_RNDIS_DATA_BUFF(pRndisPacket),
  549. MIN(pRndisPacket->DataLength, 32));
  550. NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
  551. //
  552. // Check if there is per-packet info.
  553. //
  554. if (!pAdapter->bRunningOnWin9x)
  555. {
  556. PRNDIS_PER_PACKET_INFO pPerPacketInfo;
  557. ULONG PerPacketInfoLength;
  558. if (PerPacketInfoLength = pRndisPacket->PerPacketInfoLength)
  559. {
  560. TRACE1(("ReceivePacketMessage: Adapter %p, Pkt %p:"
  561. " non-zero perpacket length %d\n",
  562. pAdapter, pRndisPacket, PerPacketInfoLength));
  563. pPerPacketInfo = (PRNDIS_PER_PACKET_INFO)((PUCHAR)pRndisPacket +
  564. pRndisPacket->PerPacketInfoOffset);
  565. while (PerPacketInfoLength != 0)
  566. {
  567. switch (pPerPacketInfo->Type)
  568. {
  569. case TcpIpChecksumPacketInfo:
  570. NDIS_PER_PACKET_INFO_FROM_PACKET(pNdisPacket, TcpIpChecksumPacketInfo) =
  571. UlongToPtr(*(PULONG)((PUCHAR)pPerPacketInfo + pPerPacketInfo->PerPacketInformationOffset));
  572. break;
  573. case Ieee8021pPriority:
  574. NDIS_PER_PACKET_INFO_FROM_PACKET(pNdisPacket, Ieee8021pPriority) =
  575. UlongToPtr(*(PULONG)((PUCHAR)pPerPacketInfo + pPerPacketInfo->PerPacketInformationOffset));
  576. default:
  577. break;
  578. }
  579. PerPacketInfoLength -= pPerPacketInfo->Size;
  580. pPerPacketInfo = (PRNDIS_PER_PACKET_INFO)((PUCHAR)pPerPacketInfo +
  581. pPerPacketInfo->Size);
  582. }
  583. }
  584. }
  585. //
  586. // Add this to the array of packets to be indicated up.
  587. //
  588. PacketArray[NumberOfPackets] = pNdisPacket;
  589. NumberOfPackets++;
  590. RNDISMP_INCR_STAT(pAdapter, RecvOk);
  591. pRcvResvd = PRNDISMP_RESERVED_FROM_RECV_PACKET(pNdisPacket);
  592. pRcvResvd->pRcvFrame = pRcvFrame;
  593. pRcvResvd->pVc = pVc;
  594. TRACE2(("ReceivePacketMessage: pRndisPkt %X, MsgLen %d,"
  595. " DataLen %d, Stat %x, Discard %d\n",
  596. pRndisPacket, pMessage->MessageLength,
  597. pRndisPacket->DataLength, ReceiveStatus, bDiscardPkt));
  598. LengthRemaining -= pMessage->MessageLength;
  599. pMessage = (PRNDIS_MESSAGE)((ULONG_PTR)pMessage + pMessage->MessageLength);
  600. NdisInterlockedIncrement(&pRcvFrame->ReturnsPending);
  601. if ((NumberOfPackets == MAX_RECV_PACKETS_IN_MSG) ||
  602. (LengthRemaining < RNDIS_MESSAGE_SIZE(RNDIS_PACKET)))
  603. {
  604. if (pVc == NULL)
  605. {
  606. RcvIndicateCount += NumberOfPackets;
  607. NdisMIndicateReceivePacket(pAdapter->MiniportAdapterHandle,
  608. PacketArray,
  609. NumberOfPackets);
  610. }
  611. else
  612. {
  613. IndicateReceiveDataOnVc(pVc, PacketArray, NumberOfPackets);
  614. }
  615. if (ReceiveStatus == NDIS_STATUS_RESOURCES)
  616. {
  617. for (i = 0; i < NumberOfPackets; i++)
  618. {
  619. RNDISMP_INCR_STAT(pAdapter, RecvLowRes);
  620. RndismpReturnPacket(pAdapter,
  621. PacketArray[i]);
  622. }
  623. }
  624. NumberOfPackets = 0;
  625. }
  626. }
  627. while (LengthRemaining >= RNDIS_MESSAGE_SIZE(RNDIS_PACKET));
  628. if (NumberOfPackets != 0)
  629. {
  630. //
  631. // We bailed out of the above loop. Return what we
  632. // have collected so far.
  633. //
  634. for (i = 0; i < NumberOfPackets; i++)
  635. {
  636. RndismpReturnPacket(pAdapter,
  637. PacketArray[i]);
  638. }
  639. }
  640. //
  641. // Remove temp ref we added at the top.
  642. //
  643. DereferenceRcvFrame(pRcvFrame, pAdapter);
  644. }
  645. while (FALSE);
  646. if (pVc != NULL)
  647. {
  648. ULONG RefCount;
  649. RNDISMP_DEREF_VC(pVc, &RefCount);
  650. }
  651. return (bDiscardPkt);
  652. }
  653. /****************************************************************************/
  654. /* ReceivePacketMessageRaw */
  655. /****************************************************************************/
  656. /* */
  657. /* Routine Description: */
  658. /* */
  659. /* Got a packet message, so send it to the upper layers */
  660. /* */
  661. /* Arguments: */
  662. /* */
  663. /* pAdapter - pointer to our Adapter structure */
  664. /* pMessage - pointer to RNDIS message */
  665. /* pMdl - pointer to MDL received from microport */
  666. /* TotalLength - length of complete message */
  667. /* MicroportMessageContext - context for message from micorport */
  668. /* ReceiveStatus - used by microport to indicate it is low on resource */
  669. /* bMessageCopied - is this a copy of the original message? */
  670. /* */
  671. /* Return: */
  672. /* */
  673. /* BOOLEAN - should the message be returned to the microport? */
  674. /* */
  675. /****************************************************************************/
  676. BOOLEAN
  677. ReceivePacketMessageRaw(IN PRNDISMP_ADAPTER pAdapter,
  678. IN PRNDIS_MESSAGE pMessage,
  679. IN PMDL pMdl,
  680. IN ULONG TotalLength,
  681. IN NDIS_HANDLE MicroportMessageContext,
  682. IN NDIS_STATUS ReceiveStatus,
  683. IN BOOLEAN bMessageCopied)
  684. {
  685. ULONG LengthRemaining; // in entire message
  686. PMDL pTmpMdl;
  687. PRNDISMP_RECV_DATA_FRAME pRcvFrame;
  688. ULONG NumberOfPackets;
  689. PRNDIS_PACKET pRndisPacket;
  690. ULONG i;
  691. #define MAX_RECV_PACKETS_IN_MSG 40
  692. PNDIS_PACKET PacketArray[MAX_RECV_PACKETS_IN_MSG];
  693. ULONG NumPackets;
  694. PNDIS_PACKET pNdisPacket;
  695. PRNDISMP_RECV_PKT_RESERVED pRcvResvd;
  696. PNDIS_BUFFER pNdisBuffer;
  697. NDIS_STATUS BufferStatus;
  698. NDIS_STATUS Status;
  699. BOOLEAN bDiscardPkt;
  700. PRNDISMP_VC pVc;
  701. bDiscardPkt = FALSE;
  702. pVc = NULL;
  703. pRcvFrame = NULL;
  704. do
  705. {
  706. #ifndef BUILD_WIN9X
  707. if (bMessageCopied)
  708. {
  709. ReceiveStatus = NDIS_STATUS_SUCCESS;
  710. }
  711. #else
  712. //
  713. // Rur ReturnPacket handler never gets called on
  714. // Win98 Gold, so we force the status to be able
  715. // to reclaim the indicated packet immediately.
  716. //
  717. ReceiveStatus = NDIS_STATUS_RESOURCES;
  718. #endif
  719. //
  720. // Allocate a receive frame to keep track of this RNDIS packet message.
  721. //
  722. pRcvFrame = AllocateReceiveFrame(pAdapter);
  723. if (pRcvFrame == NULL)
  724. {
  725. bDiscardPkt = TRUE;
  726. break;
  727. }
  728. pRcvFrame->MicroportMessageContext = MicroportMessageContext;
  729. if (bMessageCopied)
  730. {
  731. pRcvFrame->pLocalMessageCopy = pMessage;
  732. pRcvFrame->bMessageCopy = TRUE;
  733. }
  734. else
  735. {
  736. pRcvFrame->pMicroportMdl = pMdl;
  737. pRcvFrame->bMessageCopy = FALSE;
  738. }
  739. NumberOfPackets = 0;
  740. LengthRemaining = TotalLength;
  741. //
  742. // Temp ref to take care of multiple indications.
  743. //
  744. pRcvFrame->ReturnsPending = 1;
  745. //
  746. // Prepare NDIS packets for indicating up.
  747. //
  748. {
  749. pRndisPacket = RNDIS_MESSAGE_RAW_PTR_TO_MESSAGE_PTR(pMessage);
  750. //
  751. // Allocate an NDIS packet to do the indication with.
  752. //
  753. NdisAllocatePacket(&Status, &pNdisPacket, pAdapter->ReceivePacketPool);
  754. if (Status != NDIS_STATUS_SUCCESS)
  755. {
  756. pNdisPacket = NULL;
  757. TRACE2(("ReceivePacketMessage: failed to allocate packet, Adapter %X\n",
  758. pAdapter));
  759. RNDISMP_INCR_STAT(pAdapter, RecvNoBuf);
  760. bDiscardPkt = TRUE;
  761. break;
  762. }
  763. NDIS_SET_PACKET_STATUS(pNdisPacket, ReceiveStatus);
  764. switch (pAdapter->Medium)
  765. {
  766. case NdisMedium802_3:
  767. NDIS_SET_PACKET_HEADER_SIZE(pNdisPacket, ETHERNET_HEADER_SIZE);
  768. break;
  769. default:
  770. break;
  771. }
  772. NdisAllocateBuffer(&BufferStatus,
  773. &pNdisBuffer,
  774. pAdapter->ReceiveBufferPool,
  775. pRndisPacket,
  776. TotalLength);
  777. if (BufferStatus != NDIS_STATUS_SUCCESS)
  778. {
  779. TRACE1(("ReceivePacketMessage: failed to allocate"
  780. " buffer, Adapter %X\n", pAdapter));
  781. NdisFreePacket(pNdisPacket);
  782. RNDISMP_INCR_STAT(pAdapter, RecvNoBuf);
  783. bDiscardPkt = TRUE;
  784. break;
  785. }
  786. TRACE2(("Rcv: msg Pkt %d bytes\n", pMessage->MessageLength));
  787. TRACEDUMP(("Rcv %d bytes\n", pMessage->MessageLength),
  788. pRndisPacket,
  789. MIN(pMessage->MessageLength, 32));
  790. NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
  791. //
  792. // Add this to the array of packets to be indicated up.
  793. //
  794. PacketArray[NumberOfPackets] = pNdisPacket;
  795. NumberOfPackets++;
  796. RNDISMP_INCR_STAT(pAdapter, RecvOk);
  797. pRcvResvd = PRNDISMP_RESERVED_FROM_RECV_PACKET(pNdisPacket);
  798. pRcvResvd->pRcvFrame = pRcvFrame;
  799. pRcvResvd->pVc = pVc;
  800. TRACE1(("ReceivePacketMessageRaw: pRcvFrame %p/%d, pRndisPkt %p,"
  801. " DataLen %d, Stat %x, Discard %d\n",
  802. pRcvFrame, pRcvFrame->ReturnsPending,
  803. pRndisPacket,
  804. pRndisPacket->DataLength,
  805. ReceiveStatus,
  806. bDiscardPkt));
  807. LengthRemaining -= pMessage->MessageLength;
  808. NdisInterlockedIncrement(&pRcvFrame->ReturnsPending);
  809. NdisMIndicateReceivePacket(pAdapter->MiniportAdapterHandle,
  810. PacketArray,
  811. NumberOfPackets);
  812. if (ReceiveStatus == NDIS_STATUS_RESOURCES)
  813. {
  814. for (i = 0; i < NumberOfPackets; i++)
  815. {
  816. RNDISMP_INCR_STAT(pAdapter, RecvLowRes);
  817. RndismpReturnPacket(pAdapter,
  818. PacketArray[i]);
  819. }
  820. }
  821. }
  822. //
  823. // Remove temp ref we added at the top.
  824. //
  825. DereferenceRcvFrame(pRcvFrame, pAdapter);
  826. }
  827. while (FALSE);
  828. if (bDiscardPkt)
  829. {
  830. //
  831. // Some failure occured above.
  832. //
  833. if (pRcvFrame != NULL)
  834. {
  835. FreeReceiveFrame(pRcvFrame, pAdapter);
  836. }
  837. }
  838. return (bDiscardPkt);
  839. }
  840. /****************************************************************************/
  841. /* IndicateStatusMessage */
  842. /****************************************************************************/
  843. /* */
  844. /* Routine Description: */
  845. /* */
  846. /* Got an indicate status message, so send to upper layers */
  847. /* */
  848. /* Arguments: */
  849. /* */
  850. /* pAdapter - Pointer to our Adapter structure */
  851. /* pMessage - pointer to RNDIS message */
  852. /* pMdl - Pointer to MDL from microport */
  853. /* TotalLength - length of complete message */
  854. /* MicroportMessageContext - context for message from microport */
  855. /* ReceiveStatus - used by microport to indicate it is low on resource */
  856. /* bMessageCopied - is this a copy of the original message? */
  857. /* */
  858. /* Return: */
  859. /* */
  860. /* BOOLEAN - should the message be returned to the microport? */
  861. /* */
  862. /****************************************************************************/
  863. BOOLEAN
  864. IndicateStatusMessage(IN PRNDISMP_ADAPTER pAdapter,
  865. IN PRNDIS_MESSAGE pMessage,
  866. IN PMDL pMdl,
  867. IN ULONG TotalLength,
  868. IN NDIS_HANDLE MicroportMessageContext,
  869. IN NDIS_STATUS ReceiveStatus,
  870. IN BOOLEAN bMessageCopied)
  871. {
  872. PRNDIS_INDICATE_STATUS pRndisIndicateStatus;
  873. TRACE3(("IndicateStatusMessage: Adapter %x, Mdl %x\n", pAdapter, pMdl));
  874. // get a pointer to the indicate status message
  875. pRndisIndicateStatus = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage);
  876. if (!pAdapter->Initing)
  877. {
  878. #if DBG
  879. if (pRndisIndicateStatus->Status == NDIS_STATUS_MEDIA_CONNECT)
  880. {
  881. TRACE1(("Adapter %x: +++ Media Connect +++\n", pAdapter));
  882. }
  883. else if (pRndisIndicateStatus->Status == NDIS_STATUS_MEDIA_DISCONNECT)
  884. {
  885. TRACE1(("Adapter %x: --- Media Disconnect ---\n", pAdapter));
  886. }
  887. #endif // DBG
  888. // send status indication to upper layers
  889. NdisMIndicateStatus(pAdapter->MiniportAdapterHandle,
  890. (NDIS_STATUS) pRndisIndicateStatus->Status,
  891. MESSAGE_TO_STATUS_BUFFER(pRndisIndicateStatus),
  892. pRndisIndicateStatus->StatusBufferLength);
  893. // always have to indicate status complete
  894. NdisMIndicateStatusComplete(pAdapter->MiniportAdapterHandle);
  895. }
  896. else
  897. {
  898. //
  899. // drop status indications that arrive when we are
  900. // in the process of initializing.
  901. //
  902. TRACE1(("Adapter %x: indicated status %x when still initializing\n",
  903. pAdapter, (NDIS_STATUS) pRndisIndicateStatus->Status));
  904. }
  905. return (TRUE);
  906. } // IndicateStatusMessage
  907. /****************************************************************************/
  908. /* UnknownMessage */
  909. /****************************************************************************/
  910. /* */
  911. /* Routine Description: */
  912. /* */
  913. /* Process a message with unknown message type. We simply drop it for now. */
  914. /* */
  915. /* Arguments: */
  916. /* */
  917. /* pAdapter - Pointer to our Adapter structure */
  918. /* pMessage - pointer to RNDIS message */
  919. /* pMdl - Pointer to MDL from microport */
  920. /* TotalLength - length of complete message */
  921. /* MicroportMessageContext - context for message from microport */
  922. /* ReceiveStatus - used by microport to indicate it is low on resource */
  923. /* bMessageCopied - is this a copy of the original message? */
  924. /* */
  925. /* Return: */
  926. /* */
  927. /* BOOLEAN - should the message be returned to the microport? */
  928. /* */
  929. /****************************************************************************/
  930. BOOLEAN
  931. UnknownMessage(IN PRNDISMP_ADAPTER pAdapter,
  932. IN PRNDIS_MESSAGE pMessage,
  933. IN PMDL pMdl,
  934. IN ULONG TotalLength,
  935. IN NDIS_HANDLE MicroportMessageContext,
  936. IN NDIS_STATUS ReceiveStatus,
  937. IN BOOLEAN bMessageCopied)
  938. {
  939. TRACE1(("Unknown Message on Adapter %x, type %x, MDL %x, uPContext %x\n",
  940. pAdapter, pMessage->NdisMessageType, pMdl, MicroportMessageContext));
  941. ASSERT(FALSE);
  942. return TRUE;
  943. }
  944. /****************************************************************************/
  945. /* AllocateReceiveFrame */
  946. /****************************************************************************/
  947. /* */
  948. /* Routine Description: */
  949. /* */
  950. /* Allocate a receive frame to keep context about a single RNDIS_PACKET */
  951. /* message. */
  952. /* */
  953. /* Arguments: */
  954. /* */
  955. /* pAdapter - Pointer to our Adapter structure */
  956. /* */
  957. /* Return: */
  958. /* */
  959. /* PRNDISMP_RECV_DATA_FRAME */
  960. /* */
  961. /****************************************************************************/
  962. PRNDISMP_RECV_DATA_FRAME
  963. AllocateReceiveFrame(IN PRNDISMP_ADAPTER pAdapter)
  964. {
  965. PRNDISMP_RECV_DATA_FRAME pRcvFrame;
  966. #ifndef DONT_USE_LOOKASIDE_LIST
  967. pRcvFrame = (PRNDISMP_RECV_DATA_FRAME)
  968. NdisAllocateFromNPagedLookasideList(&pAdapter->RcvFramePool);
  969. #else
  970. {
  971. NDIS_STATUS Status;
  972. Status = MemAlloc(&pRcvFrame, sizeof(RNDISMP_RECV_DATA_FRAME));
  973. if (Status == NDIS_STATUS_SUCCESS)
  974. {
  975. NdisInterlockedIncrement(&RcvFrameAllocs);
  976. }
  977. else
  978. {
  979. pRcvFrame = NULL;
  980. }
  981. }
  982. #endif // DONT_USE_LOOKASIDE_LIST
  983. return (pRcvFrame);
  984. }
  985. /****************************************************************************/
  986. /* FreeReceiveFrame */
  987. /****************************************************************************/
  988. /* */
  989. /* Routine Description: */
  990. /* */
  991. /* Allocate a receive frame to keep context about a single RNDIS_PACKET */
  992. /* message. */
  993. /* */
  994. /* Arguments: */
  995. /* */
  996. /* pRcvFrame - Pointer to receive frame being freed */
  997. /* pAdapter - Pointer to our Adapter structure */
  998. /* */
  999. /* Return: */
  1000. /* */
  1001. /* VOID */
  1002. /* */
  1003. /****************************************************************************/
  1004. VOID
  1005. FreeReceiveFrame(IN PRNDISMP_RECV_DATA_FRAME pRcvFrame,
  1006. IN PRNDISMP_ADAPTER pAdapter)
  1007. {
  1008. #ifndef DONT_USE_LOOKASIDE_LIST
  1009. NdisFreeToNPagedLookasideList(&pAdapter->RcvFramePool, pRcvFrame);
  1010. #else
  1011. MemFree(pRcvFrame, sizeof(RNDISMP_RECV_DATA_FRAME));
  1012. NdisInterlockedDecrement(&RcvFrameAllocs);
  1013. #endif // DONT_USE_LOOKASIDE_LIST
  1014. }
  1015. /****************************************************************************/
  1016. /* IndicateTimeout */
  1017. /****************************************************************************/
  1018. /* */
  1019. /* Routine Description: */
  1020. /* */
  1021. /* Timeout callback routine to handle all receive indications. The actual */
  1022. /* NDIS routines to indicate receives is done from here, since this */
  1023. /* function runs in the right environment for protocols on WinME. */
  1024. /* */
  1025. /* Arguments: */
  1026. /* */
  1027. /* SystemSpecific[1-3] - Ignored */
  1028. /* Context - Pointer to our Adapter structure */
  1029. /* */
  1030. /* Return: */
  1031. /* */
  1032. /* VOID */
  1033. /* */
  1034. /****************************************************************************/
  1035. VOID
  1036. IndicateTimeout(IN PVOID SystemSpecific1,
  1037. IN PVOID Context,
  1038. IN PVOID SystemSpecific2,
  1039. IN PVOID SystemSpecific3)
  1040. {
  1041. PRNDISMP_ADAPTER pAdapter;
  1042. PLIST_ENTRY pEntry;
  1043. PRNDISMP_RECV_MSG_CONTEXT pRcvMsg;
  1044. PRNDISMP_MSG_HANDLER_FUNC pMsgHandlerFunc;
  1045. PRNDIS_MESSAGE pMessage;
  1046. BOOLEAN bMessageCopied;
  1047. BOOLEAN bReturnToMicroport;
  1048. ULONG CurMsgs;
  1049. pAdapter = (PRNDISMP_ADAPTER)Context;
  1050. CHECK_VALID_ADAPTER(pAdapter);
  1051. ASSERT(pAdapter->IndicatingReceives == TRUE);
  1052. CurMsgs = 0;
  1053. RcvTimerCount++;
  1054. RNDISMP_ACQUIRE_ADAPTER_LOCK(pAdapter);
  1055. while (!IsListEmpty(&pAdapter->PendingRcvMessageList))
  1056. {
  1057. pEntry = RemoveHeadList(&pAdapter->PendingRcvMessageList);
  1058. RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
  1059. CurMsgs++;
  1060. pRcvMsg = CONTAINING_RECORD(pEntry, RNDISMP_RECV_MSG_CONTEXT, Link);
  1061. RNDISMP_GET_MSG_HANDLER(pMsgHandlerFunc, pRcvMsg->pMessage->NdisMessageType);
  1062. bMessageCopied = pRcvMsg->bMessageCopied;
  1063. pMessage = pRcvMsg->pMessage;
  1064. bReturnToMicroport = (*pMsgHandlerFunc)(
  1065. pAdapter,
  1066. pMessage,
  1067. pRcvMsg->pMdl,
  1068. pRcvMsg->TotalLength,
  1069. pRcvMsg->MicroportMessageContext,
  1070. pRcvMsg->ReceiveStatus,
  1071. bMessageCopied);
  1072. //
  1073. // Are we done with the message?
  1074. //
  1075. if (bReturnToMicroport)
  1076. {
  1077. if (!bMessageCopied)
  1078. {
  1079. RNDISMP_RETURN_TO_MICROPORT(pAdapter,
  1080. pRcvMsg->pMdl,
  1081. pRcvMsg->MicroportMessageContext);
  1082. }
  1083. else
  1084. {
  1085. FreeRcvMessageCopy(pMessage);
  1086. }
  1087. }
  1088. MemFree(pRcvMsg, sizeof(RNDISMP_RECV_MSG_CONTEXT));
  1089. RNDISMP_ACQUIRE_ADAPTER_LOCK(pAdapter);
  1090. }
  1091. pAdapter->IndicatingReceives = FALSE;
  1092. RcvMaxPackets = MAX(RcvMaxPackets, CurMsgs);
  1093. RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
  1094. } // IndicateTimeout