buf.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. buf.c
  5. Abstract:
  6. This module handles common buffer-related support for the core networking
  7. library.
  8. Author:
  9. Evan Green 5-Apr-2013
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include "netcore.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. //
  22. // ------------------------------------------------------ Data Type Definitions
  23. //
  24. //
  25. // ----------------------------------------------- Internal Function Prototypes
  26. //
  27. //
  28. // -------------------------------------------------------------------- Globals
  29. //
  30. //
  31. // Store a pointer to the global list of network buffers.
  32. //
  33. LIST_ENTRY NetFreeBufferList;
  34. PQUEUED_LOCK NetBufferListLock;
  35. //
  36. // ------------------------------------------------------------------ Functions
  37. //
  38. NET_API
  39. KSTATUS
  40. NetAllocateBuffer (
  41. ULONG HeaderSize,
  42. ULONG Size,
  43. ULONG FooterSize,
  44. PNET_LINK Link,
  45. ULONG Flags,
  46. PNET_PACKET_BUFFER *NewBuffer
  47. )
  48. /*++
  49. Routine Description:
  50. This routine allocates a network buffer.
  51. Arguments:
  52. HeaderSize - Supplies the number of header bytes needed.
  53. Size - Supplies the number of data bytes needed.
  54. FooterSize - Supplies the number of footer bytes needed.
  55. Link - Supplies a pointer to the link the buffer will be sent through. If
  56. a link is provided, then the buffer will be backed by physically
  57. contiguous pages for the link's hardware. If no link is provided, then
  58. the buffer will not be backed by physically contiguous pages.
  59. Flags - Supplies a bitmask of allocation flags. See
  60. NET_ALLOCATE_BUFFER_FLAG_* for definitions.
  61. NewBuffer - Supplies a pointer where a pointer to the new allocation will be
  62. returned on success.
  63. Return Value:
  64. STATUS_SUCCESS on success.
  65. STATUS_INVALID_PARAMETER if a zero length buffer was requested.
  66. STATUS_INSUFFICIENT_RESOURCES if the buffer or any auxiliary structures
  67. could not be allocated.
  68. --*/
  69. {
  70. ULONG Alignment;
  71. PNET_PACKET_BUFFER Buffer;
  72. PHYSICAL_ADDRESS BufferPhysical;
  73. ULONGLONG BufferSize;
  74. PLIST_ENTRY CurrentEntry;
  75. PNET_DATA_LINK_ENTRY DataLinkEntry;
  76. ULONG DataLinkMask;
  77. ULONG DataSize;
  78. ULONG IoBufferFlags;
  79. BOOL LockHeld;
  80. PHYSICAL_ADDRESS MaximumPhysicalAddress;
  81. ULONG MinPacketSize;
  82. ULONG PacketSizeFlags;
  83. ULONG Padding;
  84. NET_PACKET_SIZE_INFORMATION SizeInformation;
  85. KSTATUS Status;
  86. ULONG TotalSize;
  87. ASSERT(KeGetRunLevel() == RunLevelLow);
  88. if (Link != NULL) {
  89. //
  90. // If requested, add the additional headers and footers.
  91. //
  92. if ((Flags & NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_HEADERS) != 0) {
  93. HeaderSize += Link->Properties.PacketSizeInformation.HeaderSize;
  94. }
  95. if ((Flags & NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_FOOTERS) != 0) {
  96. FooterSize += Link->Properties.PacketSizeInformation.FooterSize;
  97. }
  98. DataLinkMask = NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_HEADERS |
  99. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_FOOTERS;
  100. if ((Flags & DataLinkMask) != 0) {
  101. PacketSizeFlags = 0;
  102. if ((Flags & NET_ALLOCATE_BUFFER_FLAG_UNENCRYPTED) != 0) {
  103. PacketSizeFlags |= NET_PACKET_SIZE_FLAG_UNENCRYPTED;
  104. }
  105. DataLinkEntry = Link->DataLinkEntry;
  106. DataLinkEntry->Interface.GetPacketSizeInformation(
  107. Link->DataLinkContext,
  108. &SizeInformation,
  109. PacketSizeFlags);
  110. if ((Flags & NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_HEADERS) != 0) {
  111. HeaderSize += SizeInformation.HeaderSize;
  112. }
  113. if ((Flags & NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_FOOTERS) != 0) {
  114. FooterSize += SizeInformation.FooterSize;
  115. }
  116. }
  117. Alignment = Link->Properties.TransmitAlignment;
  118. if (Alignment == 0) {
  119. Alignment = 1;
  120. }
  121. ASSERT(POWER_OF_2(Alignment));
  122. MaximumPhysicalAddress = Link->Properties.MaxPhysicalAddress;
  123. MinPacketSize = Link->Properties.PacketSizeInformation.MinPacketSize;
  124. } else {
  125. Alignment = 1;
  126. MaximumPhysicalAddress = MAX_UINTN;
  127. MinPacketSize = 0;
  128. }
  129. DataSize = HeaderSize + Size + FooterSize;
  130. //
  131. // If the total packet size is less than the link's allowed minimum, record
  132. // the size of the padding so that it can be zero'd later.
  133. //
  134. Padding = 0;
  135. if (DataSize < MinPacketSize) {
  136. Padding = MinPacketSize - DataSize;
  137. }
  138. TotalSize = DataSize + Padding;
  139. TotalSize = ALIGN_RANGE_UP(TotalSize, Alignment);
  140. //
  141. // Loop through the list looking for the first buffer that fits.
  142. //
  143. KeAcquireQueuedLock(NetBufferListLock);
  144. LockHeld = TRUE;
  145. CurrentEntry = NetFreeBufferList.Next;
  146. while (CurrentEntry != &NetFreeBufferList) {
  147. Buffer = LIST_VALUE(CurrentEntry, NET_PACKET_BUFFER, ListEntry);
  148. CurrentEntry = CurrentEntry->Next;
  149. BufferSize = Buffer->IoBuffer->Fragment[0].Size;
  150. if (BufferSize < TotalSize) {
  151. continue;
  152. }
  153. BufferPhysical = Buffer->IoBuffer->Fragment[0].PhysicalAddress;
  154. if (Link == NULL) {
  155. if (BufferPhysical != INVALID_PHYSICAL_ADDRESS) {
  156. continue;
  157. }
  158. } else {
  159. if ((BufferPhysical == INVALID_PHYSICAL_ADDRESS) ||
  160. ((BufferPhysical + BufferSize) > MaximumPhysicalAddress) ||
  161. (ALIGN_RANGE_DOWN(BufferPhysical, Alignment) !=
  162. BufferPhysical)) {
  163. continue;
  164. }
  165. }
  166. LIST_REMOVE(&(Buffer->ListEntry));
  167. Status = STATUS_SUCCESS;
  168. goto AllocateBufferEnd;
  169. }
  170. KeReleaseQueuedLock(NetBufferListLock);
  171. LockHeld = FALSE;
  172. //
  173. // Allocate a network packet buffer, but do not bother to zero it. This
  174. // routine takes care to initialize all the necessary fields before it is
  175. // used.
  176. //
  177. Buffer = MmAllocatePagedPool(sizeof(NET_PACKET_BUFFER),
  178. NET_CORE_ALLOCATION_TAG);
  179. if (Buffer == NULL) {
  180. Status = STATUS_INSUFFICIENT_RESOURCES;
  181. goto AllocateBufferEnd;
  182. }
  183. //
  184. // A buffer will need to be allocated.
  185. //
  186. if (Link != NULL) {
  187. IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
  188. Buffer->IoBuffer = MmAllocateNonPagedIoBuffer(0,
  189. MaximumPhysicalAddress,
  190. Alignment,
  191. TotalSize,
  192. IoBufferFlags);
  193. } else {
  194. Buffer->IoBuffer = MmAllocatePagedIoBuffer(TotalSize, 0);
  195. }
  196. if (Buffer->IoBuffer == NULL) {
  197. Status = STATUS_INSUFFICIENT_RESOURCES;
  198. goto AllocateBufferEnd;
  199. }
  200. ASSERT(Buffer->IoBuffer->FragmentCount == 1);
  201. Buffer->BufferPhysicalAddress =
  202. Buffer->IoBuffer->Fragment[0].PhysicalAddress;
  203. Buffer->Buffer = Buffer->IoBuffer->Fragment[0].VirtualAddress;
  204. Status = STATUS_SUCCESS;
  205. AllocateBufferEnd:
  206. if (LockHeld != FALSE) {
  207. KeReleaseQueuedLock(NetBufferListLock);
  208. }
  209. if (!KSUCCESS(Status)) {
  210. if (Buffer != NULL) {
  211. if (Buffer->IoBuffer != NULL) {
  212. MmFreeIoBuffer(Buffer->IoBuffer);
  213. }
  214. MmFreePagedPool(Buffer);
  215. Buffer = NULL;
  216. }
  217. } else {
  218. Buffer->Flags = 0;
  219. if ((Flags & NET_ALLOCATE_BUFFER_FLAG_UNENCRYPTED) != 0) {
  220. Buffer->Flags |= NET_PACKET_FLAG_UNENCRYPTED;
  221. }
  222. Buffer->BufferSize = TotalSize;
  223. Buffer->DataSize = DataSize;
  224. Buffer->DataOffset = HeaderSize;
  225. Buffer->FooterOffset = Buffer->DataOffset + Size;
  226. //
  227. // If padding was added to the packet, then zero it.
  228. //
  229. if (Padding != 0) {
  230. RtlZeroMemory(Buffer->Buffer + DataSize, Padding);
  231. }
  232. }
  233. *NewBuffer = Buffer;
  234. return Status;
  235. }
  236. NET_API
  237. VOID
  238. NetFreeBuffer (
  239. PNET_PACKET_BUFFER Buffer
  240. )
  241. /*++
  242. Routine Description:
  243. This routine frees a previously allocated network buffer.
  244. Arguments:
  245. Buffer - Supplies a pointer to the buffer returned by the allocation
  246. routine.
  247. Return Value:
  248. None.
  249. --*/
  250. {
  251. KeAcquireQueuedLock(NetBufferListLock);
  252. INSERT_AFTER(&(Buffer->ListEntry), &NetFreeBufferList);
  253. KeReleaseQueuedLock(NetBufferListLock);
  254. return;
  255. }
  256. NET_API
  257. VOID
  258. NetDestroyBufferList (
  259. PNET_PACKET_LIST BufferList
  260. )
  261. /*++
  262. Routine Description:
  263. This routine destroys a list of network packet buffers, releasing all of
  264. its associated resources, not including the buffer list structure.
  265. Arguments:
  266. BufferList - Supplies a pointer to the buffer list to be destroyed.
  267. Return Value:
  268. None.
  269. --*/
  270. {
  271. PNET_PACKET_BUFFER Buffer;
  272. while (NET_PACKET_LIST_EMPTY(BufferList) == FALSE) {
  273. Buffer = LIST_VALUE(BufferList->Head.Next,
  274. NET_PACKET_BUFFER,
  275. ListEntry);
  276. NET_REMOVE_PACKET_FROM_LIST(Buffer, BufferList);
  277. NetFreeBuffer(Buffer);
  278. }
  279. return;
  280. }
  281. KSTATUS
  282. NetpInitializeBuffers (
  283. VOID
  284. )
  285. /*++
  286. Routine Description:
  287. This routine initializes support for network buffers.
  288. Arguments:
  289. None.
  290. Return Value:
  291. Status code.
  292. --*/
  293. {
  294. INITIALIZE_LIST_HEAD(&NetFreeBufferList);
  295. NetBufferListLock = KeCreateQueuedLock();
  296. if (NetBufferListLock == NULL) {
  297. return STATUS_INSUFFICIENT_RESOURCES;
  298. }
  299. return STATUS_SUCCESS;
  300. }
  301. VOID
  302. NetpDestroyBuffers (
  303. VOID
  304. )
  305. /*++
  306. Routine Description:
  307. This routine destroys any allocations made during network buffer
  308. initialization.
  309. Arguments:
  310. None.
  311. Return Value:
  312. None.
  313. --*/
  314. {
  315. if (NetBufferListLock != NULL) {
  316. KeDestroyQueuedLock(NetBufferListLock);
  317. }
  318. return;
  319. }
  320. //
  321. // --------------------------------------------------------- Internal Functions
  322. //