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