6c857a85a3a3be05f5e775aed353b10d9515f3e4
[reactos.git] / drivers / net / packet / openclos.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 "ntddk.h"
24 #include "ntiologc.h"
25 #include "ndis.h"
26 #else
27 #include <ddk/ntddk.h>
28 #include <net/ndis.h>
29 #endif
30 #include "debug.h"
31 #include "packet.h"
32
33 static NDIS_MEDIUM MediumArray[] = {
34         NdisMedium802_3,
35         NdisMediumWan,
36         NdisMediumFddi,
37         NdisMediumArcnet878_2,
38         NdisMediumAtm,
39         NdisMedium802_5
40 };
41
42 #define NUM_NDIS_MEDIA  (sizeof MediumArray / sizeof MediumArray[0])
43
44 ULONG NamedEventsCounter=0;
45
46 //Itoa. Replaces the buggy RtlIntegerToUnicodeString
47 void PacketItoa(UINT n,PUCHAR buf){
48 int i;
49
50         for(i=0;i<20;i+=2){
51                 buf[18-i]=(n%10)+48;
52                 buf[19-i]=0;
53                 n/=10;
54         }
55
56 }
57
58 /// Global start time. Used as an absolute reference for timestamp conversion.
59 struct time_conv G_Start_Time = {
60         0,      
61         {0, 0}, 
62 };
63
64 UINT n_Opened_Instances = 0;
65
66 NDIS_SPIN_LOCK Opened_Instances_Lock;
67
68 //-------------------------------------------------------------------
69
70 NTSTATUS
71 NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
72 {
73
74     PDEVICE_EXTENSION DeviceExtension;
75
76     POPEN_INSTANCE    Open;
77
78     PIO_STACK_LOCATION  IrpSp;
79
80     NDIS_STATUS     Status;
81     NDIS_STATUS     ErrorStatus;
82     UINT            i;
83         PUCHAR                  tpointer;
84     PLIST_ENTRY     PacketListEntry;
85         PCHAR                   EvName;
86
87
88     IF_LOUD(DbgPrint("NPF: OpenAdapter\n");)
89
90     DeviceExtension = DeviceObject->DeviceExtension;
91
92
93     IrpSp = IoGetCurrentIrpStackLocation(Irp);
94
95     //  allocate some memory for the open structure
96     Open=ExAllocatePoolWithTag(NonPagedPool, sizeof(OPEN_INSTANCE), '0OWA');
97
98
99     if (Open==NULL) {
100         // no memory
101         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
102         IoCompleteRequest(Irp, IO_NO_INCREMENT);
103         return STATUS_INSUFFICIENT_RESOURCES;
104     }
105
106     RtlZeroMemory(
107         Open,
108         sizeof(OPEN_INSTANCE)
109         );
110
111
112         EvName=ExAllocatePoolWithTag(NonPagedPool, sizeof(L"\\BaseNamedObjects\\NPF0000000000"), '1OWA');
113
114     if (EvName==NULL) {
115         // no memory
116         ExFreePool(Open);
117             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
118         IoCompleteRequest(Irp, IO_NO_INCREMENT);
119         return STATUS_INSUFFICIENT_RESOURCES;
120     }
121
122     //  Save or open here
123     IrpSp->FileObject->FsContext=Open;
124         
125     Open->DeviceExtension=DeviceExtension;
126         
127         
128     //  Save the Irp here for the completeion routine to retrieve
129     Open->OpenCloseIrp=Irp;
130         
131     //  Allocate a packet pool for our xmit and receive packets
132     NdisAllocatePacketPool(
133         &Status,
134         &Open->PacketPool,
135         TRANSMIT_PACKETS,
136         sizeof(PACKET_RESERVED));
137         
138         
139     if (Status != NDIS_STATUS_SUCCESS) {
140                 
141         IF_LOUD(DbgPrint("NPF: Failed to allocate packet pool\n");)
142                         
143                 ExFreePool(Open);
144                 ExFreePool(EvName);
145         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
146         IoCompleteRequest(Irp, IO_NO_INCREMENT);
147         return STATUS_INSUFFICIENT_RESOURCES;
148     }
149
150
151         RtlCopyBytes(EvName,L"\\BaseNamedObjects\\NPF0000000000",sizeof(L"\\BaseNamedObjects\\NPF0000000000"));
152
153         //Create the string containing the name of the read event
154         RtlInitUnicodeString(&Open->ReadEventName,(PCWSTR) EvName);
155
156         PacketItoa(NamedEventsCounter,(PUCHAR)(Open->ReadEventName.Buffer+21));
157
158         InterlockedIncrement(&NamedEventsCounter);
159         
160         IF_LOUD(DbgPrint("\nCreated the named event for the read; name=%ws, counter=%d\n", Open->ReadEventName.Buffer,NamedEventsCounter-1);)
161
162         //allocate the event objects
163         Open->ReadEvent=IoCreateNotificationEvent(&Open->ReadEventName,&Open->ReadEventHandle);
164         if(Open->ReadEvent==NULL){
165                 ExFreePool(Open);
166                 ExFreePool(EvName);
167         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
168         IoCompleteRequest(Irp, IO_NO_INCREMENT);
169         return STATUS_INSUFFICIENT_RESOURCES;
170         }
171         
172         KeInitializeEvent(Open->ReadEvent, NotificationEvent, FALSE);
173         KeClearEvent(Open->ReadEvent);
174         NdisInitializeEvent(&Open->WriteEvent);
175         NdisInitializeEvent(&Open->IOEvent);
176         NdisInitializeEvent(&Open->DumpEvent);
177         NdisInitializeEvent(&Open->IOEvent);
178         NdisAllocateSpinLock(&Open->machine_lock);
179
180
181     //  list to hold irp's want to reset the adapter
182     InitializeListHead(&Open->ResetIrpList);
183         
184         
185     //  Initialize the request list
186     KeInitializeSpinLock(&Open->RequestSpinLock);
187     InitializeListHead(&Open->RequestList);
188
189         // Initializes the extended memory of the NPF machine
190         Open->mem_ex.buffer = ExAllocatePoolWithTag(NonPagedPool, DEFAULT_MEM_EX_SIZE, '2OWA');
191         if((Open->mem_ex.buffer) == NULL)
192         {
193         // no memory
194         ExFreePool(Open);
195                 ExFreePool(EvName);
196             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
197         IoCompleteRequest(Irp, IO_NO_INCREMENT);
198         return STATUS_INSUFFICIENT_RESOURCES;
199     }
200         
201         Open->mem_ex.size = DEFAULT_MEM_EX_SIZE;
202         RtlZeroMemory(Open->mem_ex.buffer, DEFAULT_MEM_EX_SIZE);
203         
204         //
205         // Initialize the open instance
206         //
207         Open->BufSize = 0;
208         Open->Buffer = NULL;
209         Open->Bhead = 0;
210         Open->Btail = 0;
211         Open->BLastByte = 0;
212         Open->Dropped = 0;              //reset the dropped packets counter
213         Open->Received = 0;             //reset the received packets counter
214         Open->Accepted = 0;             //reset the accepted packets counter
215         Open->bpfprogram = NULL;        //reset the filter
216         Open->mode = MODE_CAPT;
217         Open->Nbytes.QuadPart = 0;
218         Open->Npackets.QuadPart = 0;
219         Open->Nwrites = 1;
220         Open->Multiple_Write_Counter = 0;
221         Open->MinToCopy = 0;
222         Open->TimeOut.QuadPart = (LONGLONG)1;
223         Open->Bound = TRUE;
224         Open->DumpFileName.Buffer = NULL;
225         Open->DumpFileHandle = NULL;
226         Open->tme.active = TME_NONE_ACTIVE;
227         Open->DumpLimitReached = FALSE;
228
229         //allocate the spinlock for the statistic counters
230     NdisAllocateSpinLock(&Open->CountersLock);
231
232         //allocate the spinlock for the buffer pointers
233     NdisAllocateSpinLock(&Open->BufLock);
234         
235     //
236     //  link up the request stored in our open block
237     //
238     for (i=0;i<MAX_REQUESTS;i++) {
239         ExInterlockedInsertTailList(
240             &Open->RequestList,
241             &Open->Requests[i].ListElement,
242             &Open->RequestSpinLock);
243                 
244     }
245         
246
247     IoMarkIrpPending(Irp);
248         
249     //
250     //  Try to open the MAC
251     //
252     IF_LOUD(DbgPrint("NPF: Openinig the device %ws, BindingContext=%d\n",DeviceExtension->AdapterName.Buffer, Open);)
253
254         NdisOpenAdapter(
255         &Status,
256         &ErrorStatus,
257         &Open->AdapterHandle,
258         &Open->Medium,
259         MediumArray,
260         NUM_NDIS_MEDIA,
261         DeviceExtension->NdisProtocolHandle,
262         Open,
263         &DeviceExtension->AdapterName,
264         0,
265         NULL);
266
267     IF_LOUD(DbgPrint("NPF: Opened the device, Status=%x\n",Status);)
268
269         if (Status != NDIS_STATUS_PENDING)
270     {
271                 NPF_OpenAdapterComplete(Open,Status,NDIS_STATUS_SUCCESS);
272     }
273         
274     return(STATUS_PENDING);
275 }
276
277 //-------------------------------------------------------------------
278
279 VOID NPF_OpenAdapterComplete(
280         IN NDIS_HANDLE  ProtocolBindingContext,
281     IN NDIS_STATUS  Status,
282     IN NDIS_STATUS  OpenErrorStatus)
283 {
284
285     PIRP              Irp;
286     POPEN_INSTANCE    Open;
287
288     IF_LOUD(DbgPrint("NPF: OpenAdapterComplete\n");)
289
290     Open= (POPEN_INSTANCE)ProtocolBindingContext;
291
292     //
293     //  get the open irp
294     //
295     Irp=Open->OpenCloseIrp;
296
297     if (Status != NDIS_STATUS_SUCCESS) {
298
299         IF_LOUD(DbgPrint("NPF: OpenAdapterComplete-FAILURE\n");)
300
301         NdisFreePacketPool(Open->PacketPool);
302
303                 //free mem_ex
304                 Open->mem_ex.size = 0;
305                 if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
306
307                 ExFreePool(Open->ReadEventName.Buffer);
308
309         ExFreePool(Open);
310     }
311         else {
312                 NdisAcquireSpinLock(&Opened_Instances_Lock);
313                 n_Opened_Instances++;
314                 NdisReleaseSpinLock(&Opened_Instances_Lock);
315                 
316                 IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances);)
317
318                 // Get the absolute value of the system boot time.
319                 // This is used for timestamp conversion.
320                 TIME_SYNCHRONIZE(&G_Start_Time);
321         }
322
323     Irp->IoStatus.Status = Status;
324     Irp->IoStatus.Information = 0;
325     IoCompleteRequest(Irp, IO_NO_INCREMENT);
326
327     return;
328
329 }
330
331 //-------------------------------------------------------------------
332
333 NTSTATUS
334 NPF_Close(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
335 {
336
337     POPEN_INSTANCE    Open;
338     NDIS_STATUS     Status;
339     PIO_STACK_LOCATION  IrpSp;
340         LARGE_INTEGER ThreadDelay;
341
342     IF_LOUD(DbgPrint("NPF: CloseAdapter\n");)
343
344         IrpSp = IoGetCurrentIrpStackLocation(Irp);
345
346     Open=IrpSp->FileObject->FsContext;
347
348         // Reset the buffer size. This tells the dump thread to stop.
349         Open->BufSize = 0;
350
351         if( Open->Bound == FALSE){
352
353                 NdisWaitEvent(&Open->IOEvent,10000);
354
355                 // Free the filter if it's present
356                 if(Open->bpfprogram != NULL)
357                         ExFreePool(Open->bpfprogram);
358
359                 // Free the jitted filter if it's present
360                 if(Open->Filter != NULL)
361                         BPF_Destroy_JIT_Filter(Open->Filter);
362
363                 //free the buffer
364                 Open->BufSize=0;
365                 if(Open->Buffer != NULL)ExFreePool(Open->Buffer);
366                 
367                 //free mem_ex
368                 Open->mem_ex.size = 0;
369                 if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
370                                 
371                 NdisFreePacketPool(Open->PacketPool);
372
373                 // Free the string with the name of the dump file
374                 if(Open->DumpFileName.Buffer!=NULL)
375                         ExFreePool(Open->DumpFileName.Buffer);
376                         
377                 ExFreePool(Open->ReadEventName.Buffer);
378                 ExFreePool(Open);
379
380                 Irp->IoStatus.Information = 0;
381                 Irp->IoStatus.Status = STATUS_SUCCESS;
382                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
383                 
384                 return(STATUS_SUCCESS);
385         }
386
387         // Unfreeze the consumer
388         if(Open->mode & MODE_DUMP)
389                 NdisSetEvent(&Open->DumpEvent);
390         else
391                 KeSetEvent(Open->ReadEvent,0,FALSE);
392
393     // Save the IRP
394     Open->OpenCloseIrp = Irp;
395
396     IoMarkIrpPending(Irp);
397  
398         // If this instance is in dump mode, complete the dump and close the file
399         if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL){
400 #ifndef __GNUC__
401                 NTSTATUS wres;
402
403                 ThreadDelay.QuadPart = -50000000;
404                 // Wait the completion of the thread
405                 wres = KeWaitForSingleObject(Open->DumpThreadObject,
406                                 UserRequest,
407                                 KernelMode,
408                                 TRUE,
409                                 &ThreadDelay);
410
411                 ObDereferenceObject(Open->DumpThreadObject);
412
413
414                 // Flush and close the dump file
415                 NPF_CloseDumpFile(Open);
416 #endif
417         }
418
419         // Destroy the read Event
420         ZwClose(Open->ReadEventHandle);
421
422         // Close the adapter
423         NdisCloseAdapter(
424                 &Status,
425                 Open->AdapterHandle
426                 );
427
428         if (Status != NDIS_STATUS_PENDING) {
429                 
430                 NPF_CloseAdapterComplete(
431                         Open,
432                         Status
433                         );
434                 return STATUS_SUCCESS;
435                 
436         }
437         
438         return(STATUS_PENDING);
439 }
440
441 //-------------------------------------------------------------------
442
443 VOID
444 NPF_CloseAdapterComplete(IN NDIS_HANDLE  ProtocolBindingContext,IN NDIS_STATUS  Status)
445 {
446     POPEN_INSTANCE    Open;
447     PIRP              Irp;
448
449     IF_LOUD(DbgPrint("NPF: CloseAdapterComplete\n");)
450
451     Open= (POPEN_INSTANCE)ProtocolBindingContext;
452
453         // free the allocated structures only if the instance is still bound to the adapter
454         if(Open->Bound == TRUE){
455                 
456                 // Free the filter if it's present
457                 if(Open->bpfprogram != NULL)
458                         ExFreePool(Open->bpfprogram);
459
460                 // Free the jitted filter if it's present
461                 if(Open->Filter != NULL)
462                         BPF_Destroy_JIT_Filter(Open->Filter);
463                 
464                 //free the buffer
465                 Open->BufSize = 0;
466                 if(Open->Buffer!=NULL)ExFreePool(Open->Buffer);
467                 
468                 //free mem_ex
469                 Open->mem_ex.size = 0;
470                 if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
471                 
472                 NdisFreePacketPool(Open->PacketPool);
473                 
474                 Irp=Open->OpenCloseIrp;
475                 
476                 // Free the string with the name of the dump file
477                 if(Open->DumpFileName.Buffer!=NULL)
478                         ExFreePool(Open->DumpFileName.Buffer);
479
480                 ExFreePool(Open->ReadEventName.Buffer);
481                 ExFreePool(Open);
482                 
483                 // Complete the request only if the instance is still bound to the adapter
484                 Irp->IoStatus.Status = STATUS_SUCCESS;
485                 Irp->IoStatus.Information = 0;
486                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
487         }
488         else
489                 NdisSetEvent(&Open->IOEvent);
490
491         // Decrease the counter of open instances
492         NdisAcquireSpinLock(&Opened_Instances_Lock);
493         n_Opened_Instances--;
494         NdisReleaseSpinLock(&Opened_Instances_Lock);
495
496         IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances);)
497
498         if(n_Opened_Instances == 0){
499                 // Force a synchronization at the next NPF_Open().
500                 // This hopefully avoids the synchronization issues caused by hibernation or standby.
501                 TIME_DESYNCHRONIZE(&G_Start_Time);
502         }
503
504         return;
505
506 }
507 //-------------------------------------------------------------------
508
509 #ifdef NDIS50
510 NDIS_STATUS
511 NPF_PowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent)
512 {
513     IF_LOUD(DbgPrint("NPF: PowerChange\n");)
514
515         TIME_DESYNCHRONIZE(&G_Start_Time);
516
517         TIME_SYNCHRONIZE(&G_Start_Time);
518
519         return STATUS_SUCCESS;
520 }
521 #endif
522
523 //-------------------------------------------------------------------
524
525 VOID
526 NPF_BindAdapter(
527     OUT PNDIS_STATUS            Status,
528     IN  NDIS_HANDLE             BindContext,
529     IN  PNDIS_STRING            DeviceName,
530     IN  PVOID                   SystemSpecific1,
531     IN  PVOID                   SystemSpecific2
532     )
533 {
534         IF_LOUD(DbgPrint("NPF: NPF_BindAdapter\n");)
535 }
536
537 //-------------------------------------------------------------------
538
539 VOID
540 NPF_UnbindAdapter(
541     OUT PNDIS_STATUS        Status,
542     IN  NDIS_HANDLE         ProtocolBindingContext,
543     IN  NDIS_HANDLE         UnbindContext
544     )
545 {
546     POPEN_INSTANCE   Open =(POPEN_INSTANCE)ProtocolBindingContext;
547         NDIS_STATUS              lStatus;
548
549         IF_LOUD(DbgPrint("NPF: NPF_UnbindAdapter\n");)
550
551         // Reset the buffer size. This tells the dump thread to stop.
552         Open->BufSize=0;
553
554         NdisResetEvent(&Open->IOEvent);
555
556         // This open instance is no more bound to the adapter, set Bound to False
557     InterlockedExchange( (PLONG) &Open->Bound, FALSE );
558
559         // Awake a possible pending read on this instance
560         if(Open->mode & MODE_DUMP)
561                 NdisSetEvent(&Open->DumpEvent);
562         else
563                 KeSetEvent(Open->ReadEvent,0,FALSE);
564
565         // If this instance is in dump mode, complete the dump and close the file
566         if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL)
567                 NPF_CloseDumpFile(Open);
568
569         // Destroy the read Event
570         ZwClose(Open->ReadEventHandle);
571
572     //  close the adapter
573     NdisCloseAdapter(
574         &lStatus,
575         Open->AdapterHandle
576             );
577
578     if (lStatus != NDIS_STATUS_PENDING) {
579
580         NPF_CloseAdapterComplete(
581             Open,
582             lStatus
583             );
584
585                 *Status = NDIS_STATUS_SUCCESS;
586         return;
587
588     }
589
590         *Status = NDIS_STATUS_SUCCESS;
591     return;
592 }
593
594 //-------------------------------------------------------------------
595
596 VOID
597 NPF_ResetComplete(IN NDIS_HANDLE  ProtocolBindingContext,IN NDIS_STATUS  Status)
598
599 {
600     POPEN_INSTANCE      Open;
601     PIRP                Irp;
602
603     PLIST_ENTRY         ResetListEntry;
604
605     IF_LOUD(DbgPrint("NPF: PacketResetComplte\n");)
606
607     Open= (POPEN_INSTANCE)ProtocolBindingContext;
608
609
610     //
611     //  remove the reset IRP from the list
612     //
613     ResetListEntry=ExInterlockedRemoveHeadList(
614                        &Open->ResetIrpList,
615                        &Open->RequestSpinLock
616                        );
617
618 #if DBG
619     if (ResetListEntry == NULL) {
620         DbgBreakPoint();
621         return;
622     }
623 #endif
624
625     Irp=CONTAINING_RECORD(ResetListEntry,IRP,Tail.Overlay.ListEntry);
626
627     Irp->IoStatus.Status = STATUS_SUCCESS;
628     IoCompleteRequest(Irp, IO_NO_INCREMENT);
629
630     IF_LOUD(DbgPrint("NPF: PacketResetComplte exit\n");)
631
632     return;
633
634 }