mem.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. * TAP-Windows -- A kernel driver to provide virtual tap
  3. * device functionality on Windows.
  4. *
  5. * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
  6. *
  7. * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
  8. * and is released under the GPL version 2 (see below).
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program (see the file COPYING included with this
  21. * distribution); if not, write to the Free Software Foundation, Inc.,
  22. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. //------------------
  25. // Memory Management
  26. //------------------
  27. #include "tap.h"
  28. PVOID
  29. MemAlloc(
  30. __in ULONG p_Size,
  31. __in BOOLEAN zero
  32. )
  33. {
  34. PVOID l_Return = NULL;
  35. if (p_Size)
  36. {
  37. __try
  38. {
  39. if (NdisAllocateMemoryWithTag (&l_Return, p_Size, 'APAT')
  40. == NDIS_STATUS_SUCCESS)
  41. {
  42. if (zero)
  43. {
  44. NdisZeroMemory (l_Return, p_Size);
  45. }
  46. }
  47. else
  48. {
  49. l_Return = NULL;
  50. }
  51. }
  52. __except (EXCEPTION_EXECUTE_HANDLER)
  53. {
  54. l_Return = NULL;
  55. }
  56. }
  57. return l_Return;
  58. }
  59. VOID
  60. MemFree(
  61. __in PVOID p_Addr,
  62. __in ULONG p_Size
  63. )
  64. {
  65. if (p_Addr && p_Size)
  66. {
  67. __try
  68. {
  69. #if DBG
  70. NdisZeroMemory (p_Addr, p_Size);
  71. #endif
  72. NdisFreeMemory (p_Addr, p_Size, 0);
  73. }
  74. __except (EXCEPTION_EXECUTE_HANDLER)
  75. {
  76. }
  77. }
  78. }
  79. //======================================================================
  80. // TAP Packet Queue Support
  81. //======================================================================
  82. VOID
  83. tapPacketQueueInsertTail(
  84. __in PTAP_PACKET_QUEUE TapPacketQueue,
  85. __in PTAP_PACKET TapPacket
  86. )
  87. {
  88. KIRQL irql;
  89. KeAcquireSpinLock(&TapPacketQueue->QueueLock,&irql);
  90. InsertTailList(&TapPacketQueue->Queue,&TapPacket->QueueLink);
  91. // BUGBUG!!! Enforce PACKET_QUEUE_SIZE queue count limit???
  92. // For NDIS 6 there is no per-packet status, so this will need to
  93. // be handled on per-NBL basis in AdapterSendNetBufferLists...
  94. // Update counts
  95. ++TapPacketQueue->Count;
  96. if(TapPacketQueue->Count > TapPacketQueue->MaxCount)
  97. {
  98. TapPacketQueue->MaxCount = TapPacketQueue->Count;
  99. DEBUGP (("[TAP] tapPacketQueueInsertTail: New MAX queued packet count = %d\n",
  100. TapPacketQueue->MaxCount));
  101. }
  102. KeReleaseSpinLock(&TapPacketQueue->QueueLock,irql);
  103. }
  104. // Call with QueueLock held
  105. PTAP_PACKET
  106. tapPacketRemoveHeadLocked(
  107. __in PTAP_PACKET_QUEUE TapPacketQueue
  108. )
  109. {
  110. PTAP_PACKET tapPacket = NULL;
  111. PLIST_ENTRY listEntry;
  112. listEntry = RemoveHeadList(&TapPacketQueue->Queue);
  113. if(listEntry != &TapPacketQueue->Queue)
  114. {
  115. tapPacket = CONTAINING_RECORD(listEntry, TAP_PACKET, QueueLink);
  116. // Update counts
  117. --TapPacketQueue->Count;
  118. }
  119. return tapPacket;
  120. }
  121. PTAP_PACKET
  122. tapPacketRemoveHead(
  123. __in PTAP_PACKET_QUEUE TapPacketQueue
  124. )
  125. {
  126. PTAP_PACKET tapPacket = NULL;
  127. KIRQL irql;
  128. KeAcquireSpinLock(&TapPacketQueue->QueueLock,&irql);
  129. tapPacket = tapPacketRemoveHeadLocked(TapPacketQueue);
  130. KeReleaseSpinLock(&TapPacketQueue->QueueLock,irql);
  131. return tapPacket;
  132. }
  133. VOID
  134. tapPacketQueueInitialize(
  135. __in PTAP_PACKET_QUEUE TapPacketQueue
  136. )
  137. {
  138. KeInitializeSpinLock(&TapPacketQueue->QueueLock);
  139. NdisInitializeListHead(&TapPacketQueue->Queue);
  140. }
  141. //======================================================================
  142. // TAP Cancel-Safe Queue Support
  143. //======================================================================
  144. VOID
  145. tapIrpCsqInsert (
  146. __in struct _IO_CSQ *Csq,
  147. __in PIRP Irp
  148. )
  149. {
  150. PTAP_IRP_CSQ tapIrpCsq;
  151. tapIrpCsq = (PTAP_IRP_CSQ )Csq;
  152. InsertTailList(
  153. &tapIrpCsq->Queue,
  154. &Irp->Tail.Overlay.ListEntry
  155. );
  156. // Update counts
  157. ++tapIrpCsq->Count;
  158. if(tapIrpCsq->Count > tapIrpCsq->MaxCount)
  159. {
  160. tapIrpCsq->MaxCount = tapIrpCsq->Count;
  161. DEBUGP (("[TAP] tapIrpCsqInsert: New MAX queued IRP count = %d\n",
  162. tapIrpCsq->MaxCount));
  163. }
  164. }
  165. VOID
  166. tapIrpCsqRemoveIrp(
  167. __in PIO_CSQ Csq,
  168. __in PIRP Irp
  169. )
  170. {
  171. PTAP_IRP_CSQ tapIrpCsq;
  172. tapIrpCsq = (PTAP_IRP_CSQ )Csq;
  173. // Update counts
  174. --tapIrpCsq->Count;
  175. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  176. }
  177. PIRP
  178. tapIrpCsqPeekNextIrp(
  179. __in PIO_CSQ Csq,
  180. __in PIRP Irp,
  181. __in PVOID PeekContext
  182. )
  183. {
  184. PTAP_IRP_CSQ tapIrpCsq;
  185. PIRP nextIrp = NULL;
  186. PLIST_ENTRY nextEntry;
  187. PLIST_ENTRY listHead;
  188. PIO_STACK_LOCATION irpStack;
  189. tapIrpCsq = (PTAP_IRP_CSQ )Csq;
  190. listHead = &tapIrpCsq->Queue;
  191. //
  192. // If the IRP is NULL, we will start peeking from the listhead, else
  193. // we will start from that IRP onwards. This is done under the
  194. // assumption that new IRPs are always inserted at the tail.
  195. //
  196. if (Irp == NULL)
  197. {
  198. nextEntry = listHead->Flink;
  199. }
  200. else
  201. {
  202. nextEntry = Irp->Tail.Overlay.ListEntry.Flink;
  203. }
  204. while(nextEntry != listHead)
  205. {
  206. nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry);
  207. irpStack = IoGetCurrentIrpStackLocation(nextIrp);
  208. //
  209. // If context is present, continue until you find a matching one.
  210. // Else you break out as you got next one.
  211. //
  212. if (PeekContext)
  213. {
  214. if (irpStack->FileObject == (PFILE_OBJECT) PeekContext)
  215. {
  216. break;
  217. }
  218. }
  219. else
  220. {
  221. break;
  222. }
  223. nextIrp = NULL;
  224. nextEntry = nextEntry->Flink;
  225. }
  226. return nextIrp;
  227. }
  228. //
  229. // tapIrpCsqAcquireQueueLock modifies the execution level of the current processor.
  230. //
  231. // KeAcquireSpinLock raises the execution level to Dispatch Level and stores
  232. // the current execution level in the Irql parameter to be restored at a later
  233. // time. KeAcqurieSpinLock also requires us to be running at no higher than
  234. // Dispatch level when it is called.
  235. //
  236. // The annotations reflect these changes and requirments.
  237. //
  238. __drv_raisesIRQL(DISPATCH_LEVEL)
  239. __drv_maxIRQL(DISPATCH_LEVEL)
  240. VOID
  241. tapIrpCsqAcquireQueueLock(
  242. __in PIO_CSQ Csq,
  243. __out PKIRQL Irql
  244. )
  245. {
  246. PTAP_IRP_CSQ tapIrpCsq;
  247. tapIrpCsq = (PTAP_IRP_CSQ )Csq;
  248. //
  249. // Suppressing because the address below csq is valid since it's
  250. // part of TAP_ADAPTER_CONTEXT structure.
  251. //
  252. #pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'adapter->PendingReadCsqQueueLock'")
  253. KeAcquireSpinLock(&tapIrpCsq->QueueLock, Irql);
  254. }
  255. //
  256. // tapIrpCsqReleaseQueueLock modifies the execution level of the current processor.
  257. //
  258. // KeReleaseSpinLock assumes we already hold the spin lock and are therefore
  259. // running at Dispatch level. It will use the Irql parameter saved in a
  260. // previous call to KeAcquireSpinLock to return the thread back to it's original
  261. // execution level.
  262. //
  263. // The annotations reflect these changes and requirments.
  264. //
  265. __drv_requiresIRQL(DISPATCH_LEVEL)
  266. VOID
  267. tapIrpCsqReleaseQueueLock(
  268. __in PIO_CSQ Csq,
  269. __in KIRQL Irql
  270. )
  271. {
  272. PTAP_IRP_CSQ tapIrpCsq;
  273. tapIrpCsq = (PTAP_IRP_CSQ )Csq;
  274. //
  275. // Suppressing because the address below csq is valid since it's
  276. // part of TAP_ADAPTER_CONTEXT structure.
  277. //
  278. #pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'adapter->PendingReadCsqQueueLock'")
  279. KeReleaseSpinLock(&tapIrpCsq->QueueLock, Irql);
  280. }
  281. VOID
  282. tapIrpCsqCompleteCanceledIrp(
  283. __in PIO_CSQ pCsq,
  284. __in PIRP Irp
  285. )
  286. {
  287. UNREFERENCED_PARAMETER(pCsq);
  288. Irp->IoStatus.Status = STATUS_CANCELLED;
  289. Irp->IoStatus.Information = 0;
  290. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  291. }
  292. VOID
  293. tapIrpCsqInitialize(
  294. __in PTAP_IRP_CSQ TapIrpCsq
  295. )
  296. {
  297. KeInitializeSpinLock(&TapIrpCsq->QueueLock);
  298. NdisInitializeListHead(&TapIrpCsq->Queue);
  299. IoCsqInitialize(
  300. &TapIrpCsq->CsqQueue,
  301. tapIrpCsqInsert,
  302. tapIrpCsqRemoveIrp,
  303. tapIrpCsqPeekNextIrp,
  304. tapIrpCsqAcquireQueueLock,
  305. tapIrpCsqReleaseQueueLock,
  306. tapIrpCsqCompleteCanceledIrp
  307. );
  308. }
  309. VOID
  310. tapIrpCsqFlush(
  311. __in PTAP_IRP_CSQ TapIrpCsq
  312. )
  313. {
  314. PIRP pendingIrp;
  315. //
  316. // Flush the pending read IRP queue.
  317. //
  318. pendingIrp = IoCsqRemoveNextIrp(
  319. &TapIrpCsq->CsqQueue,
  320. NULL
  321. );
  322. while(pendingIrp)
  323. {
  324. // Cancel the IRP
  325. pendingIrp->IoStatus.Information = 0;
  326. pendingIrp->IoStatus.Status = STATUS_CANCELLED;
  327. IoCompleteRequest(pendingIrp, IO_NO_INCREMENT);
  328. pendingIrp = IoCsqRemoveNextIrp(
  329. &TapIrpCsq->CsqQueue,
  330. NULL
  331. );
  332. }
  333. ASSERT(IsListEmpty(&TapIrpCsq->Queue));
  334. }