Fixed DevStudio 2003 build with memory check code.
[pwlib.git] / tools / PacketVxD / epacket.c
blob07375b1e4349eb72832d88f38aaeec8ab64e0cba
1 /*
2 * epacket.c
4 * Ethernet Packet Interface to NDIS drivers.
6 * Copyright 1998 Equivalence Pty. Ltd.
8 * Original code by William Ingle (address unknown)
10 * $Log$
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
15 * Initial revision
19 #include <basedef.h>
20 #include <vmm.h>
21 #include <ndis.h>
22 #include <vwin32.h>
23 #include <string.h>
25 #include <epacket.h> // From PWLib
27 #include "lock.h"
30 #pragma intrinsic(memset,memcpy,strlen,strcat,strcpy)
33 ///////////////////////////////////////////////////////////////////////////////
35 #define MAJOR_VERSION 1
36 #define MINOR_VERSION 2
38 #define MAX_OPEN 4
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;
52 char* lpBuffer;
53 DWORD cbBuffer;
54 DWORD* lpcbBytesReturned;
55 OVERLAPPED* lpoOverlapped;
56 DWORD hDevice;
57 DWORD tagProcess;
58 } PACKET_RESERVED, *PPACKET_RESERVED;
61 typedef struct _INTERNAL_REQUEST
63 PACKET_RESERVED Reserved;
64 NDIS_REQUEST Request;
65 } INTERNAL_REQUEST, *PINTERNAL_REQUEST;
68 typedef struct _OPEN_INSTANCE
70 LIST_ENTRY ListElement;
72 DWORD hDevice;
73 NDIS_STATUS Status;
74 NDIS_HANDLE AdapterHandle;
75 NDIS_HANDLE BindAdapterContext;
76 NDIS_HANDLE PacketPool;
77 NDIS_HANDLE BufferPool;
79 NDIS_SPIN_LOCK RcvQSpinLock;
80 LIST_ENTRY RcvList;
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;
96 LIST_ENTRY OpenList;
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 )
110 _asm mov ebx, 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);
140 if (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
152 // call.
153 VWIN32_DIOCCompletionRoutine(pOverlap->O_Internal);
155 // Unlock buffers
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);
183 if (pNdisBuffer)
184 NdisFreeBuffer(pNdisBuffer);
186 // return status
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
192 // call.
193 VWIN32_DIOCCompletionRoutine(Reserved->lpoOverlapped->O_Internal);
195 // Unlock buffers
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);
224 return;
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;
246 NDIS_STATUS Status;
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);
267 // Reset the adapter
268 NdisReset(&Status, pOpen->AdapterHandle);
270 if (Status != NDIS_STATUS_PENDING)
271 PacketResetComplete(pOpen, Status);
272 return 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);
296 else {
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
305 // call.
306 VWIN32_DIOCCompletionRoutine(pOverlap->O_Internal);
308 // Unlock buffers
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,
325 DWORD FunctionCode,
326 DWORD dwDDB,
327 DWORD hDevice,
328 PDIOCPARAMETERS pDiocParms)
330 // perform a packet request
332 PLIST_ENTRY RequestListEntry;
333 PINTERNAL_REQUEST pRequest;
334 PPACKET_RESERVED pReserved;
335 EPACKET_OID * OidData;
336 NDIS_STATUS Status;
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;
375 else {
376 if (OidData->Oid >= 0x01000000)
377 pRequest->Request.RequestType = NdisRequestQueryInformation;
378 else
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);
392 return 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,
404 IN UINT PacketSize)
406 // upcall on packet arrival
408 POPEN_INSTANCE Open;
409 PLIST_ENTRY PacketListEntry;
410 PNDIS_PACKET pPacket;
411 NDIS_STATUS Status;
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)
468 // get packet status
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);
501 else {
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;
520 UINT Medium;
521 NDIS_MEDIUM MediumArray = NdisMedium802_3;
522 UINT i;
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;
529 return;
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),
543 TRANSMIT_PACKETS,
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;
548 return;
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;
556 return;
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;
584 switch (*pStatus) {
585 case NDIS_STATUS_PENDING:
586 break;
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
594 default:
595 PacketBindAdapterComplete(oiNew, *pStatus, ErrorStatus);
596 break;
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)
616 return;
618 // Remove Adapter from global list
619 RemoveEntryList(&Open->ListElement);
621 // Free Memory
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);
655 // complete normally
656 PacketTransferDataComplete(Open, pPacket, NDIS_STATUS_SUCCESS, 0);
659 NdisReleaseSpinLock(&Open->RcvQSpinLock);
661 // close the adapter
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
679 NDIS_STATUS Status;
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");
701 NDIS_STATUS Status;
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,
736 &ProtocolChar,
737 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
739 if (Status != NDIS_STATUS_SUCCESS) {
740 NdisFreeMemory(GlobalDeviceExtension, sizeof(DEVICE_EXTENSION), 0);
741 return Status;
744 // initialize open list
745 InitializeListHead(&GlobalDeviceExtension->OpenList);
747 // initialize global device extension
748 GlobalDeviceExtension->DriverObject = DriverObject;
750 return Status;
754 ///////////////////////////////////////////////////////////////////////////////
756 POPEN_INSTANCE GetOpen(DWORD handle)
758 // return a specified Open Instance
760 PLIST_ENTRY pHead = &GlobalDeviceExtension->OpenList;
761 PLIST_ENTRY pTemp;
762 POPEN_INSTANCE Open;
765 if (GlobalDeviceExtension == NULL)
766 return 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)
773 return Open;
776 return NULL; // just in case
780 ///////////////////////////////////////////////////////////////////////////////
782 VOID PacketAllocatePacketBuffer(PNDIS_STATUS pStatus,
783 POPEN_INSTANCE pOpen,
784 PNDIS_PACKET *ppPacket,
785 PDIOCPARAMETERS pDiocParms,
786 DWORD FunctionCode )
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;
799 return;
802 pPacket = *ppPacket;
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;
809 break;
811 case IOCTL_EPACKET_WRITE:
812 RESERVED(pPacket)->lpBuffer = (PVOID)PacketPageLock(pDiocParms->lpvInBuffer, pDiocParms->cbInBuffer);
813 RESERVED(pPacket)->cbBuffer = pDiocParms->cbInBuffer;
814 break;
816 default:
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;
825 return;
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,
836 &pNdisBuffer,
837 pOpen->BufferPool,
838 (PVOID)(RESERVED(pPacket)->lpBuffer + ETHERNET_HEADER_LENGTH),
839 pDiocParms->cbOutBuffer);
840 break;
842 case IOCTL_EPACKET_WRITE:
843 NdisAllocateBuffer(pStatus,
844 &pNdisBuffer,
845 pOpen->BufferPool,
846 (PVOID)RESERVED(pPacket)->lpBuffer,
847 pDiocParms->cbInBuffer);
848 break;
851 if (*pStatus == NDIS_STATUS_SUCCESS)
852 NdisChainBufferAtFront(pPacket, pNdisBuffer); // Attach buffer to Packet
853 else {
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,
864 DWORD dwDDB,
865 DWORD hDevice,
866 PDIOCPARAMETERS pDiocParms)
868 // read a packet
870 NDIS_STATUS Status;
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,
897 DWORD dwDDB,
898 DWORD hDevice,
899 PDIOCPARAMETERS pDiocParms)
901 // write a packet
903 PNDIS_PACKET pPacket;
904 NDIS_STATUS Status;
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
911 // Call the MAC
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,
925 DWORD dwDDB,
926 DWORD hDevice,
927 PDIOCPARAMETERS pDiocParms)
929 // called from applications
931 POPEN_INSTANCE Open;
932 NDIS_STATUS Status;
933 UCHAR AdapterBuffer[5];
934 NDIS_STRING AdapterName = NDIS_STRING_CONST(AdapterBuffer);
937 switch (dwService) {
938 case DIOC_OPEN:
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;
949 else {
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,
962 &AdapterName,
963 (PVOID)hDevice, /* special */
964 NULL);
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;
971 break;
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);
977 break;
979 case IOCTL_EPACKET_READ:
980 if ((Open = GetOpen(hDevice)) != NULL)
981 return PacketRead(Open, dwDDB, hDevice, pDiocParms);
982 break;
984 case IOCTL_EPACKET_WRITE:
985 if ((Open = GetOpen(hDevice)) != NULL)
986 return PacketWrite(Open, dwDDB, hDevice, pDiocParms);
987 break;
990 *(DWORD *)pDiocParms->lpcbBytesReturned = 0;
991 return NDIS_STATUS_SUCCESS;
995 // End of File ////////////////////////////////////////////////////////////////