branch update for HEAD-2003021201
[reactos.git] / drivers / net / packet / write.c
1 /*
2  * Copyright (c) 1999, 2000
3  *      Politecnico di Torino.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the Politecnico
13  * di Torino, and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21
22 #ifdef _MSC_VER
23 #include "stdarg.h"
24 #include "ntddk.h"
25 #include "ntiologc.h"
26 #include "ndis.h"
27 #else
28 #include <ddk/ntddk.h>
29 #include <net/ndis.h>
30 #define NdisReinitializePacket(Packet)                                                                          \
31 {                                                                                                                                                       \
32         (Packet)->Private.Head = (PNDIS_BUFFER)NULL;                                                    \
33         (Packet)->Private.ValidCounts = FALSE;                                                                  \
34 }
35
36 #endif
37
38 #include "debug.h"
39 #include "packet.h"
40
41
42 //-------------------------------------------------------------------
43
44 NTSTATUS
45 NPF_Write(
46     IN PDEVICE_OBJECT DeviceObject,
47     IN PIRP Irp
48     )
49
50 {
51     POPEN_INSTANCE              Open;
52     PIO_STACK_LOCATION  IrpSp;
53     PNDIS_PACKET                pPacket;
54         UINT                            i;
55     NDIS_STATUS             Status;
56
57         IF_LOUD(DbgPrint("NPF_Write\n");)
58
59     IrpSp = IoGetCurrentIrpStackLocation(Irp);
60
61
62     Open=IrpSp->FileObject->FsContext;
63
64         IF_LOUD(DbgPrint("Max frame size = %d\n", Open->MaxFrameSize);)
65
66
67         if(IrpSp->Parameters.Write.Length == 0 ||       // Check that the buffer provided by the user is not empty
68                 Open->MaxFrameSize == 0 ||      // Check that the MaxFrameSize is correctly initialized
69                 IrpSp->Parameters.Write.Length > Open->MaxFrameSize) // Check that the fame size is smaller that the MTU
70         {
71                 IF_LOUD(DbgPrint("frame size out of range, send aborted\n");)
72
73         Irp->IoStatus.Status = NDIS_STATUS_SUCCESS;
74         IoCompleteRequest (Irp, IO_NO_INCREMENT);
75         return NDIS_STATUS_SUCCESS;
76         }
77
78
79     IoMarkIrpPending(Irp);
80
81         Open->Multiple_Write_Counter=Open->Nwrites;
82
83         NdisResetEvent(&Open->WriteEvent);
84
85
86         for(i=0;i<Open->Nwrites;i++){
87                 
88                 //  Try to get a packet from our list of free ones
89                 NdisAllocatePacket(
90                         &Status,
91                         &pPacket,
92                         Open->PacketPool
93                         );
94                 
95                 if (Status != NDIS_STATUS_SUCCESS) {
96                         
97                         //  No free packets
98                         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
99                         IoCompleteRequest (Irp, IO_NO_INCREMENT);
100                         return STATUS_INSUFFICIENT_RESOURCES;
101                 }
102                 
103                 // The packet has a buffer that needs not to be freed after every single write
104                 RESERVED(pPacket)->FreeBufAfterWrite = FALSE;
105
106                 // Save the IRP associated with the packet
107                 RESERVED(pPacket)->Irp=Irp;
108                 
109                 //  Attach the writes buffer to the packet
110                 NdisChainBufferAtFront(pPacket,Irp->MdlAddress);
111                 
112                 //  Call the MAC
113                 NdisSend(
114                         &Status,
115                         Open->AdapterHandle,
116                         pPacket);
117
118                 if (Status != NDIS_STATUS_PENDING) {
119                         //  The send didn't pend so call the completion handler now
120                         NPF_SendComplete(
121                                 Open,
122                                 pPacket,
123                                 Status
124                                 );
125                         
126                 }
127                 
128                 if(i%100==99){
129                         NdisWaitEvent(&Open->WriteEvent,1000);  
130                         NdisResetEvent(&Open->WriteEvent);
131                 }
132         }
133         
134     return(STATUS_PENDING);
135
136 }
137
138
139 //-------------------------------------------------------------------
140
141 INT
142 NPF_BufferedWrite(
143         IN PIRP Irp, 
144         IN PCHAR UserBuff, 
145         IN ULONG UserBuffSize, 
146         BOOLEAN Sync)
147 {
148     POPEN_INSTANCE              Open;
149     PIO_STACK_LOCATION  IrpSp;
150     PNDIS_PACKET                pPacket;
151         UINT                            i;
152     NDIS_STATUS             Status;
153         LARGE_INTEGER           StartTicks, CurTicks, TargetTicks;
154         LARGE_INTEGER           TimeFreq;
155         struct timeval          BufStartTime;
156         struct sf_pkthdr        *winpcap_hdr;
157         PMDL                            TmpMdl;
158         PCHAR                           CurPos;
159         PCHAR                           EndOfUserBuff = UserBuff + UserBuffSize;
160         
161     IF_LOUD(DbgPrint("NPF: BufferedWrite, UserBuff=%x, Size=%u\n", UserBuff, UserBuffSize);)
162                 
163         IrpSp = IoGetCurrentIrpStackLocation(Irp);
164         
165     Open=IrpSp->FileObject->FsContext;
166         
167         // Security check on the length of the user buffer
168         if(UserBuff==0)
169         {
170                 return 0;
171         }
172                 
173         // Check that the MaxFrameSize is correctly initialized
174         if(Open->MaxFrameSize == 0)
175         {
176                 IF_LOUD(DbgPrint("BufferedWrite: Open->MaxFrameSize not initialized, probably because of a problem in the OID query\n");)
177
178                 return 0;
179         }
180
181         
182         // Start from the first packet
183         winpcap_hdr = (struct sf_pkthdr*)UserBuff;
184         
185         // Retrieve the time references
186         StartTicks = KeQueryPerformanceCounter(&TimeFreq);
187         BufStartTime.tv_sec = winpcap_hdr->ts.tv_sec;
188         BufStartTime.tv_usec = winpcap_hdr->ts.tv_usec;
189         
190         // Chech the consistency of the user buffer
191         if( (PCHAR)winpcap_hdr + winpcap_hdr->caplen + sizeof(struct sf_pkthdr) > EndOfUserBuff )
192         {
193                 IF_LOUD(DbgPrint("Buffered Write: bogus packet buffer\n");)
194
195                 return -1;
196         }
197         
198         // Save the current time stamp counter
199         CurTicks = KeQueryPerformanceCounter(NULL);
200         
201         // Main loop: send the buffer to the wire
202         while( TRUE ){
203                 
204                 if(winpcap_hdr->caplen ==0 || winpcap_hdr->caplen > Open->MaxFrameSize)
205                 {
206                         // Malformed header
207                         IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");)
208                         
209                         return -1;
210                 }
211                 
212                 // Allocate an MDL to map the packet data
213                 TmpMdl=IoAllocateMdl((PCHAR)winpcap_hdr + sizeof(struct sf_pkthdr),
214                         winpcap_hdr->caplen,
215                         FALSE,
216                         FALSE,
217                         NULL);
218                 
219                 if (TmpMdl == NULL)
220                 {
221                         // Unable to map the memory: packet lost
222                         IF_LOUD(DbgPrint("NPF_BufferedWrite: unable to allocate the MDL.\n");)
223
224                         return -1;
225                 }
226                 
227                 MmBuildMdlForNonPagedPool(TmpMdl);      // XXX can this line be removed?
228                 
229                 // Allocate a packet from our free list
230                 NdisAllocatePacket( &Status, &pPacket, Open->PacketPool);
231                 
232                 if (Status != NDIS_STATUS_SUCCESS) {
233                         //  No free packets
234                         IF_LOUD(DbgPrint("NPF_BufferedWrite: no more free packets, returning.\n");)
235
236                         return (PCHAR)winpcap_hdr - UserBuff;
237                 }
238                 
239                 // The packet has a buffer that needs to be freed after every single write
240                 RESERVED(pPacket)->FreeBufAfterWrite = TRUE;
241                 
242                 // Attach the MDL to the packet
243                 NdisChainBufferAtFront(pPacket,TmpMdl);
244                 
245                 // Call the MAC
246                 NdisSend( &Status, Open->AdapterHandle, pPacket);
247                 
248                 if (Status != NDIS_STATUS_PENDING) {
249                         // The send didn't pend so call the completion handler now
250                         NPF_SendComplete(
251                                 Open,
252                                 pPacket,
253                                 Status
254                                 );                              
255                 }
256                 
257                 // Step to the next packet in the buffer
258                 (PCHAR)winpcap_hdr += winpcap_hdr->caplen + sizeof(struct sf_pkthdr);
259                 
260                 // Check if the end of the user buffer has been reached
261                 if( (PCHAR)winpcap_hdr >= EndOfUserBuff )
262                 {
263                         IF_LOUD(DbgPrint("NPF_BufferedWrite: End of buffer.\n");)
264
265                         return (PCHAR)winpcap_hdr - UserBuff;
266                 }
267                 
268                 if( Sync ){
269
270                         // Release the application if it has been blocked for approximately more than 1 seconds
271                         if( winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec > 1 )
272                         {
273                                 IF_LOUD(DbgPrint("NPF_BufferedWrite: timestamp elapsed, returning.\n");)
274                                         
275                                 return (PCHAR)winpcap_hdr - UserBuff;
276                         }
277                         
278 #ifndef __GNUC__
279                         // Calculate the time interval to wait before sending the next packet
280             TargetTicks.QuadPart = StartTicks.QuadPart +
281                                 (LONGLONG)((winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec) * 1000000 +
282                                 winpcap_hdr->ts.tv_usec - BufStartTime.tv_usec) *
283                                 (TimeFreq.QuadPart) / 1000000;
284
285                         // Wait until the time interval has elapsed
286                         while( CurTicks.QuadPart <= TargetTicks.QuadPart )
287                                 CurTicks = KeQueryPerformanceCounter(NULL);
288 #else
289 #endif
290                 }
291                 
292         }
293                         
294         return (PCHAR)winpcap_hdr - UserBuff;
295                 
296 }
297
298
299 //-------------------------------------------------------------------
300
301 VOID
302 NPF_SendComplete(
303                                    IN NDIS_HANDLE   ProtocolBindingContext,
304                                    IN PNDIS_PACKET  pPacket,
305                                    IN NDIS_STATUS   Status
306                                    )
307                                    
308 {
309         PIRP              Irp;
310         PIO_STACK_LOCATION  irpSp;
311         POPEN_INSTANCE      Open;
312         PMDL TmpMdl;
313         
314         IF_LOUD(DbgPrint("NPF: SendComplete, BindingContext=%d\n",ProtocolBindingContext);)
315                 
316         Open= (POPEN_INSTANCE)ProtocolBindingContext;
317         
318         if( RESERVED(pPacket)->FreeBufAfterWrite ){
319                 // Free the MDL associated with the packet
320                 NdisUnchainBufferAtFront(pPacket, &TmpMdl);
321                 IoFreeMdl(TmpMdl);
322         }
323         else{
324                 if((Open->Nwrites - Open->Multiple_Write_Counter) %100 == 99)
325                         NdisSetEvent(&Open->WriteEvent);
326                 
327                 Open->Multiple_Write_Counter--;
328         }
329         
330         //  recyle the packet
331         NdisReinitializePacket(pPacket);
332         
333         //  Put the packet back on the free list
334         NdisFreePacket(pPacket);
335         
336         if( !(RESERVED(pPacket)->FreeBufAfterWrite) ){
337                 if(Open->Multiple_Write_Counter==0){
338                         // Release the buffer and awake the application
339                         NdisUnchainBufferAtFront(pPacket, &TmpMdl);
340                         
341                         Irp=RESERVED(pPacket)->Irp;
342                         irpSp = IoGetCurrentIrpStackLocation(Irp);
343
344                         Irp->IoStatus.Status = Status;
345                         Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
346                         IoCompleteRequest(Irp, IO_NO_INCREMENT);
347                         
348                 }
349         }
350
351         return;
352 }
353
354
355 #ifdef __GNUC__
356 /*
357 __divdi3()
358 {
359     //_alldiv();
360 }
361
362 //_allmul();
363 //_allrem();
364
365 */
366 #endif