Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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