PageRenderTime 30ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/See/Write.c

https://gitlab.com/benjdag/SoftEtherVPN
C | 426 lines | 234 code | 107 blank | 85 comment | 39 complexity | 516eb1a9214bef6b94032336e7c3c3f7 MD5 | raw file
  1. /*
  2. * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
  3. * Copyright (c) 2005 CACE Technologies, Davis (California)
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the Politecnico di Torino, CACE Technologies
  16. * nor the names of its contributors may be used to endorse or promote
  17. * products derived from this software without specific prior written
  18. * permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. */
  33. #include <GlobalConst.h>
  34. #include "stdarg.h"
  35. #include "ntddk.h"
  36. #include "ntiologc.h"
  37. #include "ndis.h"
  38. #include "debug.h"
  39. #include "packet.h"
  40. void *test_addr = NULL;
  41. //-------------------------------------------------------------------
  42. NTSTATUS
  43. NPF_Write(
  44. IN PDEVICE_OBJECT DeviceObject,
  45. IN PIRP Irp
  46. )
  47. {
  48. POPEN_INSTANCE Open;
  49. PIO_STACK_LOCATION IrpSp;
  50. PNDIS_PACKET pPacket;
  51. UINT i;
  52. NDIS_STATUS Status;
  53. IF_LOUD(DbgPrint("NPF_Write\n");)
  54. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  55. Open=IrpSp->FileObject->FsContext;
  56. if( Open->Bound == FALSE )
  57. {
  58. // The Network adapter was removed.
  59. EXIT_FAILURE(0);
  60. }
  61. NdisAcquireSpinLock(&Open->WriteLock);
  62. if(Open->WriteInProgress)
  63. {
  64. // Another write operation is currently in progress
  65. NdisReleaseSpinLock(&Open->WriteLock);
  66. EXIT_FAILURE(0);
  67. }
  68. else
  69. {
  70. Open->WriteInProgress = TRUE;
  71. }
  72. NdisReleaseSpinLock(&Open->WriteLock);
  73. IF_LOUD(DbgPrint("Max frame size = %d, packet size = %d\n", Open->MaxFrameSize, IrpSp->Parameters.Write.Length);)
  74. if(IrpSp->Parameters.Write.Length == 0 || // Check that the buffer provided by the user is not empty
  75. Open->MaxFrameSize == 0/* || // Check that the MaxFrameSize is correctly initialized
  76. IrpSp->Parameters.Write.Length > Open->MaxFrameSize*/) // Check that the fame size is smaller that the MTU
  77. {
  78. IF_LOUD(DbgPrint("frame size out of range, send aborted\n");)
  79. EXIT_FAILURE(0);
  80. }
  81. IoMarkIrpPending(Irp);
  82. Open->Multiple_Write_Counter=Open->Nwrites;
  83. NdisResetEvent(&Open->WriteEvent);
  84. for(i=0;i<Open->Nwrites;i++){
  85. // Try to get a packet from our list of free ones
  86. NdisAllocatePacket(
  87. &Status,
  88. &pPacket,
  89. Open->PacketPool
  90. );
  91. if (Status != NDIS_STATUS_SUCCESS) {
  92. // No free packets
  93. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  94. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  95. return STATUS_INSUFFICIENT_RESOURCES;
  96. }
  97. if(Open->SkipSentPackets)
  98. {
  99. NdisSetPacketFlags(
  100. pPacket,
  101. g_SendPacketFlags);
  102. }
  103. // The packet hasn't a buffer that needs not to be freed after every single write
  104. RESERVED(pPacket)->FreeBufAfterWrite = FALSE;
  105. // Save the IRP associated with the packet
  106. RESERVED(pPacket)->Irp=Irp;
  107. // Attach the writes buffer to the packet
  108. NdisChainBufferAtFront(pPacket,Irp->MdlAddress);
  109. test_addr = MmGetMdlVirtualAddress(Irp->MdlAddress);
  110. // Call the MAC
  111. NdisSend(
  112. &Status,
  113. Open->AdapterHandle,
  114. pPacket);
  115. if (Status != NDIS_STATUS_PENDING) {
  116. // The send didn't pend so call the completion handler now
  117. NPF_SendComplete(
  118. Open,
  119. pPacket,
  120. Status
  121. );
  122. }
  123. if(i%100==99){
  124. NdisWaitEvent(&Open->WriteEvent,1000);
  125. NdisResetEvent(&Open->WriteEvent);
  126. }
  127. }
  128. return(STATUS_PENDING);
  129. }
  130. //-------------------------------------------------------------------
  131. INT
  132. NPF_BufferedWrite(
  133. IN PIRP Irp,
  134. IN PCHAR UserBuff,
  135. IN ULONG UserBuffSize,
  136. BOOLEAN Sync)
  137. {
  138. POPEN_INSTANCE Open;
  139. PIO_STACK_LOCATION IrpSp;
  140. PNDIS_PACKET pPacket;
  141. NDIS_STATUS Status;
  142. struct sf_pkthdr *winpcap_hdr;
  143. PMDL TmpMdl;
  144. PCHAR EndOfUserBuff = UserBuff + UserBuffSize;
  145. IF_LOUD(DbgPrint("NPF: BufferedWrite, UserBuff=%x, Size=%u\n", UserBuff, UserBuffSize);)
  146. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  147. Open=IrpSp->FileObject->FsContext;
  148. if( Open->Bound == FALSE ){
  149. // The Network adapter was removed.
  150. return 0;
  151. }
  152. // Sanity check on the user buffer
  153. if(UserBuff == NULL)
  154. {
  155. return 0;
  156. }
  157. // Check that the MaxFrameSize is correctly initialized
  158. if(Open->MaxFrameSize == 0)
  159. {
  160. IF_LOUD(DbgPrint("BufferedWrite: Open->MaxFrameSize not initialized, probably because of a problem in the OID query\n");)
  161. return 0;
  162. }
  163. // Reset the event used to synchronize packet allocation
  164. NdisResetEvent(&Open->WriteEvent);
  165. // Reset the pending packets counter
  166. Open->Multiple_Write_Counter = 0;
  167. // Start from the first packet
  168. winpcap_hdr = (struct sf_pkthdr*)UserBuff;
  169. // Chech the consistency of the user buffer
  170. if( (PCHAR)winpcap_hdr + winpcap_hdr->caplen + sizeof(struct sf_pkthdr) > EndOfUserBuff )
  171. {
  172. IF_LOUD(DbgPrint("Buffered Write: bogus packet buffer\n");)
  173. return -1;
  174. }
  175. //
  176. // Main loop: send the buffer to the wire
  177. //
  178. while(TRUE)
  179. {
  180. if(winpcap_hdr->caplen ==0/* || winpcap_hdr->caplen > Open->MaxFrameSize*/)
  181. {
  182. // Malformed header
  183. IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");)
  184. return -1;
  185. }
  186. // Allocate an MDL to map the packet data
  187. TmpMdl = IoAllocateMdl((PCHAR)winpcap_hdr + sizeof(struct sf_pkthdr),
  188. winpcap_hdr->caplen,
  189. FALSE,
  190. FALSE,
  191. NULL);
  192. if (TmpMdl == NULL)
  193. {
  194. // Unable to map the memory: packet lost
  195. IF_LOUD(DbgPrint("NPF_BufferedWrite: unable to allocate the MDL.\n");)
  196. return -1;
  197. }
  198. MmBuildMdlForNonPagedPool(TmpMdl); // XXX can this line be removed?
  199. // Allocate a packet from our free list
  200. NdisAllocatePacket( &Status, &pPacket, Open->PacketPool);
  201. if (Status != NDIS_STATUS_SUCCESS) {
  202. // No more free packets
  203. IF_LOUD(DbgPrint("NPF_BufferedWrite: no more free packets, returning.\n");)
  204. NdisResetEvent(&Open->WriteEvent);
  205. NdisWaitEvent(&Open->WriteEvent, 1000);
  206. // Try again to allocate a packet
  207. NdisAllocatePacket( &Status, &pPacket, Open->PacketPool);
  208. if (Status != NDIS_STATUS_SUCCESS) {
  209. // Second failure, report an error
  210. IoFreeMdl(TmpMdl);
  211. return -1;
  212. }
  213. // IoFreeMdl(TmpMdl);
  214. // return (PCHAR)winpcap_hdr - UserBuff;
  215. }
  216. if(Open->SkipSentPackets)
  217. {
  218. NdisSetPacketFlags(
  219. pPacket,
  220. g_SendPacketFlags);
  221. }
  222. // The packet has a buffer that needs to be freed after every single write
  223. RESERVED(pPacket)->FreeBufAfterWrite = TRUE;
  224. TmpMdl->Next = NULL;
  225. // Attach the MDL to the packet
  226. NdisChainBufferAtFront(pPacket, TmpMdl);
  227. // Increment the number of pending sends
  228. InterlockedIncrement(&Open->Multiple_Write_Counter);
  229. // Call the MAC
  230. NdisSend( &Status, Open->AdapterHandle, pPacket);
  231. if (Status != NDIS_STATUS_PENDING) {
  232. // The send didn't pend so call the completion handler now
  233. NPF_SendComplete(
  234. Open,
  235. pPacket,
  236. Status
  237. );
  238. }
  239. // Step to the next packet in the buffer
  240. (PCHAR)winpcap_hdr += winpcap_hdr->caplen + sizeof(struct sf_pkthdr);
  241. // Check if the end of the user buffer has been reached
  242. if( (PCHAR)winpcap_hdr >= EndOfUserBuff )
  243. {
  244. IF_LOUD(DbgPrint("NPF_BufferedWrite: End of buffer.\n");)
  245. // Wait the completion of pending sends
  246. NPF_WaitEndOfBufferedWrite(Open);
  247. return (INT)((PCHAR)winpcap_hdr - UserBuff);
  248. }
  249. }
  250. return (INT)((PCHAR)winpcap_hdr - UserBuff);
  251. }
  252. //-------------------------------------------------------------------
  253. VOID NPF_WaitEndOfBufferedWrite(POPEN_INSTANCE Open)
  254. {
  255. UINT i;
  256. NdisResetEvent(&Open->WriteEvent);
  257. for(i=0; Open->Multiple_Write_Counter > 0 && i < TRANSMIT_PACKETS; i++)
  258. {
  259. NdisWaitEvent(&Open->WriteEvent, 100);
  260. NdisResetEvent(&Open->WriteEvent);
  261. }
  262. return;
  263. }
  264. //-------------------------------------------------------------------
  265. VOID
  266. NPF_SendComplete(
  267. IN NDIS_HANDLE ProtocolBindingContext,
  268. IN PNDIS_PACKET pPacket,
  269. IN NDIS_STATUS Status
  270. )
  271. {
  272. PIRP Irp;
  273. PIO_STACK_LOCATION irpSp;
  274. POPEN_INSTANCE Open;
  275. PMDL TmpMdl;
  276. IF_LOUD(DbgPrint("NPF: SendComplete, BindingContext=%d\n",ProtocolBindingContext);)
  277. Open= (POPEN_INSTANCE)ProtocolBindingContext;
  278. if( RESERVED(pPacket)->FreeBufAfterWrite )
  279. {
  280. //
  281. // Packet sent by NPF_BufferedWrite()
  282. //
  283. // Free the MDL associated with the packet
  284. NdisUnchainBufferAtFront(pPacket, &TmpMdl);
  285. IoFreeMdl(TmpMdl);
  286. // recyle the packet
  287. // NdisReinitializePacket(pPacket);
  288. NdisFreePacket(pPacket);
  289. // Increment the number of pending sends
  290. InterlockedDecrement(&Open->Multiple_Write_Counter);
  291. NdisSetEvent(&Open->WriteEvent);
  292. return;
  293. }
  294. else
  295. {
  296. //
  297. // Packet sent by NPF_Write()
  298. //
  299. if((Open->Nwrites - Open->Multiple_Write_Counter) %100 == 99)
  300. NdisSetEvent(&Open->WriteEvent);
  301. Open->Multiple_Write_Counter--;
  302. if(Open->Multiple_Write_Counter == 0){
  303. // Release the buffer and awake the application
  304. NdisUnchainBufferAtFront(pPacket, &TmpMdl);
  305. // Complete the request
  306. Irp=RESERVED(pPacket)->Irp;
  307. irpSp = IoGetCurrentIrpStackLocation(Irp);
  308. Irp->IoStatus.Status = Status;
  309. Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
  310. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  311. NdisAcquireSpinLock(&Open->WriteLock);
  312. Open->WriteInProgress = FALSE;
  313. NdisReleaseSpinLock(&Open->WriteLock);
  314. }
  315. // Put the packet back on the free list
  316. NdisFreePacket(pPacket);
  317. return;
  318. }
  319. }