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 //
26 // Include files.
27 //
28 
29 #include "tap.h"
30 
31 //======================================================================
32 // TAP Receive Path Support
33 //======================================================================
34 
35 #ifdef ALLOC_PRAGMA
36 #pragma alloc_text( PAGE, TapDeviceWrite)
37 #endif // ALLOC_PRAGMA
38 
39 //===============================================================
40 // Used in cases where internally generated packets such as
41 // ARP or DHCP replies must be returned to the kernel, to be
42 // seen as an incoming packet "arriving" on the interface.
43 //===============================================================
44 
45 VOID
IndicateReceivePacket(__in PTAP_ADAPTER_CONTEXT Adapter,__in PUCHAR packetData,__in const unsigned int packetLength)46 IndicateReceivePacket(
47     __in PTAP_ADAPTER_CONTEXT  Adapter,
48     __in PUCHAR packetData,
49     __in const unsigned int packetLength
50     )
51 {
52     PUCHAR  injectBuffer;
53 
54     //
55     // Handle miniport Pause
56     // ---------------------
57     // NDIS 6 miniports implement a temporary "Pause" state normally followed
58     // by the Restart. While in the Pause state it is forbidden for the miniport
59     // to indicate receive NBLs.
60     //
61     // That is: The device interface may be "up", but the NDIS miniport send/receive
62     // interface may be temporarily "down".
63     //
64     // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas inject path
65     // the code below will simply ignore inject packets passed to the driver while
66     // the miniport is in the Paused state.
67     //
68     // The correct implementation is to go ahead and build the NBLs corresponding
69     // to the inject packet - but queue them. When Restart is entered the
70     // queued NBLs would be dequeued and indicated to the host.
71     //
72     if(tapAdapterSendAndReceiveReady(Adapter) != NDIS_STATUS_SUCCESS)
73     {
74         DEBUGP (("[%s] Lying send in IndicateReceivePacket while adapter paused\n",
75             MINIPORT_INSTANCE_ID (Adapter)));
76 
77         return;
78     }
79 
80     // Allocate flat buffer for packet data.
81     injectBuffer = (PUCHAR )NdisAllocateMemoryWithTagPriority(
82                         Adapter->MiniportAdapterHandle,
83                         packetLength,
84                         TAP_RX_INJECT_BUFFER_TAG,
85                         NormalPoolPriority
86                         );
87 
88     if( injectBuffer)
89     {
90         PMDL    mdl;
91 
92         // Copy packet data to flat buffer.
93         NdisMoveMemory (injectBuffer, packetData, packetLength);
94 
95         // Allocate MDL for flat buffer.
96         mdl = NdisAllocateMdl(
97                 Adapter->MiniportAdapterHandle,
98                 injectBuffer,
99                 packetLength
100                 );
101 
102         if( mdl )
103         {
104             PNET_BUFFER_LIST    netBufferList;
105 
106             mdl->Next = NULL;   // No next MDL
107 
108             // Allocate the NBL and NB. Link MDL chain to NB.
109             netBufferList = NdisAllocateNetBufferAndNetBufferList(
110                                 Adapter->ReceiveNblPool,
111                                 0,                  // ContextSize
112                                 0,                  // ContextBackFill
113                                 mdl,                // MDL chain
114                                 0,
115                                 packetLength
116                                 );
117 
118             if(netBufferList != NULL)
119             {
120                 ULONG       receiveFlags = 0;
121                 LONG        nblCount;
122 
123                 NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
124 
125                 if(KeGetCurrentIrql() == DISPATCH_LEVEL)
126                 {
127                     receiveFlags |= NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL;
128                 }
129 
130                 // Set flag indicating that this is an injected packet
131                 TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
132                 TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED);
133 
134                 netBufferList->MiniportReserved[0] = NULL;
135                 netBufferList->MiniportReserved[1] = NULL;
136 
137                 // Increment in-flight receive NBL count.
138                 nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount);
139                 ASSERT(nblCount > 0 );
140 
141                 netBufferList->SourceHandle = Adapter->MiniportAdapterHandle;
142 
143                 //
144                 // Indicate the packet
145                 // -------------------
146                 // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
147                 // contains the complete packet including Ethernet header and payload.
148                 //
149                 NdisMIndicateReceiveNetBufferLists(
150                     Adapter->MiniportAdapterHandle,
151                     netBufferList,
152                     NDIS_DEFAULT_PORT_NUMBER,
153                     1,      // NumberOfNetBufferLists
154                     receiveFlags
155                     );
156 
157                 return;
158             }
159             else
160             {
161                 DEBUGP (("[%s] NdisAllocateNetBufferAndNetBufferList failed in IndicateReceivePacket\n",
162                     MINIPORT_INSTANCE_ID (Adapter)));
163                 NOTE_ERROR ();
164 
165                 NdisFreeMdl(mdl);
166                 NdisFreeMemory(injectBuffer,0,0);
167             }
168         }
169         else
170         {
171             DEBUGP (("[%s] NdisAllocateMdl failed in IndicateReceivePacket\n",
172                 MINIPORT_INSTANCE_ID (Adapter)));
173             NOTE_ERROR ();
174 
175             NdisFreeMemory(injectBuffer,0,0);
176         }
177     }
178     else
179     {
180         DEBUGP (("[%s] NdisAllocateMemoryWithTagPriority failed in IndicateReceivePacket\n",
181             MINIPORT_INSTANCE_ID (Adapter)));
182         NOTE_ERROR ();
183     }
184 }
185 
186 VOID
tapCompleteIrpAndFreeReceiveNetBufferList(__in PTAP_ADAPTER_CONTEXT Adapter,__in PNET_BUFFER_LIST NetBufferList,__in NTSTATUS IoCompletionStatus)187 tapCompleteIrpAndFreeReceiveNetBufferList(
188     __in  PTAP_ADAPTER_CONTEXT  Adapter,
189     __in  PNET_BUFFER_LIST      NetBufferList,  // Only one NB here...
190     __in  NTSTATUS              IoCompletionStatus
191     )
192 {
193     PIRP    irp;
194     ULONG   frameType, netBufferCount, byteCount;
195     LONG    nblCount;
196 
197     // Fetch NB frame type.
198     frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(NetBufferList));
199 
200     // Fetch statistics for all NBs linked to the NB.
201     netBufferCount = tapGetNetBufferCountsFromNetBufferList(
202                         NetBufferList,
203                         &byteCount
204                         );
205 
206     // Update statistics by frame type
207     if(IoCompletionStatus == STATUS_SUCCESS)
208     {
209         switch(frameType)
210         {
211         case NDIS_PACKET_TYPE_DIRECTED:
212             Adapter->FramesRxDirected += netBufferCount;
213             Adapter->BytesRxDirected += byteCount;
214             break;
215 
216         case NDIS_PACKET_TYPE_BROADCAST:
217             Adapter->FramesRxBroadcast += netBufferCount;
218             Adapter->BytesRxBroadcast += byteCount;
219             break;
220 
221         case NDIS_PACKET_TYPE_MULTICAST:
222             Adapter->FramesRxMulticast += netBufferCount;
223             Adapter->BytesRxMulticast += byteCount;
224             break;
225 
226         default:
227             ASSERT(FALSE);
228             break;
229         }
230     }
231 
232     //
233     // Handle P2P Packet
234     // -----------------
235     // Free MDL allocated for P2P Ethernet header.
236     //
237     if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_P2P))
238     {
239         PNET_BUFFER     netBuffer;
240         PMDL            mdl;
241 
242         netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
243         mdl = NET_BUFFER_FIRST_MDL(netBuffer);
244         mdl->Next = NULL;
245 
246         NdisFreeMdl(mdl);
247     }
248 
249     //
250     // Handle Injected Packet
251     // -----------------------
252     // Free MDL and data buffer allocated for injected packet.
253     //
254     if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED))
255     {
256         PNET_BUFFER     netBuffer;
257         PMDL            mdl;
258         PUCHAR          injectBuffer;
259 
260         netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
261         mdl = NET_BUFFER_FIRST_MDL(netBuffer);
262 
263         injectBuffer = (PUCHAR )MmGetSystemAddressForMdlSafe(mdl,NormalPagePriority);
264 
265         if(injectBuffer)
266         {
267             NdisFreeMemory(injectBuffer,0,0);
268         }
269 
270         NdisFreeMdl(mdl);
271     }
272 
273     //
274     // Complete the IRP
275     //
276     irp = (PIRP )NetBufferList->MiniportReserved[0];
277 
278     if(irp)
279     {
280         irp->IoStatus.Status = IoCompletionStatus;
281         IoCompleteRequest(irp, IO_NO_INCREMENT);
282     }
283 
284     // Decrement in-flight receive NBL count.
285     nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount);
286     ASSERT(nblCount >= 0 );
287     if (0 == nblCount)
288     {
289         NdisSetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent);
290     }
291 
292     // Free the NBL
293     NdisFreeNetBufferList(NetBufferList);
294 }
295 
296 VOID
AdapterReturnNetBufferLists(__in NDIS_HANDLE MiniportAdapterContext,__in PNET_BUFFER_LIST NetBufferLists,__in ULONG ReturnFlags)297 AdapterReturnNetBufferLists(
298     __in  NDIS_HANDLE             MiniportAdapterContext,
299     __in  PNET_BUFFER_LIST        NetBufferLists,
300     __in  ULONG                   ReturnFlags
301     )
302 {
303     PTAP_ADAPTER_CONTEXT    adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
304     PNET_BUFFER_LIST        currentNbl, nextNbl;
305 
306     UNREFERENCED_PARAMETER(ReturnFlags);
307 
308     //
309     // Process each NBL individually
310     //
311     currentNbl = NetBufferLists;
312     while (currentNbl)
313     {
314         PNET_BUFFER_LIST    nextNbl;
315 
316         nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl);
317         NET_BUFFER_LIST_NEXT_NBL(currentNbl) = NULL;
318 
319         // Complete write IRP and free NBL and associated resources.
320         tapCompleteIrpAndFreeReceiveNetBufferList(
321             adapter,
322             currentNbl,
323             STATUS_SUCCESS
324             );
325 
326         // Move to next NBL
327         currentNbl = nextNbl;
328     }
329 }
330 
331 // IRP_MJ_WRITE callback.
332 NTSTATUS
TapDeviceWrite(PDEVICE_OBJECT DeviceObject,PIRP Irp)333 TapDeviceWrite(
334     PDEVICE_OBJECT DeviceObject,
335     PIRP Irp
336     )
337 {
338     NTSTATUS                ntStatus = STATUS_SUCCESS;// Assume success
339     PIO_STACK_LOCATION      irpSp;// Pointer to current stack location
340     PTAP_ADAPTER_CONTEXT    adapter = NULL;
341     ULONG                   dataLength;
342 
343     PAGED_CODE();
344 
345     irpSp = IoGetCurrentIrpStackLocation( Irp );
346 
347     //
348     // Fetch adapter context for this device.
349     // --------------------------------------
350     // Adapter pointer was stashed in FsContext when handle was opened.
351     //
352     adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
353 
354     ASSERT(adapter);
355 
356     //
357     // Sanity checks on state variables
358     //
359     if (!tapAdapterReadAndWriteReady(adapter))
360     {
361         //DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n",
362         //    MINIPORT_INSTANCE_ID (adapter)));
363         //NOTE_ERROR();
364 
365         Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED;
366         Irp->IoStatus.Information = 0;
367         IoCompleteRequest (Irp, IO_NO_INCREMENT);
368 
369         return ntStatus;
370     }
371 
372     // Save IRP-accessible copy of buffer length
373     Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
374 
375     if (Irp->MdlAddress == NULL)
376     {
377         DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n",
378             MINIPORT_INSTANCE_ID (adapter)));
379 
380         NOTE_ERROR();
381         Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
382         Irp->IoStatus.Information = 0;
383         IoCompleteRequest (Irp, IO_NO_INCREMENT);
384 
385         return ntStatus;
386     }
387 
388     //
389     // Try to get a virtual address for the MDL.
390     //
391     NdisQueryMdl(
392         Irp->MdlAddress,
393         &Irp->AssociatedIrp.SystemBuffer,
394         &dataLength,
395         NormalPagePriority
396         );
397 
398     if (Irp->AssociatedIrp.SystemBuffer == NULL)
399     {
400         DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n",
401             MINIPORT_INSTANCE_ID (adapter)));
402 
403         NOTE_ERROR();
404         Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES;
405         Irp->IoStatus.Information = 0;
406         IoCompleteRequest (Irp, IO_NO_INCREMENT);
407 
408         return ntStatus;
409     }
410 
411     ASSERT(dataLength == irpSp->Parameters.Write.Length);
412 
413     Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
414 
415     //
416     // Handle miniport Pause
417     // ---------------------
418     // NDIS 6 miniports implement a temporary "Pause" state normally followed
419     // by the Restart. While in the Pause state it is forbidden for the miniport
420     // to indicate receive NBLs.
421     //
422     // That is: The device interface may be "up", but the NDIS miniport send/receive
423     // interface may be temporarily "down".
424     //
425     // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path
426     // the code below will perform a "lying send" for write IRPs passed to the
427     // driver while the miniport is in the Paused state.
428     //
429     // The correct implementation is to go ahead and build the NBLs corresponding
430     // to the user-mode write - but queue them. When Restart is entered the
431     // queued NBLs would be dequeued and indicated to the host.
432     //
433     if(tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS)
434     {
435         if (/*!adapter->m_tun &&*/ ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
436         {
437             PNET_BUFFER_LIST    netBufferList;
438 
439             DUMP_PACKET ("IRP_MJ_WRITE ETH",
440                 (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
441                 irpSp->Parameters.Write.Length);
442 
443             //=====================================================
444             // If IPv4 packet, check whether or not packet
445             // was truncated.
446             //=====================================================
447 #if PACKET_TRUNCATION_CHECK
448             IPv4PacketSizeVerify (
449                 (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
450                 irpSp->Parameters.Write.Length,
451                 FALSE,
452                 "RX",
453                 &adapter->m_RxTrunc
454                 );
455 #endif
456             (Irp->MdlAddress)->Next = NULL; // No next MDL
457 
458             // Allocate the NBL and NB. Link MDL chain to NB.
459             netBufferList = NdisAllocateNetBufferAndNetBufferList(
460                 adapter->ReceiveNblPool,
461                 0,                  // ContextSize
462                 0,                  // ContextBackFill
463                 Irp->MdlAddress,    // MDL chain
464                 0,
465                 dataLength
466                 );
467 
468             if(netBufferList != NULL)
469             {
470                 LONG    nblCount;
471 
472                 NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
473 
474                 // Stash IRP pointer in NBL MiniportReserved[0] field.
475                 netBufferList->MiniportReserved[0] = Irp;
476                 netBufferList->MiniportReserved[1] = NULL;
477 
478                 // This IRP is pended.
479                 IoMarkIrpPending(Irp);
480 
481                 // This IRP cannot be cancelled while in-flight.
482                 IoSetCancelRoutine(Irp,NULL);
483 
484                 TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
485 
486                 // Increment in-flight receive NBL count.
487                 nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount);
488                 ASSERT(nblCount > 0 );
489 
490                 //
491                 // Indicate the packet
492                 // -------------------
493                 // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
494                 // contains the complete packet including Ethernet header and payload.
495                 //
496                 NdisMIndicateReceiveNetBufferLists(
497                     adapter->MiniportAdapterHandle,
498                     netBufferList,
499                     NDIS_DEFAULT_PORT_NUMBER,
500                     1,      // NumberOfNetBufferLists
501                     0       // ReceiveFlags
502                     );
503 
504                 ntStatus = STATUS_PENDING;
505             }
506             else
507             {
508                 DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n",
509                     MINIPORT_INSTANCE_ID (adapter)));
510                 NOTE_ERROR ();
511 
512                 // Fail the IRP
513                 Irp->IoStatus.Information = 0;
514                 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
515             }
516         }
517 		/*
518         else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
519         {
520             PETH_HEADER         p_UserToTap = &adapter->m_UserToTap;
521             PMDL                mdl;    // Head of MDL chain.
522 
523             // For IPv6, need to use Ethernet header with IPv6 proto
524             if ( IPH_GET_VER( ((IPHDR*) Irp->AssociatedIrp.SystemBuffer)->version_len) == 6 )
525             {
526                 p_UserToTap = &adapter->m_UserToTap_IPv6;
527             }
528 
529             DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
530                 p_UserToTap,
531                 (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
532                 irpSp->Parameters.Write.Length);
533 
534             //=====================================================
535             // If IPv4 packet, check whether or not packet
536             // was truncated.
537             //=====================================================
538 #if PACKET_TRUNCATION_CHECK
539             IPv4PacketSizeVerify (
540                 (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
541                 irpSp->Parameters.Write.Length,
542                 TRUE,
543                 "RX",
544                 &adapter->m_RxTrunc
545                 );
546 #endif
547 
548             //
549             // Allocate MDL for Ethernet header
550             // --------------------------------
551             // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
552             // contains the only the Ethernet payload. Prepend the user-mode provided
553             // payload with the Ethernet header pointed to by p_UserToTap.
554             //
555             mdl = NdisAllocateMdl(
556                 adapter->MiniportAdapterHandle,
557                 p_UserToTap,
558                 sizeof(ETH_HEADER)
559                 );
560 
561             if(mdl != NULL)
562             {
563                 PNET_BUFFER_LIST    netBufferList;
564 
565                 // Chain user's Ethernet payload behind Ethernet header.
566                 mdl->Next = Irp->MdlAddress;
567                 (Irp->MdlAddress)->Next = NULL; // No next MDL
568 
569                 // Allocate the NBL and NB. Link MDL chain to NB.
570                 netBufferList = NdisAllocateNetBufferAndNetBufferList(
571                     adapter->ReceiveNblPool,
572                     0,          // ContextSize
573                     0,          // ContextBackFill
574                     mdl,        // MDL chain
575                     0,
576                     sizeof(ETH_HEADER) + dataLength
577                     );
578 
579                 if(netBufferList != NULL)
580                 {
581                     LONG        nblCount;
582 
583                     NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
584 
585                     // This IRP is pended.
586                     IoMarkIrpPending(Irp);
587 
588                     // This IRP cannot be cancelled while in-flight.
589                     IoSetCancelRoutine(Irp,NULL);
590 
591                     // Stash IRP pointer in NBL MiniportReserved[0] field.
592                     netBufferList->MiniportReserved[0] = Irp;
593                     netBufferList->MiniportReserved[1] = NULL;
594 
595                     // Set flag indicating that this is P2P packet
596                     TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
597                     TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_P2P);
598 
599                     // Increment in-flight receive NBL count.
600                     nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount);
601                     ASSERT(nblCount > 0 );
602 
603                     //
604                     // Indicate the packet
605                     //
606                     NdisMIndicateReceiveNetBufferLists(
607                         adapter->MiniportAdapterHandle,
608                         netBufferList,
609                         NDIS_DEFAULT_PORT_NUMBER,
610                         1,      // NumberOfNetBufferLists
611                         0       // ReceiveFlags
612                         );
613 
614                     ntStatus = STATUS_PENDING;
615                 }
616                 else
617                 {
618                     mdl->Next = NULL;
619                     NdisFreeMdl(mdl);
620 
621                     DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n",
622                         MINIPORT_INSTANCE_ID (adapter)));
623                     NOTE_ERROR ();
624 
625                     // Fail the IRP
626                     Irp->IoStatus.Information = 0;
627                     ntStatus = STATUS_INSUFFICIENT_RESOURCES;
628                 }
629             }
630             else
631             {
632                 DEBUGP (("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n",
633                     MINIPORT_INSTANCE_ID (adapter)));
634                 NOTE_ERROR ();
635 
636                 // Fail the IRP
637                 Irp->IoStatus.Information = 0;
638                 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
639             }
640         }
641 		*/
642         else
643         {
644             DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n",
645                 MINIPORT_INSTANCE_ID (adapter),
646                 irpSp->Parameters.Write.Length));
647             NOTE_ERROR ();
648 
649             Irp->IoStatus.Information = 0;	// ETHERNET_HEADER_SIZE;
650             Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
651         }
652     }
653     else
654     {
655         DEBUGP (("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n",
656             MINIPORT_INSTANCE_ID (adapter)));
657 
658         ntStatus = STATUS_SUCCESS;
659     }
660 
661     if (ntStatus != STATUS_PENDING)
662     {
663         Irp->IoStatus.Status = ntStatus;
664         IoCompleteRequest(Irp, IO_NO_INCREMENT);
665     }
666 
667     return ntStatus;
668 }
669 
670