buf.c 10 KB

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