4 * Ethernet Packet Interface to NDIS drivers.
6 * Copyright 1998 Equivalence Pty. Ltd.
8 * Original code by William Ingle (address unknown)
11 * Revision 1.2 1998/10/06 10:24:42 robertj
12 * Fixed hang when using reset command, removed the command!
14 * Revision 1.1 1998/09/28 08:08:31 robertj
25 #include <epacket.h> // From PWLib
30 #pragma intrinsic(memset,memcpy,strlen,strcat,strcpy)
33 ///////////////////////////////////////////////////////////////////////////////
35 #define MAJOR_VERSION 1
36 #define MINOR_VERSION 2
39 #define MAX_REQUESTS 4
40 #define TRANSMIT_PACKETS 64 //was 16
43 #define ETHERNET_HEADER_LENGTH 14
44 #define ETHERNET_DATA_LENGTH 1500
45 #define ETHERNET_PACKET_LENGTH (ETHERNET_HEADER_LENGTH+ETHERNET_DATA_LENGTH)
48 typedef struct _PACKET_RESERVED
50 LIST_ENTRY ListElement
;
54 DWORD
* lpcbBytesReturned
;
55 OVERLAPPED
* lpoOverlapped
;
58 } PACKET_RESERVED
, *PPACKET_RESERVED
;
61 typedef struct _INTERNAL_REQUEST
63 PACKET_RESERVED Reserved
;
65 } INTERNAL_REQUEST
, *PINTERNAL_REQUEST
;
68 typedef struct _OPEN_INSTANCE
70 LIST_ENTRY ListElement
;
74 NDIS_HANDLE AdapterHandle
;
75 NDIS_HANDLE BindAdapterContext
;
76 NDIS_HANDLE PacketPool
;
77 NDIS_HANDLE BufferPool
;
79 NDIS_SPIN_LOCK RcvQSpinLock
;
82 NDIS_SPIN_LOCK RequestSpinLock
;
83 LIST_ENTRY RequestList
;
85 NDIS_SPIN_LOCK ResetSpinLock
;
86 LIST_ENTRY ResetIrpList
;
88 INTERNAL_REQUEST Requests
[MAX_REQUESTS
];
89 } OPEN_INSTANCE
, *POPEN_INSTANCE
;
92 typedef struct _DEVICE_EXTENSION
94 PDRIVER_OBJECT DriverObject
;
95 NDIS_HANDLE NdisProtocolHandle
;
97 } DEVICE_EXTENSION
, *PDEVICE_EXTENSION
;
101 #define RESERVED(_p) ((PPACKET_RESERVED)((_p)->ProtocolReserved))
105 // define wrapper for VWIN32_DIOCCompletionRoutine
108 void VXDINLINE
VWIN32_DIOCCompletionRoutine( DWORD hEvent
)
111 VxDCall( VWIN32_DIOCCompletionRoutine
);
115 #pragma VxD_LOCKED_CODE_SEG
116 #pragma VxD_LOCKED_DATA_SEG
120 PDEVICE_EXTENSION GlobalDeviceExtension
= NULL
;
123 ///////////////////////////////////////////////////////////////////////////////
125 VOID NDIS_API
PacketTransferDataComplete(IN NDIS_HANDLE ProtocolBindingContext
,
126 IN PNDIS_PACKET pPacket
,
127 IN NDIS_STATUS Status
,
128 IN UINT BytesTransfered
)
130 // upcall when no more data available
132 POPEN_INSTANCE Open
= (POPEN_INSTANCE
)ProtocolBindingContext
;
133 PPACKET_RESERVED pReserved
= (PPACKET_RESERVED
)(pPacket
->ProtocolReserved
);
134 OVERLAPPED
* pOverlap
= (OVERLAPPED
*)(pReserved
->lpoOverlapped
);
135 PNDIS_BUFFER pNdisBuffer
;
138 // free buffer descriptor
139 NdisUnchainBufferAtFront(pPacket
, &pNdisBuffer
);
141 NdisFreeBuffer(pNdisBuffer
);
143 // set total bytes returned
144 BytesTransfered
+= ETHERNET_HEADER_LENGTH
;
145 *pReserved
->lpcbBytesReturned
+= BytesTransfered
;
147 pOverlap
->O_InternalHigh
= *(pReserved
->lpcbBytesReturned
);
149 // The internal member of overlapped structure contains
150 // a pointer to the event structure that will be signalled,
151 // resuming the execution of the waitng GetOverlappedResult
153 VWIN32_DIOCCompletionRoutine(pOverlap
->O_Internal
);
156 PacketPageUnlock(pReserved
->lpBuffer
, pReserved
->cbBuffer
);
157 PacketPageUnlock(pReserved
->lpcbBytesReturned
, sizeof(DWORD
));
158 PacketPageUnlock(pReserved
->lpoOverlapped
, sizeof(OVERLAPPED
));
160 // recycle the packet
161 NdisReinitializePacket(pPacket
);
163 // Put the packet on the free queue
164 NdisFreePacket(pPacket
);
168 ///////////////////////////////////////////////////////////////////////////////
170 VOID NDIS_API
PacketSendComplete(IN NDIS_HANDLE ProtocolBindingContext
,
171 IN PNDIS_PACKET pPacket
,
172 IN NDIS_STATUS Status
)
174 // upcall on completion of send
176 PNDIS_BUFFER pNdisBuffer
;
177 PPACKET_RESERVED Reserved
= (PPACKET_RESERVED
)pPacket
->ProtocolReserved
;
180 // free buffer descriptor
181 NdisUnchainBufferAtFront(pPacket
, &pNdisBuffer
);
184 NdisFreeBuffer(pNdisBuffer
);
187 Reserved
->lpoOverlapped
->O_InternalHigh
= Status
;
189 // The internal member of overlapped structure contains
190 // a pointer to the event structure that will be signalled,
191 // resuming the execution of the waiting GetOverlappedResult
193 VWIN32_DIOCCompletionRoutine(Reserved
->lpoOverlapped
->O_Internal
);
196 PacketPageUnlock(Reserved
->lpBuffer
, Reserved
->cbBuffer
);
197 PacketPageUnlock(Reserved
->lpcbBytesReturned
, sizeof(DWORD
));
198 PacketPageUnlock(Reserved
->lpoOverlapped
, sizeof(OVERLAPPED
));
200 // recycle the packet
201 NdisReinitializePacket(pPacket
);
203 // Put the packet back on the free list
204 NdisFreePacket(pPacket
);
208 ///////////////////////////////////////////////////////////////////////////////
210 VOID NDIS_API
PacketResetComplete(IN NDIS_HANDLE ProtocolBindingContext
,
211 IN NDIS_STATUS Status
)
213 // upcall on reset completion
215 POPEN_INSTANCE Open
= (POPEN_INSTANCE
)ProtocolBindingContext
;
216 PLIST_ENTRY ResetListEntry
;
219 // remove the reset request from the list
220 NdisAcquireSpinLock(&Open
->ResetSpinLock
);
222 if (IsListEmpty(&Open
->ResetIrpList
)) {
223 NdisReleaseSpinLock(&Open
->ResetSpinLock
);
227 ResetListEntry
= RemoveHeadList(&Open
->ResetIrpList
);
228 NdisReleaseSpinLock(&Open
->ResetSpinLock
);
230 // Acquire request element from list
231 NdisAcquireSpinLock(&Open
->RequestSpinLock
);
233 InsertTailList(&Open
->RequestList
, ResetListEntry
);
235 NdisReleaseSpinLock(&Open
->RequestSpinLock
);
239 ///////////////////////////////////////////////////////////////////////////////
241 NDIS_STATUS NDIS_API
PacketReset(POPEN_INSTANCE pOpen
)
243 // reset the protocol
245 PLIST_ENTRY ResetListEntry
;
249 // Acquire request element from list
250 NdisAllocateSpinLock(&pOpen
->RequestSpinLock
);
252 if (IsListEmpty(&pOpen
->RequestList
)) {
253 NdisReleaseSpinLock(&pOpen
->RequestSpinLock
);
254 return NDIS_STATUS_RESOURCES
;
257 ResetListEntry
= RemoveHeadList(&pOpen
->RequestList
);
258 NdisReleaseSpinLock(&pOpen
->RequestSpinLock
);
260 // Insert Reset IRP into Request Queue
261 NdisAcquireSpinLock(&pOpen
->ResetSpinLock
);
263 InsertTailList(&pOpen
->ResetIrpList
, ResetListEntry
);
265 NdisReleaseSpinLock(&pOpen
->ResetSpinLock
);
268 NdisReset(&Status
, pOpen
->AdapterHandle
);
270 if (Status
!= NDIS_STATUS_PENDING
)
271 PacketResetComplete(pOpen
, Status
);
276 ///////////////////////////////////////////////////////////////////////////////
278 VOID NDIS_API
PacketRequestComplete(IN NDIS_HANDLE ProtocolBindingContext
,
279 IN PNDIS_REQUEST NdisRequest
,
280 IN NDIS_STATUS Status
)
282 // perform a packet request complete
284 POPEN_INSTANCE Open
= (POPEN_INSTANCE
)ProtocolBindingContext
;
285 PINTERNAL_REQUEST pRequest
= CONTAINING_RECORD(NdisRequest
, INTERNAL_REQUEST
, Request
);
286 PPACKET_RESERVED pReserved
= &pRequest
->Reserved
;
287 OVERLAPPED
* pOverlap
= (OVERLAPPED
*)pReserved
->lpoOverlapped
;
288 EPACKET_OID
* oidData
= (EPACKET_OID
*)pReserved
->lpBuffer
;
291 if (Status
== NDIS_STATUS_SUCCESS
) {
292 // set total bytes returned
293 *pReserved
->lpcbBytesReturned
= oidData
->Length
+ sizeof(EPACKET_OID
) - sizeof(oidData
->Data
);
294 pOverlap
->O_InternalHigh
= *(pReserved
->lpcbBytesReturned
);
297 *pReserved
->lpcbBytesReturned
= 0; // set total bytes returned
298 pOverlap
->O_InternalHigh
= *pReserved
->lpcbBytesReturned
;
299 oidData
->Length
= Status
; // return status in oidData if there is an error
302 // The internal member of overlapped structure contains
303 // a pointer to the event structure that will be signalled,
304 // resuming the execution of the waitng GetOverlappedResult
306 VWIN32_DIOCCompletionRoutine(pOverlap
->O_Internal
);
309 PacketPageUnlock(pReserved
->lpBuffer
, pReserved
->cbBuffer
);
310 PacketPageUnlock(pReserved
->lpcbBytesReturned
, sizeof(DWORD
));
311 PacketPageUnlock(pReserved
->lpoOverlapped
, sizeof(OVERLAPPED
));
313 // Return request element to list
314 NdisAcquireSpinLock(&Open
->RequestSpinLock
);
316 InsertTailList(&Open
->RequestList
, &pReserved
->ListElement
);
318 NdisReleaseSpinLock(&Open
->RequestSpinLock
);
322 ///////////////////////////////////////////////////////////////////////////////
324 DWORD NDIS_API
PacketRequest(POPEN_INSTANCE Open
,
328 PDIOCPARAMETERS pDiocParms
)
330 // perform a packet request
332 PLIST_ENTRY RequestListEntry
;
333 PINTERNAL_REQUEST pRequest
;
334 PPACKET_RESERVED pReserved
;
335 EPACKET_OID
* OidData
;
339 // Acquire request element from list
340 NdisAcquireSpinLock(&Open
->RequestSpinLock
);
342 if (IsListEmpty(&Open
->RequestList
)) {
343 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = 0;
344 NdisReleaseSpinLock(&Open
->RequestSpinLock
);
345 return NDIS_STATUS_SUCCESS
;
348 RequestListEntry
= RemoveHeadList(&Open
->RequestList
);
349 NdisReleaseSpinLock(&Open
->RequestSpinLock
);
351 pReserved
= CONTAINING_RECORD(RequestListEntry
, PACKET_RESERVED
, ListElement
);
352 pRequest
= CONTAINING_RECORD(pReserved
, INTERNAL_REQUEST
, Reserved
);
353 OidData
= (EPACKET_OID
*)(pDiocParms
->lpvInBuffer
);
355 if ((pDiocParms
->cbInBuffer
!= pDiocParms
->cbOutBuffer
) ||
356 (pDiocParms
->cbInBuffer
< sizeof(*OidData
) - sizeof(OidData
->Data
) + OidData
->Length
)) {
357 *(DWORD
*)pDiocParms
->lpcbBytesReturned
= 1;
358 return NDIS_STATUS_BUFFER_TOO_SHORT
;
361 // The buffer is valid
362 pReserved
->lpBuffer
= (PVOID
)PacketPageLock(pDiocParms
->lpvInBuffer
, pDiocParms
->cbInBuffer
);
363 pReserved
->lpcbBytesReturned
= (PVOID
)PacketPageLock(pDiocParms
->lpcbBytesReturned
, sizeof(DWORD
));
364 pReserved
->lpoOverlapped
= (PVOID
)PacketPageLock(pDiocParms
->lpoOverlapped
, sizeof(OVERLAPPED
));
365 pReserved
->cbBuffer
= pDiocParms
->cbInBuffer
;
366 pReserved
->hDevice
= pDiocParms
->hDevice
;
367 pReserved
->tagProcess
= pDiocParms
->tagProcess
;
369 if (FunctionCode
== IOCTL_EPACKET_SET_OID
) {
370 pRequest
->Request
.RequestType
= NdisRequestSetInformation
;
371 pRequest
->Request
.DATA
.SET_INFORMATION
.Oid
= OidData
->Oid
;
372 pRequest
->Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= OidData
->Length
;
373 pRequest
->Request
.DATA
.SET_INFORMATION
.InformationBuffer
= OidData
->Data
;
376 if (OidData
->Oid
>= 0x01000000)
377 pRequest
->Request
.RequestType
= NdisRequestQueryInformation
;
379 pRequest
->Request
.RequestType
= NdisRequestGeneric1
;
380 pRequest
->Request
.DATA
.QUERY_INFORMATION
.Oid
= OidData
->Oid
;
381 pRequest
->Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= OidData
->Length
;
382 pRequest
->Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= OidData
->Data
;
385 // submit the request
386 NdisRequest(&Status
, Open
->AdapterHandle
, &pRequest
->Request
);
388 if (Status
== NDIS_STATUS_PENDING
)
389 return(-1); // This will make DeviceIOControl return ERROR_IO_PENDING
391 PacketRequestComplete(Open
, &pRequest
->Request
, Status
);
396 ///////////////////////////////////////////////////////////////////////////////
398 NDIS_STATUS NDIS_API
PacketReceiveIndicate(IN NDIS_HANDLE ProtocolBindingContext
,
399 IN NDIS_HANDLE MacReceiveContext
,
400 IN PVOID HeaderBuffer
,
401 IN UINT HeaderBufferSize
,
402 IN PVOID LookaheadBuffer
,
403 IN UINT LookaheadBufferSize
,
406 // upcall on packet arrival
409 PLIST_ENTRY PacketListEntry
;
410 PNDIS_PACKET pPacket
;
412 UINT BytesTransfered
= 0;
413 PPACKET_RESERVED pReserved
;
416 if (HeaderBufferSize
!= ETHERNET_HEADER_LENGTH
)
417 return NDIS_STATUS_NOT_ACCEPTED
;
419 Open
= (POPEN_INSTANCE
) ProtocolBindingContext
;
421 // See if there are any pending reads that we can satisfy
422 NdisAcquireSpinLock(&Open
->RcvQSpinLock
); // fixed 5.11.97
424 if (IsListEmpty(&Open
->RcvList
)) {
425 NdisReleaseSpinLock(&Open
->RcvQSpinLock
);
426 return NDIS_STATUS_NOT_ACCEPTED
;
429 PacketListEntry
= RemoveHeadList(&Open
->RcvList
);
430 NdisReleaseSpinLock(&Open
->RcvQSpinLock
);
432 pReserved
= CONTAINING_RECORD(PacketListEntry
, PACKET_RESERVED
, ListElement
);
433 pPacket
= CONTAINING_RECORD(pReserved
, NDIS_PACKET
, ProtocolReserved
);
435 // Copy the MAC header
436 NdisMoveMemory(RESERVED(pPacket
)->lpBuffer
, HeaderBuffer
, HeaderBufferSize
);
438 // Call the Mac to transfer the data portion of the packet
439 NdisTransferData(&Status
, Open
->AdapterHandle
, MacReceiveContext
, 0, PacketSize
, pPacket
, &BytesTransfered
);
440 if (Status
== NDIS_STATUS_PENDING
)
441 return NDIS_STATUS_PENDING
;
443 if (Status
== NDIS_STATUS_SUCCESS
) {
444 PacketTransferDataComplete(Open
, pPacket
, Status
, BytesTransfered
);
445 return NDIS_STATUS_SUCCESS
;
448 PacketTransferDataComplete(Open
, pPacket
, Status
, 0);
449 return NDIS_STATUS_SUCCESS
;
453 ///////////////////////////////////////////////////////////////////////////////
455 VOID NDIS_API
PacketReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext
)
457 // upcall when receive complete
461 ///////////////////////////////////////////////////////////////////////////////
463 VOID NDIS_API
PacketStatus(IN NDIS_HANDLE ProtocolBindingContext
,
464 IN NDIS_STATUS Status
,
465 IN PVOID StatusBuffer
,
466 IN UINT StatusBufferSize
)
472 ///////////////////////////////////////////////////////////////////////////////
474 VOID NDIS_API
PacketStatusComplete(IN NDIS_HANDLE ProtocolBindingContext
)
476 // completion handler
480 ///////////////////////////////////////////////////////////////////////////////
482 VOID NDIS_API
PacketBindAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext
,
483 IN NDIS_STATUS Status
,
484 IN NDIS_STATUS OpenErrorStatus
)
486 // upcall on Bind completion
488 POPEN_INSTANCE Open
= (POPEN_INSTANCE
)ProtocolBindingContext
;
490 // If the binding is unsuccessful then we deallocate data structures in
491 // preparation for unloading
492 if (Status
!= NDIS_STATUS_SUCCESS
) {
493 NdisFreeSpinLock(&Open
->RequestSpinLock
);
494 NdisFreeSpinLock(&Open
->RcvQSpinLock
);
496 NdisFreeBufferPool(Open
->BufferPool
);
497 NdisFreePacketPool(Open
->PacketPool
);
499 NdisFreeMemory(Open
, sizeof(OPEN_INSTANCE
), 0);
502 // Insert New Adapter into list
503 InsertTailList(&GlobalDeviceExtension
->OpenList
, &Open
->ListElement
);
508 ///////////////////////////////////////////////////////////////////////////////
510 VOID NDIS_API
PacketBindAdapter(OUT PNDIS_STATUS pStatus
,
511 IN NDIS_HANDLE BindAdapterContext
,
512 IN PNDIS_STRING pAdapterName
,
513 IN PVOID SystemSpecific1
,
514 IN PVOID SystemSpecific2
)
516 // bind this driver to a NIC
518 POPEN_INSTANCE oiNew
;
519 NDIS_STATUS ErrorStatus
, AllocStatus
;
521 NDIS_MEDIUM MediumArray
= NdisMedium802_3
;
525 // allocate some memory for the open structure
526 NdisAllocateMemory((PVOID
*)&oiNew
, sizeof(OPEN_INSTANCE
), 0, -1);
527 if (oiNew
== NULL
) { // not enough memory
528 *pStatus
= NDIS_STATUS_RESOURCES
;
532 NdisZeroMemory((PVOID
)oiNew
, sizeof(OPEN_INSTANCE
));
534 // Save Binding Context
535 oiNew
->BindAdapterContext
= BindAdapterContext
;
537 // Save the device handle
538 oiNew
->hDevice
= (DWORD
)SystemSpecific1
;
540 // Allocate a packet pool for our xmit and receive packets
541 NdisAllocatePacketPool(&AllocStatus
,
542 &(oiNew
->PacketPool
),
544 sizeof(PACKET_RESERVED
));
545 if (AllocStatus
!= NDIS_STATUS_SUCCESS
) { // not enough memory
546 NdisFreeMemory(oiNew
, sizeof(OPEN_INSTANCE
), 0);
547 *pStatus
= NDIS_STATUS_RESOURCES
;
551 // Allocate a buffer pool for our xmit and receive buffers
552 NdisAllocateBufferPool(&AllocStatus
, &(oiNew
->BufferPool
), TRANSMIT_PACKETS
);
553 if (AllocStatus
!= NDIS_STATUS_SUCCESS
) { // not enough memory
554 NdisFreeMemory(oiNew
, sizeof(OPEN_INSTANCE
), 0);
555 *pStatus
= NDIS_STATUS_RESOURCES
;
559 // list to hold irp's that want to reset the adapter
560 NdisAllocateSpinLock(&oiNew
->ResetSpinLock
);
561 InitializeListHead(&oiNew
->ResetIrpList
);
563 // Initialize list for holding pending read requests
564 NdisAllocateSpinLock(&oiNew
->RcvQSpinLock
);
565 InitializeListHead(&oiNew
->RcvList
);
567 // Initialize the request list
568 NdisAllocateSpinLock(&oiNew
->RequestSpinLock
);
569 InitializeListHead(&oiNew
->RequestList
);
571 // link up the request stored in our open block
572 for (i
= 0; i
< MAX_REQUESTS
; i
++) {
573 // Braces are required as InsertTailList macro has multiple statements in it
574 InsertTailList(&oiNew
->RequestList
, &oiNew
->Requests
[i
].Reserved
.ListElement
);
577 // Try to open the MAC
578 NdisOpenAdapter(pStatus
, &ErrorStatus
, &oiNew
->AdapterHandle
, &Medium
, &MediumArray
, 1,
579 GlobalDeviceExtension
->NdisProtocolHandle
, oiNew
, pAdapterName
, 0, NULL
);
581 // Save the status returned by NdisOpenAdapter for completion routine
582 oiNew
->Status
= *pStatus
;
585 case NDIS_STATUS_PENDING
:
588 case NDIS_STATUS_SUCCESS
:
589 ErrorStatus
= NDIS_STATUS_SUCCESS
;
591 // fall through to completion routine with oiNew->Status
592 // set to !NDIS_STATUS_PENDING
595 PacketBindAdapterComplete(oiNew
, *pStatus
, ErrorStatus
);
601 ///////////////////////////////////////////////////////////////////////////////
603 VOID NDIS_API
PacketUnbindAdapterComplete(IN POPEN_INSTANCE Open
,
604 IN NDIS_STATUS Status
)
606 // upcall on NdisCloseAdapter completion
609 // If Open->Status == NDIS_STATUS_PENDING then we must complete the pended unbinding
610 if (Open
->Status
== NDIS_STATUS_PENDING
) {
611 NdisCompleteUnbindAdapter(Open
->BindAdapterContext
, Status
);
612 Open
->Status
= NDIS_STATUS_SUCCESS
;
615 if (Status
!= NDIS_STATUS_SUCCESS
)
618 // Remove Adapter from global list
619 RemoveEntryList(&Open
->ListElement
);
622 NdisFreeSpinLock(&Open
->RequestSpinLock
);
623 NdisFreeSpinLock(&Open
->RcvQSpinLock
);
624 NdisFreeSpinLock(&Open
->ResetSpinLock
);
626 NdisFreeBufferPool(Open
->BufferPool
);
628 NdisFreePacketPool(Open
->PacketPool
);
630 NdisFreeMemory(Open
, sizeof(OPEN_INSTANCE
), 0);
634 ///////////////////////////////////////////////////////////////////////////////
636 VOID NDIS_API
PacketUnbindAdapter(OUT PNDIS_STATUS Status
,
637 IN POPEN_INSTANCE Open
,
638 IN POPEN_INSTANCE junk
)
640 // detach protocol from the NIC clean up any pending I/O requests
642 PLIST_ENTRY PacketListEntry
;
643 PNDIS_PACKET pPacket
;
646 // The open instance of the device is about to close
647 // We need to complete all pending I/O requests
648 // First we complete any pending read requests
649 NdisAcquireSpinLock(&Open
->RcvQSpinLock
);
651 while (!IsListEmpty(&Open
->RcvList
)) {
652 PacketListEntry
= RemoveHeadList(&Open
->RcvList
);
653 pPacket
= CONTAINING_RECORD(PacketListEntry
, NDIS_PACKET
, ProtocolReserved
);
656 PacketTransferDataComplete(Open
, pPacket
, NDIS_STATUS_SUCCESS
, 0);
659 NdisReleaseSpinLock(&Open
->RcvQSpinLock
);
662 NdisCloseAdapter(Status
, Open
->AdapterHandle
);
664 // Save status returned from NdisCloseAdapter for completion routine
665 Open
->Status
= *Status
;
667 if (*Status
!= NDIS_STATUS_PENDING
)
668 PacketUnbindAdapterComplete(Open
, *Status
);
672 ///////////////////////////////////////////////////////////////////////////////
674 VOID NDIS_API
PacketUnload()
676 // deregister the protocol, free remaining memory
677 // - called by NdisCloseAdapter when last adapter closed
681 if (GlobalDeviceExtension
!= NULL
) {
682 NdisDeregisterProtocol(&Status
, GlobalDeviceExtension
->NdisProtocolHandle
);
684 if (Status
== NDIS_STATUS_SUCCESS
)
685 NdisFreeMemory(GlobalDeviceExtension
, sizeof(DEVICE_EXTENSION
), 0);
686 GlobalDeviceExtension
= NULL
;
691 ///////////////////////////////////////////////////////////////////////////////
693 NTSTATUS NDIS_API
DriverEntry(IN PDRIVER_OBJECT DriverObject
,
694 IN PUNICODE_STRING RegistryPath
)
697 // initialiae the driver
699 NDIS_PROTOCOL_CHARACTERISTICS ProtocolChar
;
700 NDIS_STRING ProtoName
= NDIS_STRING_CONST("EPACKET");
704 // Because the driver can be loaded once for each Netcard on the system,
705 // and because DriverEntry is called each time, we must ensure that
706 // initialization is performed only once.
707 if (GlobalDeviceExtension
!= NULL
)
708 return NDIS_STATUS_SUCCESS
;
710 NdisAllocateMemory((PVOID
*)&GlobalDeviceExtension
, sizeof(DEVICE_EXTENSION
), 0, -1 );
711 if (GlobalDeviceExtension
== NULL
)
712 return NDIS_STATUS_RESOURCES
;
714 NdisZeroMemory((UCHAR
*)GlobalDeviceExtension
, sizeof(DEVICE_EXTENSION
));
715 NdisZeroMemory((UCHAR
*)&ProtocolChar
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
716 ProtocolChar
.MajorNdisVersion
= 0x03;
717 ProtocolChar
.MinorNdisVersion
= 0x0a;
718 ProtocolChar
.Reserved
= 0;
719 ProtocolChar
.OpenAdapterCompleteHandler
= PacketBindAdapterComplete
;
720 ProtocolChar
.CloseAdapterCompleteHandler
= PacketUnbindAdapterComplete
;
721 ProtocolChar
.SendCompleteHandler
= PacketSendComplete
;
722 ProtocolChar
.TransferDataCompleteHandler
= PacketTransferDataComplete
;
723 ProtocolChar
.ResetCompleteHandler
= PacketResetComplete
;
724 ProtocolChar
.RequestCompleteHandler
= PacketRequestComplete
;
725 ProtocolChar
.ReceiveHandler
= PacketReceiveIndicate
;
726 ProtocolChar
.ReceiveCompleteHandler
= PacketReceiveComplete
;
727 ProtocolChar
.StatusHandler
= PacketStatus
;
728 ProtocolChar
.StatusCompleteHandler
= PacketStatusComplete
;
729 ProtocolChar
.BindAdapterHandler
= PacketBindAdapter
;
730 ProtocolChar
.UnbindAdapterHandler
= PacketUnbindAdapter
;
731 ProtocolChar
.UnloadProtocolHandler
= PacketUnload
;
732 ProtocolChar
.Name
= ProtoName
;
734 NdisRegisterProtocol(&Status
,
735 &GlobalDeviceExtension
->NdisProtocolHandle
,
737 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
739 if (Status
!= NDIS_STATUS_SUCCESS
) {
740 NdisFreeMemory(GlobalDeviceExtension
, sizeof(DEVICE_EXTENSION
), 0);
744 // initialize open list
745 InitializeListHead(&GlobalDeviceExtension
->OpenList
);
747 // initialize global device extension
748 GlobalDeviceExtension
->DriverObject
= DriverObject
;
754 ///////////////////////////////////////////////////////////////////////////////
756 POPEN_INSTANCE
GetOpen(DWORD handle
)
758 // return a specified Open Instance
760 PLIST_ENTRY pHead
= &GlobalDeviceExtension
->OpenList
;
765 if (GlobalDeviceExtension
== NULL
)
768 // search the list for the Open Instance containing the specified handle
770 for (pTemp
= pHead
->Flink
; pTemp
!= pHead
; pTemp
= pTemp
->Flink
) {
771 Open
= CONTAINING_RECORD(pTemp
, OPEN_INSTANCE
, ListElement
);
772 if (Open
&& Open
->hDevice
== handle
)
776 return NULL
; // just in case
780 ///////////////////////////////////////////////////////////////////////////////
782 VOID
PacketAllocatePacketBuffer(PNDIS_STATUS pStatus
,
783 POPEN_INSTANCE pOpen
,
784 PNDIS_PACKET
*ppPacket
,
785 PDIOCPARAMETERS pDiocParms
,
788 // allocate a buffer for reading/writing
790 PNDIS_BUFFER pNdisBuffer
;
791 PNDIS_PACKET pPacket
;
794 // Try to get a packet from our list of free ones
795 NdisAllocatePacket(pStatus
, ppPacket
, pOpen
->PacketPool
);
797 if (*pStatus
!= NDIS_STATUS_SUCCESS
) {
798 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = 0;
804 // Buffers used asynchronously must be page locked
805 switch (FunctionCode
) {
806 case IOCTL_EPACKET_READ
:
807 RESERVED(pPacket
)->lpBuffer
= (PVOID
)PacketPageLock(pDiocParms
->lpvOutBuffer
, pDiocParms
->cbOutBuffer
);
808 RESERVED(pPacket
)->cbBuffer
= pDiocParms
->cbOutBuffer
;
811 case IOCTL_EPACKET_WRITE
:
812 RESERVED(pPacket
)->lpBuffer
= (PVOID
)PacketPageLock(pDiocParms
->lpvInBuffer
, pDiocParms
->cbInBuffer
);
813 RESERVED(pPacket
)->cbBuffer
= pDiocParms
->cbInBuffer
;
817 // recycle the packet
818 NdisReinitializePacket(pPacket
);
820 // Put the packet on the free queue
821 NdisFreePacket(pPacket
);
823 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = 0;
824 *pStatus
= NDIS_STATUS_NOT_ACCEPTED
;
828 RESERVED(pPacket
)->lpcbBytesReturned
= (PVOID
)PacketPageLock(pDiocParms
->lpcbBytesReturned
, sizeof(DWORD
));
829 RESERVED(pPacket
)->lpoOverlapped
= (PVOID
)PacketPageLock(pDiocParms
->lpoOverlapped
, sizeof(OVERLAPPED
));
830 RESERVED(pPacket
)->hDevice
= pDiocParms
->hDevice
;
831 RESERVED(pPacket
)->tagProcess
= pDiocParms
->tagProcess
;
833 switch (FunctionCode
) {
834 case IOCTL_EPACKET_READ
:
835 NdisAllocateBuffer(pStatus
,
838 (PVOID
)(RESERVED(pPacket
)->lpBuffer
+ ETHERNET_HEADER_LENGTH
),
839 pDiocParms
->cbOutBuffer
);
842 case IOCTL_EPACKET_WRITE
:
843 NdisAllocateBuffer(pStatus
,
846 (PVOID
)RESERVED(pPacket
)->lpBuffer
,
847 pDiocParms
->cbInBuffer
);
851 if (*pStatus
== NDIS_STATUS_SUCCESS
)
852 NdisChainBufferAtFront(pPacket
, pNdisBuffer
); // Attach buffer to Packet
854 NdisReinitializePacket(pPacket
); // recycle the packet
855 NdisFreePacket(pPacket
); // Put the packet on the free queue
856 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = 0;
861 ///////////////////////////////////////////////////////////////////////////////
863 DWORD
PacketRead(POPEN_INSTANCE Open
,
866 PDIOCPARAMETERS pDiocParms
)
871 PNDIS_PACKET pPacket
;
873 // Check that the buffer can hold a max length Ethernet packet
874 if (pDiocParms
->cbOutBuffer
< ETHERNET_PACKET_LENGTH
) {
875 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = 0; // Need bigger buffer
876 return NDIS_STATUS_SUCCESS
;
879 PacketAllocatePacketBuffer(&Status
, Open
, &pPacket
, pDiocParms
, IOCTL_EPACKET_READ
);
881 if (Status
== NDIS_STATUS_SUCCESS
) {
882 // Put this packet in a list of pending reads.
883 // The receive indication handler will attempt to remove packets
884 // from this list for use in transfer data calls
885 NdisAcquireSpinLock(&Open
->RcvQSpinLock
); // fixed 6.11.97
886 InsertTailList(&Open
->RcvList
, &RESERVED(pPacket
)->ListElement
);
887 NdisReleaseSpinLock(&Open
->RcvQSpinLock
);
890 return -1; // This will make DeviceIOControl return ERROR_IO_PENDING
894 ///////////////////////////////////////////////////////////////////////////////
896 DWORD
PacketWrite(POPEN_INSTANCE Open
,
899 PDIOCPARAMETERS pDiocParms
)
903 PNDIS_PACKET pPacket
;
907 PacketAllocatePacketBuffer(&Status
, Open
, &pPacket
, pDiocParms
, IOCTL_EPACKET_WRITE
);
908 if (Status
!= NDIS_STATUS_SUCCESS
)
909 return 0; // This will return immediately with no data written
912 NdisSend(&Status
, Open
->AdapterHandle
, pPacket
);
913 if (Status
!= NDIS_STATUS_PENDING
) {
914 // The send didn't pend so call the completion handler now
915 PacketSendComplete(Open
, pPacket
, Status
);
918 return(-1); // This will make DeviceIOControl return ERROR_IO_PENDING
922 ///////////////////////////////////////////////////////////////////////////////
924 DWORD _stdcall
PacketIOControl(DWORD dwService
,
927 PDIOCPARAMETERS pDiocParms
)
929 // called from applications
933 UCHAR AdapterBuffer
[5];
934 NDIS_STRING AdapterName
= NDIS_STRING_CONST(AdapterBuffer
);
939 return NDIS_STATUS_SUCCESS
;
941 case DIOC_CLOSEHANDLE
:
942 if ((Open
= GetOpen(hDevice
)) != NULL
)
943 PacketUnbindAdapter(&Status
, Open
, NULL
);
944 return NDIS_STATUS_SUCCESS
;
946 case IOCTL_EPACKET_VERSION
:
947 if (pDiocParms
->cbOutBuffer
< 2)
948 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = 0;
950 ((BYTE
*)pDiocParms
->lpvOutBuffer
)[0] = MAJOR_VERSION
;
951 ((BYTE
*)pDiocParms
->lpvOutBuffer
)[1] = MINOR_VERSION
;
952 *(DWORD
*)pDiocParms
->lpcbBytesReturned
= 2;
954 return NDIS_STATUS_SUCCESS
;
956 case IOCTL_EPACKET_BIND
:
957 memcpy(AdapterName
.Buffer
, (BYTE
*)pDiocParms
->lpvInBuffer
,
958 min(strlen((char *)pDiocParms
->lpvInBuffer
), sizeof(AdapterBuffer
)-1));
959 AdapterName
.Buffer
[sizeof(AdapterBuffer
)-1] = '\0';
960 PacketBindAdapter(&Status
,
961 GlobalDeviceExtension
->NdisProtocolHandle
,
963 (PVOID
)hDevice
, /* special */
965 // Note: If the above usage of the 4'th arg to PacketBindAdapter
966 // causes problems, use a global variable instead.
967 if (Status
== NDIS_STATUS_SUCCESS
|| Status
== NDIS_STATUS_PENDING
) {
968 *(DWORD
*)pDiocParms
->lpcbBytesReturned
= 1;
969 return NDIS_STATUS_SUCCESS
;
973 case IOCTL_EPACKET_SET_OID
:
974 case IOCTL_EPACKET_QUERY_OID
:
975 if ((Open
= GetOpen(hDevice
)) != NULL
)
976 return PacketRequest(Open
, dwService
, dwDDB
, hDevice
, pDiocParms
);
979 case IOCTL_EPACKET_READ
:
980 if ((Open
= GetOpen(hDevice
)) != NULL
)
981 return PacketRead(Open
, dwDDB
, hDevice
, pDiocParms
);
984 case IOCTL_EPACKET_WRITE
:
985 if ((Open
= GetOpen(hDevice
)) != NULL
)
986 return PacketWrite(Open
, dwDDB
, hDevice
, pDiocParms
);
990 *(DWORD
*)pDiocParms
->lpcbBytesReturned
= 0;
991 return NDIS_STATUS_SUCCESS
;
995 // End of File ////////////////////////////////////////////////////////////////