Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1505 lines
42 KiB

  1. /*++
  2. Copyright(c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. brdgbuf.c
  5. Abstract:
  6. Ethernet MAC level bridge.
  7. Buffer management section
  8. Author:
  9. Mark Aiken
  10. (original bridge by Jameel Hyder)
  11. Environment:
  12. Kernel mode driver
  13. Revision History:
  14. Feb 2000 - Original version
  15. --*/
  16. #define NDIS_MINIPORT_DRIVER
  17. #define NDIS50_MINIPORT 1
  18. #define NDIS_WDM 1
  19. #pragma warning( push, 3 )
  20. #include <ndis.h>
  21. #include <ntddk.h>
  22. #pragma warning( pop )
  23. #include "bridge.h"
  24. #include "brdgbuf.h"
  25. #include "brdgprot.h"
  26. #include "brdgmini.h"
  27. // ===========================================================================
  28. //
  29. // PRIVATE DECLARATIONS
  30. //
  31. // ===========================================================================
  32. //
  33. // A guess at how many buffer descriptors an average packet indicated on the
  34. // no-copy path is likely to have.
  35. //
  36. // The size of the pool of MDLs used to construct wrapper packets is based on this
  37. // guess
  38. //
  39. #define GUESS_BUFFERS_PER_PACKET 3
  40. //
  41. // Transit unicast packets on the no-copy path require one packet descriptor to wrap
  42. // them for relay.
  43. //
  44. // Transit broadcast packets require n descriptors (where n == # of adapters) to
  45. // wrap them for relay.
  46. //
  47. // We can't allow our descriptor usage to reach n^2, which is the worst case to handle
  48. // broadcast traffic from all adapters. This number is a guess at how many wrapping
  49. // descriptors we will need, on **average**, per packet. The idea is to not run out
  50. // of packet descriptors under regular traffic conditions. If running on a machine
  51. // with lots of adapters and lots of broadcast traffic, the # of wrapper descriptors
  52. // may become a limiting factor if this guess is wrong.
  53. //
  54. // The size of the wrapper packet descriptor pool is based on this guess.
  55. //
  56. #define GUESS_AVERAGE_FANOUT 2
  57. //
  58. // In case we can't read it out of the registry, use this default value for the
  59. // size of the copy packet pool safety buffer.
  60. //
  61. #define DEFAULT_SAFETY_MARGIN 10 // A percentage (10%)
  62. //
  63. // In case we can't read it out of the registry, use this default value for the
  64. // total memory footprint we are allowed.
  65. //
  66. #define DEFAULT_MAX_BUF_MEMORY 2 * 1024 * 1024 // 2MB in bytes
  67. //
  68. // Registry values that hold our config values
  69. //
  70. const PWCHAR gMaxBufMemoryParameterName = L"MaxBufferMemory";
  71. const PWCHAR gSafetyMarginParameterName = L"SafetyMargin";
  72. //
  73. // Constant for different types of quota-restricted packets
  74. //
  75. typedef enum
  76. {
  77. BrdgQuotaCopyPacket = 0,
  78. BrdgQuotaWrapperPacket = 1
  79. } QUOTA_PACKET_TYPE;
  80. // ===========================================================================
  81. //
  82. // GLOBALS
  83. //
  84. // ===========================================================================
  85. // List of free packet descriptors for copy-receives
  86. BSINGLE_LIST_HEAD gFreeCopyPacketList;
  87. NDIS_SPIN_LOCK gFreeCopyPacketListLock;
  88. // List of free packet descriptors for wrapper packets
  89. BSINGLE_LIST_HEAD gFreeWrapperPacketList;
  90. NDIS_SPIN_LOCK gFreeWrapperPacketListLock;
  91. // Look-aside list for copy-receive buffers
  92. NPAGED_LOOKASIDE_LIST gCopyBufferList;
  93. BOOLEAN gInitedCopyBufferList = FALSE;
  94. // Look-aside list for packet info blocks
  95. NPAGED_LOOKASIDE_LIST gPktInfoList;
  96. BOOLEAN gInitedPktInfoList = FALSE;
  97. // Packet descriptor pools for copy receives and wrapper packets
  98. NDIS_HANDLE gCopyPacketPoolHandle = NULL;
  99. NDIS_HANDLE gWrapperPacketPoolHandle = NULL;
  100. // MDL pools for copy receives and wrapper packets
  101. NDIS_HANDLE gCopyBufferPoolHandle = NULL;
  102. NDIS_HANDLE gWrapperBufferPoolHandle = NULL;
  103. // Spin lock to protect quota information
  104. NDIS_SPIN_LOCK gQuotaLock;
  105. // Quota information for the local miniport
  106. ADAPTER_QUOTA gMiniportQuota;
  107. //
  108. // Maximum number of available packets of each type
  109. //
  110. // [0] == Copy packets
  111. // [1] == Wrapper packets
  112. //
  113. ULONG gMaxPackets[2] = { 0L, 0L };
  114. //
  115. // Number of packets currently allocated from each pool
  116. //
  117. // [0] == Copy packets
  118. // [1] == Wrapper packets
  119. //
  120. ULONG gUsedPackets[2] = { 0L, 0L };
  121. #if DBG
  122. ULONG gMaxUsedPackets[2] = { 0L, 0L };
  123. #endif
  124. //
  125. // Amount of packets to keep as a buffer in each pool (the maximum consumption
  126. // of any single adapter is gMaxPackets[X] - gSafetyBuffer[X].
  127. //
  128. // These values are computed from the safety margin proportion, which can
  129. // optionally be specified by a registry value
  130. //
  131. ULONG gSafetyBuffer[2] = { 0L, 0L };
  132. //
  133. // Number of times we have had to deny an allocation request even though we wanted
  134. // to allow it because we were flat out of packets. For debugging performance.
  135. //
  136. LARGE_INTEGER gStatOverflows[2] = {{ 0L, 0L }, {0L, 0L}};
  137. //
  138. // Number of times we failed to allocated memory unexpectedly (i.e., when we had
  139. // not allocated up to the preset maximum size of our resource pool). Should only
  140. // occur if the host machine is actually out of non-paged memory (yikes!)
  141. //
  142. LARGE_INTEGER gStatFailures = { 0L, 0L };
  143. // ===========================================================================
  144. //
  145. // PRIVATE PROTOTYPES
  146. //
  147. // ===========================================================================
  148. PNDIS_PACKET
  149. BrdgBufCommonGetNewPacket(
  150. IN NDIS_HANDLE Pool,
  151. OUT PPACKET_INFO *pppi
  152. );
  153. PNDIS_PACKET
  154. BrdgBufGetNewCopyPacket(
  155. OUT PPACKET_INFO *pppi
  156. );
  157. // Type of function to pass to BrgBufCommonGetPacket
  158. typedef PNDIS_PACKET (*PNEWPACKET_FUNC)(PPACKET_INFO*);
  159. PNDIS_PACKET
  160. BrdgBufCommonGetPacket(
  161. OUT PPACKET_INFO *pppi,
  162. IN PNEWPACKET_FUNC pNewPacketFunc,
  163. IN PBSINGLE_LIST_HEAD pCacheList,
  164. IN PNDIS_SPIN_LOCK ListLock
  165. );
  166. BOOLEAN
  167. BrdgBufAssignQuota(
  168. IN QUOTA_PACKET_TYPE type,
  169. IN PADAPT pAdapt,
  170. IN BOOLEAN bCountAlloc
  171. );
  172. VOID
  173. BrdgBufReleaseQuota(
  174. IN QUOTA_PACKET_TYPE type,
  175. IN PADAPT pAdapt
  176. );
  177. // ===========================================================================
  178. //
  179. // INLINES / MACROS
  180. //
  181. // ===========================================================================
  182. //
  183. // Allocates a new wrapper packet
  184. //
  185. __forceinline PNDIS_PACKET
  186. BrdgBufGetNewWrapperPacket(
  187. OUT PPACKET_INFO *pppi
  188. )
  189. {
  190. return BrdgBufCommonGetNewPacket( gWrapperPacketPoolHandle, pppi );
  191. }
  192. //
  193. // Handles the special LOCAL_MINIPORT pseudo-pointer value
  194. //
  195. __forceinline PADAPTER_QUOTA
  196. QUOTA_FROM_ADAPTER(
  197. IN PADAPT pAdapt
  198. )
  199. {
  200. SAFEASSERT( pAdapt != NULL );
  201. if( pAdapt == LOCAL_MINIPORT )
  202. {
  203. return &gMiniportQuota;
  204. }
  205. else
  206. {
  207. return &pAdapt->Quota;
  208. }
  209. }
  210. //
  211. // Switches from the packet type constant to an index
  212. //
  213. __forceinline UINT
  214. INDEX_FROM_TYPE(
  215. IN QUOTA_PACKET_TYPE type
  216. )
  217. {
  218. SAFEASSERT( (type == BrdgQuotaCopyPacket) || (type == BrdgQuotaWrapperPacket) );
  219. return (type == BrdgQuotaCopyPacket) ? 0 : 1;
  220. }
  221. //
  222. // Reinitializes a packet for reuse later
  223. //
  224. __forceinline
  225. VOID
  226. BrdgBufScrubPacket(
  227. IN PNDIS_PACKET pPacket,
  228. IN PPACKET_INFO ppi
  229. )
  230. {
  231. // This scrubs NDIS's state
  232. NdisReinitializePacket( pPacket );
  233. // Aggressively forget previous state to catch bugs
  234. NdisZeroMemory( ppi, sizeof(PACKET_INFO) );
  235. ppi->pOwnerPacket = pPacket;
  236. }
  237. //
  238. // Decrements an adapter's used packet count
  239. //
  240. __forceinline
  241. VOID
  242. BrdgBufReleaseQuota(
  243. IN QUOTA_PACKET_TYPE type,
  244. IN PADAPT pAdapt
  245. )
  246. {
  247. PADAPTER_QUOTA pQuota = QUOTA_FROM_ADAPTER(pAdapt);
  248. UINT index = INDEX_FROM_TYPE(type);
  249. NdisAcquireSpinLock( &gQuotaLock );
  250. SAFEASSERT( pQuota->UsedPackets[index] > 0L );
  251. pQuota->UsedPackets[index] --;
  252. NdisReleaseSpinLock( &gQuotaLock );
  253. }
  254. //
  255. // Decrements the global usage count
  256. //
  257. __forceinline
  258. VOID
  259. BrdgBufCountDealloc(
  260. IN QUOTA_PACKET_TYPE type
  261. )
  262. {
  263. UINT index = INDEX_FROM_TYPE(type);
  264. NdisAcquireSpinLock( &gQuotaLock );
  265. SAFEASSERT( gUsedPackets[index] > 0L );
  266. gUsedPackets[index]--;
  267. NdisReleaseSpinLock( &gQuotaLock );
  268. }
  269. // ===========================================================================
  270. //
  271. // PUBLIC FUNCTIONS
  272. //
  273. // ===========================================================================
  274. VOID
  275. BrdgBufGetStatistics(
  276. PBRIDGE_BUFFER_STATISTICS pStats
  277. )
  278. /*++
  279. Routine Description:
  280. Retrieves our internal statistics on buffer management.
  281. Arguments:
  282. pStats The statistics structure to fill in
  283. Return Value:
  284. None
  285. --*/
  286. {
  287. pStats->CopyPoolOverflows = gStatOverflows[0];
  288. pStats->WrapperPoolOverflows = gStatOverflows[1];
  289. pStats->AllocFailures = gStatFailures;
  290. pStats->MaxCopyPackets = gMaxPackets[0];
  291. pStats->MaxWrapperPackets = gMaxPackets[1];
  292. pStats->SafetyCopyPackets = gSafetyBuffer[0];
  293. pStats->SafetyWrapperPackets = gSafetyBuffer[1];
  294. NdisAcquireSpinLock( &gQuotaLock );
  295. pStats->UsedCopyPackets = gUsedPackets[0];
  296. pStats->UsedWrapperPackets = gUsedPackets[1];
  297. NdisReleaseSpinLock( &gQuotaLock );
  298. }
  299. PACKET_OWNERSHIP
  300. BrdgBufGetPacketOwnership(
  301. IN PNDIS_PACKET pPacket
  302. )
  303. /*++
  304. Routine Description:
  305. Returns a value indicating who owns this packet (i.e., whether we own this
  306. packet and it is from our copy pool, we own it and it's from our wrapper
  307. pool, or we don't own the packet at all).
  308. Arguments:
  309. pPacket The packet to examine
  310. Return Value:
  311. Ownership enumerated value
  312. --*/
  313. {
  314. NDIS_HANDLE Pool = NdisGetPoolFromPacket(pPacket);
  315. if( Pool == gCopyPacketPoolHandle )
  316. {
  317. return BrdgOwnCopyPacket;
  318. }
  319. else if ( Pool == gWrapperPacketPoolHandle )
  320. {
  321. return BrdgOwnWrapperPacket;
  322. }
  323. return BrdgNotOwned;
  324. }
  325. VOID
  326. BrdgBufFreeWrapperPacket(
  327. IN PNDIS_PACKET pPacket,
  328. IN PPACKET_INFO ppi,
  329. IN PADAPT pQuotaOwner
  330. )
  331. /*++
  332. Routine Description:
  333. Frees a packet allocated from the wrapper pool and releases the quota previously
  334. assigned to the owning adapter
  335. Arguments:
  336. pPacket The packet
  337. ppi The packet's associated info block
  338. pQuotaOwner The adapter previously "charged" for this packet
  339. Return Value:
  340. None
  341. --*/
  342. {
  343. SAFEASSERT( pQuotaOwner != NULL );
  344. SAFEASSERT( pPacket != NULL );
  345. SAFEASSERT( ppi != NULL );
  346. // Free the packet
  347. BrdgBufFreeBaseWrapperPacket( pPacket, ppi );
  348. // Account for this packet having been returned
  349. BrdgBufReleaseQuota( BrdgQuotaWrapperPacket, pQuotaOwner );
  350. }
  351. PNDIS_PACKET
  352. BrdgBufGetBaseCopyPacket(
  353. OUT PPACKET_INFO *pppi
  354. )
  355. /*++
  356. Routine Description:
  357. Returns a new copy packet and associated info block from our pools
  358. WITHOUT CHECKING FOR QUOTA against any particular adapter
  359. This call is made to allocated copy packets for wrapping inbound packets before
  360. any target adapter has been identified.
  361. Arguments:
  362. pppi Receives the info block pointer (NULL if the alloc fails)
  363. Return Value:
  364. The new packet or NULL if the target adapter failed quota
  365. --*/
  366. {
  367. PNDIS_PACKET pPacket;
  368. BOOLEAN bAvail = FALSE;
  369. NdisAcquireSpinLock( &gQuotaLock );
  370. if( gUsedPackets[BrdgQuotaCopyPacket] < gMaxPackets[BrdgQuotaCopyPacket] )
  371. {
  372. // There are packets still available in the pool. Grab one.
  373. bAvail = TRUE;
  374. gUsedPackets[BrdgQuotaCopyPacket]++;
  375. #if DBG
  376. // Keep track of the maximum used packets
  377. if( gMaxUsedPackets[BrdgQuotaCopyPacket] < gUsedPackets[BrdgQuotaCopyPacket] )
  378. {
  379. gMaxUsedPackets[BrdgQuotaCopyPacket] = gUsedPackets[BrdgQuotaCopyPacket];
  380. }
  381. #endif
  382. }
  383. else if( gUsedPackets[BrdgQuotaCopyPacket] == gMaxPackets[BrdgQuotaCopyPacket] )
  384. {
  385. // We are at our limit. Hopefully this doesn't happen too often
  386. ExInterlockedAddLargeStatistic( &gStatOverflows[BrdgQuotaCopyPacket], 1L );
  387. bAvail = FALSE;
  388. }
  389. else
  390. {
  391. // This should never happen; it means we are over our limit somehow
  392. SAFEASSERT( FALSE );
  393. bAvail = FALSE;
  394. }
  395. NdisReleaseSpinLock( &gQuotaLock );
  396. if( ! bAvail )
  397. {
  398. // None available
  399. *pppi = NULL;
  400. return NULL;
  401. }
  402. pPacket = BrdgBufCommonGetPacket( pppi, BrdgBufGetNewCopyPacket, &gFreeCopyPacketList,
  403. &gFreeCopyPacketListLock );
  404. if( pPacket == NULL )
  405. {
  406. // Our allocation failed. Reverse the usage increment.
  407. BrdgBufCountDealloc( BrdgQuotaCopyPacket );
  408. }
  409. return pPacket;
  410. }
  411. PNDIS_PACKET
  412. BrdgBufGetWrapperPacket(
  413. OUT PPACKET_INFO *pppi,
  414. IN PADAPT pAdapt
  415. )
  416. /*++
  417. Routine Description:
  418. Returns a new packet and associated info block from the wrapper pool, unless the
  419. owning adapter does not does pass a quota check
  420. Arguments:
  421. pppi Receives the info block pointer (NULL if the target
  422. adapter fails quota)
  423. pAdapt The adapter to be "charged" for this packet
  424. Return Value:
  425. The new packet or NULL if the target adapter failed quota
  426. --*/
  427. {
  428. PNDIS_PACKET NewPacket = NULL;
  429. *pppi = NULL;
  430. if( BrdgBufAssignQuota(BrdgQuotaWrapperPacket, pAdapt, TRUE/*Count the alloc we are about to do*/) )
  431. {
  432. // Passed quota. We can allocate.
  433. NewPacket = BrdgBufCommonGetPacket( pppi, BrdgBufGetNewWrapperPacket, &gFreeWrapperPacketList,
  434. &gFreeWrapperPacketListLock );
  435. if( NewPacket == NULL )
  436. {
  437. // We failed to allocate even though we haven't yet hit the ceiling on our
  438. // resource pool. This should only happen if we are physically out of non-paged
  439. // memory.
  440. // Reverse the adapter's quota bump
  441. BrdgBufReleaseQuota( BrdgQuotaWrapperPacket, pAdapt );
  442. // Reverse the usage count in BrdgBufAssignQuota
  443. BrdgBufCountDealloc( BrdgQuotaWrapperPacket );
  444. }
  445. }
  446. return NewPacket;
  447. }
  448. VOID
  449. BrdgBufReleaseBasePacketQuota(
  450. IN PNDIS_PACKET pPacket,
  451. IN PADAPT pAdapt
  452. )
  453. /*++
  454. Routine Description:
  455. Called to release the previously assigned cost of a wrapper packet. The packet
  456. provided can be any packet, even one we don't own. If we own the packet, we
  457. decrement the appropriate usage count in the adapter's quota structure.
  458. Arguments:
  459. pPacket The packet the indicated adapter is no longer referring to
  460. pAdapt The adapter no longer referring to pPacket
  461. Return Value:
  462. NULL
  463. --*/
  464. {
  465. PACKET_OWNERSHIP Own = BrdgBufGetPacketOwnership(pPacket);
  466. // This gets called for any base packet, even ones we don't own. Just NOOP if we
  467. // don't own it.
  468. if( Own != BrdgNotOwned )
  469. {
  470. BrdgBufReleaseQuota( (Own == BrdgOwnCopyPacket) ? BrdgQuotaCopyPacket : BrdgQuotaWrapperPacket,
  471. pAdapt );
  472. }
  473. }
  474. BOOLEAN
  475. BrdgBufAssignBasePacketQuota(
  476. IN PNDIS_PACKET pPacket,
  477. IN PADAPT pAdapt
  478. )
  479. /*++
  480. Routine Description:
  481. Called to assign the cost of a base packet to an adapter, which is presumably attempting
  482. to construct a child wrapper packet that refers to the given base packet. A "cost" is
  483. assigned to pAdapt because by building a child wrapper packet that refers to the given
  484. base packet, pAdapt will cause it to not be disposed until it is done using it.
  485. It's OK for the input packet to be a packet we don't own; in that case, there is no cost
  486. to assign so we do nothing.
  487. Arguments:
  488. pPacket The base packet that pAdapt wishes to build a child wrapper packet
  489. referring to.
  490. pAdapt The adapter wishing to refer to pPacket
  491. Return Value:
  492. TRUE : The adapter is permitted to refer to the given base packet
  493. FALSE : The adapter did not pass qutoa and may not refer to the given base packet
  494. --*/
  495. {
  496. PACKET_OWNERSHIP Own = BrdgBufGetPacketOwnership(pPacket);
  497. // We get called for any base packet, even if we don't own it.
  498. if( Own != BrdgNotOwned )
  499. {
  500. return BrdgBufAssignQuota( (Own == BrdgOwnCopyPacket) ? BrdgQuotaCopyPacket : BrdgQuotaWrapperPacket,
  501. pAdapt, FALSE/*We aren't going to do an alloc for this quota bump*/);
  502. }
  503. else
  504. {
  505. return TRUE;
  506. }
  507. }
  508. PNDIS_PACKET
  509. BrdgBufCommonGetPacket(
  510. OUT PPACKET_INFO *pppi,
  511. IN PNEWPACKET_FUNC pNewPacketFunc,
  512. IN PBSINGLE_LIST_HEAD pCacheList,
  513. IN PNDIS_SPIN_LOCK ListLock
  514. )
  515. /*++
  516. Routine Description:
  517. Common processing for retrieving a new packet from either the copy pool or the wrapper pool
  518. Since we know how many packets we've allocated from each pool at all times, the only time this
  519. function should fail is if the host machine is physically out of memory.
  520. Arguments:
  521. pppi Receives the new info block (NULL if the alloc fails, which it shouldn't)
  522. pNewPacketFunc Function to call to alloc a packet if the cache is empty
  523. pCacheList Queue of cached packets that can be used to satisfy the alloc
  524. ListLock The lock to use when manipulating the cache queue
  525. Return Value:
  526. The newly allocated packet, or NULL if severe memory constraints cause the allocation to fail
  527. (this should be unusual)
  528. --*/
  529. {
  530. PNDIS_PACKET pPacket;
  531. PPACKET_INFO ppi;
  532. PBSINGLE_LIST_ENTRY entry;
  533. // Try to get a packet out of our cache.
  534. entry = BrdgInterlockedRemoveHeadSingleList( pCacheList, ListLock );
  535. if( entry == NULL )
  536. {
  537. // Try to allocate a packet and info block from our underlying pools
  538. pPacket = (*pNewPacketFunc)( &ppi );
  539. if( (pPacket == NULL) || (ppi == NULL) )
  540. {
  541. // This should only occur if our host machine is actually out
  542. // of nonpaged memory; we should normally be able to allocate
  543. // up to our preset limit from our pools.
  544. ExInterlockedAddLargeStatistic( &gStatFailures, 1L );
  545. }
  546. }
  547. else
  548. {
  549. ppi = CONTAINING_RECORD( entry, PACKET_INFO, List );
  550. pPacket = ppi->pOwnerPacket;
  551. SAFEASSERT( pPacket != NULL );
  552. }
  553. *pppi = ppi;
  554. return pPacket;
  555. }
  556. VOID
  557. BrdgBufFreeBaseCopyPacket(
  558. IN PNDIS_PACKET pPacket,
  559. IN PPACKET_INFO ppi
  560. )
  561. /*++
  562. Routine Description:
  563. Frees a packet allocated from the copy pool without quota adjustements. This is called directly
  564. from non-buffer-management code to free base packets because the cost for base packets is
  565. assigned and released directly with calls to BrdgBuf<Assign|Release>BasePacketQuota.
  566. Arguments:
  567. pPacket The packet to free
  568. ppi Its info block to free
  569. Return Value:
  570. None
  571. --*/
  572. {
  573. // If we're holding less than our cache amount, free the packet by putting it on the
  574. // cache list
  575. ULONG holding;
  576. PNDIS_BUFFER pBuffer = BrdgBufPacketHeadBuffer( pPacket );
  577. SAFEASSERT( (ppi != NULL) && (pPacket != NULL) );
  578. SAFEASSERT( ppi->pOwnerPacket == pPacket );
  579. SAFEASSERT( pBuffer != NULL );
  580. // Return this packet descriptor to its original state
  581. NdisAdjustBufferLength(pBuffer, MAX_PACKET_SIZE);
  582. NdisAcquireSpinLock( &gFreeCopyPacketListLock );
  583. holding = BrdgQuerySingleListLength( &gFreeCopyPacketList );
  584. if( holding < gSafetyBuffer[BrdgQuotaCopyPacket] )
  585. {
  586. // Prep the packet for reuse
  587. // This blows away the buffer chain
  588. BrdgBufScrubPacket( pPacket, ppi );
  589. // Put the buffer back on
  590. SAFEASSERT( BrdgBufPacketHeadBuffer(pPacket) == NULL );
  591. NdisChainBufferAtFront( pPacket, pBuffer );
  592. // Push the packet onto the list
  593. BrdgInsertHeadSingleList( &gFreeCopyPacketList, &ppi->List );
  594. NdisReleaseSpinLock( &gFreeCopyPacketListLock );
  595. }
  596. else
  597. {
  598. PVOID pBuf;
  599. UINT Size;
  600. NdisReleaseSpinLock( &gFreeCopyPacketListLock );
  601. NdisQueryBufferSafe( pBuffer, &pBuf, &Size, NormalPagePriority );
  602. // Free the packet, the packet info block and the copy buffer to the underlying pools
  603. NdisFreeBuffer( pBuffer );
  604. NdisFreePacket( pPacket );
  605. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  606. if( pBuf != NULL )
  607. {
  608. NdisFreeToNPagedLookasideList( &gCopyBufferList, pBuf );
  609. }
  610. else
  611. {
  612. // Shouldn't be possible since the alloced memory is in kernel space
  613. SAFEASSERT( FALSE );
  614. }
  615. }
  616. // Note the deallocation
  617. BrdgBufCountDealloc( BrdgQuotaCopyPacket );
  618. }
  619. VOID
  620. BrdgBufFreeBaseWrapperPacket(
  621. IN PNDIS_PACKET pPacket,
  622. IN PPACKET_INFO ppi
  623. )
  624. /*++
  625. Routine Description:
  626. Frees a packet allocated from the wrapper pool without quota adjustements. This is called directly
  627. from non-buffer-management code to free base packets because the cost for base packets is
  628. assigned and released directly with calls to BrdgBuf<Assign|Release>BasePacketQuota.
  629. Arguments:
  630. pPacket The packet to free
  631. ppi Its info block to free
  632. Return Value:
  633. None
  634. --*/
  635. {
  636. // If we're holding less than our cache amount, free the packet by putting it on the
  637. // cache list
  638. ULONG holding;
  639. SAFEASSERT( (ppi != NULL) && (pPacket != NULL) );
  640. SAFEASSERT( ppi->pOwnerPacket == pPacket );
  641. NdisAcquireSpinLock( &gFreeWrapperPacketListLock );
  642. holding = BrdgQuerySingleListLength( &gFreeWrapperPacketList );
  643. if( holding < gSafetyBuffer[BrdgQuotaWrapperPacket] )
  644. {
  645. // Prep the packet for reuse
  646. SAFEASSERT( BrdgBufPacketHeadBuffer(pPacket) == NULL );
  647. BrdgBufScrubPacket( pPacket, ppi );
  648. // Push the packet onto the list
  649. BrdgInsertHeadSingleList( &gFreeWrapperPacketList, &ppi->List );
  650. NdisReleaseSpinLock( &gFreeWrapperPacketListLock );
  651. }
  652. else
  653. {
  654. NdisReleaseSpinLock( &gFreeWrapperPacketListLock );
  655. // Free the packet and packet info block to the underlying pools
  656. NdisFreePacket( pPacket );
  657. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  658. }
  659. // Note the deallocation
  660. BrdgBufCountDealloc( BrdgQuotaWrapperPacket );
  661. }
  662. NDIS_STATUS
  663. BrdgBufChainCopyBuffers(
  664. IN PNDIS_PACKET pTargetPacket,
  665. IN PNDIS_PACKET pSourcePacket
  666. )
  667. /*++
  668. Routine Description:
  669. Allocates and chains buffer descriptors onto the target packet so it describes exactly
  670. the same areas of memory as the source packet
  671. Arguments:
  672. pTargetPacket Target packet
  673. pSourcePacket Source packet
  674. Return Value:
  675. Status of the operation. We have a limited-size pool of packet descriptors, so this
  676. operation can fail if we run out.
  677. --*/
  678. {
  679. PNDIS_BUFFER pCopyBuffer, pCurBuf = BrdgBufPacketHeadBuffer( pSourcePacket );
  680. NDIS_STATUS Status;
  681. SAFEASSERT( BrdgBufPacketHeadBuffer(pTargetPacket) == NULL );
  682. // There must be something in the source packet!
  683. if( pCurBuf == NULL )
  684. {
  685. SAFEASSERT( FALSE );
  686. return NDIS_STATUS_RESOURCES;
  687. }
  688. while( pCurBuf != NULL )
  689. {
  690. PVOID p;
  691. UINT Length;
  692. // Pull the virtual address and size out of the MDL being copied
  693. NdisQueryBufferSafe( pCurBuf, &p, &Length, NormalPagePriority );
  694. if( p == NULL )
  695. {
  696. BrdgBufUnchainCopyBuffers( pTargetPacket );
  697. return NDIS_STATUS_RESOURCES;
  698. }
  699. // Is wacky to have a MDL describing no memory
  700. if( Length > 0 )
  701. {
  702. // Get a new MDL from our pool and point it to the same address
  703. NdisAllocateBuffer( &Status, &pCopyBuffer, gWrapperBufferPoolHandle, p, Length );
  704. if( Status != NDIS_STATUS_SUCCESS )
  705. {
  706. THROTTLED_DBGPRINT(BUF, ("Failed to allocate a MDL in BrdgBufChainCopyBuffers: %08x\n", Status));
  707. BrdgBufUnchainCopyBuffers( pTargetPacket );
  708. return Status;
  709. }
  710. // Use the new MDL to chain to the target packet
  711. NdisChainBufferAtBack( pTargetPacket, pCopyBuffer );
  712. }
  713. else
  714. {
  715. SAFEASSERT( FALSE );
  716. }
  717. NdisGetNextBuffer( pCurBuf, &pCurBuf );
  718. }
  719. return NDIS_STATUS_SUCCESS;
  720. }
  721. NTSTATUS
  722. BrdgBufDriverInit( )
  723. /*++
  724. Routine Description:
  725. Driver-load-time initialization routine.
  726. Arguments:
  727. None
  728. Return Value:
  729. Status of initialization. A return code != STATUS_SUCCESS causes the driver load to fail.
  730. Any event causing an error return code must be logged.
  731. --*/
  732. {
  733. NDIS_STATUS Status;
  734. ULONG NumCopyPackets, ConsumptionPerCopyPacket, SizeOfPacket, i;
  735. ULONG MaxMemory = 0L, SafetyMargin = 0L;
  736. NTSTATUS NtStatus;
  737. // Initialize protective locks
  738. NdisAllocateSpinLock( &gFreeCopyPacketListLock );
  739. NdisAllocateSpinLock( &gFreeWrapperPacketListLock );
  740. NdisAllocateSpinLock( &gQuotaLock );
  741. // Initialize cache lists
  742. BrdgInitializeSingleList( &gFreeCopyPacketList );
  743. BrdgInitializeSingleList( &gFreeWrapperPacketList );
  744. // Initialize look-aside lists for receive buffers and packet info blocks
  745. NdisInitializeNPagedLookasideList( &gCopyBufferList, NULL, NULL, 0, MAX_PACKET_SIZE, 'gdrB', 0 );
  746. NdisInitializeNPagedLookasideList( &gPktInfoList, NULL, NULL, 0, sizeof(PACKET_INFO), 'gdrB', 0 );
  747. // Initialize the miniport's quota information
  748. BrdgBufInitializeQuota( &gMiniportQuota );
  749. //
  750. // Read in registry values. Substitute default values on failure.
  751. //
  752. NtStatus = BrdgReadRegDWord( &gRegistryPath, gMaxBufMemoryParameterName, &MaxMemory );
  753. if( NtStatus != STATUS_SUCCESS )
  754. {
  755. MaxMemory = DEFAULT_MAX_BUF_MEMORY;
  756. DBGPRINT(BUF, ( "Using DEFAULT maximum memory of %i\n", MaxMemory ));
  757. }
  758. NtStatus = BrdgReadRegDWord( &gRegistryPath, gSafetyMarginParameterName, &SafetyMargin );
  759. if( NtStatus != STATUS_SUCCESS )
  760. {
  761. SafetyMargin = DEFAULT_SAFETY_MARGIN;
  762. DBGPRINT(BUF, ( "Using DEFAULT safety margin of %i%%\n", SafetyMargin ));
  763. }
  764. //
  765. // Figure out the maximum number of packet descriptors in each pool we can allocate in order to
  766. // fit in the prescribed maximum memory space.
  767. //
  768. // For every copy packet, we allow ourselves GUESS_AVERAGE_FANOUT wrapper packets.
  769. // *Each* wrapper packet is allowed to consume GUESS_BUFFERS_PER_PACKET MDLs.
  770. // Given these relationships, we can calculate the number of copy packets that will fit in a given
  771. // memory footprint. The max for all other resources are set in relationship to that number.
  772. //
  773. SizeOfPacket = NdisPacketSize( PROTOCOL_RESERVED_SIZE_IN_PACKET );
  774. ConsumptionPerCopyPacket = SizeOfPacket * (GUESS_AVERAGE_FANOUT + 1) + // Packet decriptor memory
  775. MAX_PACKET_SIZE + // Copy buffer memory
  776. sizeof(PACKET_INFO) * (GUESS_AVERAGE_FANOUT + 1) + // Packet info block memory
  777. sizeof(NDIS_BUFFER) * ((GUESS_AVERAGE_FANOUT * GUESS_BUFFERS_PER_PACKET) + 1); // MDL memory
  778. NumCopyPackets = MaxMemory / ConsumptionPerCopyPacket;
  779. // Allocate the packet pools
  780. NdisAllocatePacketPool( &Status, &gCopyPacketPoolHandle, NumCopyPackets, PROTOCOL_RESERVED_SIZE_IN_PACKET );
  781. if( Status != NDIS_STATUS_SUCCESS )
  782. {
  783. NdisDeleteNPagedLookasideList( &gCopyBufferList );
  784. NdisDeleteNPagedLookasideList( &gPktInfoList );
  785. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_PACKET_POOL_CREATION_FAILED, 0L, 0L, NULL,
  786. sizeof(NDIS_STATUS), &Status );
  787. DBGPRINT(BUF, ("Unable to allocate copy-packet pool: %08x\n", Status));
  788. return STATUS_INSUFFICIENT_RESOURCES;
  789. }
  790. NdisAllocatePacketPool( &Status, &gWrapperPacketPoolHandle, GUESS_AVERAGE_FANOUT * NumCopyPackets, PROTOCOL_RESERVED_SIZE_IN_PACKET );
  791. if( Status != NDIS_STATUS_SUCCESS )
  792. {
  793. NdisDeleteNPagedLookasideList( &gCopyBufferList );
  794. NdisDeleteNPagedLookasideList( &gPktInfoList );
  795. NdisFreePacketPool( gCopyPacketPoolHandle );
  796. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_PACKET_POOL_CREATION_FAILED, 0L, 0L, NULL,
  797. sizeof(NDIS_STATUS), &Status );
  798. DBGPRINT(BUF, ("Unable to allocate wrapper packet pool: %08x\n", Status));
  799. return STATUS_INSUFFICIENT_RESOURCES;
  800. }
  801. // Allocate the buffer pools
  802. NdisAllocateBufferPool( &Status, &gCopyBufferPoolHandle, NumCopyPackets );
  803. if( Status != NDIS_STATUS_SUCCESS )
  804. {
  805. NdisDeleteNPagedLookasideList( &gCopyBufferList );
  806. NdisDeleteNPagedLookasideList( &gPktInfoList );
  807. NdisFreePacketPool( gCopyPacketPoolHandle );
  808. NdisFreePacketPool( gWrapperPacketPoolHandle );
  809. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_BUFFER_POOL_CREATION_FAILED, 0L, 0L, NULL,
  810. sizeof(NDIS_STATUS), &Status );
  811. DBGPRINT(BUF, ("Unable to allocate copy buffer pool: %08x\n", Status));
  812. return STATUS_INSUFFICIENT_RESOURCES;
  813. }
  814. NdisAllocateBufferPool( &Status, &gWrapperBufferPoolHandle, GUESS_AVERAGE_FANOUT * GUESS_BUFFERS_PER_PACKET * NumCopyPackets );
  815. if( Status != NDIS_STATUS_SUCCESS )
  816. {
  817. NdisDeleteNPagedLookasideList( &gCopyBufferList );
  818. NdisDeleteNPagedLookasideList( &gPktInfoList );
  819. NdisFreePacketPool( gCopyPacketPoolHandle );
  820. NdisFreePacketPool( gWrapperPacketPoolHandle );
  821. NdisFreeBufferPool( gCopyBufferPoolHandle );
  822. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_BUFFER_POOL_CREATION_FAILED, 0L, 0L, NULL,
  823. sizeof(NDIS_STATUS), &Status );
  824. DBGPRINT(BUF, ("Unable to allocate wrapper buffer pool: %08x\n", Status));
  825. return STATUS_INSUFFICIENT_RESOURCES;
  826. }
  827. gInitedCopyBufferList = gInitedPktInfoList = TRUE;
  828. // Note the number of each packet type
  829. gMaxPackets[BrdgQuotaCopyPacket] = NumCopyPackets;
  830. gMaxPackets[BrdgQuotaWrapperPacket] = NumCopyPackets * GUESS_AVERAGE_FANOUT;
  831. // Calculate the safety buffer size in packets
  832. SAFEASSERT( SafetyMargin > 0L );
  833. gSafetyBuffer[BrdgQuotaCopyPacket] = (gMaxPackets[BrdgQuotaCopyPacket] * SafetyMargin) / 100;
  834. gSafetyBuffer[BrdgQuotaWrapperPacket] = (gMaxPackets[BrdgQuotaWrapperPacket] * SafetyMargin) / 100;
  835. DBGPRINT(BUF, ( "Max memory usage of %d == %d copy packets, %d wrapper packets, %d copy-buffer space, %d/%d safety packets\n",
  836. MaxMemory, gMaxPackets[0], gMaxPackets[1], NumCopyPackets * MAX_PACKET_SIZE, gSafetyBuffer[0], gSafetyBuffer[1] ));
  837. // Pre-allocate the appropriate number of packets from each pool for perf.
  838. for( i = 0; i < gSafetyBuffer[BrdgQuotaCopyPacket]; i++ )
  839. {
  840. PNDIS_PACKET pPacket;
  841. PPACKET_INFO ppi;
  842. pPacket = BrdgBufGetNewCopyPacket( &ppi );
  843. // Should be impossible for this to fail
  844. if( (pPacket != NULL) && (ppi != NULL) )
  845. {
  846. // Count the usage ourselves because we're not going through normal channels
  847. gUsedPackets[BrdgQuotaCopyPacket]++;
  848. // This should retain the packet in memory and decrement the usage count
  849. BrdgBufFreeBaseCopyPacket( pPacket, ppi );
  850. }
  851. else
  852. {
  853. SAFEASSERT( FALSE );
  854. }
  855. }
  856. for( i = 0; i < gSafetyBuffer[BrdgQuotaWrapperPacket]; i++ )
  857. {
  858. PNDIS_PACKET pPacket;
  859. PPACKET_INFO ppi;
  860. pPacket = BrdgBufGetNewWrapperPacket( &ppi );
  861. // Should be impossible for this to fail
  862. if( (pPacket != NULL) && (ppi != NULL) )
  863. {
  864. // Count the usage ourselves because we're not going through normal channels
  865. gUsedPackets[BrdgQuotaWrapperPacket]++;
  866. // This should retain the packet in memory and decrement the usage count
  867. BrdgBufFreeBaseWrapperPacket( pPacket, ppi );
  868. }
  869. else
  870. {
  871. SAFEASSERT( FALSE );
  872. }
  873. }
  874. return STATUS_SUCCESS;
  875. }
  876. VOID
  877. BrdgBufCleanup()
  878. /*++
  879. Routine Description:
  880. Unload-time orderly shutdown
  881. This function is guaranteed to be called exactly once
  882. Arguments:
  883. None
  884. Return Value:
  885. None
  886. --*/
  887. {
  888. NDIS_HANDLE TmpHandle;
  889. if( gCopyPacketPoolHandle != NULL )
  890. {
  891. PBSINGLE_LIST_ENTRY entry;
  892. TmpHandle = gCopyPacketPoolHandle;
  893. gCopyPacketPoolHandle = NULL;
  894. // Free all cached packets before freeing the pool
  895. entry = BrdgInterlockedRemoveHeadSingleList( &gFreeCopyPacketList, &gFreeCopyPacketListLock );
  896. while( entry != NULL )
  897. {
  898. PNDIS_PACKET pPacket;
  899. PPACKET_INFO ppi;
  900. PNDIS_BUFFER pBuffer;
  901. ppi = CONTAINING_RECORD( entry, PACKET_INFO, List );
  902. pPacket = ppi->pOwnerPacket;
  903. SAFEASSERT( pPacket != NULL );
  904. // Pull off the data buffer
  905. NdisUnchainBufferAtFront( pPacket, &pBuffer );
  906. if( pBuffer != NULL )
  907. {
  908. PVOID pBuf;
  909. UINT Size;
  910. NdisQueryBufferSafe( pBuffer, &pBuf, &Size, NormalPagePriority );
  911. if( pBuf != NULL )
  912. {
  913. // Ditch the data buffer
  914. NdisFreeToNPagedLookasideList( &gCopyBufferList, pBuf );
  915. }
  916. // else can only fail under extreme memory pressure
  917. NdisFreeBuffer( pBuffer );
  918. }
  919. else
  920. {
  921. // This packet should have a chained buffer
  922. SAFEASSERT( FALSE );
  923. }
  924. NdisFreePacket( pPacket );
  925. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  926. entry = BrdgInterlockedRemoveHeadSingleList( &gFreeCopyPacketList, &gFreeCopyPacketListLock );
  927. }
  928. // Free the pool now that all packets have been returned
  929. NdisFreePacketPool( TmpHandle );
  930. }
  931. if( gWrapperPacketPoolHandle != NULL )
  932. {
  933. PBSINGLE_LIST_ENTRY entry;
  934. TmpHandle = gWrapperPacketPoolHandle;
  935. gWrapperPacketPoolHandle = NULL;
  936. // Free all cached packets before freeing the pool
  937. entry = BrdgInterlockedRemoveHeadSingleList( &gFreeWrapperPacketList, &gFreeWrapperPacketListLock );
  938. while( entry != NULL )
  939. {
  940. PNDIS_PACKET pPacket;
  941. PPACKET_INFO ppi;
  942. ppi = CONTAINING_RECORD( entry, PACKET_INFO, List );
  943. pPacket = ppi->pOwnerPacket;
  944. SAFEASSERT( pPacket != NULL );
  945. NdisFreePacket( pPacket );
  946. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  947. entry = BrdgInterlockedRemoveHeadSingleList( &gFreeWrapperPacketList, &gFreeWrapperPacketListLock );
  948. }
  949. // Free the pool now that all packets have been returned
  950. NdisFreePacketPool( TmpHandle );
  951. }
  952. // The two lookaside lists should now be empty as well
  953. if( gInitedCopyBufferList )
  954. {
  955. gInitedCopyBufferList = FALSE;
  956. NdisDeleteNPagedLookasideList( &gCopyBufferList );
  957. }
  958. if( gInitedPktInfoList )
  959. {
  960. gInitedPktInfoList = FALSE;
  961. NdisDeleteNPagedLookasideList( &gPktInfoList );
  962. }
  963. if( gCopyBufferPoolHandle != NULL )
  964. {
  965. TmpHandle = gCopyBufferPoolHandle;
  966. gCopyBufferPoolHandle = NULL;
  967. NdisFreeBufferPool( TmpHandle );
  968. }
  969. if( gWrapperBufferPoolHandle != NULL )
  970. {
  971. TmpHandle = gWrapperBufferPoolHandle;
  972. gWrapperBufferPoolHandle = NULL;
  973. NdisFreeBufferPool( TmpHandle );
  974. }
  975. }
  976. // ===========================================================================
  977. //
  978. // PRIVATE FUNCTIONS
  979. //
  980. // ===========================================================================
  981. BOOLEAN
  982. BrdgBufAssignQuota(
  983. IN QUOTA_PACKET_TYPE type,
  984. IN PADAPT pAdapt,
  985. IN BOOLEAN bCountAlloc
  986. )
  987. /*++
  988. Routine Description:
  989. Determines whether a particular adapter should be permitted to allocate a new packet
  990. from a particular pool. Implements our quota algorithm.
  991. This can be called either to pre-approve an actual memory allocation or to check if
  992. an adapter should be permitted to refer to a base packet in constructing a child
  993. wrapper packet
  994. Arguments:
  995. type Type of packet pAdapt wishes to allocate or refer to
  996. pAdapt The adapter involved
  997. bCountAlloc Whether this is a check before an actual allocation. If it
  998. is, the global usage counts will be incremented within the
  999. gQuotaLock spin lock so everything is atomic
  1000. Return Value:
  1001. TRUE : The adapter is permitted to allocate / refer
  1002. FALSE : The adapter is not permitted to allocate / refer
  1003. --*/
  1004. {
  1005. BOOLEAN rc;
  1006. PADAPTER_QUOTA pQuota = QUOTA_FROM_ADAPTER(pAdapt);
  1007. UINT index = INDEX_FROM_TYPE(type);
  1008. // Freeze this value for the duration of the function
  1009. ULONG numAdapters = gNumAdapters;
  1010. NdisAcquireSpinLock( &gQuotaLock );
  1011. if( (numAdapters > 0) && (pQuota->UsedPackets[index] < (gMaxPackets[index] - gSafetyBuffer[index]) / numAdapters) )
  1012. {
  1013. // This adapter is under its "fair share"; it can allocate if there are actually
  1014. // any packets left!
  1015. if( gUsedPackets[index] < gMaxPackets[index] )
  1016. {
  1017. // There are packets left. This is the normal case.
  1018. rc = TRUE;
  1019. }
  1020. else if( gUsedPackets[index] == gMaxPackets[index] )
  1021. {
  1022. // This should be unusual; we've blown past our safety buffer. Hopefully this is
  1023. // transitory.
  1024. ExInterlockedAddLargeStatistic( &gStatOverflows[index], 1L );
  1025. rc = FALSE;
  1026. }
  1027. else
  1028. {
  1029. // This should never happen; it means we have allocated more than we should be able
  1030. // to.
  1031. SAFEASSERT( FALSE );
  1032. rc = FALSE;
  1033. }
  1034. }
  1035. else
  1036. {
  1037. // This adapter is over its "fair share"; it can allocate only if there are more packets
  1038. // left than the safety buffer calls for
  1039. if( gMaxPackets[index] - gUsedPackets[index] > gSafetyBuffer[index] )
  1040. {
  1041. rc = TRUE;
  1042. }
  1043. else
  1044. {
  1045. // We're too close to the wire; deny the request.
  1046. rc = FALSE;
  1047. }
  1048. }
  1049. if( rc )
  1050. {
  1051. pQuota->UsedPackets[index]++;
  1052. if( bCountAlloc )
  1053. {
  1054. // The caller will allocate. Count the allocation before releasing the spin lock.
  1055. gUsedPackets[index]++;
  1056. #if DBG
  1057. // Keep track of the maximum used packets
  1058. if( gMaxUsedPackets[index] < gUsedPackets[index] )
  1059. {
  1060. gMaxUsedPackets[index] = gUsedPackets[index];
  1061. }
  1062. #endif
  1063. }
  1064. }
  1065. NdisReleaseSpinLock( &gQuotaLock );
  1066. return rc;
  1067. }
  1068. PNDIS_PACKET
  1069. BrdgBufGetNewCopyPacket(
  1070. OUT PPACKET_INFO *pppi
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. Allocates a brand new packet from the copy-packet pool. Every copy packet comes with
  1075. an associated data buffer large enough to hold a complete Ethernet frame, so the allocation
  1076. attempt has several steps
  1077. Arguments:
  1078. pppi The packet's info block, or NULL if the allocation fails
  1079. Return Value:
  1080. The new packet
  1081. --*/
  1082. {
  1083. PNDIS_PACKET pPacket;
  1084. PPACKET_INFO ppi;
  1085. // Try to allocate a packet and info block from our underlying pools
  1086. pPacket = BrdgBufCommonGetNewPacket( gCopyPacketPoolHandle, &ppi );
  1087. if( (pPacket == NULL) || (ppi == NULL) )
  1088. {
  1089. SAFEASSERT( (pPacket == NULL) && (ppi == NULL) );
  1090. }
  1091. else
  1092. {
  1093. PVOID pBuf;
  1094. // Allocate a copy buffer for the packet
  1095. pBuf = NdisAllocateFromNPagedLookasideList( &gCopyBufferList );
  1096. if( pBuf == NULL )
  1097. {
  1098. NdisFreePacket( pPacket );
  1099. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  1100. ppi = NULL;
  1101. pPacket = NULL;
  1102. }
  1103. else
  1104. {
  1105. NDIS_STATUS Status;
  1106. PNDIS_BUFFER pBuffer;
  1107. // Allocate a buffer descriptor for the copy buffer
  1108. NdisAllocateBuffer( &Status, &pBuffer, gCopyBufferPoolHandle, pBuf, MAX_PACKET_SIZE );
  1109. if( Status != NDIS_STATUS_SUCCESS )
  1110. {
  1111. NdisFreePacket( pPacket );
  1112. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  1113. NdisFreeToNPagedLookasideList( &gCopyBufferList, pBuf );
  1114. ppi = NULL;
  1115. pPacket = NULL;
  1116. }
  1117. else
  1118. {
  1119. SAFEASSERT( pBuffer != NULL );
  1120. NdisChainBufferAtFront( pPacket, pBuffer );
  1121. }
  1122. }
  1123. }
  1124. *pppi = ppi;
  1125. return pPacket;
  1126. }
  1127. PNDIS_PACKET
  1128. BrdgBufCommonGetNewPacket(
  1129. IN NDIS_HANDLE Pool,
  1130. OUT PPACKET_INFO *pppi
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. Common logic for allocating a brand new packet from either the wrapper pool or the copy pool.
  1135. Every packet of any flavor comes with an associated info block. Both the alloc of the
  1136. packet descriptor and the info block must succeed for the packet allocation to succeed.
  1137. Arguments:
  1138. Pool The pool to allocate from
  1139. pppi The allocated info block or NULL if the alloc failed
  1140. Return Value:
  1141. The new packet or NULL if the alloc failed
  1142. --*/
  1143. {
  1144. PNDIS_PACKET pPacket;
  1145. PPACKET_INFO ppi;
  1146. NDIS_STATUS Status;
  1147. // Try to allocate a new packet descriptor
  1148. NdisAllocatePacket( &Status, &pPacket, Pool );
  1149. if( Status != NDIS_STATUS_SUCCESS )
  1150. {
  1151. *pppi = NULL;
  1152. return NULL;
  1153. }
  1154. SAFEASSERT( pPacket != NULL );
  1155. // Try to allocate a new packet info block
  1156. ppi = NdisAllocateFromNPagedLookasideList( &gPktInfoList );
  1157. if( ppi == NULL )
  1158. {
  1159. NdisFreePacket( pPacket );
  1160. pPacket = NULL;
  1161. }
  1162. else
  1163. {
  1164. ppi->pOwnerPacket = pPacket;
  1165. }
  1166. *pppi = ppi;
  1167. return pPacket;
  1168. }