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.

1519 lines
44 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. if (pBuffer)
  581. {
  582. // Return this packet descriptor to its original state
  583. NdisAdjustBufferLength(pBuffer, MAX_PACKET_SIZE);
  584. NdisAcquireSpinLock( &gFreeCopyPacketListLock );
  585. holding = BrdgQuerySingleListLength( &gFreeCopyPacketList );
  586. if( holding < gSafetyBuffer[BrdgQuotaCopyPacket] )
  587. {
  588. // Prep the packet for reuse
  589. // This blows away the buffer chain
  590. BrdgBufScrubPacket( pPacket, ppi );
  591. // Put the buffer back on
  592. SAFEASSERT( BrdgBufPacketHeadBuffer(pPacket) == NULL );
  593. NdisChainBufferAtFront( pPacket, pBuffer );
  594. // Push the packet onto the list
  595. BrdgInsertHeadSingleList( &gFreeCopyPacketList, &ppi->List );
  596. NdisReleaseSpinLock( &gFreeCopyPacketListLock );
  597. }
  598. else
  599. {
  600. PVOID pBuf;
  601. UINT Size;
  602. NdisReleaseSpinLock( &gFreeCopyPacketListLock );
  603. NdisQueryBufferSafe( pBuffer, &pBuf, &Size, NormalPagePriority );
  604. // Free the packet, the packet info block and the copy buffer to the underlying pools
  605. NdisFreeBuffer( pBuffer );
  606. NdisFreePacket( pPacket );
  607. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  608. if( pBuf != NULL )
  609. {
  610. NdisFreeToNPagedLookasideList( &gCopyBufferList, pBuf );
  611. }
  612. else
  613. {
  614. // Shouldn't be possible since the alloced memory is in kernel space
  615. SAFEASSERT( FALSE );
  616. }
  617. }
  618. // Note the deallocation
  619. BrdgBufCountDealloc( BrdgQuotaCopyPacket );
  620. }
  621. }
  622. VOID
  623. BrdgBufFreeBaseWrapperPacket(
  624. IN PNDIS_PACKET pPacket,
  625. IN PPACKET_INFO ppi
  626. )
  627. /*++
  628. Routine Description:
  629. Frees a packet allocated from the wrapper pool without quota adjustements. This is called directly
  630. from non-buffer-management code to free base packets because the cost for base packets is
  631. assigned and released directly with calls to BrdgBuf<Assign|Release>BasePacketQuota.
  632. Arguments:
  633. pPacket The packet to free
  634. ppi Its info block to free
  635. Return Value:
  636. None
  637. --*/
  638. {
  639. // If we're holding less than our cache amount, free the packet by putting it on the
  640. // cache list
  641. ULONG holding;
  642. SAFEASSERT( (ppi != NULL) && (pPacket != NULL) );
  643. SAFEASSERT( ppi->pOwnerPacket == pPacket );
  644. NdisAcquireSpinLock( &gFreeWrapperPacketListLock );
  645. holding = BrdgQuerySingleListLength( &gFreeWrapperPacketList );
  646. if( holding < gSafetyBuffer[BrdgQuotaWrapperPacket] )
  647. {
  648. // Prep the packet for reuse
  649. SAFEASSERT( BrdgBufPacketHeadBuffer(pPacket) == NULL );
  650. BrdgBufScrubPacket( pPacket, ppi );
  651. // Push the packet onto the list
  652. BrdgInsertHeadSingleList( &gFreeWrapperPacketList, &ppi->List );
  653. NdisReleaseSpinLock( &gFreeWrapperPacketListLock );
  654. }
  655. else
  656. {
  657. NdisReleaseSpinLock( &gFreeWrapperPacketListLock );
  658. // Free the packet and packet info block to the underlying pools
  659. NdisFreePacket( pPacket );
  660. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  661. }
  662. // Note the deallocation
  663. BrdgBufCountDealloc( BrdgQuotaWrapperPacket );
  664. }
  665. NDIS_STATUS
  666. BrdgBufChainCopyBuffers(
  667. IN PNDIS_PACKET pTargetPacket,
  668. IN PNDIS_PACKET pSourcePacket
  669. )
  670. /*++
  671. Routine Description:
  672. Allocates and chains buffer descriptors onto the target packet so it describes exactly
  673. the same areas of memory as the source packet
  674. Arguments:
  675. pTargetPacket Target packet
  676. pSourcePacket Source packet
  677. Return Value:
  678. Status of the operation. We have a limited-size pool of packet descriptors, so this
  679. operation can fail if we run out.
  680. --*/
  681. {
  682. PNDIS_BUFFER pCopyBuffer, pCurBuf = BrdgBufPacketHeadBuffer( pSourcePacket );
  683. NDIS_STATUS Status;
  684. SAFEASSERT( BrdgBufPacketHeadBuffer(pTargetPacket) == NULL );
  685. // There must be something in the source packet!
  686. if( pCurBuf == NULL )
  687. {
  688. SAFEASSERT( FALSE );
  689. return NDIS_STATUS_RESOURCES;
  690. }
  691. while( pCurBuf != NULL )
  692. {
  693. PVOID p;
  694. UINT Length;
  695. // Pull the virtual address and size out of the MDL being copied
  696. NdisQueryBufferSafe( pCurBuf, &p, &Length, NormalPagePriority );
  697. if( p == NULL )
  698. {
  699. BrdgBufUnchainCopyBuffers( pTargetPacket );
  700. return NDIS_STATUS_RESOURCES;
  701. }
  702. // Is wacky to have a MDL describing no memory
  703. if( Length > 0 )
  704. {
  705. // Get a new MDL from our pool and point it to the same address
  706. NdisAllocateBuffer( &Status, &pCopyBuffer, gWrapperBufferPoolHandle, p, Length );
  707. if( Status != NDIS_STATUS_SUCCESS )
  708. {
  709. THROTTLED_DBGPRINT(BUF, ("Failed to allocate a MDL in BrdgBufChainCopyBuffers: %08x\n", Status));
  710. BrdgBufUnchainCopyBuffers( pTargetPacket );
  711. return Status;
  712. }
  713. // Use the new MDL to chain to the target packet
  714. NdisChainBufferAtBack( pTargetPacket, pCopyBuffer );
  715. }
  716. else
  717. {
  718. SAFEASSERT( FALSE );
  719. }
  720. NdisGetNextBuffer( pCurBuf, &pCurBuf );
  721. }
  722. return NDIS_STATUS_SUCCESS;
  723. }
  724. NTSTATUS
  725. BrdgBufDriverInit( )
  726. /*++
  727. Routine Description:
  728. Driver-load-time initialization routine.
  729. Arguments:
  730. None
  731. Return Value:
  732. Status of initialization. A return code != STATUS_SUCCESS causes the driver load to fail.
  733. Any event causing an error return code must be logged.
  734. --*/
  735. {
  736. NDIS_STATUS Status;
  737. ULONG NumCopyPackets, ConsumptionPerCopyPacket, SizeOfPacket, i;
  738. ULONG MaxMemory = 0L, SafetyMargin = 0L;
  739. NTSTATUS NtStatus;
  740. // Initialize protective locks
  741. NdisAllocateSpinLock( &gFreeCopyPacketListLock );
  742. NdisAllocateSpinLock( &gFreeWrapperPacketListLock );
  743. NdisAllocateSpinLock( &gQuotaLock );
  744. // Initialize cache lists
  745. BrdgInitializeSingleList( &gFreeCopyPacketList );
  746. BrdgInitializeSingleList( &gFreeWrapperPacketList );
  747. // Initialize look-aside lists for receive buffers and packet info blocks
  748. NdisInitializeNPagedLookasideList( &gCopyBufferList, NULL, NULL, 0, MAX_PACKET_SIZE, 'gdrB', 0 );
  749. NdisInitializeNPagedLookasideList( &gPktInfoList, NULL, NULL, 0, sizeof(PACKET_INFO), 'gdrB', 0 );
  750. // Initialize the miniport's quota information
  751. BrdgBufInitializeQuota( &gMiniportQuota );
  752. //
  753. // Read in registry values. Substitute default values on failure.
  754. //
  755. NtStatus = BrdgReadRegDWord( &gRegistryPath, gMaxBufMemoryParameterName, &MaxMemory );
  756. if( NtStatus != STATUS_SUCCESS )
  757. {
  758. MaxMemory = DEFAULT_MAX_BUF_MEMORY;
  759. DBGPRINT(BUF, ( "Using DEFAULT maximum memory of %i\n", MaxMemory ));
  760. }
  761. NtStatus = BrdgReadRegDWord( &gRegistryPath, gSafetyMarginParameterName, &SafetyMargin );
  762. if( NtStatus != STATUS_SUCCESS )
  763. {
  764. SafetyMargin = DEFAULT_SAFETY_MARGIN;
  765. DBGPRINT(BUF, ( "Using DEFAULT safety margin of %i%%\n", SafetyMargin ));
  766. }
  767. //
  768. // Figure out the maximum number of packet descriptors in each pool we can allocate in order to
  769. // fit in the prescribed maximum memory space.
  770. //
  771. // For every copy packet, we allow ourselves GUESS_AVERAGE_FANOUT wrapper packets.
  772. // *Each* wrapper packet is allowed to consume GUESS_BUFFERS_PER_PACKET MDLs.
  773. // Given these relationships, we can calculate the number of copy packets that will fit in a given
  774. // memory footprint. The max for all other resources are set in relationship to that number.
  775. //
  776. SizeOfPacket = NdisPacketSize( PROTOCOL_RESERVED_SIZE_IN_PACKET );
  777. ConsumptionPerCopyPacket = SizeOfPacket * (GUESS_AVERAGE_FANOUT + 1) + // Packet decriptor memory
  778. MAX_PACKET_SIZE + // Copy buffer memory
  779. sizeof(PACKET_INFO) * (GUESS_AVERAGE_FANOUT + 1) + // Packet info block memory
  780. sizeof(NDIS_BUFFER) * ((GUESS_AVERAGE_FANOUT * GUESS_BUFFERS_PER_PACKET) + 1); // MDL memory
  781. NumCopyPackets = MaxMemory / ConsumptionPerCopyPacket;
  782. // Allocate the packet pools
  783. NdisAllocatePacketPool( &Status, &gCopyPacketPoolHandle, NumCopyPackets, PROTOCOL_RESERVED_SIZE_IN_PACKET );
  784. if( Status != NDIS_STATUS_SUCCESS )
  785. {
  786. NdisDeleteNPagedLookasideList( &gCopyBufferList );
  787. NdisDeleteNPagedLookasideList( &gPktInfoList );
  788. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_PACKET_POOL_CREATION_FAILED, 0L, 0L, NULL,
  789. sizeof(NDIS_STATUS), &Status );
  790. DBGPRINT(BUF, ("Unable to allocate copy-packet pool: %08x\n", Status));
  791. return STATUS_INSUFFICIENT_RESOURCES;
  792. }
  793. NdisAllocatePacketPool( &Status, &gWrapperPacketPoolHandle, GUESS_AVERAGE_FANOUT * NumCopyPackets, PROTOCOL_RESERVED_SIZE_IN_PACKET );
  794. if( Status != NDIS_STATUS_SUCCESS )
  795. {
  796. NdisDeleteNPagedLookasideList( &gCopyBufferList );
  797. NdisDeleteNPagedLookasideList( &gPktInfoList );
  798. NdisFreePacketPool( gCopyPacketPoolHandle );
  799. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_PACKET_POOL_CREATION_FAILED, 0L, 0L, NULL,
  800. sizeof(NDIS_STATUS), &Status );
  801. DBGPRINT(BUF, ("Unable to allocate wrapper packet pool: %08x\n", Status));
  802. return STATUS_INSUFFICIENT_RESOURCES;
  803. }
  804. // Allocate the buffer pools
  805. NdisAllocateBufferPool( &Status, &gCopyBufferPoolHandle, NumCopyPackets );
  806. if( Status != NDIS_STATUS_SUCCESS )
  807. {
  808. NdisDeleteNPagedLookasideList( &gCopyBufferList );
  809. NdisDeleteNPagedLookasideList( &gPktInfoList );
  810. NdisFreePacketPool( gCopyPacketPoolHandle );
  811. NdisFreePacketPool( gWrapperPacketPoolHandle );
  812. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_BUFFER_POOL_CREATION_FAILED, 0L, 0L, NULL,
  813. sizeof(NDIS_STATUS), &Status );
  814. DBGPRINT(BUF, ("Unable to allocate copy buffer pool: %08x\n", Status));
  815. return STATUS_INSUFFICIENT_RESOURCES;
  816. }
  817. NdisAllocateBufferPool( &Status, &gWrapperBufferPoolHandle, GUESS_AVERAGE_FANOUT * GUESS_BUFFERS_PER_PACKET * NumCopyPackets );
  818. if( Status != NDIS_STATUS_SUCCESS )
  819. {
  820. NdisDeleteNPagedLookasideList( &gCopyBufferList );
  821. NdisDeleteNPagedLookasideList( &gPktInfoList );
  822. NdisFreePacketPool( gCopyPacketPoolHandle );
  823. NdisFreePacketPool( gWrapperPacketPoolHandle );
  824. NdisFreeBufferPool( gCopyBufferPoolHandle );
  825. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_BUFFER_POOL_CREATION_FAILED, 0L, 0L, NULL,
  826. sizeof(NDIS_STATUS), &Status );
  827. DBGPRINT(BUF, ("Unable to allocate wrapper buffer pool: %08x\n", Status));
  828. return STATUS_INSUFFICIENT_RESOURCES;
  829. }
  830. gInitedCopyBufferList = gInitedPktInfoList = TRUE;
  831. // Note the number of each packet type
  832. gMaxPackets[BrdgQuotaCopyPacket] = NumCopyPackets;
  833. gMaxPackets[BrdgQuotaWrapperPacket] = NumCopyPackets * GUESS_AVERAGE_FANOUT;
  834. // Calculate the safety buffer size in packets
  835. SAFEASSERT( SafetyMargin > 0L );
  836. gSafetyBuffer[BrdgQuotaCopyPacket] = (gMaxPackets[BrdgQuotaCopyPacket] * SafetyMargin) / 100;
  837. gSafetyBuffer[BrdgQuotaWrapperPacket] = (gMaxPackets[BrdgQuotaWrapperPacket] * SafetyMargin) / 100;
  838. DBGPRINT(BUF, ( "Max memory usage of %d == %d copy packets, %d wrapper packets, %d copy-buffer space, %d/%d safety packets\n",
  839. MaxMemory, gMaxPackets[0], gMaxPackets[1], NumCopyPackets * MAX_PACKET_SIZE, gSafetyBuffer[0], gSafetyBuffer[1] ));
  840. // Pre-allocate the appropriate number of packets from each pool for perf.
  841. for( i = 0; i < gSafetyBuffer[BrdgQuotaCopyPacket]; i++ )
  842. {
  843. PNDIS_PACKET pPacket;
  844. PPACKET_INFO ppi;
  845. pPacket = BrdgBufGetNewCopyPacket( &ppi );
  846. // Should be impossible for this to fail
  847. if( (pPacket != NULL) && (ppi != NULL) )
  848. {
  849. // Count the usage ourselves because we're not going through normal channels
  850. gUsedPackets[BrdgQuotaCopyPacket]++;
  851. // This should retain the packet in memory and decrement the usage count
  852. BrdgBufFreeBaseCopyPacket( pPacket, ppi );
  853. }
  854. else
  855. {
  856. SAFEASSERT( FALSE );
  857. }
  858. }
  859. for( i = 0; i < gSafetyBuffer[BrdgQuotaWrapperPacket]; i++ )
  860. {
  861. PNDIS_PACKET pPacket;
  862. PPACKET_INFO ppi;
  863. pPacket = BrdgBufGetNewWrapperPacket( &ppi );
  864. // Should be impossible for this to fail
  865. if( (pPacket != NULL) && (ppi != NULL) )
  866. {
  867. // Count the usage ourselves because we're not going through normal channels
  868. gUsedPackets[BrdgQuotaWrapperPacket]++;
  869. // This should retain the packet in memory and decrement the usage count
  870. BrdgBufFreeBaseWrapperPacket( pPacket, ppi );
  871. }
  872. else
  873. {
  874. SAFEASSERT( FALSE );
  875. }
  876. }
  877. return STATUS_SUCCESS;
  878. }
  879. VOID
  880. BrdgBufCleanup()
  881. /*++
  882. Routine Description:
  883. Unload-time orderly shutdown
  884. This function is guaranteed to be called exactly once
  885. Arguments:
  886. None
  887. Return Value:
  888. None
  889. --*/
  890. {
  891. NDIS_HANDLE TmpHandle;
  892. if( gCopyPacketPoolHandle != NULL )
  893. {
  894. PBSINGLE_LIST_ENTRY entry;
  895. TmpHandle = gCopyPacketPoolHandle;
  896. gCopyPacketPoolHandle = NULL;
  897. // Free all cached packets before freeing the pool
  898. entry = BrdgInterlockedRemoveHeadSingleList( &gFreeCopyPacketList, &gFreeCopyPacketListLock );
  899. while( entry != NULL )
  900. {
  901. PNDIS_PACKET pPacket;
  902. PPACKET_INFO ppi;
  903. PNDIS_BUFFER pBuffer;
  904. ppi = CONTAINING_RECORD( entry, PACKET_INFO, List );
  905. SAFEASSERT(ppi);
  906. if (ppi)
  907. {
  908. pPacket = ppi->pOwnerPacket;
  909. SAFEASSERT( pPacket != NULL );
  910. if (pPacket)
  911. {
  912. // Pull off the data buffer
  913. NdisUnchainBufferAtFront( pPacket, &pBuffer );
  914. if( pBuffer != NULL )
  915. {
  916. PVOID pBuf;
  917. UINT Size;
  918. NdisQueryBufferSafe( pBuffer, &pBuf, &Size, NormalPagePriority );
  919. if( pBuf != NULL )
  920. {
  921. // Ditch the data buffer
  922. NdisFreeToNPagedLookasideList( &gCopyBufferList, pBuf );
  923. }
  924. // else can only fail under extreme memory pressure
  925. NdisFreeBuffer( pBuffer );
  926. }
  927. else
  928. {
  929. // This packet should have a chained buffer
  930. SAFEASSERT( FALSE );
  931. }
  932. }
  933. NdisFreePacket( pPacket );
  934. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  935. }
  936. entry = BrdgInterlockedRemoveHeadSingleList( &gFreeCopyPacketList, &gFreeCopyPacketListLock );
  937. }
  938. // Free the pool now that all packets have been returned
  939. NdisFreePacketPool( TmpHandle );
  940. }
  941. if( gWrapperPacketPoolHandle != NULL )
  942. {
  943. PBSINGLE_LIST_ENTRY entry;
  944. TmpHandle = gWrapperPacketPoolHandle;
  945. gWrapperPacketPoolHandle = NULL;
  946. // Free all cached packets before freeing the pool
  947. entry = BrdgInterlockedRemoveHeadSingleList( &gFreeWrapperPacketList, &gFreeWrapperPacketListLock );
  948. while( entry != NULL )
  949. {
  950. PNDIS_PACKET pPacket;
  951. PPACKET_INFO ppi;
  952. ppi = CONTAINING_RECORD( entry, PACKET_INFO, List );
  953. pPacket = ppi->pOwnerPacket;
  954. SAFEASSERT( pPacket != NULL );
  955. if (pPacket)
  956. {
  957. NdisFreePacket( pPacket );
  958. }
  959. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  960. entry = BrdgInterlockedRemoveHeadSingleList( &gFreeWrapperPacketList, &gFreeWrapperPacketListLock );
  961. }
  962. // Free the pool now that all packets have been returned
  963. NdisFreePacketPool( TmpHandle );
  964. }
  965. // The two lookaside lists should now be empty as well
  966. if( gInitedCopyBufferList )
  967. {
  968. gInitedCopyBufferList = FALSE;
  969. NdisDeleteNPagedLookasideList( &gCopyBufferList );
  970. }
  971. if( gInitedPktInfoList )
  972. {
  973. gInitedPktInfoList = FALSE;
  974. NdisDeleteNPagedLookasideList( &gPktInfoList );
  975. }
  976. if( gCopyBufferPoolHandle != NULL )
  977. {
  978. TmpHandle = gCopyBufferPoolHandle;
  979. gCopyBufferPoolHandle = NULL;
  980. NdisFreeBufferPool( TmpHandle );
  981. }
  982. if( gWrapperBufferPoolHandle != NULL )
  983. {
  984. TmpHandle = gWrapperBufferPoolHandle;
  985. gWrapperBufferPoolHandle = NULL;
  986. NdisFreeBufferPool( TmpHandle );
  987. }
  988. }
  989. // ===========================================================================
  990. //
  991. // PRIVATE FUNCTIONS
  992. //
  993. // ===========================================================================
  994. BOOLEAN
  995. BrdgBufAssignQuota(
  996. IN QUOTA_PACKET_TYPE type,
  997. IN PADAPT pAdapt,
  998. IN BOOLEAN bCountAlloc
  999. )
  1000. /*++
  1001. Routine Description:
  1002. Determines whether a particular adapter should be permitted to allocate a new packet
  1003. from a particular pool. Implements our quota algorithm.
  1004. This can be called either to pre-approve an actual memory allocation or to check if
  1005. an adapter should be permitted to refer to a base packet in constructing a child
  1006. wrapper packet
  1007. Arguments:
  1008. type Type of packet pAdapt wishes to allocate or refer to
  1009. pAdapt The adapter involved
  1010. bCountAlloc Whether this is a check before an actual allocation. If it
  1011. is, the global usage counts will be incremented within the
  1012. gQuotaLock spin lock so everything is atomic
  1013. Return Value:
  1014. TRUE : The adapter is permitted to allocate / refer
  1015. FALSE : The adapter is not permitted to allocate / refer
  1016. --*/
  1017. {
  1018. BOOLEAN rc;
  1019. PADAPTER_QUOTA pQuota = QUOTA_FROM_ADAPTER(pAdapt);
  1020. UINT index = INDEX_FROM_TYPE(type);
  1021. // Freeze this value for the duration of the function
  1022. ULONG numAdapters = gNumAdapters;
  1023. NdisAcquireSpinLock( &gQuotaLock );
  1024. if( (numAdapters > 0) && (pQuota->UsedPackets[index] < (gMaxPackets[index] - gSafetyBuffer[index]) / numAdapters) )
  1025. {
  1026. // This adapter is under its "fair share"; it can allocate if there are actually
  1027. // any packets left!
  1028. if( gUsedPackets[index] < gMaxPackets[index] )
  1029. {
  1030. // There are packets left. This is the normal case.
  1031. rc = TRUE;
  1032. }
  1033. else if( gUsedPackets[index] == gMaxPackets[index] )
  1034. {
  1035. // This should be unusual; we've blown past our safety buffer. Hopefully this is
  1036. // transitory.
  1037. ExInterlockedAddLargeStatistic( &gStatOverflows[index], 1L );
  1038. rc = FALSE;
  1039. }
  1040. else
  1041. {
  1042. // This should never happen; it means we have allocated more than we should be able
  1043. // to.
  1044. SAFEASSERT( FALSE );
  1045. rc = FALSE;
  1046. }
  1047. }
  1048. else
  1049. {
  1050. // This adapter is over its "fair share"; it can allocate only if there are more packets
  1051. // left than the safety buffer calls for
  1052. if( gMaxPackets[index] - gUsedPackets[index] > gSafetyBuffer[index] )
  1053. {
  1054. rc = TRUE;
  1055. }
  1056. else
  1057. {
  1058. // We're too close to the wire; deny the request.
  1059. rc = FALSE;
  1060. }
  1061. }
  1062. if( rc )
  1063. {
  1064. pQuota->UsedPackets[index]++;
  1065. if( bCountAlloc )
  1066. {
  1067. // The caller will allocate. Count the allocation before releasing the spin lock.
  1068. gUsedPackets[index]++;
  1069. #if DBG
  1070. // Keep track of the maximum used packets
  1071. if( gMaxUsedPackets[index] < gUsedPackets[index] )
  1072. {
  1073. gMaxUsedPackets[index] = gUsedPackets[index];
  1074. }
  1075. #endif
  1076. }
  1077. }
  1078. NdisReleaseSpinLock( &gQuotaLock );
  1079. return rc;
  1080. }
  1081. PNDIS_PACKET
  1082. BrdgBufGetNewCopyPacket(
  1083. OUT PPACKET_INFO *pppi
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. Allocates a brand new packet from the copy-packet pool. Every copy packet comes with
  1088. an associated data buffer large enough to hold a complete Ethernet frame, so the allocation
  1089. attempt has several steps
  1090. Arguments:
  1091. pppi The packet's info block, or NULL if the allocation fails
  1092. Return Value:
  1093. The new packet
  1094. --*/
  1095. {
  1096. PNDIS_PACKET pPacket;
  1097. PPACKET_INFO ppi = NULL;
  1098. // Try to allocate a packet and info block from our underlying pools
  1099. pPacket = BrdgBufCommonGetNewPacket( gCopyPacketPoolHandle, &ppi );
  1100. if( (pPacket == NULL) || (ppi == NULL) )
  1101. {
  1102. SAFEASSERT( (pPacket == NULL) && (ppi == NULL) );
  1103. }
  1104. else
  1105. {
  1106. PVOID pBuf;
  1107. // Allocate a copy buffer for the packet
  1108. pBuf = NdisAllocateFromNPagedLookasideList( &gCopyBufferList );
  1109. if( pBuf == NULL )
  1110. {
  1111. NdisFreePacket( pPacket );
  1112. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  1113. ppi = NULL;
  1114. pPacket = NULL;
  1115. }
  1116. else
  1117. {
  1118. NDIS_STATUS Status;
  1119. PNDIS_BUFFER pBuffer;
  1120. // Allocate a buffer descriptor for the copy buffer
  1121. NdisAllocateBuffer( &Status, &pBuffer, gCopyBufferPoolHandle, pBuf, MAX_PACKET_SIZE );
  1122. if( Status != NDIS_STATUS_SUCCESS )
  1123. {
  1124. NdisFreePacket( pPacket );
  1125. NdisFreeToNPagedLookasideList( &gPktInfoList, ppi );
  1126. NdisFreeToNPagedLookasideList( &gCopyBufferList, pBuf );
  1127. ppi = NULL;
  1128. pPacket = NULL;
  1129. }
  1130. else
  1131. {
  1132. SAFEASSERT( pBuffer != NULL );
  1133. NdisChainBufferAtFront( pPacket, pBuffer );
  1134. }
  1135. }
  1136. }
  1137. *pppi = ppi;
  1138. return pPacket;
  1139. }
  1140. PNDIS_PACKET
  1141. BrdgBufCommonGetNewPacket(
  1142. IN NDIS_HANDLE Pool,
  1143. OUT PPACKET_INFO *pppi
  1144. )
  1145. /*++
  1146. Routine Description:
  1147. Common logic for allocating a brand new packet from either the wrapper pool or the copy pool.
  1148. Every packet of any flavor comes with an associated info block. Both the alloc of the
  1149. packet descriptor and the info block must succeed for the packet allocation to succeed.
  1150. Arguments:
  1151. Pool The pool to allocate from
  1152. pppi The allocated info block or NULL if the alloc failed
  1153. Return Value:
  1154. The new packet or NULL if the alloc failed
  1155. --*/
  1156. {
  1157. PNDIS_PACKET pPacket;
  1158. PPACKET_INFO ppi = NULL;
  1159. NDIS_STATUS Status;
  1160. // Try to allocate a new packet descriptor
  1161. NdisAllocatePacket( &Status, &pPacket, Pool );
  1162. if( Status != NDIS_STATUS_SUCCESS )
  1163. {
  1164. *pppi = NULL;
  1165. return NULL;
  1166. }
  1167. SAFEASSERT( pPacket != NULL );
  1168. if (pPacket)
  1169. {
  1170. // Try to allocate a new packet info block
  1171. ppi = NdisAllocateFromNPagedLookasideList( &gPktInfoList );
  1172. if( ppi == NULL )
  1173. {
  1174. NdisFreePacket( pPacket );
  1175. pPacket = NULL;
  1176. }
  1177. else
  1178. {
  1179. ppi->pOwnerPacket = pPacket;
  1180. }
  1181. }
  1182. *pppi = ppi;
  1183. return pPacket;
  1184. }