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.

4122 lines
107 KiB

  1. //
  2. // Copyright (c) 1998-1999, Microsoft Corporation, all rights reserved
  3. //
  4. // receive.c
  5. //
  6. // IEEE1394 mini-port/call-manager driver
  7. //
  8. // Mini-port Receive routines
  9. //
  10. // 2/13/1998 ADube Created,
  11. //
  12. #include <precomp.h>
  13. #define MAX_NUM_SLIST_ENTRY 0x10
  14. //-----------------------------------------------------------------------------
  15. // Local prototypes (alphabetically)
  16. //-----------------------------------------------------------------------------
  17. VOID
  18. nicAllocateAddressRangeCallback(
  19. IN PNOTIFICATION_INFO NotificationInfo
  20. );
  21. VOID
  22. nicAllocateAddressRangeDebugSpew(
  23. IN PIRB pIrb
  24. );
  25. NDIS_STATUS
  26. nicGetInitializedAddressFifoElement(
  27. IN UINT BufferLength,
  28. IN OUT PADDRESS_FIFO *ppElement
  29. );
  30. NDIS_STATUS
  31. nicGetEmptyAddressFifoElement(
  32. IN PADDRESS_FIFO *ppElement
  33. );
  34. VOID
  35. nicReceivePacketWorkItem(
  36. PNDIS_WORK_ITEM pWorkItem,
  37. PVOID pContext
  38. );
  39. VOID
  40. nicAllocateRemainingFifoWorkItem (
  41. PNDIS_WORK_ITEM pNdisWorkItem,
  42. IN PVOID Context
  43. );
  44. VOID
  45. nicFifoAllocationScheme (
  46. PRECVFIFO_VCCB pRecvFIFOVc
  47. );
  48. ULONG ReassemblyAllocated = 0;
  49. extern ULONG NdisBufferAllocated[NoMoreCodePaths];
  50. extern ULONG NdisBufferFreed[NoMoreCodePaths];
  51. //-----------------------------------------------------------------------------
  52. // prototype implementation (alphabetically)
  53. //-----------------------------------------------------------------------------
  54. /*
  55. NDIS_STATUS
  56. nicAllocateAddressRange(
  57. IN PREMOTE_NODE pRemoteNode
  58. )
  59. */
  60. NDIS_STATUS
  61. nicAllocateAddressRange(
  62. IN PADAPTERCB pAdapter,
  63. IN PRECVFIFO_VCCB pRecvFIFOVc
  64. )
  65. // Function Description:
  66. // This function will use the AllocateAddressRange Bus Api
  67. // To do this it must initialize an S-list with structures
  68. // Allocate and Initialize an Irb and an Irp and call the nic
  69. // nicSubmitIrp routine
  70. // This routine will complete synchronously
  71. //
  72. //
  73. // Arguments
  74. // pdo Cb The Pdo for the remote node on which the address range will
  75. // be allocated. There is also a pointer to the Paramters that need to be
  76. //
  77. // Return Value:
  78. //
  79. //
  80. {
  81. PIRB pIrb = NULL;
  82. PIRP pIrp = NULL;
  83. PSLIST_HEADER pSlistHead = NULL;
  84. UINT cnt = 0;
  85. PDEVICE_OBJECT pPdo = NULL;
  86. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  87. UINT Length;
  88. ADDRESS_OFFSET AddressOffset;
  89. UINT MaxNumSlistEntry = MAX_NUM_SLIST_ENTRY;
  90. BOOLEAN bRefCall = FALSE;
  91. STORE_CURRENT_IRQL;
  92. ASSERT (pRecvFIFOVc == pAdapter->pRecvFIFOVc);
  93. ASSERT (pRecvFIFOVc != NULL);
  94. TRACE( TL_T, TM_Recv, ( "==>nicAllocateAddressRange, pAdapter 8x, pRecvFIFOVc %x", pAdapter, pRecvFIFOVc ) );
  95. do
  96. {
  97. // Increment the Refcount on the VC, so we can gaurantee its presence
  98. //
  99. VC_ACQUIRE_LOCK (pRecvFIFOVc)
  100. //
  101. // Add a reference to the pdo block.
  102. // This reference is added to guarantee its presence
  103. // Removed in Free Address Range or at the end of the function
  104. //
  105. bRefCall = nicReferenceCall ((PVCCB) pRecvFIFOVc, "nicAllocateAddressRange" ) ;
  106. VC_RELEASE_LOCK (pRecvFIFOVc);
  107. if ( bRefCall == FALSE )
  108. {
  109. //
  110. // This will only fail if the Vc is not activated
  111. //
  112. NdisStatus = NDIS_STATUS_FAILURE;
  113. break;
  114. }
  115. //
  116. // Allocate an IRB
  117. //
  118. NdisStatus = nicGetIrb (&pIrb);
  119. if (NdisStatus != NDIS_STATUS_SUCCESS)
  120. {
  121. break;
  122. }
  123. ASSERT (pIrb != NULL);
  124. //
  125. // Initalize the IrB with the correct values
  126. // AllocateAddressRange
  127. //
  128. ASSERT (pRecvFIFOVc->Hdr.Nic1394MediaParams.Destination.AddressType == NIC1394AddressType_FIFO);
  129. AddressOffset.Off_High = pRecvFIFOVc->Hdr.Nic1394MediaParams.Destination.FifoAddress.Off_High;
  130. AddressOffset.Off_Low = pRecvFIFOVc->Hdr.Nic1394MediaParams.Destination.FifoAddress.Off_Low;
  131. ASSERT (pRecvFIFOVc->Hdr.MTU !=0 );
  132. Length = pRecvFIFOVc->Hdr.MTU;
  133. nicInitAllocateAddressIrb( pIrb,
  134. pAdapter,
  135. 0,
  136. Length,
  137. 0,
  138. ACCESS_FLAGS_TYPE_WRITE|ACCESS_FLAGS_TYPE_BROADCAST,
  139. NOTIFY_FLAGS_AFTER_WRITE,
  140. &AddressOffset,
  141. pRecvFIFOVc);
  142. //
  143. // Allocate an Irp
  144. //
  145. NdisStatus = nicGetIrp (pAdapter->pNdisDeviceObject, &pIrp);
  146. if (NdisStatus != NDIS_STATUS_SUCCESS)
  147. {
  148. break;
  149. }
  150. ASSERT(pIrp != NULL);
  151. NdisStatus = nicSubmitIrp_LocalHostSynch(pAdapter,
  152. pIrp,
  153. pIrb );
  154. //
  155. // Make this a synchronous call as this is during init
  156. //
  157. if (NdisStatus != NDIS_STATUS_SUCCESS)
  158. {
  159. TRACE( TL_A, TM_Recv, ( "nicAllocateAddressRange SUBMIT IRP FAILED NdisStatus %.8x", NdisStatus ) );
  160. break;
  161. }
  162. nicAllocateAddressRangeDebugSpew(pIrb);
  163. //
  164. // Check to see if the IoCallDriver succeeded
  165. //
  166. if(pIrp->IoStatus.Status == STATUS_SUCCESS)
  167. {
  168. NdisStatus = nicAllocateAddressRangeSucceeded (pIrb, pRecvFIFOVc);
  169. if (NdisStatus != NDIS_STATUS_SUCCESS)
  170. {
  171. break;
  172. }
  173. }
  174. else
  175. {
  176. ASSERT (pIrp->IoStatus.Status != STATUS_MORE_PROCESSING_REQUIRED);
  177. // else mark status as failure
  178. //
  179. //
  180. //This means dereference will happen in this function
  181. NdisStatus = NDIS_STATUS_FAILURE;
  182. }
  183. //
  184. // we need to clean up the Irb and the Irp
  185. //
  186. } while (FALSE);
  187. //
  188. // Clean up -dereference the Call if things failed
  189. // If we successfully completed the Irp then all the references made above
  190. // will be dereferenced when the remote node goes away or the
  191. // Call is closed
  192. //
  193. // Deref the references that were made above.
  194. VC_ACQUIRE_LOCK (pRecvFIFOVc);
  195. if (! NT_SUCCESS (NdisStatus))
  196. {
  197. if (bRefCall == TRUE)
  198. {
  199. nicDereferenceCall ( (PVCCB) pRecvFIFOVc , "nicAllocateAddressRange");
  200. }
  201. }
  202. VC_RELEASE_LOCK (pRecvFIFOVc);
  203. // We don't care about the status as we are just freeing locally allocated memory
  204. //
  205. if (pIrb != NULL)
  206. {
  207. nicFreeIrb (pIrb);
  208. }
  209. if (pIrp!= NULL)
  210. {
  211. nicFreeIrp (pIrp);
  212. }
  213. MATCH_IRQL
  214. TRACE( TL_T, TM_Recv, ( "<==nicAllocateAddressRange, pVc %.8x, Status %.8x ", pRecvFIFOVc, NdisStatus ) );
  215. return NdisStatus;
  216. }
  217. VOID
  218. nicAllocateAddressRangeCallback(
  219. IN PNOTIFICATION_INFO pNotificationInfo
  220. )
  221. {
  222. PADAPTERCB pAdapter = (PADAPTERCB) pNotificationInfo->Context;
  223. PRECVFIFO_VCCB pRecvFIFOVc = pAdapter->pRecvFIFOVc;
  224. PNODE_ADDRESS pSenderNodeAddress = NULL;
  225. //
  226. // Debug spew for debugging
  227. //
  228. TRACE( TL_V, TM_Recv, ( " Mdl is at %.8x",pNotificationInfo->Mdl ) );
  229. TRACE( TL_V, TM_Recv, ( " ulLength is %.8x",pNotificationInfo->nLength) );
  230. TRACE( TL_V, TM_Recv, ( " pNotificationInfo->RequestPacket %x, ", pNotificationInfo->RequestPacket) );
  231. TRACE( TL_V, TM_Recv, ( " tLabel %x, ", ((PASYNC_PACKET)pNotificationInfo->RequestPacket)->AP_tLabel) );
  232. pSenderNodeAddress = & (((PASYNC_PACKET)pNotificationInfo->RequestPacket)->AP_Source_ID);
  233. TRACE( TL_V, TM_Recv, ( " Senders' NodeAddress %x, ", pSenderNodeAddress->NA_Node_Number ) );
  234. TRACE (TL_V, TM_Reas,("tLabel %x ", ((PASYNC_PACKET)pNotificationInfo->RequestPacket)->AP_tLabel));
  235. NdisInterlockedIncrement (&pRecvFIFOVc->NumIndicatedFifos);
  236. pNotificationInfo->Fifo->FifoList.Next = NULL;
  237. pNotificationInfo->Fifo->FifoMdl->Next = NULL;
  238. nicFifoAllocationScheme (pRecvFIFOVc);
  239. nicSetTagInFifoWrapper(pNotificationInfo->Fifo, NIC1394_TAG_IN_CALLBACK);
  240. nicStatsRecordNumIndicatedFifos(pRecvFIFOVc->NumIndicatedFifos);
  241. nicReceiveCommonCallback (pNotificationInfo,
  242. (PVCCB)pRecvFIFOVc ,
  243. AddressRange,
  244. pNotificationInfo->Mdl );
  245. }
  246. VOID
  247. nicAllocateAddressRangeDebugSpew(
  248. IN PIRB pIrb )
  249. // Prints out all the parameters of the allocateaddressrange Irb
  250. //
  251. {
  252. ASSERT(pIrb);
  253. /* TRACE( TL_T, TM_Recv, ( "==>nicAllocateAddressRangeDebugSpew pIrb %.8x", pIrb ) );
  254. //
  255. // Spew out all the information you can
  256. //
  257. TRACE(TL_V, TM_Recv, ("MaxSegmentSize = 0x%x\n", pIrb->u.AllocateAddressRange.MaxSegmentSize));
  258. TRACE(TL_V, TM_Recv, ("fulAccessType = 0x%x\n", pIrb->u.AllocateAddressRange.fulAccessType));
  259. TRACE(TL_V, TM_Recv, ("fulNotificationOptions = 0x%x\n", pIrb->u.AllocateAddressRange.fulNotificationOptions));
  260. TRACE(TL_V, TM_Recv, ("Callback = 0x%x\n", pIrb->u.AllocateAddressRange.Callback));
  261. TRACE(TL_V, TM_Recv, ("Context = 0x%x\n", pIrb->u.AllocateAddressRange.Context));
  262. TRACE(TL_V, TM_Recv, ("Required1394Offset->Off_High = 0x%x\n", pIrb->u.AllocateAddressRange.Required1394Offset.Off_High));
  263. TRACE(TL_V, TM_Recv, ("Required1394Offset->Off_Low = 0x%x\n", pIrb->u.AllocateAddressRange.Required1394Offset.Off_Low));
  264. TRACE(TL_V, TM_Recv, ("FifoSListHeader = 0x%x\n", pIrb->u.AllocateAddressRange.FifoSListHead));
  265. TRACE(TL_V, TM_Recv, ("FifoSListSpinLock = 0x%x\n", pIrb->u.AllocateAddressRange.FifoSpinLock));
  266. TRACE(TL_V, TM_Recv, ("AddressesReturned = 0x%x\n", pIrb->u.AllocateAddressRange.AddressesReturned));
  267. TRACE(TL_V, TM_Recv, ("p1394AddressRange = 0x%x\n", pIrb->u.AllocateAddressRange.p1394AddressRange));
  268. TRACE(TL_V, TM_Recv, ("hAddressRange = 0x%x\n", pIrb->u.AllocateAddressRange.hAddressRange));
  269. TRACE(TL_V, TM_Recv, ("AR_Off_High 0x%.4x\n",pIrb->u.AllocateAddressRange.p1394AddressRange[0].AR_Off_High));
  270. TRACE(TL_V, TM_Recv, ("AR_Off_Low 0x%.8x\n",pIrb->u.AllocateAddressRange.p1394AddressRange[0].AR_Off_Low));
  271. TRACE(TL_V, TM_Recv, ("AR_Length 0x%.8x\n",pIrb->u.AllocateAddressRange.p1394AddressRange[0].AR_Length));
  272. ASSERT(pIrb->u.AllocateAddressRange.AddressesReturned == 1);
  273. */
  274. TRACE( TL_T, TM_Recv, ( "<==nicAllocateAddressRangeComplete" ) );
  275. return;
  276. }
  277. NDIS_STATUS
  278. nicAllocateAddressRangeSucceeded (
  279. IN PIRB pIrb,
  280. IN OUT PRECVFIFO_VCCB pRecvFIFOVc
  281. )
  282. // Function Description:
  283. // This function updates all the Vc, PdoCb structures once the allocate address range Irb has succeeded
  284. // If the Irp succeeds but the rempte node is going away then it will free the address range before
  285. // returning
  286. // The Irb is used to initialize the fields. If this is the first Pdo for Vc, then it will initlalize the VC.
  287. // It will also check to see if the data returned by the Irb matches with the data in the Vc
  288. // Arguments:
  289. // PIRB : The Irb that was used in the Irp that just succeeded
  290. // REMOTE_NODE : The PdoCb that was used to perform the IoCallDriver ... (remote node)
  291. //
  292. // Return Value:
  293. // Success if the remote node is active
  294. // failure if the remote node has gone away and it need to free the address range
  295. //
  296. {
  297. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  298. BOOLEAN fPdoBeingRemoved = FALSE;
  299. NIC1394_FIFO_ADDRESS *pFifoAddress = NULL;
  300. BOOLEAN fFirstAddressRangeOnVc = FALSE;
  301. //
  302. // These are pointers to the locations that the newly allocated address range needs to be copied to
  303. //
  304. ADDRESS_RANGE *pSrcAddressRange = &pIrb->u.AllocateAddressRange.p1394AddressRange[0];
  305. // ADDRESS_RANGE *pPdoAddressRange = &pRemoteNode->RecvFIFOData.VcAddressRange;
  306. ADDRESS_RANGE *pVcAddressRange = &pRecvFIFOVc->VcAddressRange;
  307. TRACE( TL_T, TM_Recv, ( "==>nicAllocateAddressRangeSucceeded pIrb %.8x, ", pIrb) );
  308. ASSERT (pIrb->u.AllocateAddressRange.AddressesReturned == 1);
  309. //
  310. // we expect this to be populated or
  311. // nicFreeAllAllocatedAddressRangesOnPdo will have problems
  312. //
  313. ASSERT (pRecvFIFOVc != NULL);
  314. //
  315. // If both high and low are zero, the bus driver is doing something wrong, return Failure
  316. //
  317. if (pSrcAddressRange->AR_Off_Low ==0 && pSrcAddressRange ->AR_Off_High == 0)
  318. {
  319. // Some fun with DeMorgan's theorem
  320. ASSERT (pSrcAddressRange->AR_Off_Low!=0 || pSrcAddressRange ->AR_Off_High!=0);
  321. return NDIS_STATUS_FAILURE;
  322. }
  323. //
  324. // Copy the Address Ranges returned. For now just copy locally without allocating extra memory
  325. //
  326. pFifoAddress = &pRecvFIFOVc->Hdr.Nic1394MediaParams.Destination.FifoAddress;
  327. VC_ACQUIRE_LOCK (pRecvFIFOVc);
  328. do
  329. {
  330. //
  331. // Now we need copy the returned values to the Pdo structure.
  332. //
  333. // pPdoAddressRange->AR_Off_Low = pSrcAddressRange->AR_Off_Low;
  334. // pPdoAddressRange ->AR_Off_High = pSrcAddressRange ->AR_Off_High;
  335. // pPdoAddressRange->AR_Length = pSrcAddressRange->AR_Length;
  336. // pRemoteNode->RecvFIFOData.AddressesReturned = pIrb->u.AllocateAddressRange.AddressesReturned;
  337. // pRemoteNode->RecvFIFOData.hAddressRange = pIrb->u.AllocateAddressRange.hAddressRange ;
  338. //
  339. // check to see if we need to update the Recv Fifo's structures. This needs to be done if the addresses are zeroes
  340. //
  341. if (pFifoAddress->Off_Low == 0 && pFifoAddress->Off_High == 0)
  342. {
  343. fFirstAddressRangeOnVc = TRUE;
  344. pFifoAddress->Off_Low = pSrcAddressRange->AR_Off_Low;
  345. pFifoAddress->Off_High = pSrcAddressRange->AR_Off_High;
  346. pVcAddressRange->AR_Off_Low = pSrcAddressRange->AR_Off_Low;
  347. pVcAddressRange->AR_Off_High = pSrcAddressRange->AR_Off_High;
  348. pVcAddressRange->AR_Length = pSrcAddressRange->AR_Length;
  349. }
  350. else
  351. {
  352. ASSERT (pFifoAddress->Off_Low == pSrcAddressRange->AR_Off_Low);
  353. ASSERT (pFifoAddress->Off_High == pSrcAddressRange->AR_Off_High);
  354. }
  355. pRecvFIFOVc->AddressesReturned = pIrb->u.AllocateAddressRange.AddressesReturned;
  356. pRecvFIFOVc->hAddressRange = pIrb->u.AllocateAddressRange.hAddressRange;
  357. // if (REMOTE_NODE_TEST_FLAGS (pRemoteNode, PDO_BeingRemoved))
  358. // {
  359. // fPdoBeingRemoved = TRUE;
  360. //
  361. // This flag implies that the allocate address range Irp will be failed
  362. // i.e. nicAllocateAddressIrp will return failure, it is now our responsiblity
  363. // to free all resources
  364. //
  365. // NdisStatus = NDIS_STATUS_FAILURE;
  366. // break;
  367. // }
  368. //
  369. // otherwise we have succeeded, now it is the remote node's responsibility to free us
  370. //
  371. // pRemoteNode->RecvFIFOData.AllocatedAddressRange = TRUE;
  372. //
  373. // If we reached this far, we have succeeded
  374. //
  375. NdisStatus = NDIS_STATUS_SUCCESS;
  376. } while (FALSE);
  377. VC_RELEASE_LOCK (pRecvFIFOVc);
  378. TRACE( TL_T, TM_Recv, ( " hAddressRange %x, NumReturned %x , Low %x , Hi %x, Length %x",
  379. pRecvFIFOVc->hAddressRange ,
  380. pRecvFIFOVc->AddressesReturned,
  381. pSrcAddressRange->AR_Off_Low,
  382. pSrcAddressRange->AR_Off_High,
  383. pSrcAddressRange->AR_Length) );
  384. // if (fPdoBeingRemoved == TRUE)
  385. // {
  386. //
  387. // We need to free the address range as the pdo is being
  388. // removed and we have not updated any of the Pdo's data structures
  389. //
  390. // nicFreeRecvFifoAddressRange (pRemoteNode);
  391. //
  392. // Clear the pointers to the Address Range, they exist in both
  393. // the Pdo Block and the VC Block.
  394. // However clear the Vc blocks' copy of the address range only if this
  395. // is the Allocate Address Range that populated it
  396. //
  397. // NdisZeroMemory (&pRemoteNode->RecvFIFOData, sizeof (RECV_FIFO_DATA));
  398. // if (fFirstAddressRangeOnVc = TRUE)
  399. // {
  400. // pFifoAddress->Off_Low = 0;
  401. // pFifoAddress->Off_High = 0;
  402. // pVcAddressRange->AR_Off_Low = 0;
  403. // pVcAddressRange->AR_Off_High = 0;
  404. // pVcAddressRange->AR_Length = 0;
  405. // pRecvFIFOVc->AddressesReturned = 0;
  406. // }
  407. // }
  408. TRACE( TL_T, TM_Recv, ( "<==nicAllocateAddressRangeSucceeded Status %.8x", NdisStatus ) );
  409. return NdisStatus;
  410. }
  411. NDIS_STATUS
  412. nicFreeAddressFifo(
  413. IN PADDRESS_FIFO pAddressFifo,
  414. IN PRECVFIFO_VCCB pRecvFIFOVc
  415. )
  416. //
  417. // Frees the address fifo element and also its local buffer
  418. // IMP: The Addressfifo should belong to the pRecvFIFOVc
  419. //
  420. {
  421. PVOID SystemAddress = NIC_GET_SYSTEM_ADDRESS_FOR_MDL (pAddressFifo->FifoMdl);
  422. UINT Length = MmGetMdlByteCount(pAddressFifo->FifoMdl);
  423. ASSERT (SystemAddress!=NULL);
  424. ASSERT (Length != 0);
  425. TRACE( TL_T, TM_Recv, ( "==>nicFreeAddressFifo") );
  426. if (SystemAddress != NULL)
  427. {
  428. nicFreeLocalBuffer(Length, SystemAddress);
  429. }
  430. nicFreeMdl (pAddressFifo->FifoMdl);
  431. nicSetTagInFifoWrapper(pAddressFifo, NIC1394_TAG_FREED );
  432. FREE_NONPAGED((PVOID)pAddressFifo);
  433. //
  434. // Dereference the reference added when this AddressFifo was inserted into the list
  435. //
  436. nicDereferenceCall ((PVCCB)pRecvFIFOVc, "nicFreeAddressFifo");
  437. TRACE( TL_T, TM_Recv, ( "<==nicFreeAddressFifo") );
  438. return NDIS_STATUS_SUCCESS;
  439. }
  440. NDIS_STATUS
  441. nicFreeAllocateAddressRangeSList(
  442. IN PRECVFIFO_VCCB pRecvFIFOVc
  443. )
  444. //
  445. // This function should pop entries from the Slist
  446. // Each entry is an Adress_fifo element containing an MDl
  447. // The function should call nicFreeAddressFifo to free the Address FIFO element
  448. //
  449. {
  450. NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
  451. PADDRESS_FIFO pAddressFifoElement = NULL;
  452. SINGLE_LIST_ENTRY *pSingleListEntry = NULL;
  453. UINT NumFreed = 0;
  454. STORE_CURRENT_IRQL;
  455. TRACE( TL_T, TM_Recv, ( "==>nicFreeAllocateAddressRangeSList, Num %.8x",
  456. ExQueryDepthSList (&pRecvFIFOVc->FifoSListHead) ) );
  457. while ( ExQueryDepthSList (&pRecvFIFOVc->FifoSListHead) != 0)
  458. {
  459. pSingleListEntry= ExInterlockedPopEntrySList ( &pRecvFIFOVc->FifoSListHead,
  460. &pRecvFIFOVc->FifoSListSpinLock );
  461. //
  462. // This will dereference the call
  463. //
  464. pAddressFifoElement = CONTAINING_RECORD (pSingleListEntry, ADDRESS_FIFO, FifoList);
  465. ASSERT (pAddressFifoElement != NULL);
  466. //
  467. // This will dereference the Vc and free the address fifo
  468. //
  469. NdisStatus = nicFreeAddressFifo ( pAddressFifoElement,
  470. pRecvFIFOVc );
  471. NumFreed ++;
  472. }
  473. VC_ACQUIRE_LOCK (pRecvFIFOVc);
  474. ASSERT ( ExQueryDepthSList (&pRecvFIFOVc->FifoSListHead) == 0);
  475. pRecvFIFOVc->FifoSListHead.Alignment = 0;
  476. pRecvFIFOVc->NumOfFifosInSlistInCloseCall = NumFreed;
  477. VC_RELEASE_LOCK (pRecvFIFOVc);
  478. MATCH_IRQL;
  479. TRACE( TL_T, TM_Recv, ( "<==nicFreeAllocateAddressRangeSList %.8x, NumFreed %x", NdisStatus, NumFreed ) );
  480. return NdisStatus;
  481. }
  482. NDIS_STATUS
  483. nicFreeRecvFifoAddressRangeOnAllRemoteNodes (
  484. IN PADAPTERCB pAdapter
  485. )
  486. // Function Description:
  487. // This will walk through all the remote nodes and remove the address range
  488. // on each remote node
  489. // The implicit assumption is that RecvFIFO's will be allocated on all remote nodes
  490. // on an adapter
  491. // Arguments
  492. // pAdapter - the adapter on which all the remote nodes are on.
  493. //
  494. // Return Value:
  495. // Success : Always
  496. // Even if one fails this will continue to try on all remaining nodes
  497. {
  498. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  499. PLIST_ENTRY pPdoListEntry = NULL;
  500. REMOTE_NODE *pRemoteNode = NULL;
  501. TRACE( TL_T, TM_Recv, ( "==>nicFreeRecvFifoAddressRangeOnAllRemoteNodes Adapter %.8x", pAdapter) );
  502. ADAPTER_ACQUIRE_LOCK (pAdapter);
  503. //
  504. // Now Walk the list and free the address range on each pdo
  505. //
  506. for (pPdoListEntry = ListNext (&pAdapter->PDOList);
  507. pPdoListEntry != &pAdapter->PDOList;
  508. pPdoListEntry = ListNext(pPdoListEntry))
  509. {
  510. ADDRESS_RANGE *pPdoAddressRange, *pVcAddressRange;
  511. pRemoteNode = CONTAINING_RECORD (pPdoListEntry, REMOTE_NODE, linkPdo);
  512. pPdoAddressRange = &pRemoteNode->RecvFIFOData.VcAddressRange;
  513. pVcAddressRange = &pRemoteNode->pAdapter->pRecvFIFOVc->VcAddressRange;
  514. TRACE( TL_V, TM_Recv, ( "Closing all address ranges on pRemoteNode %.8x", pRemoteNode) );
  515. if (REMOTE_NODE_TEST_FLAG (pRemoteNode, PDO_BeingRemoved) == TRUE)
  516. {
  517. //
  518. // This flag is set in the Remove Remote node code path.
  519. // If this flag is set, we do not have to free the address range
  520. // If Not Set, then Arp has asked to close the call and we must free
  521. // the address range
  522. //
  523. continue;
  524. }
  525. //
  526. // Debug checks to see if the values match up
  527. //
  528. ASSERT ( pPdoAddressRange->AR_Off_Low == pVcAddressRange->AR_Off_Low);
  529. ASSERT ( pPdoAddressRange->AR_Off_High == pVcAddressRange->AR_Off_High);
  530. ASSERT ( pPdoAddressRange->AR_Length == pVcAddressRange->AR_Length);
  531. //
  532. // Now free the address range
  533. // This function expects the lock to be held
  534. //
  535. NdisStatus = nicFreeAllAllocatedAddressRangesOnPdo (pRemoteNode);
  536. if (pRemoteNode != NULL)
  537. {
  538. NdisZeroMemory (&pRemoteNode->RecvFIFOData, sizeof (RECV_FIFO_DATA) );
  539. }
  540. }
  541. ADAPTER_RELEASE_LOCK (pAdapter);
  542. NdisStatus = NDIS_STATUS_SUCCESS;
  543. TRACE( TL_T, TM_Recv, ( "<==nicFreeRecvFifoAddressRangeOnAllRemoteNodes Status %.8x", NdisStatus) );
  544. return NdisStatus;
  545. }
  546. NDIS_STATUS
  547. nicFreeAllAllocatedAddressRangesOnPdo (
  548. IN PREMOTE_NODE pRemoteNode
  549. )
  550. // Function Description:
  551. // Goes through the PdoCb and frees all the allocated address ranges.
  552. // for now we have one RecvFIFOVc only so this is a small function
  553. // This will be called from the remove remote node code path
  554. //
  555. // Arguments
  556. // PdoCb * Pdo Control Block that has the address ranges that this
  557. // function will free
  558. //
  559. // Return Value:
  560. // Success: always.
  561. //
  562. // Called With the Lock held
  563. {
  564. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  565. PVCCB pVc = (PVCCB)(pRemoteNode->RecvFIFOData.pRecvFIFOVc);
  566. STORE_CURRENT_IRQL;
  567. TRACE( TL_T, TM_Recv, ( "==>nicFreeAllAllocatedAddressRangesOnPdo pRemoteNode %.8x", pRemoteNode) );
  568. //
  569. // Check if the Allocated Address Range is true for the RecvFifoData structure in the
  570. // PdoCb. If it is, then it is this thread's responsibility to free the address range
  571. //
  572. if (pRemoteNode->RecvFIFOData.AllocatedAddressRange == TRUE)
  573. {
  574. ULONG AddressesReturned = pRemoteNode->RecvFIFOData.AddressesReturned;
  575. ADDRESS_RANGE VcAddressRange = pRemoteNode->RecvFIFOData.VcAddressRange;
  576. HANDLE hAddressRange = pRemoteNode->RecvFIFOData.hAddressRange ;
  577. pRemoteNode->RecvFIFOData.AllocatedAddressRange = FALSE;
  578. REMOTE_NODE_RELEASE_LOCK (pRemoteNode);
  579. //
  580. // Now we free the address range.
  581. //
  582. ASSERT (0);
  583. NdisStatus = nicFreeAddressRange (pRemoteNode->pAdapter,
  584. AddressesReturned ,
  585. &VcAddressRange ,
  586. &hAddressRange );
  587. REMOTE_NODE_ACQUIRE_LOCK (pRemoteNode);
  588. nicDereferenceCall (pVc, "nicFreeAllAllocatedAddressRangesOnPdo ");
  589. }
  590. else
  591. {
  592. NdisStatus = NDIS_STATUS_SUCCESS;
  593. }
  594. //
  595. // Now if anyone tries to access this pointer they will bugcheck,..
  596. // So we can ensure that there will be no more indications via this pointer
  597. //
  598. NdisZeroMemory (&pRemoteNode->RecvFIFOData, sizeof (RECV_FIFO_DATA) );
  599. MATCH_IRQL;
  600. TRACE( TL_T, TM_Recv, ( "<==nicFreeAllAllocatedAddressRangesOnPdo Status %.8x (always success)", NdisStatus) );
  601. NdisStatus = NDIS_STATUS_SUCCESS;
  602. return NdisStatus;
  603. }
  604. NDIS_STATUS
  605. nicFillAllocateAddressRangeSList(
  606. PRECVFIFO_VCCB pRecvFIFOVc,
  607. UINT *Num )
  608. //
  609. // Function inits the Slist that will be sent down with the
  610. // AllocateAddressRange Irb
  611. // RedvFifoVc - VC to be linked with the Slist
  612. // Num - Num of AddressFifo Elements that are inserted into the SList
  613. //
  614. {
  615. PADDRESS_FIFO pRecvFifoElement = NULL;
  616. NDIS_STATUS NdisStatus;
  617. UINT cnt = 0;
  618. BOOLEAN bRef = FALSE;
  619. TRACE( TL_T, TM_Recv, ( "==>nicFillAllocateAddressRangeSList" ) );
  620. ASSERT (pRecvFIFOVc != NULL);
  621. ASSERT (pRecvFIFOVc->Hdr.MTU != 0);
  622. do
  623. {
  624. NdisStatus = nicGetInitializedAddressFifoElement (pRecvFIFOVc->Hdr.MTU,
  625. &pRecvFifoElement);
  626. if (NdisStatus != NDIS_STATUS_SUCCESS)
  627. {
  628. break;
  629. }
  630. ASSERT (pRecvFifoElement != NULL);
  631. nicSetTagInFifoWrapper(pRecvFifoElement, NIC1394_TAG_QUEUED);
  632. ExInterlockedPushEntrySList ( &pRecvFIFOVc->FifoSListHead,
  633. &pRecvFifoElement->FifoList,
  634. &pRecvFIFOVc->FifoSListSpinLock);
  635. //
  636. // Add this once for every Address Fifo element inserted
  637. // Will be decremented by a call to nicFreeAddressFifo
  638. //
  639. VC_ACQUIRE_LOCK (pRecvFIFOVc);
  640. #if FIFO_WRAPPER
  641. pRecvFIFOVc->pFifoTable[cnt] = pRecvFifoElement;
  642. #endif
  643. bRef = nicReferenceCall ((PVCCB) pRecvFIFOVc, "nicFillAllocateAddressRangeSList");
  644. VC_RELEASE_LOCK (pRecvFIFOVc);
  645. if (bRef == FALSE)
  646. {
  647. NdisStatus = NDIS_STATUS_VC_NOT_ACTIVATED;
  648. break;
  649. }
  650. TRACE( TL_V, TM_Recv, ( "cnt %.8x, Num %.8x, ",cnt, *Num) );
  651. } while (++cnt < *Num);
  652. //
  653. // Need to handle failure cases and also return number allocated
  654. //
  655. *Num = cnt;
  656. if (NdisStatus != NDIS_STATUS_SUCCESS)
  657. {
  658. TRACE( TL_V, TM_Recv, ( "nicFillAllocateAddressRangeSList Failed, num allotted %.8x, MTU %,8x ",cnt ,pRecvFIFOVc->Hdr.MTU ) );
  659. NdisStatus = nicFreeAllocateAddressRangeSList (pRecvFIFOVc);
  660. ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
  661. }
  662. TRACE( TL_T, TM_Recv, ( "==>nicFillAllocateAddressRangeSList Num %.8x, MTU %.8x",cnt,pRecvFIFOVc->Hdr.MTU ) );
  663. return NdisStatus;
  664. }
  665. NDIS_STATUS
  666. nicGetInitializedAddressFifoElement(
  667. IN UINT BufferLength,
  668. IN OUT PADDRESS_FIFO *ppElement )
  669. //
  670. // This function return a single AddressFifo element,
  671. // with an MDL pointing to locally owned allocated memory
  672. // The size of the memory needs to be specified at MTU of
  673. // the VC that this belongs to and is the BufferLength.
  674. //
  675. // Get locally owned buffer, get address fifo , init MDL with
  676. // local buffer. return the AddressFifo
  677. //
  678. {
  679. PVOID pLocalBuffer = NULL;
  680. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  681. TRACE( TL_T, TM_Recv, ( "==>nicGetAddressInitializedFifoElement" ) );
  682. ASSERT (BufferLength != 0);
  683. do
  684. {
  685. if (BufferLength == 0)
  686. {
  687. NdisStatus = NDIS_STATUS_FAILURE;
  688. TRACE( TL_A, TM_Recv, ( "BufferLength is 0" ) );
  689. break;
  690. }
  691. //
  692. // Get Locally owned memory for the data
  693. //
  694. NdisStatus = nicGetLocalBuffer (BufferLength, &pLocalBuffer);
  695. if (NdisStatus != NDIS_STATUS_SUCCESS)
  696. {
  697. (*ppElement) = NULL;
  698. break;
  699. }
  700. //
  701. // Get Empty memory for the Address Fifo element
  702. //
  703. NdisStatus = nicGetEmptyAddressFifoElement (ppElement);
  704. if (NdisStatus != NDIS_STATUS_SUCCESS)
  705. {
  706. nicFreeLocalBuffer (BufferLength,
  707. pLocalBuffer);
  708. (*ppElement) = NULL;
  709. break;
  710. }
  711. //
  712. // Get an MDL and initialze the MDL with the buffer
  713. // and initialize the fifo ,with MDL.
  714. //
  715. nicGetMdl ( BufferLength,
  716. pLocalBuffer,
  717. &((*ppElement)->FifoMdl));
  718. } while(FALSE);
  719. TRACE( TL_T, TM_Recv, ( "<==nicGetInitializedAddressFifoElement, Status %.8x, AddressFifo at %.8x, LocalBuffer at %.8x",
  720. NdisStatus, *ppElement,MmGetMdlVirtualAddress((*ppElement)->FifoMdl ) ) );
  721. return NdisStatus;
  722. }
  723. NDIS_STATUS
  724. nicGetEmptyAddressFifoElement(
  725. IN PADDRESS_FIFO *ppElement)
  726. //
  727. // Returns an empty Address Fifo element.
  728. // NULL otherwise
  729. //
  730. // i.e just allocates memory and returns for now
  731. {
  732. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  733. ULONG Size = 0;
  734. TRACE( TL_T, TM_Recv, ( "==>nicGetEmptyAddressFifoElement" ) );
  735. #if FIFO_WRAPPER // Used to track missing Address Fifo elements
  736. Size = sizeof (ADDRESS_FIFO_WRAPPER);
  737. #else
  738. Size = sizeof (ADDRESS_FIFO );
  739. #endif
  740. *ppElement = ALLOC_NONPAGED (Size, MTAG_FIFO);
  741. if (*ppElement != NULL)
  742. {
  743. NdisZeroMemory (*ppElement, Size);
  744. nicSetTagInFifoWrapper(*ppElement, NIC1394_TAG_ALLOCATED );
  745. NdisStatus = NDIS_STATUS_SUCCESS;
  746. }
  747. TRACE( TL_T, TM_Recv, ( "<==nicGetEmptyAddressFifoElement, Status % .8x, at %.8x",NdisStatus,*ppElement ) );
  748. return NdisStatus;
  749. }
  750. NDIS_STATUS
  751. nicGetNdisBuffer(
  752. IN UINT Length,
  753. IN PVOID pLocalBuffer,
  754. IN OUT PNDIS_BUFFER *ppNdisBuffer )
  755. // This function will be used by the receive side
  756. // This returns an NdisBuffer as opposed to an MDL
  757. // initialized to the corect start addresses
  758. //
  759. {
  760. NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
  761. ASSERT (pLocalBuffer != NULL);
  762. ASSERT (Length > 0);
  763. ASSERT (ppNdisBuffer != NULL);
  764. TRACE( TL_T, TM_Recv, ( "==>nicGetNdisBuffer Local Buffer %.8x, Length %.8x", pLocalBuffer, Length) );
  765. if ( Length > 0 &&
  766. pLocalBuffer != NULL &&
  767. ppNdisBuffer != NULL)
  768. {
  769. NdisAllocateBuffer( &NdisStatus,
  770. ppNdisBuffer,
  771. NULL,
  772. pLocalBuffer,
  773. Length );
  774. }
  775. else
  776. {
  777. nicIncrementMallocFailure();
  778. NdisStatus = NDIS_STATUS_FAILURE;
  779. }
  780. TRACE( TL_T, TM_Recv, ( "<==nicGetNdisBuffer Buffer %x, NdisStatus %.8x", *ppNdisBuffer, NdisStatus ) );
  781. return NdisStatus;
  782. }
  783. NDIS_STATUS
  784. nicInitAllocateAddressIrb(
  785. IN PIRB pIrb,
  786. IN PVOID pContext,
  787. IN ULONG fulFlags,
  788. IN ULONG nLength,
  789. IN ULONG MaxSegmentSize,
  790. IN ULONG fulAccessType,
  791. IN ULONG fulNotificationOptions,
  792. IN PADDRESS_OFFSET pOffset,
  793. IN PRECVFIFO_VCCB pRecvFIFOVc
  794. )
  795. //
  796. // Initializes the allocate adddress Irb with the
  797. // values passed to the function
  798. //
  799. // And adds constants for certain preknown values (e.g. callback, context)
  800. // Spew as much debug as possible
  801. //
  802. {
  803. NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
  804. ASSERT (pRecvFIFOVc != NULL);
  805. TRACE( TL_T, TM_Recv, ( "==>nicInitAllocateAddressIrb" ) );
  806. pIrb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
  807. pIrb->Flags = 0;
  808. pIrb->u.AllocateAddressRange.Mdl = NULL;
  809. pIrb->u.AllocateAddressRange.fulFlags = 0;
  810. pIrb->u.AllocateAddressRange.nLength = nLength;
  811. pIrb->u.AllocateAddressRange.MaxSegmentSize = 0;
  812. pIrb->u.AllocateAddressRange.fulAccessType = fulAccessType;
  813. pIrb->u.AllocateAddressRange.fulNotificationOptions = NOTIFY_FLAGS_AFTER_WRITE;
  814. pIrb->u.AllocateAddressRange.Callback = nicAllocateAddressRangeCallback;
  815. pIrb->u.AllocateAddressRange.Context = pContext; // should be pAdapter
  816. pIrb->u.AllocateAddressRange.Required1394Offset.Off_High = pOffset->Off_High;
  817. pIrb->u.AllocateAddressRange.Required1394Offset.Off_Low = pOffset->Off_Low;
  818. pIrb->u.AllocateAddressRange.FifoSListHead = &pRecvFIFOVc->FifoSListHead;
  819. pIrb->u.AllocateAddressRange.FifoSpinLock = &pRecvFIFOVc->FifoSListSpinLock;
  820. pIrb->u.AllocateAddressRange.AddressesReturned = 0;
  821. pIrb->u.AllocateAddressRange.p1394AddressRange = &pRecvFIFOVc->VcAddressRange;
  822. TRACE(TL_V, TM_Recv, ("nLength = 0x%x\n", pIrb->u.AllocateAddressRange.nLength));
  823. TRACE(TL_V, TM_Recv, ("MaxSegmentSize = 0x%x\n", pIrb->u.AllocateAddressRange.MaxSegmentSize));
  824. TRACE(TL_V, TM_Recv, ("fulAccessType = 0x%x\n", pIrb->u.AllocateAddressRange.fulAccessType));
  825. TRACE(TL_V, TM_Recv, ("fulNotificationOptions = 0x%x\n", pIrb->u.AllocateAddressRange.fulNotificationOptions));
  826. TRACE(TL_V, TM_Recv, ("Callback = 0x%x\n", pIrb->u.AllocateAddressRange.Callback));
  827. TRACE(TL_V, TM_Recv, ("Context = 0x%x\n", pIrb->u.AllocateAddressRange.Context));
  828. TRACE(TL_V, TM_Recv, ("Required1394Offset->Off_High = 0x%x\n", pIrb->u.AllocateAddressRange.Required1394Offset.Off_High));
  829. TRACE(TL_V, TM_Recv, ("Required1394Offset->Off_Low = 0x%x\n", pIrb->u.AllocateAddressRange.Required1394Offset.Off_Low));
  830. TRACE(TL_V, TM_Recv, ("FifoSListHeader = 0x%x\n", pIrb->u.AllocateAddressRange.FifoSListHead));
  831. TRACE(TL_V, TM_Recv, ("FifoSListSpinLock = 0x%x\n", pIrb->u.AllocateAddressRange.FifoSpinLock));
  832. TRACE(TL_V, TM_Recv, ("AddressesReturned = 0x%x\n", pIrb->u.AllocateAddressRange.AddressesReturned));
  833. TRACE(TL_V, TM_Recv, ("p1394AddressRange = 0x%x\n", pIrb->u.AllocateAddressRange.p1394AddressRange));
  834. TRACE( TL_T, TM_Recv, ( "<==nicInitAllocateAddressIrb" ) );
  835. return NdisStatus;
  836. }
  837. VOID
  838. nicFifoReturnPacket (
  839. IN PVCCB pVc,
  840. IN PNDIS_PACKET pMyPacket
  841. )
  842. // Function Description:
  843. // Return Packets Handler -
  844. // For FIFO's will reinsert the buffer (MDL) into the Fifo SList
  845. // Check for the VC Active and then return it ot the SList . Free it otherwise
  846. //
  847. // Arguments
  848. // RecvFIFOVc - Vc of the packet
  849. // pPacket = Packet in question
  850. //
  851. // Return Value:
  852. //
  853. //
  854. //
  855. {
  856. PRECVFIFO_VCCB pRecvFIFOVc = (PRECVFIFO_VCCB) pVc;
  857. PNDIS_BUFFER pMyNdisBuffer;
  858. PADAPTERCB pAdapter = pRecvFIFOVc->Hdr.pAF->pAdapter;
  859. BOOLEAN fVcActive = FALSE;
  860. PADDRESS_FIFO pAddressFifo;
  861. PPKT_CONTEXT pPktContext = (PPKT_CONTEXT)&pMyPacket->MiniportReserved;
  862. TRACE( TL_T, TM_Recv, ( "==>nicFifoReturnPacket pVc %x, pPacket %x, pAdapter %x, ",
  863. pRecvFIFOVc, pMyPacket, pAdapter) );
  864. //
  865. // Either the reassembly structure has the indicated Fifo's or if no reassembly was done
  866. // then the PktContext has it.
  867. //
  868. pAddressFifo = pPktContext->AllocateAddressRange.pIndicatedFifo;
  869. //
  870. // Do not push it back in the list if the VC is about to close.
  871. // However, we push it back in, if the VC has not been activated yet
  872. //
  873. nicReturnFifoChain ( pAddressFifo , pRecvFIFOVc) ;
  874. //
  875. // Now we have to free the packet and ndis buffers that we got in the
  876. // Calback code
  877. //
  878. TRACE( TL_V, TM_Recv, ( " AllocateAddress Range - Free Packet and Free Buffer" ) );
  879. nicReturnNdisBufferChain (pMyPacket->Private.Head, pVc);
  880. nicFreePacket(pMyPacket, &pRecvFIFOVc->PacketPool);
  881. TRACE( TL_T, TM_Recv, ( "<==nicFifoReturnPacket " ) );
  882. return;
  883. }
  884. VOID
  885. nicReturnNdisBufferChain (
  886. IN PNDIS_BUFFER pNdisBuffer ,
  887. IN PVCCB pVc
  888. )
  889. {
  890. PNDIS_BUFFER pNext;
  891. BOOLEAN fIsFifo = (pVc->Hdr.VcType == NIC1394_RecvFIFO);
  892. if (pNdisBuffer == NULL)
  893. {
  894. ASSERT (pNdisBuffer != NULL);
  895. return;
  896. }
  897. while (pNdisBuffer != NULL)
  898. {
  899. pNext = pNdisBuffer->Next;
  900. NdisFreeBuffer(pNdisBuffer);
  901. nicDecRecvBuffer(fIsFifo);
  902. pNdisBuffer = pNext;
  903. }
  904. }
  905. VOID
  906. nicReturnFifoChain (
  907. IN PADDRESS_FIFO pAddressFifo,
  908. IN PRECVFIFO_VCCB pRecvFIFOVc
  909. )
  910. // Function Description:
  911. // This takes a chain of Address Fifos and returns it to the slist
  912. // if the VC is active or frees it if the VC is not active
  913. //
  914. //
  915. //
  916. // Arguments
  917. // pAddressFifo - chain of address fifo element
  918. // pRecvFIFOVc - Recv VC
  919. //
  920. // Return Value:
  921. //
  922. // None
  923. //
  924. {
  925. TRACE( TL_T, TM_Recv, ( "==> nicReturnFifoChain pAddressFifo %x, pRecvFifoVc %x", pAddressFifo, pRecvFIFOVc) );
  926. VC_ACQUIRE_LOCK (pRecvFIFOVc);
  927. //
  928. // lets update the value again, before we insert the Address Fifo back in to the Slist
  929. // If there are any remote nodes present and the VC is active
  930. // , then we should insert this back into the SList
  931. //
  932. if ( VC_ACTIVE (pRecvFIFOVc) == TRUE )
  933. {
  934. //
  935. // Return all the AddressFifo elements to the slist
  936. // Do this with the lock held so no one can change the
  937. // VC state from under us
  938. //
  939. while (pAddressFifo != NULL)
  940. {
  941. PADDRESS_FIFO pNextFifo = (PADDRESS_FIFO)(pAddressFifo->FifoList.Next);
  942. nicSetTagInFifoWrapper(pAddressFifo, NIC1394_TAG_QUEUED);
  943. ExInterlockedPushEntrySList ( &pRecvFIFOVc->FifoSListHead,
  944. &pAddressFifo ->FifoList,
  945. &pRecvFIFOVc->FifoSListSpinLock);
  946. TRACE( TL_V, TM_Recv, ( " VcActive Address Fifo %x, Next Fifo %x",pAddressFifo , pNextFifo) );
  947. pAddressFifo = pNextFifo;
  948. NdisInterlockedDecrement (&pRecvFIFOVc->NumIndicatedFifos);
  949. }
  950. VC_RELEASE_LOCK (pRecvFIFOVc);
  951. }
  952. else //VC_ACTIVE (pRecvFIFOVc) == TRUE
  953. {
  954. VC_RELEASE_LOCK (pRecvFIFOVc);
  955. //
  956. // free all the Address Fifo after releasing the lock
  957. //
  958. while (pAddressFifo != NULL)
  959. {
  960. PADDRESS_FIFO pNextFifo = (PADDRESS_FIFO)(pAddressFifo->FifoList.Next);
  961. //
  962. // Free the Mdl and Address Fifo structure and decrease the refcount
  963. // on the call. Do not touch the Vc after this
  964. //
  965. TRACE( TL_V, TM_Recv, ( " Vc NOT Active Address Fifo %x, Next Fifo %x",pAddressFifo , pNextFifo) );
  966. nicFreeAddressFifo(pAddressFifo ,
  967. pRecvFIFOVc);
  968. NdisInterlockedDecrement (&pRecvFIFOVc->NumIndicatedFifos);
  969. pAddressFifo = pNextFifo;
  970. }
  971. }
  972. TRACE( TL_T, TM_Recv, ( "<== nicReturnFifoChain ") );
  973. return;
  974. }
  975. VOID
  976. nicInternalReturnPacket(
  977. IN PVCCB pVc ,
  978. IN PNDIS_PACKET pPacket
  979. )
  980. /*++
  981. Routine Description:
  982. Finds out what type of Vc is being indicated and calls the appropriate VC return packets handler
  983. Arguments:
  984. MiniportAdapterContext - the pAdapter structure,
  985. pPacket - pPacket that the protocol returns
  986. Return Value:
  987. --*/
  988. {
  989. PPKT_CONTEXT pPktContext = (PPKT_CONTEXT)&pPacket->MiniportReserved;
  990. switch (pVc->Hdr.VcType)
  991. {
  992. case NIC1394_SendRecvChannel:
  993. case NIC1394_RecvChannel:
  994. {
  995. nicChannelReturnPacket (pVc, pPacket );
  996. break;
  997. }
  998. case NIC1394_RecvFIFO:
  999. {
  1000. nicFifoReturnPacket ( pVc, pPacket);
  1001. break;
  1002. }
  1003. case NIC1394_Ethernet:
  1004. {
  1005. ASSERT (pVc->Hdr.VcType != NIC1394_Ethernet);
  1006. break;
  1007. }
  1008. case NIC1394_MultiChannel:
  1009. {
  1010. ASSERT (pVc->Hdr.VcType != NIC1394_MultiChannel);
  1011. break;
  1012. }
  1013. case NIC1394_SendChannel:
  1014. {
  1015. ASSERT (pVc->Hdr.VcType != NIC1394_SendChannel);
  1016. break;
  1017. }
  1018. default :
  1019. {
  1020. ASSERT (0);
  1021. break;
  1022. }
  1023. }
  1024. return;
  1025. }
  1026. VOID
  1027. NicReturnPacket(
  1028. IN NDIS_HANDLE MiniportAdapterContext,
  1029. IN PNDIS_PACKET pPacket
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. This is the return packets handler.
  1034. This functikon handles all the instrumentation to catch outstanding packets and
  1035. then calls the internal return packets function
  1036. Arguments:
  1037. MiniportAdapterContext - the pAdapter structure,
  1038. pPacket - pPacket that the protocol returns
  1039. Return Value:
  1040. --*/
  1041. {
  1042. PADAPTERCB pAdapter = (PADAPTERCB) MiniportAdapterContext;
  1043. PPKT_CONTEXT pPktContext = (PPKT_CONTEXT)&pPacket->MiniportReserved;
  1044. PINDICATE_RSVD pIndicateRsvd = NULL;
  1045. PRSVD pRsvd = NULL;
  1046. //
  1047. // The first parameter of the MiniportReserved will always contain the VC
  1048. //
  1049. PVCCB pVc = (PVCCB)pPktContext->AllocateAddressRange.pRecvFIFOVc;
  1050. TRACE( TL_T, TM_Recv, ( "==> NicReturnPacket pPacket %x ", pPacket) );
  1051. do
  1052. {
  1053. //
  1054. // Mark the packet as returned
  1055. //
  1056. pRsvd =(PRSVD)(pPacket->ProtocolReserved);
  1057. pIndicateRsvd = &pRsvd->IndicateRsvd;
  1058. ASSERT (pIndicateRsvd->Tag == NIC1394_TAG_INDICATED);
  1059. pIndicateRsvd->Tag = NIC1394_TAG_RETURNED;
  1060. #if MISSING_PACKETS
  1061. if (pVc == NULL)
  1062. {
  1063. NDIS_STATUS Status = NDIS_GET_PACKET_STATUS(pPacket);
  1064. TRACE (TL_V, TM_Recv, ("Packet %x Status %x\n", pPacket, Status) );
  1065. ASSERT (0);
  1066. break;
  1067. }
  1068. #endif
  1069. nicInternalReturnPacket (pVc, pPacket);
  1070. }while (FALSE);
  1071. TRACE( TL_T, TM_Recv, ( " <== NicReturnPacket ") );
  1072. return;
  1073. }
  1074. NDIS_STATUS
  1075. nicFindReassemblyStructure (
  1076. IN PREMOTE_NODE pRemoteNode,
  1077. IN USHORT Dgl,
  1078. IN BUS_OPERATION BusOp,
  1079. IN PVCCB pVc,
  1080. OUT PNDIS1394_REASSEMBLY_STRUCTURE* ppReassembly
  1081. )
  1082. // Function Description:
  1083. // Walk through all the reassembly operations on this remote node
  1084. // and see if one is present
  1085. //
  1086. // If no reassembly is found, it will allocate and initialie a structure.
  1087. // All within the context of the reassembly lock
  1088. //
  1089. // Arguments
  1090. // pRemoteNode - Remote Node that is sending the fragments
  1091. // dgl - identifier for reassembly packet
  1092. // Together they are unique for each reassembly operation
  1093. // Return Value:
  1094. //
  1095. //
  1096. {
  1097. PNDIS1394_REASSEMBLY_STRUCTURE pTempReassembly = NULL;
  1098. PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL;
  1099. PLIST_ENTRY pReassemblyList = NULL;
  1100. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  1101. TRACE( TL_T, TM_Recv, ( "==>nicFindReassemblyStructure pRemoteNode %x, dgl %x " , pRemoteNode , Dgl) );
  1102. //
  1103. // Acquire the reassebly lock . Only let go when either a reassembly structure is found or a new
  1104. // reassembly structure is inserted into the remote node's reassembly list
  1105. //
  1106. REMOTE_NODE_ACQUIRE_LOCK (pRemoteNode);
  1107. REMOTE_NODE_REASSEMBLY_ACQUIRE_LOCK (pRemoteNode)
  1108. pReassemblyList = pRemoteNode->ReassemblyList.Flink;
  1109. //
  1110. // Find the reassembly with the same dgl
  1111. //
  1112. while ( pReassemblyList != &pRemoteNode->ReassemblyList)
  1113. {
  1114. pTempReassembly = CONTAINING_RECORD (pReassemblyList ,
  1115. NDIS1394_REASSEMBLY_STRUCTURE,
  1116. ReassemblyListEntry );
  1117. TRACE( TL_V, TM_Recv, ( "Current Dgl %x, dgl %x " , pTempReassembly->Dgl , Dgl) );
  1118. if (pTempReassembly->Dgl == Dgl)
  1119. {
  1120. pReassembly = pTempReassembly;
  1121. break;
  1122. }
  1123. pReassemblyList = pReassemblyList->Flink;
  1124. }
  1125. do
  1126. {
  1127. //
  1128. // If we have found a valid reassembly then return
  1129. //
  1130. if (pReassembly != NULL )
  1131. {
  1132. *ppReassembly = pReassembly ;
  1133. NdisStatus = NDIS_STATUS_SUCCESS;
  1134. }
  1135. else
  1136. {
  1137. //
  1138. // We need to allocate and initialize a reassembly structure
  1139. //
  1140. NdisStatus = nicGetReassemblyStructure (&pReassembly);
  1141. if (NdisStatus != NDIS_STATUS_SUCCESS)
  1142. {
  1143. BREAK (TM_Recv, (" nicGetReassemblyStructure nicGetReassemblyStructure FAILED") );
  1144. }
  1145. NdisStatus = nicInitializeReassemblyStructure (pReassembly,
  1146. Dgl,
  1147. pRemoteNode,
  1148. pVc,
  1149. BusOp);
  1150. if (NdisStatus != NDIS_STATUS_SUCCESS)
  1151. {
  1152. pReassembly = NULL;
  1153. BREAK (TM_Recv, (" nicFindReassemblyStructure nicInitializeReassemblyStructure FAILED" ) );
  1154. }
  1155. }
  1156. } while (FALSE);
  1157. if (NdisStatus == NDIS_STATUS_SUCCESS)
  1158. {
  1159. //
  1160. // Increment the ref count. Ref Count will be freed when the fragment is inserted into
  1161. // the reassembly structure or the packet indicated up
  1162. //
  1163. nicReferenceReassembly ( pReassembly, "nicFindReassemblyStructure " );
  1164. }
  1165. REMOTE_NODE_REASSEMBLY_RELEASE_LOCK (pRemoteNode)
  1166. REMOTE_NODE_RELEASE_LOCK (pRemoteNode);
  1167. if (NdisStatus == NDIS_STATUS_SUCCESS)
  1168. {
  1169. //
  1170. // Update output parameters
  1171. //
  1172. *ppReassembly = pReassembly;
  1173. }
  1174. TRACE( TL_T, TM_Recv, ( "<==nicFindReassemblyStructure NdisStatus %x, *ppReassembly %x" , NdisStatus ,*ppReassembly ) );
  1175. return NdisStatus ;
  1176. }
  1177. NDIS_STATUS
  1178. nicGetReassemblyStructure (
  1179. IN OUT PNDIS1394_REASSEMBLY_STRUCTURE* ppReassembly
  1180. )
  1181. // Function Description:
  1182. // Just allocates a structure and returns
  1183. //
  1184. // Arguments
  1185. // ppReassembly - to point to the newly allocated structure
  1186. //
  1187. //
  1188. //
  1189. // Return Value:
  1190. // Success - if succeeded
  1191. //
  1192. // Called with the lock held
  1193. {
  1194. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  1195. TRACE( TL_T, TM_Recv, ( "==>nicGetReassemblyStructure ppReassembly %x", ppReassembly ) );
  1196. *ppReassembly = ALLOC_NONPAGED (sizeof (NDIS1394_REASSEMBLY_STRUCTURE), MTAG_REASSEMBLY);
  1197. if (*ppReassembly == NULL)
  1198. {
  1199. nicIncrementMallocFailure();
  1200. NdisStatus = NDIS_STATUS_FAILURE;
  1201. }
  1202. else
  1203. {
  1204. NdisZeroMemory (*ppReassembly, sizeof (NDIS1394_REASSEMBLY_STRUCTURE) );
  1205. NdisStatus = NDIS_STATUS_SUCCESS;
  1206. (*ppReassembly)->Tag = MTAG_REASSEMBLY;
  1207. ReassemblyAllocated++;
  1208. }
  1209. TRACE( TL_T, TM_Recv, ( " <==nicGetReassemblyStructure NdisStatus %x, pReassembly %x", NdisStatus, *ppReassembly) );
  1210. return NdisStatus;
  1211. }
  1212. VOID
  1213. nicFreeReassemblyStructure (
  1214. IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly
  1215. )
  1216. // Function Description:
  1217. // Just Frees the structure and returns
  1218. //
  1219. // Arguments
  1220. // ppReassembly - to point to the newly allocated structure
  1221. //
  1222. //
  1223. // Return Value:
  1224. // Success - if succeeded
  1225. //
  1226. {
  1227. TRACE( TL_T, TM_Recv, ( "== nicFreeReassemblyStructure ppReassembly %x", pReassembly ) );
  1228. pReassembly->Tag = MTAG_FREED;
  1229. nicDereferenceReassembly (pReassembly, "nicFreeReassemblyStructure ");
  1230. return;
  1231. }
  1232. NDIS_STATUS
  1233. nicInitializeReassemblyStructure (
  1234. IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
  1235. IN USHORT Dgl,
  1236. IN PREMOTE_NODE pRemoteNode,
  1237. IN PVCCB pVc,
  1238. IN BUS_OPERATION ReceiveOp
  1239. )
  1240. // Function Description:
  1241. // Goes in and assigns values to all the structures
  1242. //
  1243. // Arguments
  1244. // pReassembly = pReassembly structure all zeroed out,
  1245. // Dgl,- Datagram Label to be used in reassembly
  1246. // pRemoteNode - pRemoteNode pointing to the sender
  1247. //
  1248. //
  1249. // Return Value:
  1250. // Success : - If remote node active and this has been inserted into the remote node's list
  1251. // Failure - If remote Node is not active
  1252. // Called with the lock held
  1253. //
  1254. {
  1255. BOOLEAN fRemoteNodeActive = FALSE;
  1256. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  1257. PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter;
  1258. TRACE( TL_T, TM_Recv, ( "==> nicInitializeReassemblyStructure pReassembly %x, ReceiveOp %x", pReassembly, ReceiveOp ) );
  1259. TRACE( TL_T, TM_Recv, ( " pRemoteNode %x, Dgl %x, pVc %x ", pReassembly, Dgl, pVc ) );
  1260. //
  1261. // Increment the reassembly count
  1262. //
  1263. nicReassemblyStarted(pAdapter);
  1264. pAdapter->AdaptStats.TempStats.ulMaxOutstandingReassemblies =
  1265. max(pAdapter->AdaptStats.TempStats.ulMaxOutstandingReassemblies,
  1266. pAdapter->AdaptStats.TempStats.ulNumOutstandingReassemblies);
  1267. //
  1268. // Dgl - Datagram label. Unique for every reassembly structure gernerated by this local host
  1269. //
  1270. pReassembly->Dgl = Dgl;
  1271. //
  1272. // pRemoteNode -> RemoteNode + Dgl are unique for each reassembly structure
  1273. //
  1274. pReassembly->pRemoteNode = pRemoteNode;
  1275. //
  1276. // ExpectedFragmentOffset is computed by the Last Fragment's Offset +
  1277. // length of fragment. Does not account for gaps in the reassembled packet.
  1278. //
  1279. pReassembly->ExpectedFragmentOffset = 0;
  1280. //
  1281. // LastNdisBuffer that was appended to the packet
  1282. //
  1283. pReassembly->pTailNdisBuffer = NULL;
  1284. //
  1285. // Packet that is being reassembled
  1286. //
  1287. pReassembly->pNdisPacket = NULL;
  1288. pReassembly->Head.pAddressFifo = NULL;
  1289. pReassembly->Tail.pAddressFifo = NULL;
  1290. pReassembly->ReceiveOp = ReceiveOp;
  1291. pReassembly->pVc = pVc;
  1292. //
  1293. // Reference the remote node. This will be derefernced when the packet is returned
  1294. //
  1295. fRemoteNodeActive = (REMOTE_NODE_ACTIVE (pRemoteNode));
  1296. TRACE( TL_V, TM_Recv, ( " nicInitializeReassemblyStructure fRemoteNodeActive %x", fRemoteNodeActive) );
  1297. if (fRemoteNodeActive == TRUE)
  1298. {
  1299. //
  1300. // REfcount made as the reassembly will happen on the remote node.
  1301. // REfcount released when the last fragment is complete
  1302. //
  1303. nicReferenceRemoteNode (pRemoteNode, "nicInitializeReassemblyStructure");
  1304. InsertTailList(&pRemoteNode->ReassemblyList, &pReassembly->ReassemblyListEntry);
  1305. //
  1306. // Reerence REassembly . Ref removed when this is removed from the Remote node list
  1307. //
  1308. nicReferenceReassembly (pReassembly, "nicInitializeReassembly" );
  1309. }
  1310. if (fRemoteNodeActive == FALSE)
  1311. {
  1312. //
  1313. // Temporary assert
  1314. //
  1315. FREE_NONPAGED (pReassembly);
  1316. NdisStatus = NDIS_STATUS_FAILURE;
  1317. }
  1318. else
  1319. {
  1320. NdisStatus = NDIS_STATUS_SUCCESS;
  1321. }
  1322. //
  1323. // reference the reassembly for its creation. Dereferenced in the Indicate Packet Code path
  1324. //
  1325. nicReferenceReassembly (pReassembly, " nicInitializeReassemblyStructure ");
  1326. TRACE( TL_T, TM_Recv, ( "<== nicInitializeReassemblyStructure NdisStatus %x, pReassembly%x ", NdisStatus,pReassembly ) );
  1327. return NdisStatus;
  1328. }
  1329. VOID
  1330. nicAbortReassembly (
  1331. IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly
  1332. )
  1333. // Function Description:
  1334. //
  1335. // Assumes that the Reassembly structure is no longer in the remote node's list
  1336. //
  1337. // This funciotn will free all allocated NdisBuffers and return all AddressFifo
  1338. // elements to the bus driver (or frees them if the VC is closing down).
  1339. //
  1340. // Arguments
  1341. // pReasssembly - Reassembly structure that needs to be freed
  1342. //
  1343. //
  1344. // Return Value:
  1345. // None
  1346. //
  1347. {
  1348. PNDIS_BUFFER pNdisBuffer = NULL;
  1349. PRECVFIFO_VCCB pRecvFIFOVc = NULL;
  1350. PCHANNEL_VCCB pChannelVc = NULL;
  1351. PADAPTERCB pAdapter = pReassembly->pVc->Hdr.pAF->pAdapter;
  1352. STORE_CURRENT_IRQL;
  1353. TRACE( TL_T, TM_Recv, ( "==> nicAbortReassembly pReassembly %x", pReassembly ) );
  1354. //
  1355. // Free all the ndis buffers and so forth
  1356. //
  1357. if (pReassembly != NULL)
  1358. {
  1359. //
  1360. // First Chain the reassembly array into a linked so our return functions can deal with it
  1361. //
  1362. nicChainReassembly (pReassembly);
  1363. if (pReassembly->pHeadNdisBuffer != NULL)
  1364. {
  1365. nicReturnNdisBufferChain(pReassembly->pHeadNdisBuffer, pReassembly->pVc);
  1366. }
  1367. switch (pReassembly->ReceiveOp)
  1368. {
  1369. case AddressRange:
  1370. {
  1371. pRecvFIFOVc = (PRECVFIFO_VCCB) pReassembly->pVc;
  1372. //
  1373. // Time to return all of our address fifos
  1374. //
  1375. nicReturnFifoChain (pReassembly->Head.pAddressFifo,
  1376. pRecvFIFOVc
  1377. );
  1378. pReassembly->Head.pAddressFifo = NULL;
  1379. break;
  1380. }
  1381. case IsochReceive:
  1382. {
  1383. pChannelVc = (PCHANNEL_VCCB)pReassembly->pVc;
  1384. nicReturnDescriptorChain ( pReassembly->Head.pIsochDescriptor,
  1385. pChannelVc);
  1386. pReassembly->Head.pIsochDescriptor = NULL;
  1387. break;
  1388. }
  1389. default:
  1390. {
  1391. ASSERT (0);
  1392. }
  1393. }
  1394. }
  1395. else
  1396. {
  1397. ASSERT (0);
  1398. }
  1399. //
  1400. // Now deref the reassembly and free it.
  1401. //
  1402. nicReassemblyAborted (pAdapter);
  1403. nicFreeReassemblyStructure (pReassembly);
  1404. TRACE( TL_T, TM_Recv, ( "<== nicAbortReassembly pReassembly %x", pReassembly ) );
  1405. MATCH_IRQL;
  1406. return;
  1407. }
  1408. NDIS_STATUS
  1409. nicDoReassembly (
  1410. IN PNIC_RECV_DATA_INFO pRcvInfo,
  1411. OUT PNDIS1394_REASSEMBLY_STRUCTURE *ppReassembly,
  1412. PBOOLEAN pfReassemblyComplete
  1413. )
  1414. /*++
  1415. Routine Description:
  1416. Does the reassembly work .
  1417. Allocates an ndisbuffer pointing to the data .
  1418. Does In order or out of order reassembly
  1419. Arguments:
  1420. pRcvInfo - pRcv Information
  1421. pReassembly reassmbly structure associated with this fragment
  1422. pfReassemblyComplete - Is the REassembly complete
  1423. Return Value:
  1424. Success - if this fragment was successfully associated with a reassembly structure
  1425. --*/
  1426. {
  1427. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  1428. PNDIS_BUFFER pNdisBuffer = NULL;
  1429. PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL;
  1430. BOOLEAN fInOrder = FALSE;
  1431. BOOLEAN fNeedToReleaseReassemblyLock = FALSE;
  1432. BOOLEAN fReassemblyComplete = FALSE;
  1433. PADAPTERCB pAdapter = pRcvInfo->pRemoteNode->pAdapter;
  1434. STORE_CURRENT_IRQL;
  1435. TRACE( TL_T, TM_Recv, ( "==> nicDoReassembly ppReassembly %x pRcvInfo %x",
  1436. ppReassembly, pRcvInfo ) );
  1437. do
  1438. {
  1439. //
  1440. // Get an NdisBuffer pointing to the data
  1441. //
  1442. NdisStatus = nicGetNdisBufferForReassembly( pRcvInfo, &pNdisBuffer);
  1443. if (NdisStatus != NDIS_STATUS_SUCCESS)
  1444. {
  1445. //
  1446. // If we break from here, the reassmbly will never get completed and the
  1447. // garbage collector will eventually free this.
  1448. //
  1449. pNdisBuffer = NULL;
  1450. BREAK (TM_Send, ("nicDoReassembly nicGetNdisBufferForReassembly FAILED" ) );
  1451. }
  1452. //
  1453. // Either there is a reassembly currently going or one will be allocated and initialized
  1454. //
  1455. NdisStatus = nicFindReassemblyStructure (pRcvInfo->pRemoteNode,
  1456. pRcvInfo->Dgl,
  1457. pRcvInfo->RecvOp,
  1458. (PVCCB)pRcvInfo->pVc,
  1459. &pReassembly);
  1460. if (NdisStatus != NDIS_STATUS_SUCCESS)
  1461. {
  1462. pReassembly=NULL;
  1463. BREAK (TM_Recv, (" nicDoReassembly nicFindReassemblyStructure FAILED"));
  1464. }
  1465. //
  1466. // Now we start doing the actual work . Acquire the
  1467. // reassembly lock so no one else can touch the reassembly
  1468. //
  1469. ASSERT (pReassembly != NULL);
  1470. TRACE( TL_V, TM_Recv, ( " ExpectedFragmentOffset %x FragmentHeader Offset %x, ",
  1471. pReassembly->ExpectedFragmentOffset , pRcvInfo->FragmentOffset) );
  1472. //
  1473. // Code expects that if the reassembly is not Null, then the lock is acquired.
  1474. //
  1475. REASSEMBLY_ACQUIRE_LOCK (pReassembly);
  1476. fNeedToReleaseReassemblyLock = TRUE;
  1477. if (REASSEMBLY_ACTIVE (pReassembly) == FALSE)
  1478. {
  1479. //
  1480. // Drop the reassembly, as this structure is about to be freed
  1481. //
  1482. NdisStatus = NDIS_STATUS_FAILURE;
  1483. break;
  1484. }
  1485. //
  1486. // This is the new reassembly scheme, which uses a table and does out of order and inorder
  1487. // reassembly
  1488. //
  1489. NdisStatus = nicInsertFragmentInReassembly (pReassembly,
  1490. pRcvInfo);
  1491. if (NdisStatus != NDIS_STATUS_SUCCESS)
  1492. {
  1493. //
  1494. // Do not assert
  1495. //
  1496. TRACE (TL_V, TM_Reas, ("nicDoReassembly nicInsertFragmentInReassembly FAILED") );
  1497. break;
  1498. }
  1499. fReassemblyComplete = pReassembly->fReassemblyComplete;
  1500. } while (FALSE);
  1501. //
  1502. // Release the reassembly lock (if acquired)
  1503. //
  1504. if (fNeedToReleaseReassemblyLock == TRUE)
  1505. {
  1506. REASSEMBLY_RELEASE_LOCK (pReassembly);
  1507. if (fReassemblyComplete == TRUE)
  1508. {
  1509. //
  1510. // Dereference the remote node as we are removing the reassembly from the remote node
  1511. //
  1512. nicDereferenceReassembly (pReassembly, "nicInsertFragmentInReassembly " );
  1513. //
  1514. // now dereference the remote node. ref was added when the reassembly was
  1515. // inserted into the remote node's list
  1516. //
  1517. nicDereferenceRemoteNode(pReassembly->pRemoteNode, "nicInsertFragmentInReassembly ");
  1518. pReassembly->pRemoteNode = NULL;
  1519. }
  1520. }
  1521. //
  1522. // Clean up time. First handle the failure case.
  1523. // If reassembly is != NULL, then free the lock
  1524. // and free the reassembly structure
  1525. //
  1526. if (NdisStatus == NDIS_STATUS_SUCCESS)
  1527. {
  1528. *ppReassembly = pReassembly;
  1529. //
  1530. // Queue a Reassembly timer, if reassembly was not complete
  1531. //
  1532. if (fReassemblyComplete == FALSE)
  1533. {
  1534. nicQueueReassemblyTimer(pAdapter, FALSE);
  1535. }
  1536. }
  1537. if (NdisStatus != NDIS_STATUS_SUCCESS )
  1538. {
  1539. //
  1540. // Do not touch the reassembly.
  1541. //
  1542. if (pNdisBuffer)
  1543. {
  1544. NdisFreeBuffer (pNdisBuffer);
  1545. }
  1546. //
  1547. // Return NULL as output. The Reassembly structure is
  1548. // in the remote node's list. The timer routine will pick it up
  1549. //
  1550. //
  1551. // Deref the ref made the REassembly was found/
  1552. //
  1553. if (pReassembly != NULL)
  1554. {
  1555. nicDereferenceReassembly (pReassembly, "nicDoReassembly - failure" );
  1556. }
  1557. *ppReassembly = pReassembly = NULL;
  1558. }
  1559. *pfReassemblyComplete = fReassemblyComplete;
  1560. TRACE( TL_T, TM_Recv, ( "<== nicDoReassembly NdisStatus %x, , pReassembly %x, Complete %x", NdisStatus, *ppReassembly, *pfReassemblyComplete ) );
  1561. MATCH_IRQL;
  1562. return NdisStatus;
  1563. }
  1564. NDIS_STATUS
  1565. nicGetNdisBufferForReassembly(
  1566. IN PNIC_RECV_DATA_INFO pRcvInfo,
  1567. OUT PNDIS_BUFFER *ppNdisBuffer
  1568. )
  1569. // Function Description:
  1570. // This function gets an Ndis Buffer that points to the start of the data
  1571. // that the Mdl points to. The Data starts from the point after the
  1572. // Fragmentation Header
  1573. //
  1574. // If this is the First fragment, then 32 bytes of the fragment header are also
  1575. // copied to make room for the header that the ARP module expects
  1576. // Arguments
  1577. //
  1578. // Return Value:
  1579. // Success - if the mem alloc succeeded
  1580. // NdisBuffer - Buffer pointing ot the data ,
  1581. // Data Length Length of the NdisBuffer
  1582. // StartValidData - StartVa of the NdisBuffer
  1583. //
  1584. {
  1585. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  1586. PVOID pStartValidData = NULL;
  1587. ULONG ulValidDataLength = 0;
  1588. PNDIS1394_FRAGMENT_HEADER pNonByteSwappedFragmentHeader = NULL;
  1589. USHORT Dgl;
  1590. PNDIS_BUFFER pNdisBuffer = NULL;
  1591. ULONG IsochPrefix = ISOCH_PREFIX_LENGTH;
  1592. PPACKET_FORMAT pIndicatedData = NULL;
  1593. TRACE( TL_T, TM_Recv, ( "==> nicGetNdisBufferForReassembly ") );
  1594. do
  1595. {
  1596. //
  1597. // Get a pointer to the start of the data, ie. it should point past the encapsulation header
  1598. //
  1599. pStartValidData = (PVOID)((ULONG_PTR)pRcvInfo->pEncapHeader + sizeof(NDIS1394_FRAGMENT_HEADER));
  1600. ulValidDataLength = pRcvInfo->DataLength - sizeof (NDIS1394_FRAGMENT_HEADER);
  1601. //
  1602. // if this is the first fragment, then leave room for the Unfragmented header that will need
  1603. // to be added before sending it up to the IP module
  1604. //
  1605. if (pRcvInfo->fFirstFragment == TRUE)
  1606. {
  1607. ULONG ExtraData = (sizeof(NDIS1394_FRAGMENT_HEADER) - sizeof (NDIS1394_UNFRAGMENTED_HEADER)) ;
  1608. pStartValidData = (PVOID)((ULONG_PTR)pStartValidData - ExtraData);
  1609. ulValidDataLength += ExtraData ;
  1610. }
  1611. NdisStatus = nicGetNdisBuffer ( ulValidDataLength,
  1612. pStartValidData,
  1613. &pNdisBuffer);
  1614. if (NdisStatus != NDIS_STATUS_SUCCESS)
  1615. {
  1616. BREAK (TM_Recv, ( "nicGetNdisBufferForReassembly: nicGetNdisBuffer Failed" ) );
  1617. }
  1618. nicIncRecvBuffer(pRcvInfo->pVc->Hdr.VcType == NIC1394_RecvFIFO);
  1619. *ppNdisBuffer = pNdisBuffer;
  1620. pRcvInfo->pNdisBuffer = pNdisBuffer;
  1621. pRcvInfo->pNdisBufferData = pStartValidData;
  1622. }while (FALSE);
  1623. TRACE( TL_T, TM_Recv, ( "<== nicGetNdisBufferForReassembly NdisStatus %x, *ppNdisbuffer %x, pStartValidData%x ,ulValidDataLength %x",
  1624. NdisStatus, *ppNdisBuffer, pStartValidData, ulValidDataLength) );
  1625. return NdisStatus;
  1626. }
  1627. VOID
  1628. nicAddUnfragmentedHeader (
  1629. IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
  1630. IN PVOID pEncapHeader
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. Its purpose is to add the fragment header that arp expects.
  1635. There is room in the Head NdisBuffer to do this
  1636. We own the buffer, so we can manipulate the data
  1637. Arguments:
  1638. pReassembty Structure - contains all the necessary reasembly info
  1639. pEncapHeader - Pointer to where th Unfragmented header will be stored
  1640. Return Value:
  1641. None
  1642. --*/
  1643. {
  1644. PNDIS1394_UNFRAGMENTED_HEADER pHeader = NULL;
  1645. ASSERT (sizeof(NDIS1394_UNFRAGMENTED_HEADER) == sizeof(ULONG));
  1646. TRACE( TL_T, TM_Recv, ( "==> nicAddUnfragmentedHeader %x, pEncapHeader %x", pReassembly, pEncapHeader) );
  1647. pHeader = (PNDIS1394_UNFRAGMENTED_HEADER) pEncapHeader;
  1648. //
  1649. // Now we add the unfragmented header. first zero it, then add the approriate values
  1650. //
  1651. pHeader->HeaderUlong = 0;
  1652. pHeader->u.FH_lf = lf_Unfragmented;
  1653. pHeader->u.FH_EtherType = pReassembly->EtherType;
  1654. //
  1655. // Convert the header to network order and indicate it up.
  1656. //
  1657. pHeader->HeaderUlong = SWAPBYTES_ULONG (pHeader->HeaderUlong);
  1658. TRACE( TL_T, TM_Recv, ( "<== nicAddUnfragmentedHeader pReasembly %x, pHeader %x ", pReassembly, pHeader->HeaderUlong) );
  1659. return;
  1660. }
  1661. VOID
  1662. nicAbortReassemblyList (
  1663. PLIST_ENTRY pToBeFreedList
  1664. )
  1665. // Function Description:
  1666. // Walks the list and calls nicAbortReassembly on each structure
  1667. //
  1668. // Does not do any lock or refcount work
  1669. //
  1670. //
  1671. // Arguments
  1672. // pToBeFreedList - list of reassembly structures that are going to be freed
  1673. //
  1674. //
  1675. // Return Value:
  1676. // None
  1677. //
  1678. //
  1679. //
  1680. {
  1681. PLIST_ENTRY pReassemblyList = ListNext (pToBeFreedList);
  1682. PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL;
  1683. TRACE( TL_T, TM_Recv, ( "==> nicAbortReassemblyList pToBeFreedList %x", pToBeFreedList));
  1684. while (pReassemblyList != pToBeFreedList)
  1685. {
  1686. pReassembly = CONTAINING_RECORD(pReassemblyList,
  1687. NDIS1394_REASSEMBLY_STRUCTURE,
  1688. ReassemblyListEntry);
  1689. pReassemblyList = ListNext(pReassemblyList);
  1690. TRACE( TL_T, TM_Recv, ( " Aborting pReassembly %x", pReassembly));
  1691. nicAbortReassembly(pReassembly);
  1692. }
  1693. }
  1694. VOID
  1695. nicFreeAllPendingReassemblyStructures(
  1696. IN PADAPTERCB pAdapter
  1697. )
  1698. // Function Description:
  1699. // When we are notified of a reset we need to go and invalidate all
  1700. // reassemblies
  1701. //
  1702. // This will always be called from the Reset code path . and will be at dispatch
  1703. // It will clear out all the remote node reaassembly and mark them as aborted.
  1704. // The Timer routine will then pick them up and free it
  1705. //
  1706. // Does not actually free anything. Just marks them as aborted
  1707. //
  1708. // Arguments
  1709. // pAdapter - pAdapter that has been resets
  1710. //
  1711. //
  1712. // Return Value:
  1713. //
  1714. //
  1715. {
  1716. PLIST_ENTRY pRemoteNodeList = NULL;
  1717. PREMOTE_NODE pRemoteNode = NULL;
  1718. PLIST_ENTRY pReassemblyList = NULL;
  1719. PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL;
  1720. ULONG NumMarkedAborted = 0;
  1721. TRACE( TL_T, TM_Recv, ( "==> nicFreeAllPendingReassemblyStructures "));
  1722. pRemoteNodeList = ListNext(&pAdapter->PDOList);
  1723. ADAPTER_ACQUIRE_LOCK (pAdapter);
  1724. //
  1725. // Walking through the remote nodes
  1726. //
  1727. while (pRemoteNodeList != &pAdapter->PDOList)
  1728. {
  1729. pRemoteNode = CONTAINING_RECORD(pRemoteNodeList,
  1730. REMOTE_NODE,
  1731. linkPdo);
  1732. pRemoteNodeList = ListNext (pRemoteNodeList);
  1733. //
  1734. // Reference the remote node, so we can guarantee its presence
  1735. //
  1736. if (REMOTE_NODE_ACTIVE (pRemoteNode)== FALSE)
  1737. {
  1738. //
  1739. // The remote node is going away. Skip this remote node
  1740. //
  1741. continue;
  1742. }
  1743. if (nicReferenceRemoteNode (pRemoteNode, "nicFreeAllPendingReassemblyStructures" )== FALSE )
  1744. {
  1745. //
  1746. // The remote node is going away. Skip this remote node
  1747. //
  1748. continue;
  1749. }
  1750. //
  1751. // Now walking through all the reassembly structures on that remote node
  1752. //
  1753. REMOTE_NODE_REASSEMBLY_ACQUIRE_LOCK(pRemoteNode);
  1754. pReassemblyList = ListNext (&pRemoteNode->ReassemblyList);
  1755. while (pReassemblyList != &pRemoteNode->ReassemblyList)
  1756. {
  1757. pReassembly = CONTAINING_RECORD (pReassemblyList,
  1758. NDIS1394_REASSEMBLY_STRUCTURE,
  1759. ReassemblyListEntry);
  1760. pReassemblyList = ListNext(pReassemblyList);
  1761. //
  1762. // If the reassembly has not been touched since the last timer it needs to be freed.
  1763. // Other threads can ask us to free the reassembly by setting the aborted flag
  1764. //
  1765. if (REASSEMBLY_TEST_FLAG (pReassembly, REASSEMBLY_ABORTED) == FALSE);
  1766. {
  1767. REASSEMBLY_SET_FLAG (pReassembly, REASSEMBLY_ABORTED);
  1768. NdisInterlockedIncrement (&NumMarkedAborted);
  1769. }
  1770. }
  1771. REMOTE_NODE_REASSEMBLY_RELEASE_LOCK(pRemoteNode);
  1772. nicDereferenceRemoteNode (pRemoteNode, "nicFreeAllPendingReassemblyStructures" );
  1773. }
  1774. ADAPTER_RELEASE_LOCK (pAdapter);
  1775. TRACE( TL_T, TM_Recv, ( "<== nicFreeAllPendingReassemblyStructures NumMarkedAborted %x"));
  1776. }
  1777. ULONG
  1778. nicReferenceReassembly (
  1779. IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
  1780. PCHAR pString
  1781. )
  1782. {
  1783. ULONG Ref;
  1784. Ref = NdisInterlockedIncrement (&pReassembly->Ref);
  1785. TRACE( TL_V, TM_Ref, ( "**nicReferenceReassembly pReassembly %x, to %d, %s ", pReassembly, pReassembly->Ref, pString) );
  1786. return Ref;
  1787. }
  1788. ULONG
  1789. nicDereferenceReassembly (
  1790. IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
  1791. PCHAR pString
  1792. )
  1793. {
  1794. ULONG Ref;
  1795. Ref = NdisInterlockedDecrement (&pReassembly->Ref);
  1796. TRACE( TL_V, TM_Ref, ( "**nicDereferenceReassembly pReassembly %x, to %d, %s ", pReassembly, pReassembly->Ref, pString) );
  1797. if ( Ref ==0 )
  1798. {
  1799. TRACE( TL_V, TM_Ref, ( "**FREEING pReassembly %x, ", pReassembly) );
  1800. FREE_NONPAGED (pReassembly);
  1801. }
  1802. return Ref;
  1803. }
  1804. VOID
  1805. nicIndicateNdisPacketToNdis (
  1806. PNDIS_PACKET pPacket,
  1807. PVCCB pVc,
  1808. PADAPTERCB pAdapter
  1809. )
  1810. // Function Description:
  1811. // This is to be used to indicate packets to NDIS .
  1812. // In Win 9x indications will go through a timer routine
  1813. //
  1814. // Assumption - There will be only one packet in the array
  1815. //
  1816. // Arguments
  1817. // ppPacket - Packet Array
  1818. // pVc -Vc
  1819. // MiniportAdapterhandle
  1820. // Return Value:
  1821. // None
  1822. //
  1823. {
  1824. NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
  1825. PRSVD pRsvd = NULL;
  1826. PNDIS_MINIPORT_TIMER pRcvTimer= NULL;
  1827. PINDICATE_RSVD pIndicateRsvd = NULL;
  1828. TRACE( TL_T, TM_Recv, ( "==> nicIndicateNdisPacketToNdis pPacket %x, pVc %x, pAdapter %x ",
  1829. pPacket , pVc, pAdapter));
  1830. TRACE (TL_V, TM_Reas, ("Indicating packet " ));
  1831. do
  1832. {
  1833. NdisInterlockedIncrement (&pAdapter->AdaptStats.ulRcvOk);
  1834. nicDumpPkt (pPacket,"Indicating Rcv ");
  1835. ASSERT (pPacket != NULL);
  1836. //
  1837. // Set up the Context for the indication
  1838. //
  1839. pRsvd =(PRSVD)(pPacket->ProtocolReserved);
  1840. pIndicateRsvd = &pRsvd->IndicateRsvd;
  1841. #if QUEUED_PACKETS
  1842. pIndicateRsvd->Tag = NIC1394_TAG_QUEUED;
  1843. NdisStatus = nicQueueReceivedPacket( pPacket, pVc, pAdapter);
  1844. if (NdisStatus != NDIS_STATUS_SUCCESS)
  1845. {
  1846. //
  1847. // We were not able to queue the packet.
  1848. // Call the return packet handler
  1849. //
  1850. ASSERT (0);
  1851. NicReturnPacket (pAdapter, pPacket);
  1852. }
  1853. #else // QUEUED_PACKETS
  1854. TRACE( TL_V, TM_Recv, ( " Indicating without timer"));
  1855. //
  1856. // Update the tag increment counter and indicate rcv
  1857. //
  1858. pIndicateRsvd->Tag = NIC1394_TAG_INDICATED;
  1859. ASSERT (pPacket != NULL);
  1860. nicIncrementRcvVcPktCount(pVc,pPacket);
  1861. NdisMCoIndicateReceivePacket(pVc->Hdr.NdisVcHandle, &pPacket, 1);
  1862. ASSERT (pAdapter->MiniportAdapterHandle != NULL);
  1863. NdisMCoReceiveComplete(pAdapter->MiniportAdapterHandle);
  1864. #endif //QUEUED_PACKETS
  1865. }while (FALSE);
  1866. TRACE( TL_T, TM_Recv, ( "<==nicIndicateNdisPacketToNdis %x"));
  1867. }
  1868. NDIS_STATUS
  1869. nicValidateRecvDataIsoch(
  1870. IN PMDL pMdl,
  1871. IN PISOCH_DESCRIPTOR pIsochDescriptor,
  1872. IN PVCCB pVc,
  1873. OUT PNIC_RECV_DATA_INFO pRcvInfo
  1874. )
  1875. {
  1876. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  1877. do
  1878. {
  1879. NODE_ADDRESS NodeAddress;
  1880. PGASP_HEADER pGaspHeader;
  1881. //
  1882. // Isoch header is already byte swapped
  1883. //
  1884. pRcvInfo->DataLength = pRcvInfo->p1394Data->IsochReceiveFragmented.IsochHeader.IH_Data_Length;
  1885. if (pRcvInfo->DataLength <= (UINT)FIELD_OFFSET(DATA_FORMAT,IsochReceiveFragmented.Data))
  1886. {
  1887. // Too small. Note that for simplicitly we check for the
  1888. // fragmented case.
  1889. //
  1890. NdisStatus = NDIS_STATUS_FAILURE;
  1891. break;
  1892. }
  1893. pRcvInfo->fGasp = TRUE;
  1894. //
  1895. // The total length of the data indicated by the bus driver
  1896. //
  1897. pRcvInfo->Length1394 = pRcvInfo->DataLength + sizeof (ISOCH_HEADER) + sizeof(ULONG); // Account for the prefix and isoch header
  1898. //
  1899. // The valid data does not include the gasp header
  1900. //
  1901. pRcvInfo->DataLength -= sizeof (GASP_HEADER);
  1902. pRcvInfo->NdisPktContext.pIsochContext = pIsochDescriptor;
  1903. pRcvInfo->pPacketPool = &((PCHANNEL_VCCB) pVc)->PacketPool;
  1904. //
  1905. // Get the source Info out.
  1906. //
  1907. //
  1908. // pRcvInfo->p1394Data points to the start of the Mdl's VA that was indicated by the bus driver
  1909. //
  1910. pGaspHeader = &pRcvInfo->p1394Data->IsochReceiveFragmented.GaspHeader;
  1911. //
  1912. // Byte swap the Gasp Header in the actual data. we own the buffer, so we can byte swap it
  1913. //
  1914. pGaspHeader->FirstQuadlet.GaspHeaderHigh = SWAPBYTES_ULONG(pGaspHeader->FirstQuadlet.GaspHeaderHigh);
  1915. pGaspHeader->SecondQuadlet.GaspHeaderLow = SWAPBYTES_ULONG(pGaspHeader->SecondQuadlet.GaspHeaderLow);
  1916. TRACE (TL_V, TM_Recv, (" Gasp Hi %x, Gasp Lo %x.",
  1917. pGaspHeader->FirstQuadlet.GaspHeaderHigh,
  1918. pGaspHeader->SecondQuadlet.GaspHeaderLow ) );
  1919. pRcvInfo->pGaspHeader = pGaspHeader;
  1920. pRcvInfo->SourceID = pGaspHeader->FirstQuadlet.u1.GH_NodeAddress.NA_Node_Number;
  1921. pRcvInfo->SourceID = pGaspHeader->FirstQuadlet.u1.GH_NodeAddress.NA_Node_Number;
  1922. NdisStatus = NDIS_STATUS_SUCCESS;
  1923. } while (FALSE);
  1924. return NdisStatus;
  1925. }
  1926. NDIS_STATUS
  1927. nicValidateRecvDataFifo(
  1928. IN PMDL pMdl,
  1929. IN PNOTIFICATION_INFO pFifoContext,
  1930. IN PVCCB pVc,
  1931. OUT PNIC_RECV_DATA_INFO pRcvInfo
  1932. )
  1933. {
  1934. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  1935. do
  1936. {
  1937. pRcvInfo->DataLength = pFifoContext->nLength;
  1938. if (pRcvInfo->DataLength <= (UINT)FIELD_OFFSET(DATA_FORMAT, AsyncWriteFragmented.Data))
  1939. {
  1940. // Too small. Note that for simplicitly we check for the
  1941. // fragmented case.
  1942. //
  1943. NdisStatus = NDIS_STATUS_FAILURE;
  1944. break;
  1945. }
  1946. pRcvInfo->fGasp = FALSE;
  1947. //
  1948. //In Fifo receives the DataLength is equal to the total amount of data indicated by the bus driver
  1949. //
  1950. pRcvInfo->Length1394 = pRcvInfo->DataLength;
  1951. pRcvInfo->NdisPktContext.pFifoContext = pFifoContext ->Fifo;
  1952. pRcvInfo->pPacketPool = &((PRECVFIFO_VCCB) pVc)->PacketPool;
  1953. pRcvInfo->SourceID = ((PASYNC_PACKET)pFifoContext->RequestPacket)->AP_Source_ID.NA_Node_Number;
  1954. NdisStatus = NDIS_STATUS_SUCCESS;
  1955. }while (FALSE);
  1956. return NdisStatus;
  1957. }
  1958. NDIS_STATUS
  1959. nicValidateRecvData(
  1960. IN PMDL pMdl,
  1961. IN BUS_OPERATION RecvOp,
  1962. IN PVOID pIndicatedStruct,
  1963. IN PVCCB pVc,
  1964. OUT PNIC_RECV_DATA_INFO pRcvInfo
  1965. )
  1966. /*++
  1967. Routine Description:
  1968. This routine verifies that the length is not too small
  1969. This routine initializes the RecvDataInfo for the default (unfragmented case).
  1970. If the data is unfragmented the main recv routine will then call the Fragmented version of this routine
  1971. This initializes the length and StartData and fGasp fields of the struct only
  1972. Arguments:
  1973. pMdl - Mdl that was indicated up by the bus driver
  1974. RecvOp - Is this part of isoch callback, or AddrRange Callback
  1975. pIndicatedStruct - NotificationInfo or IsochDescriptor
  1976. pRcvInfo - Recv Structure that will be updated
  1977. Return Value:
  1978. Success - if all the operations succeeded
  1979. --*/
  1980. {
  1981. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  1982. PDATA_FORMAT pData = NULL;
  1983. NDIS1394_UNFRAGMENTED_HEADER EncapHeader;
  1984. PNDIS1394_UNFRAGMENTED_HEADER pEncapHeader = NULL;
  1985. NDIS1394_FRAGMENT_LF lf;
  1986. ULONG UlongLf;
  1987. NdisZeroMemory (pRcvInfo , sizeof (NIC_RECV_DATA_INFO) );
  1988. TRACE( TL_T, TM_Recv, ( "==>nicValidateRecvData pMdl %x, RecvOp %x, pIndicatedStruct %x, pRcvInfo %x",
  1989. pMdl, RecvOp , pIndicatedStruct, pRcvInfo));
  1990. ASSERT (RecvOp == IsochReceive || RecvOp == AddressRange);
  1991. pRcvInfo->RecvOp = RecvOp;
  1992. pRcvInfo->pVc = pVc;
  1993. do
  1994. {
  1995. if (pMdl == NULL)
  1996. {
  1997. NdisStatus = NDIS_STATUS_FAILURE;
  1998. BREAK (TM_Recv, ("nicValidateRecvData , no Mdl present") );
  1999. }
  2000. pRcvInfo->p1394Data = (PPACKET_FORMAT)NIC_GET_SYSTEM_ADDRESS_FOR_MDL (pMdl);
  2001. if (pRcvInfo->p1394Data == NULL)
  2002. {
  2003. NdisStatus = NDIS_STATUS_RESOURCES;
  2004. break;
  2005. }
  2006. //
  2007. // Check minimum valid packet size . Checks whether the data length that was passed to us includes
  2008. // at least the first byte of data
  2009. //
  2010. if (RecvOp == IsochReceive)
  2011. {
  2012. NdisStatus = nicValidateRecvDataIsoch (pMdl,
  2013. (PISOCH_DESCRIPTOR)pIndicatedStruct,
  2014. pVc,
  2015. pRcvInfo
  2016. );
  2017. if (NdisStatus != NDIS_STATUS_SUCCESS)
  2018. {
  2019. // Validation failed . exit
  2020. break;
  2021. }
  2022. //
  2023. // Get to the Encap header. Should be at the same position for Fragmented and nonfragmented
  2024. //
  2025. pEncapHeader = &pRcvInfo->p1394Data->IsochReceiveNonFragmented.NonFragmentedHeader;
  2026. }
  2027. else
  2028. {
  2029. NdisStatus = nicValidateRecvDataFifo(pMdl,(PNOTIFICATION_INFO)pIndicatedStruct,pVc,pRcvInfo);
  2030. if (NdisStatus != NDIS_STATUS_SUCCESS)
  2031. {
  2032. // Failure
  2033. break;
  2034. }
  2035. pEncapHeader = &pRcvInfo->p1394Data->AsyncWriteNonFragmented.NonFragmentedHeader;
  2036. }
  2037. //
  2038. // Byteswap Unfrag Header into a local variable
  2039. //
  2040. //EncapHeader.HeaderUlong = SwapBytesUlong (pEncapHeader->HeaderUlong);
  2041. EncapHeader.HeaderUlong = SWAPBYTES_ULONG (pEncapHeader->HeaderUlong);
  2042. EncapHeader.HeaderUlong = pEncapHeader->HeaderUlong & 0x000000C0;
  2043. EncapHeader.HeaderUlong = EncapHeader.HeaderUlong >> 6;
  2044. pRcvInfo->lf = EncapHeader.HeaderUlong ;
  2045. //
  2046. // Update the lf
  2047. //
  2048. pRcvInfo->lf = EncapHeader.HeaderUlong;
  2049. TRACE (TL_V, TM_Reas,("Header %x\n",pRcvInfo->lf ) );
  2050. ASSERT (EncapHeader.HeaderUlong <= lf_InteriorFragment);
  2051. if (pRcvInfo->lf != lf_Unfragmented)
  2052. {
  2053. pRcvInfo->fFragmented = TRUE;
  2054. }
  2055. else
  2056. {
  2057. pRcvInfo->fFragmented = FALSE;
  2058. }
  2059. if (pRcvInfo->DataLength > pVc->Hdr.MTU)
  2060. {
  2061. //
  2062. // This cannot belong to us
  2063. //
  2064. NdisStatus = NDIS_STATUS_FAILURE;
  2065. break;
  2066. }
  2067. NdisStatus = NDIS_STATUS_SUCCESS;
  2068. pRcvInfo->pEncapHeader = (PVOID)pEncapHeader;
  2069. //
  2070. // Spew out all the information discovered
  2071. //
  2072. TRACE ( TL_V, TM_Recv, ( "lf %x, p1394Data %x, Length1394 %x, DataLength %x, pEncapHeader %x " ,
  2073. pRcvInfo->lf,
  2074. pRcvInfo->p1394Data,
  2075. pRcvInfo->Length1394,
  2076. pRcvInfo->DataLength,
  2077. pRcvInfo->pEncapHeader ) );
  2078. } while (FALSE);
  2079. TRACE( TL_T, TM_Recv, ( "<==nicValidateRecvData %x", NdisStatus));
  2080. return NdisStatus;
  2081. }
  2082. VOID
  2083. nicInitRecvDataFragmented (
  2084. IN PMDL pMdl,
  2085. IN BUS_OPERATION RecvOp,
  2086. IN PVOID pIndicatedStruct,
  2087. OUT PNIC_RECV_DATA_INFO pRcvInfo
  2088. )
  2089. /*++
  2090. Routine Description:
  2091. The routine will extract from the packet all the information that is required for reassembly
  2092. and store it in the pRcvInfo
  2093. Arguments:
  2094. pMdl - Indicated Mdl
  2095. RecvOp - IsochReceive ot AddressRange Callback
  2096. pIndicatedStruct - IsochDesc or Address Fifo
  2097. pRcvInfo - output structure
  2098. Return Value:
  2099. None
  2100. --*/
  2101. {
  2102. PNOTIFICATION_INFO pNotificationInfo = NULL;
  2103. PGASP_HEADER pGaspHeader = NULL;
  2104. PNDIS1394_FRAGMENT_HEADER pEncapHeader = NULL;
  2105. TRACE( TL_T, TM_Recv, ( "==> nicInitRecvDataFragmented pMdl, %x, RecvOp %x, pIndicatedStruct %x, pRcvInfo %x",
  2106. pMdl, RecvOp, pIndicatedStruct, pRcvInfo));
  2107. do
  2108. {
  2109. pRcvInfo->pMdl = pMdl;
  2110. if (RecvOp == IsochReceive)
  2111. {
  2112. pRcvInfo->NdisPktContext.pIsochContext = (PISOCH_DESCRIPTOR) pIndicatedStruct;
  2113. }
  2114. else
  2115. {
  2116. pNotificationInfo = (PNOTIFICATION_INFO) pIndicatedStruct;
  2117. pRcvInfo->NdisPktContext.pFifoContext = pNotificationInfo->Fifo;
  2118. }
  2119. //
  2120. // Now byte swap the fragment header so it can be correctly interpreted
  2121. //
  2122. pEncapHeader = (PNDIS1394_FRAGMENT_HEADER )pRcvInfo->pEncapHeader;
  2123. pRcvInfo->FragmentHeader.u.FH_High = SWAPBYTES_ULONG(pEncapHeader->u.FH_High);
  2124. pRcvInfo->FragmentHeader.u1.FH_Low = SWAPBYTES_ULONG(pEncapHeader->u1.FH_Low);
  2125. //
  2126. // Now get the Dgl
  2127. //
  2128. pRcvInfo->Dgl = (USHORT)pRcvInfo->FragmentHeader.u1.SecondQuadlet.FH_dgl;
  2129. if (pRcvInfo->lf == lf_FirstFragment)
  2130. {
  2131. pRcvInfo->fFirstFragment = TRUE;
  2132. pRcvInfo->EtherType = pRcvInfo->FragmentHeader.u.FirstQuadlet_FirstFragment.FH_EtherType;
  2133. pRcvInfo->FragmentOffset = 0;
  2134. }
  2135. else
  2136. {
  2137. pRcvInfo->fFirstFragment = FALSE ;
  2138. pRcvInfo->FragmentOffset = pRcvInfo->FragmentHeader.u.FirstQuadlet.FH_fragment_offset;
  2139. }
  2140. pRcvInfo->BufferSize = pRcvInfo->FragmentHeader.u.FirstQuadlet.FH_buffersize ;
  2141. //
  2142. // Spew out all the information that has been found
  2143. //
  2144. TRACE ( TL_V, TM_Recv, (" SourceId %x, FragHead Hi %x, FragHead Lo %x, Dgl %x, fFirstFragment %x",
  2145. pRcvInfo->SourceID,
  2146. pRcvInfo->FragmentHeader.u.FH_High,
  2147. pRcvInfo->FragmentHeader.u1.FH_Low ,
  2148. pRcvInfo->Dgl,
  2149. pRcvInfo->fFirstFragment ) );
  2150. TRACE ( TL_V, TM_Recv, (" Fragment Offset %x, bufferSize %x", pRcvInfo->FragmentOffset, pRcvInfo->BufferSize));
  2151. ASSERT (pRcvInfo->SourceID < 64);
  2152. } while (FALSE);
  2153. TRACE( TL_T, TM_Recv, ( "<==nicInitRecvDataFragmented " ));
  2154. }
  2155. NDIS_STATUS
  2156. nicInsertFragmentInReassembly (
  2157. PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
  2158. PNIC_RECV_DATA_INFO pRcvInfo
  2159. )
  2160. /*++
  2161. Routine Description:
  2162. Checks for over laps and if valid then copies current fragment
  2163. into the table
  2164. This function does the validation for overlaps
  2165. Arguments:
  2166. PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
  2167. PNDIS_BUFFER pNdisBuffer,
  2168. PMDL pMdl,
  2169. PVOID pIndicatedStructure,
  2170. ULONG FragOffset,
  2171. ULONG IPLength
  2172. Return Value:
  2173. --*/
  2174. {
  2175. NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
  2176. BOOLEAN fFragPositionFound = FALSE;
  2177. ULONG FragmentNum = 0;
  2178. BOOLEAN Completed = FALSE;
  2179. PNDIS_BUFFER pNdisBuffer = pRcvInfo->pNdisBuffer;
  2180. PMDL pMdl = pRcvInfo->pMdl;
  2181. PVOID pIndicatedStructure = pRcvInfo->NdisPktContext.pCommon;
  2182. ULONG FragOffset = pRcvInfo->FragmentOffset;
  2183. ULONG IPLength = pRcvInfo->DataLength - sizeof (NDIS1394_FRAGMENT_HEADER);
  2184. TRACE( TL_T, TM_Recv, ( "==> nicInsertFragmentInReassembly " ));
  2185. do
  2186. {
  2187. if (pReassembly->BufferSize != 0 &&
  2188. FragOffset >= pReassembly->BufferSize )
  2189. {
  2190. NdisStatus = NDIS_STATUS_FAILURE;
  2191. break;
  2192. }
  2193. //
  2194. // First Find the correct entry in the frag table.
  2195. //
  2196. nicFindInsertionPosition (pReassembly,
  2197. FragOffset,
  2198. IPLength,
  2199. &FragmentNum);
  2200. if (pReassembly->FragTable[FragmentNum].IPLength != 0)
  2201. {
  2202. //
  2203. // we must copy the current fragments descriptors in the table
  2204. // so as not to overwrite the table
  2205. //
  2206. LONG OffsetIndex =0;
  2207. //
  2208. // First lets check for overlaps. Do we overlap the last fragment.
  2209. // At this point, FragmentNum contains the record for the
  2210. // next fragment in the reassembly
  2211. //
  2212. if (FragmentNum != 0)
  2213. {
  2214. if (pReassembly->FragTable[FragmentNum-1].Offset + pReassembly->FragTable[FragmentNum-1].IPLength > FragOffset)
  2215. {
  2216. NdisStatus = NDIS_STATUS_FAILURE;
  2217. break;
  2218. }
  2219. }
  2220. //
  2221. // Do we overlap the next fragment
  2222. //
  2223. if (FragmentNum < pReassembly->MaxOffsetTableIndex)
  2224. {
  2225. if (FragOffset + IPLength > pReassembly->FragTable[FragmentNum].Offset )
  2226. {
  2227. NdisStatus = NDIS_STATUS_FAILURE;
  2228. break;
  2229. }
  2230. }
  2231. //
  2232. // Now make room for this fragment
  2233. //
  2234. OffsetIndex = pReassembly->MaxOffsetTableIndex ;
  2235. //
  2236. // Signed compare and move the records ahead by one
  2237. //
  2238. while (OffsetIndex >= (LONG)FragmentNum)
  2239. {
  2240. pReassembly->FragTable[OffsetIndex+1].Offset = pReassembly->FragTable[OffsetIndex].Offset ;
  2241. pReassembly->FragTable[OffsetIndex+1].IPLength = pReassembly->FragTable[OffsetIndex].IPLength;
  2242. pReassembly->FragTable[OffsetIndex+1].pMdl = pReassembly->FragTable[OffsetIndex].pMdl;
  2243. pReassembly->FragTable[OffsetIndex+1].pNdisBuffer= pReassembly->FragTable[OffsetIndex].pNdisBuffer;
  2244. pReassembly->FragTable[OffsetIndex+1].pNdisBuffer= pReassembly->FragTable[OffsetIndex].pNdisBuffer;
  2245. pReassembly->FragTable[OffsetIndex+1].IndicatedStructure.pCommon = pReassembly->FragTable[OffsetIndex].IndicatedStructure.pCommon ;
  2246. pReassembly->FragTable[OffsetIndex+1].FragHeader = pReassembly->FragTable[OffsetIndex].FragHeader;
  2247. OffsetIndex --;
  2248. }
  2249. }
  2250. pNdisBuffer->Next = NULL;
  2251. pMdl->Next = NULL;
  2252. //
  2253. // Copy the current fragment into the table
  2254. //
  2255. pReassembly->FragTable[FragmentNum].Offset = FragOffset;
  2256. pReassembly->FragTable[FragmentNum].IPLength = IPLength;
  2257. pReassembly->FragTable[FragmentNum].pNdisBuffer = pNdisBuffer;
  2258. pReassembly->FragTable[FragmentNum].pMdl = pMdl;
  2259. pReassembly->FragTable[FragmentNum].FragHeader = pRcvInfo->FragmentHeader;
  2260. if (pReassembly->ReceiveOp == IsochReceive)
  2261. {
  2262. pReassembly->FragTable[FragmentNum].IndicatedStructure.pCommon = &((PISOCH_DESCRIPTOR)pIndicatedStructure)->DeviceReserved[IsochNext];
  2263. }
  2264. else
  2265. {
  2266. pReassembly->FragTable[FragmentNum].IndicatedStructure.pFifo = (PADDRESS_FIFO)pIndicatedStructure;
  2267. }
  2268. pReassembly->BytesRecvSoFar += IPLength;
  2269. //
  2270. // Now increment the Max offset
  2271. //
  2272. pReassembly->MaxOffsetTableIndex ++;
  2273. if (pReassembly->BufferSize == 0)
  2274. {
  2275. pReassembly->BufferSize = pRcvInfo->BufferSize;
  2276. }
  2277. //
  2278. // Add the unfragmented header here as we have to extract the EtherType here
  2279. //
  2280. if (pRcvInfo->fFirstFragment == TRUE)
  2281. {
  2282. pReassembly->EtherType = (USHORT)pRcvInfo->EtherType;
  2283. nicAddUnfragmentedHeader (pReassembly, pRcvInfo->pNdisBufferData );
  2284. }
  2285. if (pReassembly->BytesRecvSoFar == pReassembly->BufferSize + 1)
  2286. {
  2287. nicChainReassembly (pReassembly);
  2288. pReassembly->fReassemblyComplete = TRUE;
  2289. RemoveEntryList (&pReassembly->ReassemblyListEntry);
  2290. //
  2291. // These references are done in nicDoReassembly AFTER the lock has been freed
  2292. //
  2293. //
  2294. // Dereference the remote node as we are removing the reassembly from the remote node
  2295. //
  2296. //nicDereferenceReassembly (pReassembly, "nicInsertFragmentInReassembly " );
  2297. //
  2298. // now dereference the remote node. ref was added when the reassembly was
  2299. // inserted into the remote node's list
  2300. //
  2301. //nicDereferenceRemoteNode(pReassembly->pRemoteNode, "nicInsertFragmentInReassembly ");
  2302. //pReassembly->pRemoteNode = NULL;
  2303. }
  2304. } while (FALSE);
  2305. TRACE( TL_T, TM_Recv, ( "<== nicInsertFragmentInReassembly Status %x, Complete ", NdisStatus , pReassembly->fReassemblyComplete ));
  2306. return NdisStatus;
  2307. }
  2308. VOID
  2309. nicFindInsertionPosition (
  2310. PNDIS1394_REASSEMBLY_STRUCTURE pReassembly,
  2311. ULONG FragOffset,
  2312. ULONG IPLength,
  2313. PULONG pFragmentNum
  2314. )
  2315. {
  2316. ULONG FragmentNum = 0;
  2317. do
  2318. {
  2319. //
  2320. // First Do quick checks for Inorder reassembly
  2321. //
  2322. //
  2323. // Is it the first arrived fragment
  2324. //
  2325. if (pReassembly->MaxOffsetTableIndex == 0 ||
  2326. FragOffset < pReassembly->FragTable[0].Offset +pReassembly->FragTable[0].IPLength )
  2327. {
  2328. FragmentNum = 0;
  2329. break;
  2330. }
  2331. //
  2332. // Do we need to insert it in the last position
  2333. //
  2334. if ((pReassembly->FragTable[pReassembly->MaxOffsetTableIndex-1].Offset +
  2335. pReassembly->FragTable[pReassembly->MaxOffsetTableIndex-1].IPLength ) <=
  2336. FragOffset)
  2337. {
  2338. FragmentNum = pReassembly->MaxOffsetTableIndex;
  2339. break;
  2340. }
  2341. //
  2342. // Now walk the table and try to find the correct offset
  2343. // We know there is atleast one entry and the current fragment
  2344. // goes is not the last entry
  2345. //
  2346. while ( FragmentNum != pReassembly->MaxOffsetTableIndex)
  2347. {
  2348. if (FragOffset < pReassembly->FragTable[FragmentNum].Offset)
  2349. {
  2350. //
  2351. //We have found the Correct position
  2352. //
  2353. break;
  2354. }
  2355. FragmentNum++;
  2356. }
  2357. ASSERT (FragmentNum != pReassembly->MaxOffsetTableIndex);
  2358. } while (FALSE);
  2359. *pFragmentNum = FragmentNum;
  2360. }
  2361. VOID
  2362. nicChainReassembly (
  2363. IN PNDIS1394_REASSEMBLY_STRUCTURE pReassembly
  2364. )
  2365. /*++
  2366. Routine Description:
  2367. Chains the mdl, ndis buffers and indicated structures
  2368. This can be called from abort on the reasssembly complete code path
  2369. Arguments:
  2370. preassembly
  2371. Return Value:
  2372. --*/
  2373. {
  2374. ULONG i = 0;
  2375. //
  2376. // first chain all fragments save the last one
  2377. //
  2378. while (i< pReassembly->MaxOffsetTableIndex-1)
  2379. {
  2380. PFRAGMENT_DESCRIPTOR pCurr = & pReassembly->FragTable[i];
  2381. PFRAGMENT_DESCRIPTOR pNext = & pReassembly->FragTable[i+1];
  2382. ASSERT (pNext->IPLength != 0);
  2383. pCurr->pMdl->Next = pNext->pMdl;
  2384. pCurr->pNdisBuffer->Next = pNext->pNdisBuffer;
  2385. pCurr->IndicatedStructure.pListEntry->Next = pNext->IndicatedStructure.pListEntry;
  2386. i++;
  2387. }
  2388. //
  2389. // Clear the next pointers for the last descriptor
  2390. //
  2391. {
  2392. PFRAGMENT_DESCRIPTOR pLast = & pReassembly->FragTable[pReassembly->MaxOffsetTableIndex-1];
  2393. pLast->pMdl->Next = NULL;
  2394. pLast->pNdisBuffer->Next = NULL;
  2395. pLast->IndicatedStructure.pListEntry->Next = NULL;
  2396. }
  2397. pReassembly->pHeadNdisBuffer = pReassembly->FragTable[0].pNdisBuffer;
  2398. pReassembly->pHeadMdl = pReassembly->FragTable[0].pMdl;
  2399. if (pReassembly->ReceiveOp == IsochReceive)
  2400. {
  2401. //
  2402. // The pointer currently has the Next field. But the Head expects that start of an IsochDescriptor
  2403. //
  2404. pReassembly->Head.pCommon = CONTAINING_RECORD (pReassembly->FragTable[0].IndicatedStructure.pCommon,
  2405. ISOCH_DESCRIPTOR,
  2406. DeviceReserved[IsochNext] );
  2407. }
  2408. else
  2409. {
  2410. pReassembly->Head.pCommon = pReassembly->FragTable[0].IndicatedStructure.pCommon;
  2411. }
  2412. }
  2413. NDIS_STATUS
  2414. nicInitSerializedReceiveStruct(
  2415. PADAPTERCB pAdapter
  2416. )
  2417. /*++
  2418. Routine Description:
  2419. Initialize the Recv serialization structure
  2420. Arguments:
  2421. padapter
  2422. Return Value:
  2423. Success
  2424. --*/
  2425. {
  2426. NdisZeroMemory (&pAdapter->SerRcv, sizeof(pAdapter->SerRcv));
  2427. InitializeListHead(&pAdapter->SerRcv.Queue);
  2428. NdisMInitializeTimer (&pAdapter->SerRcv.Timer,
  2429. pAdapter->MiniportAdapterHandle,
  2430. RcvIndicateTimer ,
  2431. pAdapter);
  2432. return NDIS_STATUS_SUCCESS;
  2433. }
  2434. VOID
  2435. nicDeInitSerializedReceiveStruct(
  2436. PADAPTERCB pAdapter
  2437. )
  2438. /*++
  2439. Routine Description:
  2440. Deinits the Recv Init routine
  2441. Arguments:
  2442. Return Value:
  2443. --*/
  2444. {
  2445. }
  2446. NDIS_STATUS
  2447. nicQueueReceivedPacket(
  2448. PNDIS_PACKET pPacket,
  2449. PVCCB pVc,
  2450. PADAPTERCB pAdapter
  2451. )
  2452. /*++
  2453. Routine Description:
  2454. Queues a receive packet in the adapter's receive packet queue.
  2455. If no timer routins is in operation or already set, then this thread
  2456. will set the timer
  2457. Arguments:
  2458. Self explanatory
  2459. Return Value:
  2460. --*/
  2461. {
  2462. NDIS_STATUS Status = NDIS_STATUS_FAILURE;
  2463. BOOLEAN fSetTimer = FALSE;
  2464. do
  2465. {
  2466. PRSVD pRsvd;
  2467. PINDICATE_RSVD pIRsvd;
  2468. extern ULONG TotRecvs;
  2469. TotRecvs++;
  2470. pRsvd =(PRSVD)((pPacket)->ProtocolReserved);
  2471. pIRsvd = &pRsvd->IndicateRsvd;
  2472. pIRsvd->pPacket = pPacket;
  2473. pIRsvd->pVc = pVc;
  2474. pIRsvd->pAdapter = pAdapter;
  2475. ADAPTER_ACQUIRE_LOCK (pAdapter);
  2476. //
  2477. // Set up a tag used to track the packet
  2478. //
  2479. pIRsvd->Tag = NIC1394_TAG_QUEUED; // perhaps change to something else
  2480. ASSERT (pAdapter->SerRcv.PktsInQueue < 100);
  2481. //
  2482. // If the timer is not set, then this thread must set it
  2483. //
  2484. if (pAdapter->SerRcv.bTimerAlreadySet == FALSE)
  2485. {
  2486. fSetTimer = TRUE;
  2487. pAdapter->SerRcv.bTimerAlreadySet = TRUE;
  2488. }
  2489. InsertTailList(
  2490. &pAdapter->SerRcv.Queue,
  2491. &pIRsvd->Link
  2492. );
  2493. pAdapter->SerRcv.PktsInQueue++;
  2494. ADAPTER_RELEASE_LOCK (pAdapter);
  2495. //
  2496. // Now queue the timer
  2497. //
  2498. if (fSetTimer == TRUE)
  2499. {
  2500. //
  2501. // Set the timer
  2502. //
  2503. TRACE( TL_V, TM_Recv, ( " Set Timer "));
  2504. NdisMSetTimer ( &pAdapter->SerRcv.Timer, 0);
  2505. }
  2506. Status = NDIS_STATUS_SUCCESS;
  2507. } while (FALSE);
  2508. ASSERT (Status == NDIS_STATUS_SUCCESS);
  2509. return Status;
  2510. }
  2511. VOID
  2512. RcvIndicateTimer (
  2513. IN PVOID SystemSpecific1,
  2514. IN PVOID FunctionContext,
  2515. IN PVOID SystemSpecific2,
  2516. IN PVOID SystemSpecific3
  2517. )
  2518. /*++
  2519. Routine Description:
  2520. This function dequeues a packet and sends it upto NDIS and the protocols/.
  2521. The Function context is the adapter object which has the Receive queue in it.
  2522. Arguments:
  2523. Function context - adapter
  2524. Return Value:
  2525. --*/
  2526. {
  2527. PADAPTERCB pAdapter = (PADAPTERCB)FunctionContext;
  2528. TRACE( TL_T, TM_Recv, ( "==>RcvIndicateTimer Context %x", FunctionContext));
  2529. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  2530. {
  2531. ASSERT (pAdapter->ulTag == MTAG_ADAPTERCB);
  2532. return;
  2533. }
  2534. ADAPTER_ACQUIRE_LOCK (pAdapter);
  2535. //
  2536. // Get the stats out
  2537. //
  2538. nicSetCountInHistogram(pAdapter->SerRcv.PktsInQueue, RcvStats);
  2539. nicSetMax(nicMaxRcv, pAdapter->SerRcv.PktsInQueue);
  2540. nicIncrementRcvTimerCount();
  2541. //
  2542. // Empty the Queue indicating as many packets as possible
  2543. //
  2544. while (IsListEmpty(&pAdapter->SerRcv.Queue)==FALSE)
  2545. {
  2546. LIST_ENTRY *pLink;
  2547. PINDICATE_RSVD pIRsvd;
  2548. pAdapter->SerRcv.PktsInQueue--;
  2549. pLink = RemoveHeadList(&pAdapter->SerRcv.Queue);
  2550. ADAPTER_RELEASE_LOCK (pAdapter);
  2551. //
  2552. // Indicate the packet without the lock
  2553. //
  2554. pIRsvd = CONTAINING_RECORD(
  2555. pLink,
  2556. INDICATE_RSVD,
  2557. Link
  2558. );
  2559. pIRsvd->Tag = NIC1394_TAG_INDICATED;
  2560. nicIncrementRcvVcPktCount(pIRsvd->pVc,pIRsvd->pPacket);
  2561. NdisMCoIndicateReceivePacket(pIRsvd->pVc->Hdr.NdisVcHandle, &pIRsvd->pPacket, 1);
  2562. if (NDIS_GET_PACKET_STATUS(pIRsvd->pPacket) == NDIS_STATUS_RESOURCES)
  2563. {
  2564. //
  2565. // Complete the packet
  2566. //
  2567. ASSERT (0);
  2568. pIRsvd->Tag = NIC1394_TAG_RETURNED;
  2569. nicInternalReturnPacket(pIRsvd->pVc, pIRsvd->pPacket );
  2570. }
  2571. ADAPTER_ACQUIRE_LOCK (pAdapter);
  2572. }
  2573. //
  2574. // clear the flag
  2575. //
  2576. ASSERT (pAdapter->SerRcv.PktsInQueue==0);
  2577. ASSERT (IsListEmpty(&pAdapter->SerRcv.Queue));
  2578. pAdapter->SerRcv.bTimerAlreadySet = FALSE;
  2579. ADAPTER_RELEASE_LOCK (pAdapter);
  2580. NdisMCoReceiveComplete(pAdapter->MiniportAdapterHandle);
  2581. TRACE( TL_T, TM_Recv, ( "<==RcvIndicateTimer "));
  2582. }
  2583. NDIS_STATUS
  2584. nicInitSerializedReassemblyStruct(
  2585. PADAPTERCB pAdapter
  2586. )
  2587. /*++
  2588. Routine Description:
  2589. Initialize the Reassembly serialization structure
  2590. Arguments:
  2591. padapter
  2592. Return Value:
  2593. Success
  2594. --*/
  2595. {
  2596. NdisZeroMemory (&pAdapter->Reassembly, sizeof(pAdapter->Reassembly));
  2597. InitializeListHead(&pAdapter->Reassembly.Queue); // Not be Used
  2598. NdisInitializeEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent);
  2599. pAdapter->Reassembly.CompleteEvent.EventCode = Nic1394EventCode_InvalidEventCode;
  2600. NdisMInitializeTimer (&pAdapter->Reassembly.Timer,
  2601. pAdapter->MiniportAdapterHandle,
  2602. ReassemblyTimerFunction ,
  2603. pAdapter);
  2604. return NDIS_STATUS_SUCCESS;
  2605. }
  2606. VOID
  2607. nicDeInitSerializedReassmblyStruct(
  2608. PADAPTERCB pAdapter
  2609. )
  2610. /*++
  2611. Routine Description:
  2612. Deinits the Reassembly routine routine
  2613. if the timer is set, it waits the timer out.
  2614. As all the reassemblies will be marked as aborted in nicFreeAllPendingReassemblies (below)
  2615. it queues a timer one last time to go in and delete all the reassembly structures.
  2616. Arguments:
  2617. Return Value:
  2618. --*/
  2619. {
  2620. do
  2621. {
  2622. BOOLEAN bTimerAlreadySet = FALSE;
  2623. //
  2624. // If this adapter is halting, then mark all reassemblies as aborted
  2625. //
  2626. nicFreeAllPendingReassemblyStructures(pAdapter);
  2627. //
  2628. // First wait for any pending timer to fire.
  2629. //
  2630. ADAPTER_ACQUIRE_LOCK (pAdapter);
  2631. bTimerAlreadySet = pAdapter->Reassembly.bTimerAlreadySet ;
  2632. if (bTimerAlreadySet == TRUE)
  2633. {
  2634. //
  2635. // if the (bTimerAlreadySet==TRUE ), it means we can clear/init the event.
  2636. // Because the TimerAlreadySet is cleared and the Event is always set within
  2637. // the same Acquire-Release Spinlock
  2638. //
  2639. NdisResetEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent);
  2640. pAdapter->Reassembly.CompleteEvent.EventCode = Nic1394EventCode_InvalidEventCode;
  2641. }
  2642. ADAPTER_RELEASE_LOCK(pAdapter);
  2643. if (bTimerAlreadySet == TRUE)
  2644. {
  2645. NdisWaitEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent,WAIT_INFINITE);
  2646. }
  2647. //
  2648. // Reset the event , to prepare for the next wait.
  2649. //
  2650. pAdapter->Reassembly.CompleteEvent.EventCode = Nic1394EventCode_InvalidEventCode;
  2651. NdisResetEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent);
  2652. //
  2653. // Now enqueue the timer one last time to free all pending reassemblies.
  2654. // and Stop any further reassembly timers
  2655. //
  2656. nicQueueReassemblyTimer (pAdapter,TRUE);
  2657. //
  2658. // Wait for the last timer to fire.
  2659. //
  2660. bTimerAlreadySet = pAdapter->Reassembly.bTimerAlreadySet ;
  2661. //
  2662. // Only do the wait, if nicQueueReassembly Timer actually queued a reassembly timer
  2663. //
  2664. if (bTimerAlreadySet == TRUE)
  2665. {
  2666. NdisWaitEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent,WAIT_INFINITE);
  2667. }
  2668. } while (FALSE);
  2669. }
  2670. NDIS_STATUS
  2671. nicQueueReassemblyTimer(
  2672. PADAPTERCB pAdapter,
  2673. BOOLEAN fIsLastTimer
  2674. )
  2675. /*++
  2676. Routine Description:
  2677. Queues a timer to be fired in one second.
  2678. If there is already a timer active it quietly exists
  2679. Arguments:
  2680. Self explanatory
  2681. Return Value:
  2682. --*/
  2683. {
  2684. NDIS_STATUS Status = NDIS_STATUS_FAILURE;
  2685. BOOLEAN fSetTimer = FALSE;
  2686. do
  2687. {
  2688. ADAPTER_ACQUIRE_LOCK (pAdapter);
  2689. //
  2690. // If the timer is not set, then this thread must set it
  2691. //
  2692. if (pAdapter->Reassembly.bTimerAlreadySet == FALSE && // timer is not set
  2693. pAdapter->Reassembly.PktsInQueue > 0 && // there are packets to be reassembled
  2694. ADAPTER_TEST_FLAG (pAdapter,fADAPTER_NoMoreReassembly) == FALSE ) // the adapter is not halting
  2695. {
  2696. fSetTimer = TRUE;
  2697. pAdapter->Reassembly.bTimerAlreadySet = TRUE;
  2698. }
  2699. if (fIsLastTimer == TRUE)
  2700. {
  2701. //
  2702. // Stop any further reassembly timers
  2703. //
  2704. ADAPTER_SET_FLAG (pAdapter, fADAPTER_NoMoreReassembly);
  2705. }
  2706. ADAPTER_RELEASE_LOCK (pAdapter);
  2707. //
  2708. // Now queue the timer
  2709. //
  2710. if (fSetTimer == TRUE)
  2711. {
  2712. //
  2713. // Set the timer
  2714. //
  2715. TRACE( TL_V, TM_Recv, ( " Set Timer "));
  2716. NdisMSetTimer ( &pAdapter->Reassembly.Timer, 2000);
  2717. }
  2718. Status = NDIS_STATUS_SUCCESS;
  2719. } while (FALSE);
  2720. ASSERT (Status == NDIS_STATUS_SUCCESS);
  2721. return Status;
  2722. }
  2723. VOID
  2724. nicFifoAllocationScheme (
  2725. PRECVFIFO_VCCB pRecvFIFOVc
  2726. )
  2727. /*++
  2728. Routine Description:
  2729. If there are less than 20 fifo allocated, it starts a workitem to
  2730. allocate a lot more fifos
  2731. Arguments:
  2732. Return Value:
  2733. --*/
  2734. {
  2735. BOOLEAN fQueueWorkItemInThisThread = FALSE;
  2736. PNIC_WORK_ITEM pFifoWorkItem = NULL;
  2737. do
  2738. {
  2739. if (pRecvFIFOVc->NumAllocatedFifos != NUM_RECV_FIFO_FIRST_PHASE)
  2740. {
  2741. break ;
  2742. }
  2743. if (pRecvFIFOVc->FifoWorkItemInProgress == TRUE)
  2744. {
  2745. break;
  2746. }
  2747. pFifoWorkItem = ALLOC_NONPAGED (sizeof(NIC_WORK_ITEM), MTAG_WORKITEM);
  2748. if (pFifoWorkItem == NULL)
  2749. {
  2750. break;
  2751. }
  2752. VC_ACQUIRE_LOCK(pRecvFIFOVc);
  2753. if (pRecvFIFOVc->FifoWorkItemInProgress == FALSE)
  2754. {
  2755. fQueueWorkItemInThisThread = TRUE;
  2756. pRecvFIFOVc->FifoWorkItemInProgress = TRUE;
  2757. // Add reference to the VC . Derefed in the WorkItem
  2758. //
  2759. nicReferenceCall((VCCB*)pRecvFIFOVc, "Queueing miniport Work Item\n");
  2760. }
  2761. VC_RELEASE_LOCK (pRecvFIFOVc);
  2762. if (fQueueWorkItemInThisThread == FALSE)
  2763. {
  2764. break;
  2765. }
  2766. //
  2767. // Queue the workitem
  2768. //
  2769. NdisInitializeWorkItem ( &pFifoWorkItem->NdisWorkItem,
  2770. (NDIS_PROC) nicAllocateRemainingFifoWorkItem,
  2771. (PVOID) pRecvFIFOVc);
  2772. NdisScheduleWorkItem (&pFifoWorkItem->NdisWorkItem);
  2773. } while (FALSE);
  2774. }
  2775. VOID
  2776. nicAllocateRemainingFifoWorkItem (
  2777. PNDIS_WORK_ITEM pNdisWorkItem,
  2778. IN PVOID Context
  2779. )
  2780. /*++
  2781. Routine Description:
  2782. This follows a simple algorithm. It simply allocates fifos
  2783. until we reach our expected number of 100
  2784. Arguments:
  2785. Return Value:
  2786. --*/
  2787. {
  2788. PRECVFIFO_VCCB pRecvFIFOVc = NULL;
  2789. BOOLEAN fIsVcActive = FALSE;
  2790. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  2791. pRecvFIFOVc = (PRECVFIFO_VCCB) (Context);
  2792. fIsVcActive = VC_ACTIVE(pRecvFIFOVc);
  2793. do
  2794. {
  2795. PADDRESS_FIFO pRecvFifoElement = NULL;
  2796. fIsVcActive = VC_ACTIVE(pRecvFIFOVc);
  2797. if (fIsVcActive == FALSE)
  2798. {
  2799. break;
  2800. }
  2801. NdisStatus = nicGetInitializedAddressFifoElement (pRecvFIFOVc->Hdr.MTU,
  2802. &pRecvFifoElement);
  2803. if (NdisStatus != NDIS_STATUS_SUCCESS)
  2804. {
  2805. break;
  2806. }
  2807. ASSERT (pRecvFifoElement != NULL);
  2808. nicSetTagInFifoWrapper(pRecvFifoElement, NIC1394_TAG_QUEUED);
  2809. ExInterlockedPushEntrySList ( &pRecvFIFOVc->FifoSListHead,
  2810. &pRecvFifoElement->FifoList,
  2811. &pRecvFIFOVc->FifoSListSpinLock);
  2812. //
  2813. // Add this once for every Address Fifo element inserted
  2814. // Will be decremented by a call to nicFreeAddressFifo
  2815. //
  2816. VC_ACQUIRE_LOCK (pRecvFIFOVc);
  2817. #if FIFO_WRAPPER
  2818. pRecvFIFOVc->pFifoTable[pRecvFIFOVc->NumAllocatedFifos] = pRecvFifoElement;
  2819. #endif
  2820. nicReferenceCall ((PVCCB) pRecvFIFOVc, "nicWorkItemFileSList");
  2821. pRecvFIFOVc->NumAllocatedFifos++;
  2822. VC_RELEASE_LOCK (pRecvFIFOVc);
  2823. } while (pRecvFIFOVc->NumAllocatedFifos < NUM_RECV_FIFO_BUFFERS);
  2824. pRecvFIFOVc->FifoWorkItemInProgress = FALSE;
  2825. nicDereferenceCall ((PVCCB)pRecvFIFOVc,"nicAllocateRemainingFifoWorkItem" );
  2826. FREE_NONPAGED(pNdisWorkItem);
  2827. }