epacket.c
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:32k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * epacket.c
  3.  *
  4.  * Ethernet Packet Interface to NDIS drivers.
  5.  *
  6.  * Copyright 1998 Equivalence Pty. Ltd.
  7.  *
  8.  * Original code by William Ingle (address unknown)
  9.  *
  10.  * $Log: epacket.c,v $
  11.  * Revision 1.2  1998/10/06 10:24:42  robertj
  12.  * Fixed hang when using reset command, removed the command!
  13.  *
  14.  * Revision 1.1  1998/09/28 08:08:31  robertj
  15.  * Initial revision
  16.  *
  17.  */
  18. #include <basedef.h>
  19. #include <vmm.h>
  20. #include <ndis.h>
  21. #include <vwin32.h>
  22. #include <string.h>
  23. #include <epacket.h>   // From PWLib
  24. #include "lock.h"
  25. #pragma intrinsic(memset,memcpy,strlen,strcat,strcpy)
  26. ///////////////////////////////////////////////////////////////////////////////
  27. #define MAJOR_VERSION 1
  28. #define MINOR_VERSION 2
  29. #define MAX_OPEN 4
  30. #define MAX_REQUESTS 4
  31. #define TRANSMIT_PACKETS 64 //was 16
  32. #define  ETHERNET_HEADER_LENGTH   14
  33. #define  ETHERNET_DATA_LENGTH     1500
  34. #define  ETHERNET_PACKET_LENGTH   (ETHERNET_HEADER_LENGTH+ETHERNET_DATA_LENGTH)
  35. typedef struct _PACKET_RESERVED 
  36. {
  37.   LIST_ENTRY ListElement;
  38.   char* lpBuffer;
  39.   DWORD cbBuffer;
  40.   DWORD* lpcbBytesReturned;
  41.   OVERLAPPED* lpoOverlapped;
  42.   DWORD hDevice;
  43.   DWORD tagProcess;
  44. } PACKET_RESERVED, *PPACKET_RESERVED;
  45. typedef struct _INTERNAL_REQUEST 
  46. {
  47.   PACKET_RESERVED Reserved;
  48.   NDIS_REQUEST    Request;
  49. } INTERNAL_REQUEST, *PINTERNAL_REQUEST;
  50. typedef struct _OPEN_INSTANCE 
  51. {
  52.   LIST_ENTRY      ListElement;
  53.   DWORD           hDevice;
  54.   NDIS_STATUS     Status; 
  55.   NDIS_HANDLE     AdapterHandle;
  56.   NDIS_HANDLE     BindAdapterContext;
  57.   NDIS_HANDLE     PacketPool;
  58.   NDIS_HANDLE     BufferPool;
  59.   NDIS_SPIN_LOCK  RcvQSpinLock;
  60.   LIST_ENTRY      RcvList;
  61.   NDIS_SPIN_LOCK  RequestSpinLock;
  62.   LIST_ENTRY      RequestList;
  63.   NDIS_SPIN_LOCK  ResetSpinLock;
  64.   LIST_ENTRY      ResetIrpList;
  65.   INTERNAL_REQUEST  Requests[MAX_REQUESTS];
  66. } OPEN_INSTANCE, *POPEN_INSTANCE;
  67. typedef struct _DEVICE_EXTENSION 
  68. {
  69.   PDRIVER_OBJECT  DriverObject;
  70.   NDIS_HANDLE   NdisProtocolHandle;
  71.   LIST_ENTRY   OpenList;
  72. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
  73. #define RESERVED(_p) ((PPACKET_RESERVED)((_p)->ProtocolReserved))
  74. //
  75. // define wrapper for VWIN32_DIOCCompletionRoutine 
  76. //
  77. void VXDINLINE VWIN32_DIOCCompletionRoutine( DWORD hEvent )
  78. {
  79.   _asm mov ebx, hEvent
  80.   VxDCall( VWIN32_DIOCCompletionRoutine );
  81. }
  82. #pragma VxD_LOCKED_CODE_SEG
  83. #pragma VxD_LOCKED_DATA_SEG
  84. PDEVICE_EXTENSION GlobalDeviceExtension = NULL;
  85.  
  86. ///////////////////////////////////////////////////////////////////////////////
  87.     
  88. VOID NDIS_API PacketTransferDataComplete(IN NDIS_HANDLE  ProtocolBindingContext,
  89.                                          IN PNDIS_PACKET pPacket,
  90.                                          IN NDIS_STATUS  Status,
  91.                                          IN UINT         BytesTransfered)
  92. {
  93.   // upcall when no more data available
  94.   POPEN_INSTANCE Open = (POPEN_INSTANCE)ProtocolBindingContext;
  95.   PPACKET_RESERVED pReserved = (PPACKET_RESERVED)(pPacket->ProtocolReserved);
  96.   OVERLAPPED * pOverlap = (OVERLAPPED *)(pReserved->lpoOverlapped);
  97.   PNDIS_BUFFER pNdisBuffer;
  98.   // free buffer descriptor
  99.   NdisUnchainBufferAtFront(pPacket, &pNdisBuffer);
  100.   if (pNdisBuffer)
  101.     NdisFreeBuffer(pNdisBuffer);
  102.   // set total bytes returned
  103.   BytesTransfered += ETHERNET_HEADER_LENGTH;
  104.   *pReserved->lpcbBytesReturned += BytesTransfered;
  105.   pOverlap->O_InternalHigh = *(pReserved->lpcbBytesReturned);
  106.   // The internal member of overlapped structure contains
  107.   // a pointer to the event structure that will be signalled,
  108.   // resuming the execution of the waitng GetOverlappedResult
  109.   // call.
  110.   VWIN32_DIOCCompletionRoutine(pOverlap->O_Internal);
  111.   // Unlock buffers   
  112.   PacketPageUnlock(pReserved->lpBuffer, pReserved->cbBuffer);
  113.   PacketPageUnlock(pReserved->lpcbBytesReturned, sizeof(DWORD));
  114.   PacketPageUnlock(pReserved->lpoOverlapped, sizeof(OVERLAPPED));
  115.   // recycle the packet
  116.   NdisReinitializePacket(pPacket);
  117.   // Put the packet on the free queue
  118.   NdisFreePacket(pPacket);
  119. }
  120. ///////////////////////////////////////////////////////////////////////////////
  121. VOID NDIS_API PacketSendComplete(IN NDIS_HANDLE  ProtocolBindingContext,
  122.                                  IN PNDIS_PACKET pPacket,
  123.                                  IN NDIS_STATUS  Status)
  124. {
  125.   // upcall on completion of send
  126.   PNDIS_BUFFER     pNdisBuffer;
  127.   PPACKET_RESERVED Reserved = (PPACKET_RESERVED)pPacket->ProtocolReserved;
  128.   
  129.   // free buffer descriptor
  130.   NdisUnchainBufferAtFront(pPacket, &pNdisBuffer);
  131.   
  132.   if (pNdisBuffer)
  133.     NdisFreeBuffer(pNdisBuffer);
  134.   
  135.   // return status
  136.   Reserved->lpoOverlapped->O_InternalHigh = Status;
  137.   
  138.   // The internal member of overlapped structure contains
  139.   // a pointer to the event structure that will be signalled,
  140.   // resuming the execution of the waiting GetOverlappedResult
  141.   // call.
  142.   VWIN32_DIOCCompletionRoutine(Reserved->lpoOverlapped->O_Internal);
  143.   
  144.   // Unlock buffers
  145.   PacketPageUnlock(Reserved->lpBuffer, Reserved->cbBuffer);
  146.   PacketPageUnlock(Reserved->lpcbBytesReturned, sizeof(DWORD));
  147.   PacketPageUnlock(Reserved->lpoOverlapped, sizeof(OVERLAPPED));
  148.   
  149.   // recycle the packet
  150.   NdisReinitializePacket(pPacket);
  151.   
  152.   // Put the packet back on the free list
  153.   NdisFreePacket(pPacket);
  154. }
  155. ///////////////////////////////////////////////////////////////////////////////
  156. VOID NDIS_API PacketResetComplete(IN NDIS_HANDLE ProtocolBindingContext,
  157.                                   IN NDIS_STATUS Status)
  158. {
  159.   // upcall on reset completion
  160.   POPEN_INSTANCE Open = (POPEN_INSTANCE)ProtocolBindingContext;
  161.   PLIST_ENTRY    ResetListEntry;
  162.   //  remove the reset request from the list
  163.   NdisAcquireSpinLock(&Open->ResetSpinLock);
  164.   
  165.   if (IsListEmpty(&Open->ResetIrpList)) { 
  166.     NdisReleaseSpinLock(&Open->ResetSpinLock);
  167.     return;
  168.   }
  169.   ResetListEntry = RemoveHeadList(&Open->ResetIrpList);
  170.   NdisReleaseSpinLock(&Open->ResetSpinLock);
  171.   
  172.   // Acquire request element from list
  173.   NdisAcquireSpinLock(&Open->RequestSpinLock);
  174.   
  175.   InsertTailList(&Open->RequestList, ResetListEntry);
  176.   
  177.   NdisReleaseSpinLock(&Open->RequestSpinLock);
  178. }
  179. ///////////////////////////////////////////////////////////////////////////////
  180. NDIS_STATUS NDIS_API PacketReset(POPEN_INSTANCE pOpen)
  181. {
  182.   // reset the protocol
  183.   PLIST_ENTRY ResetListEntry;
  184.   NDIS_STATUS Status;
  185.   
  186.   // Acquire request element from list
  187.   NdisAllocateSpinLock(&pOpen->RequestSpinLock);
  188.   
  189.   if (IsListEmpty(&pOpen->RequestList)) { 
  190.     NdisReleaseSpinLock(&pOpen->RequestSpinLock);
  191.     return NDIS_STATUS_RESOURCES;
  192.   }
  193.   ResetListEntry = RemoveHeadList(&pOpen->RequestList);
  194.   NdisReleaseSpinLock(&pOpen->RequestSpinLock);
  195.   
  196.   // Insert Reset IRP into Request Queue
  197.   NdisAcquireSpinLock(&pOpen->ResetSpinLock);
  198.   
  199.   InsertTailList(&pOpen->ResetIrpList, ResetListEntry);
  200.   
  201.   NdisReleaseSpinLock(&pOpen->ResetSpinLock);
  202.   
  203.   // Reset the adapter
  204.   NdisReset(&Status, pOpen->AdapterHandle);
  205.   
  206.   if (Status != NDIS_STATUS_PENDING)
  207.     PacketResetComplete(pOpen, Status);
  208.   return Status;
  209. }
  210. ///////////////////////////////////////////////////////////////////////////////
  211. VOID NDIS_API PacketRequestComplete(IN NDIS_HANDLE   ProtocolBindingContext,
  212.                                     IN PNDIS_REQUEST NdisRequest,
  213.                                     IN NDIS_STATUS   Status)
  214. {
  215.   // perform a packet request complete
  216.   POPEN_INSTANCE    Open      = (POPEN_INSTANCE)ProtocolBindingContext;
  217.   PINTERNAL_REQUEST pRequest  = CONTAINING_RECORD(NdisRequest, INTERNAL_REQUEST, Request);
  218.   PPACKET_RESERVED  pReserved = &pRequest->Reserved;
  219.   OVERLAPPED      * pOverlap  = (OVERLAPPED *)pReserved->lpoOverlapped;
  220.   EPACKET_OID     * oidData   = (EPACKET_OID*)pReserved->lpBuffer;
  221.   if (Status == NDIS_STATUS_SUCCESS) {
  222.     // set total bytes returned
  223.     *pReserved->lpcbBytesReturned = oidData->Length + sizeof(EPACKET_OID) - sizeof(oidData->Data);
  224.     pOverlap->O_InternalHigh      = *(pReserved->lpcbBytesReturned);
  225.   }
  226.   else {
  227.     *pReserved->lpcbBytesReturned = 0; // set total bytes returned
  228.     pOverlap->O_InternalHigh      = *pReserved->lpcbBytesReturned;
  229.     oidData->Length = Status;         // return status in oidData if there is an error 
  230.   }
  231.   
  232.   // The internal member of overlapped structure contains
  233.   // a pointer to the event structure that will be signalled,
  234.   // resuming the execution of the waitng GetOverlappedResult
  235.   // call.
  236.   VWIN32_DIOCCompletionRoutine(pOverlap->O_Internal);
  237.   
  238.   // Unlock buffers
  239.   PacketPageUnlock(pReserved->lpBuffer, pReserved->cbBuffer);
  240.   PacketPageUnlock(pReserved->lpcbBytesReturned, sizeof(DWORD));
  241.   PacketPageUnlock(pReserved->lpoOverlapped, sizeof(OVERLAPPED));
  242.   
  243.   // Return request element to list
  244.   NdisAcquireSpinLock(&Open->RequestSpinLock);
  245.   
  246.   InsertTailList(&Open->RequestList, &pReserved->ListElement);
  247.   
  248.   NdisReleaseSpinLock(&Open->RequestSpinLock);
  249. }
  250. ///////////////////////////////////////////////////////////////////////////////
  251. DWORD NDIS_API PacketRequest(POPEN_INSTANCE  Open,
  252.                              DWORD           FunctionCode,
  253.                              DWORD           dwDDB,
  254.                              DWORD           hDevice,
  255.                              PDIOCPARAMETERS pDiocParms)
  256. {
  257.   // perform a packet request
  258.   PLIST_ENTRY       RequestListEntry;
  259.   PINTERNAL_REQUEST pRequest;
  260.   PPACKET_RESERVED  pReserved;
  261.   EPACKET_OID *  OidData;
  262.   NDIS_STATUS       Status;
  263.   
  264.   // Acquire request element from list
  265.   NdisAcquireSpinLock(&Open->RequestSpinLock);
  266.   
  267.   if (IsListEmpty(&Open->RequestList)) { 
  268.     *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0;
  269.     NdisReleaseSpinLock(&Open->RequestSpinLock);
  270.     return NDIS_STATUS_SUCCESS;
  271.   }
  272.   RequestListEntry = RemoveHeadList(&Open->RequestList);
  273.   NdisReleaseSpinLock(&Open->RequestSpinLock);
  274.   
  275.   pReserved = CONTAINING_RECORD(RequestListEntry, PACKET_RESERVED, ListElement);
  276.   pRequest  = CONTAINING_RECORD(pReserved, INTERNAL_REQUEST, Reserved);
  277.   OidData   = (EPACKET_OID*)(pDiocParms->lpvInBuffer);
  278.   if ((pDiocParms->cbInBuffer != pDiocParms->cbOutBuffer) ||
  279.       (pDiocParms->cbInBuffer < sizeof(*OidData) - sizeof(OidData->Data) + OidData->Length)) {
  280.     *(DWORD *)pDiocParms->lpcbBytesReturned = 1;
  281.     return NDIS_STATUS_BUFFER_TOO_SHORT;
  282.   }
  283.   // The buffer is valid
  284.   pReserved->lpBuffer          = (PVOID)PacketPageLock(pDiocParms->lpvInBuffer, pDiocParms->cbInBuffer);
  285.   pReserved->lpcbBytesReturned = (PVOID)PacketPageLock(pDiocParms->lpcbBytesReturned, sizeof(DWORD));
  286.   pReserved->lpoOverlapped     = (PVOID)PacketPageLock(pDiocParms->lpoOverlapped, sizeof(OVERLAPPED));
  287.   pReserved->cbBuffer          = pDiocParms->cbInBuffer;
  288.   pReserved->hDevice           = pDiocParms->hDevice;
  289.   pReserved->tagProcess        = pDiocParms->tagProcess;
  290.   
  291.   if (FunctionCode == IOCTL_EPACKET_SET_OID) {                      
  292.     pRequest->Request.RequestType                                  = NdisRequestSetInformation;
  293.     pRequest->Request.DATA.SET_INFORMATION.Oid                     = OidData->Oid;
  294.     pRequest->Request.DATA.SET_INFORMATION.InformationBufferLength = OidData->Length;
  295.     pRequest->Request.DATA.SET_INFORMATION.InformationBuffer       = OidData->Data;
  296.   } 
  297.   else {
  298.     if (OidData->Oid >= 0x01000000)
  299.       pRequest->Request.RequestType = NdisRequestQueryInformation;
  300.     else
  301.       pRequest->Request.RequestType = NdisRequestGeneric1;
  302.     pRequest->Request.DATA.QUERY_INFORMATION.Oid                     = OidData->Oid;
  303.     pRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = OidData->Length;
  304.     pRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer       = OidData->Data;
  305.   }
  306.   // submit the request
  307.   NdisRequest(&Status, Open->AdapterHandle, &pRequest->Request);
  308.   if (Status == NDIS_STATUS_PENDING)
  309.     return(-1);      // This will make DeviceIOControl return ERROR_IO_PENDING
  310.   PacketRequestComplete(Open, &pRequest->Request, Status);
  311.   return Status;
  312. }
  313. ///////////////////////////////////////////////////////////////////////////////
  314. NDIS_STATUS NDIS_API PacketReceiveIndicate(IN NDIS_HANDLE ProtocolBindingContext,
  315.                                            IN NDIS_HANDLE MacReceiveContext,
  316.                                            IN PVOID       HeaderBuffer,
  317.                                            IN UINT        HeaderBufferSize,
  318.                                            IN PVOID       LookaheadBuffer,
  319.                                            IN UINT        LookaheadBufferSize,
  320.                                            IN UINT        PacketSize)
  321. {
  322.   // upcall on packet arrival
  323.   POPEN_INSTANCE      Open;
  324.   PLIST_ENTRY         PacketListEntry;
  325.   PNDIS_PACKET        pPacket;
  326.   NDIS_STATUS         Status;
  327.   UINT                BytesTransfered = 0;
  328.   PPACKET_RESERVED    pReserved;
  329.   if (HeaderBufferSize != ETHERNET_HEADER_LENGTH)
  330.     return NDIS_STATUS_NOT_ACCEPTED;
  331.   
  332.   Open = (POPEN_INSTANCE) ProtocolBindingContext;
  333.   
  334.   //  See if there are any pending reads that we can satisfy
  335.   NdisAcquireSpinLock(&Open->RcvQSpinLock); // fixed 5.11.97
  336.   
  337.   if (IsListEmpty(&Open->RcvList)) { 
  338.     NdisReleaseSpinLock(&Open->RcvQSpinLock);
  339.     return NDIS_STATUS_NOT_ACCEPTED;
  340.   }
  341.   PacketListEntry = RemoveHeadList(&Open->RcvList);
  342.   NdisReleaseSpinLock(&Open->RcvQSpinLock);
  343.   
  344.   pReserved = CONTAINING_RECORD(PacketListEntry, PACKET_RESERVED, ListElement);
  345.   pPacket = CONTAINING_RECORD(pReserved, NDIS_PACKET, ProtocolReserved);
  346.   
  347.   // Copy the MAC header
  348.   NdisMoveMemory(RESERVED(pPacket)->lpBuffer, HeaderBuffer, HeaderBufferSize);
  349.   //  Call the Mac to transfer the data portion of the packet
  350.   NdisTransferData(&Status, Open->AdapterHandle, MacReceiveContext, 0, PacketSize, pPacket, &BytesTransfered);
  351.   if (Status == NDIS_STATUS_PENDING)
  352.     return NDIS_STATUS_PENDING;
  353.   if (Status == NDIS_STATUS_SUCCESS) {
  354.     PacketTransferDataComplete(Open, pPacket, Status, BytesTransfered);
  355.     return NDIS_STATUS_SUCCESS;
  356.   }
  357.   PacketTransferDataComplete(Open, pPacket, Status, 0);
  358.   return NDIS_STATUS_SUCCESS;
  359. }
  360. ///////////////////////////////////////////////////////////////////////////////
  361. VOID NDIS_API PacketReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext)
  362. {
  363.   // upcall when receive complete
  364. }
  365. ///////////////////////////////////////////////////////////////////////////////
  366. VOID NDIS_API PacketStatus(IN NDIS_HANDLE ProtocolBindingContext,
  367.                            IN NDIS_STATUS Status,
  368.                            IN PVOID       StatusBuffer,
  369.                            IN UINT        StatusBufferSize)
  370. {
  371.   // get packet status
  372. }
  373. ///////////////////////////////////////////////////////////////////////////////
  374. VOID NDIS_API PacketStatusComplete(IN NDIS_HANDLE ProtocolBindingContext)
  375. {
  376.   // completion handler
  377. }
  378. ///////////////////////////////////////////////////////////////////////////////
  379. VOID NDIS_API PacketBindAdapterComplete(IN NDIS_HANDLE  ProtocolBindingContext,
  380.                                         IN NDIS_STATUS  Status,
  381.                                         IN NDIS_STATUS  OpenErrorStatus)
  382. {
  383.   // upcall on Bind completion
  384.   POPEN_INSTANCE Open = (POPEN_INSTANCE)ProtocolBindingContext;
  385.   // If the binding is unsuccessful then we deallocate data structures in 
  386.   // preparation for unloading
  387.   if (Status != NDIS_STATUS_SUCCESS) {
  388.     NdisFreeSpinLock(&Open->RequestSpinLock);
  389.     NdisFreeSpinLock(&Open->RcvQSpinLock);
  390.     NdisFreeBufferPool(Open->BufferPool);
  391.     NdisFreePacketPool(Open->PacketPool);
  392.     NdisFreeMemory(Open, sizeof(OPEN_INSTANCE), 0);
  393.   }
  394.   else {
  395.     // Insert New Adapter into list
  396.     InsertTailList(&GlobalDeviceExtension->OpenList, &Open->ListElement);
  397.   }
  398. }
  399. ///////////////////////////////////////////////////////////////////////////////
  400. VOID NDIS_API PacketBindAdapter(OUT PNDIS_STATUS pStatus,
  401.                                 IN  NDIS_HANDLE  BindAdapterContext,
  402.                                 IN  PNDIS_STRING pAdapterName,
  403.                                 IN  PVOID        SystemSpecific1,
  404.                                 IN  PVOID        SystemSpecific2)
  405. {
  406.   //   bind this driver to a NIC
  407.   
  408.   POPEN_INSTANCE    oiNew;
  409.   NDIS_STATUS     ErrorStatus, AllocStatus;
  410.   UINT              Medium;
  411.   NDIS_MEDIUM       MediumArray = NdisMedium802_3;
  412.   UINT              i;
  413.   //  allocate some memory for the open structure
  414.   NdisAllocateMemory((PVOID *)&oiNew, sizeof(OPEN_INSTANCE), 0, -1);
  415.   if (oiNew == NULL) { // not enough memory
  416.     *pStatus = NDIS_STATUS_RESOURCES;
  417.     return;
  418.   }
  419.   
  420.   NdisZeroMemory((PVOID)oiNew, sizeof(OPEN_INSTANCE));
  421.   
  422.   // Save Binding Context
  423.   oiNew->BindAdapterContext = BindAdapterContext;
  424.   
  425.   // Save the device handle
  426.   oiNew->hDevice = (DWORD)SystemSpecific1;
  427.   
  428.   // Allocate a packet pool for our xmit and receive packets
  429.   NdisAllocatePacketPool(&AllocStatus,
  430.                          &(oiNew->PacketPool),
  431.                          TRANSMIT_PACKETS,
  432.                          sizeof(PACKET_RESERVED));
  433.   if (AllocStatus != NDIS_STATUS_SUCCESS) { // not enough memory
  434.     NdisFreeMemory(oiNew, sizeof(OPEN_INSTANCE), 0);
  435.     *pStatus = NDIS_STATUS_RESOURCES;
  436.     return;
  437.   }
  438.   
  439.   // Allocate a buffer pool for our xmit and receive buffers
  440.   NdisAllocateBufferPool(&AllocStatus, &(oiNew->BufferPool), TRANSMIT_PACKETS);
  441.   if (AllocStatus != NDIS_STATUS_SUCCESS) { // not enough memory
  442.     NdisFreeMemory(oiNew, sizeof(OPEN_INSTANCE), 0);
  443.     *pStatus = NDIS_STATUS_RESOURCES;
  444.     return;
  445.   }
  446.   //  list to hold irp's that want to reset the adapter
  447.   NdisAllocateSpinLock(&oiNew->ResetSpinLock);
  448.   InitializeListHead(&oiNew->ResetIrpList);
  449.   //  Initialize list for holding pending read requests
  450.   NdisAllocateSpinLock(&oiNew->RcvQSpinLock);
  451.   InitializeListHead(&oiNew->RcvList);
  452.   
  453.   //  Initialize the request list
  454.   NdisAllocateSpinLock(&oiNew->RequestSpinLock);
  455.   InitializeListHead(&oiNew->RequestList);
  456.   
  457.   //  link up the request stored in our open block
  458.   for (i = 0; i < MAX_REQUESTS; i++) {
  459.     // Braces are required as InsertTailList macro has multiple statements in it
  460.     InsertTailList(&oiNew->RequestList, &oiNew->Requests[i].Reserved.ListElement);
  461.   }
  462.   
  463.   //  Try to open the MAC
  464.   NdisOpenAdapter(pStatus, &ErrorStatus, &oiNew->AdapterHandle, &Medium, &MediumArray, 1,
  465.                   GlobalDeviceExtension->NdisProtocolHandle, oiNew, pAdapterName, 0, NULL);
  466.   
  467.   //  Save the status returned by NdisOpenAdapter for completion routine
  468.   oiNew->Status = *pStatus;
  469.   
  470.   switch (*pStatus) {
  471.     case NDIS_STATUS_PENDING:
  472.       break;
  473.     
  474.     case NDIS_STATUS_SUCCESS:
  475.       ErrorStatus = NDIS_STATUS_SUCCESS;
  476.     
  477.       // fall through to completion routine with oiNew->Status 
  478.       // set to !NDIS_STATUS_PENDING
  479.     
  480.     default:
  481.       PacketBindAdapterComplete(oiNew, *pStatus, ErrorStatus);
  482.       break;
  483.   }
  484. }
  485. ///////////////////////////////////////////////////////////////////////////////
  486. VOID NDIS_API PacketUnbindAdapterComplete(IN POPEN_INSTANCE Open,
  487.                                           IN NDIS_STATUS Status)
  488. {
  489.   // upcall on NdisCloseAdapter completion
  490.   // If Open->Status == NDIS_STATUS_PENDING then we must complete the pended unbinding
  491.   if (Open->Status == NDIS_STATUS_PENDING) {
  492.     NdisCompleteUnbindAdapter(Open->BindAdapterContext, Status);
  493.     Open->Status = NDIS_STATUS_SUCCESS;
  494.   }
  495.   if (Status != NDIS_STATUS_SUCCESS)
  496.     return;
  497.   // Remove Adapter from global list
  498.   RemoveEntryList(&Open->ListElement);
  499.   // Free Memory
  500.   NdisFreeSpinLock(&Open->RequestSpinLock);
  501.   NdisFreeSpinLock(&Open->RcvQSpinLock);
  502.   NdisFreeSpinLock(&Open->ResetSpinLock);
  503.   NdisFreeBufferPool(Open->BufferPool);
  504.   NdisFreePacketPool(Open->PacketPool);
  505.   NdisFreeMemory(Open, sizeof(OPEN_INSTANCE), 0);
  506. }
  507. ///////////////////////////////////////////////////////////////////////////////
  508. VOID NDIS_API PacketUnbindAdapter(OUT PNDIS_STATUS   Status,
  509.                                   IN  POPEN_INSTANCE Open,
  510.                                   IN  POPEN_INSTANCE junk)
  511. {
  512.   // detach protocol from the NIC clean up any pending I/O requests
  513.   PLIST_ENTRY  PacketListEntry;
  514.   PNDIS_PACKET pPacket;
  515.   //  The open instance of the device is about to close
  516.   //  We need to complete all pending I/O requests
  517.   //  First we complete any pending read requests
  518.   NdisAcquireSpinLock(&Open->RcvQSpinLock);
  519.   while (!IsListEmpty(&Open->RcvList)) {
  520.     PacketListEntry = RemoveHeadList(&Open->RcvList);
  521.     pPacket = CONTAINING_RECORD(PacketListEntry, NDIS_PACKET, ProtocolReserved);
  522.     //  complete normally
  523.     PacketTransferDataComplete(Open, pPacket, NDIS_STATUS_SUCCESS, 0);
  524.   }
  525.   NdisReleaseSpinLock(&Open->RcvQSpinLock);
  526.   // close the adapter
  527.   NdisCloseAdapter(Status, Open->AdapterHandle);
  528.   // Save status returned from NdisCloseAdapter for completion routine
  529.   Open->Status = *Status;
  530.   if (*Status != NDIS_STATUS_PENDING)
  531.     PacketUnbindAdapterComplete(Open, *Status);
  532. }
  533. ///////////////////////////////////////////////////////////////////////////////
  534. VOID NDIS_API PacketUnload()
  535. {
  536.   // deregister the protocol, free remaining memory 
  537.   //  - called by NdisCloseAdapter when last adapter closed
  538.   NDIS_STATUS Status;
  539.   
  540.   if (GlobalDeviceExtension != NULL) {
  541.     NdisDeregisterProtocol(&Status, GlobalDeviceExtension->NdisProtocolHandle);
  542.     
  543.     if (Status == NDIS_STATUS_SUCCESS)
  544.       NdisFreeMemory(GlobalDeviceExtension, sizeof(DEVICE_EXTENSION), 0);
  545.     GlobalDeviceExtension = NULL;
  546.   }
  547. }
  548. ///////////////////////////////////////////////////////////////////////////////
  549. NTSTATUS NDIS_API DriverEntry(IN PDRIVER_OBJECT  DriverObject,
  550.                               IN PUNICODE_STRING RegistryPath)
  551. {
  552.   // initialiae the driver
  553.   NDIS_PROTOCOL_CHARACTERISTICS ProtocolChar;
  554.   NDIS_STRING ProtoName = NDIS_STRING_CONST("EPACKET");
  555.   NDIS_STATUS Status;
  556.   // Because the driver can be loaded once for each Netcard on the system,
  557.   // and because DriverEntry is called each time, we must ensure that
  558.   // initialization is performed only once.
  559.   if (GlobalDeviceExtension != NULL)
  560.     return NDIS_STATUS_SUCCESS;
  561.         
  562.   NdisAllocateMemory((PVOID *)&GlobalDeviceExtension, sizeof(DEVICE_EXTENSION), 0, -1 );
  563.   if (GlobalDeviceExtension == NULL)
  564.     return NDIS_STATUS_RESOURCES;
  565.   NdisZeroMemory((UCHAR*)GlobalDeviceExtension, sizeof(DEVICE_EXTENSION));
  566.   NdisZeroMemory((UCHAR*)&ProtocolChar, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
  567.   ProtocolChar.MajorNdisVersion            = 0x03;
  568.   ProtocolChar.MinorNdisVersion            = 0x0a;
  569.   ProtocolChar.Reserved                    = 0;
  570.   ProtocolChar.OpenAdapterCompleteHandler  = PacketBindAdapterComplete;
  571.   ProtocolChar.CloseAdapterCompleteHandler = PacketUnbindAdapterComplete;
  572.   ProtocolChar.SendCompleteHandler         = PacketSendComplete;
  573.   ProtocolChar.TransferDataCompleteHandler = PacketTransferDataComplete;
  574.   ProtocolChar.ResetCompleteHandler        = PacketResetComplete;
  575.   ProtocolChar.RequestCompleteHandler      = PacketRequestComplete;
  576.   ProtocolChar.ReceiveHandler              = PacketReceiveIndicate;
  577.   ProtocolChar.ReceiveCompleteHandler      = PacketReceiveComplete;
  578.   ProtocolChar.StatusHandler               = PacketStatus;
  579.   ProtocolChar.StatusCompleteHandler       = PacketStatusComplete;
  580.   ProtocolChar.BindAdapterHandler          = PacketBindAdapter;
  581.   ProtocolChar.UnbindAdapterHandler        = PacketUnbindAdapter;
  582.   ProtocolChar.UnloadProtocolHandler       = PacketUnload;
  583.   ProtocolChar.Name                        = ProtoName;
  584.   
  585.   NdisRegisterProtocol(&Status,
  586.                        &GlobalDeviceExtension->NdisProtocolHandle,
  587.                        &ProtocolChar,
  588.                        sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
  589.   
  590.   if (Status != NDIS_STATUS_SUCCESS) {
  591.     NdisFreeMemory(GlobalDeviceExtension, sizeof(DEVICE_EXTENSION), 0);
  592.     return Status;
  593.   }
  594.   
  595.   // initialize open list
  596.   InitializeListHead(&GlobalDeviceExtension->OpenList);
  597.   
  598.   // initialize global device extension
  599.   GlobalDeviceExtension->DriverObject = DriverObject;
  600.   
  601.   return Status;
  602. }
  603. ///////////////////////////////////////////////////////////////////////////////
  604. POPEN_INSTANCE GetOpen(DWORD handle)
  605. {
  606.   // return a specified Open Instance      
  607.   PLIST_ENTRY     pHead = &GlobalDeviceExtension->OpenList;
  608.   PLIST_ENTRY     pTemp;
  609.   POPEN_INSTANCE  Open;
  610.   
  611.   if (GlobalDeviceExtension == NULL)
  612.     return NULL;
  613.   
  614.   // search the list for the Open Instance containing the specified handle
  615.   
  616.   for (pTemp = pHead->Flink; pTemp != pHead; pTemp = pTemp->Flink) {
  617.     Open = CONTAINING_RECORD(pTemp, OPEN_INSTANCE, ListElement);        
  618.     if (Open && Open->hDevice == handle)
  619.       return Open;
  620.   }
  621.   
  622.   return NULL; // just in case
  623. }
  624. ///////////////////////////////////////////////////////////////////////////////
  625. VOID PacketAllocatePacketBuffer(PNDIS_STATUS    pStatus,
  626.                                 POPEN_INSTANCE  pOpen,
  627.                                 PNDIS_PACKET    *ppPacket,
  628.                                 PDIOCPARAMETERS pDiocParms,
  629.                                 DWORD           FunctionCode )
  630. {
  631.   // allocate a buffer for reading/writing
  632.   PNDIS_BUFFER pNdisBuffer;
  633.   PNDIS_PACKET pPacket;
  634.   
  635.   //  Try to get a packet from our list of free ones
  636.   NdisAllocatePacket(pStatus, ppPacket, pOpen->PacketPool);
  637.   
  638.   if (*pStatus != NDIS_STATUS_SUCCESS) {
  639.     *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0;
  640.     return;
  641.   }
  642.   
  643.   pPacket = *ppPacket;
  644.   
  645.   // Buffers used asynchronously must be page locked
  646.   switch (FunctionCode) {
  647.     case IOCTL_EPACKET_READ:
  648.       RESERVED(pPacket)->lpBuffer = (PVOID)PacketPageLock(pDiocParms->lpvOutBuffer, pDiocParms->cbOutBuffer);
  649.       RESERVED(pPacket)->cbBuffer = pDiocParms->cbOutBuffer;
  650.       break;
  651.     
  652.     case IOCTL_EPACKET_WRITE:
  653.       RESERVED(pPacket)->lpBuffer = (PVOID)PacketPageLock(pDiocParms->lpvInBuffer, pDiocParms->cbInBuffer);
  654.       RESERVED(pPacket)->cbBuffer = pDiocParms->cbInBuffer;
  655.       break;
  656.     
  657.     default:
  658.       // recycle the packet
  659.       NdisReinitializePacket(pPacket);
  660.     
  661.       // Put the packet on the free queue
  662.       NdisFreePacket(pPacket);
  663.     
  664.       *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0;
  665.       *pStatus = NDIS_STATUS_NOT_ACCEPTED;
  666.       return;
  667.   }
  668.   
  669.   RESERVED(pPacket)->lpcbBytesReturned = (PVOID)PacketPageLock(pDiocParms->lpcbBytesReturned, sizeof(DWORD));
  670.   RESERVED(pPacket)->lpoOverlapped     = (PVOID)PacketPageLock(pDiocParms->lpoOverlapped, sizeof(OVERLAPPED));
  671.   RESERVED(pPacket)->hDevice           = pDiocParms->hDevice;
  672.   RESERVED(pPacket)->tagProcess        = pDiocParms->tagProcess;
  673.   
  674.   switch (FunctionCode) {
  675.     case IOCTL_EPACKET_READ:
  676.       NdisAllocateBuffer(pStatus,
  677.                          &pNdisBuffer,
  678.                          pOpen->BufferPool,
  679.                          (PVOID)(RESERVED(pPacket)->lpBuffer + ETHERNET_HEADER_LENGTH),
  680.                          pDiocParms->cbOutBuffer);
  681.       break;
  682.     
  683.     case IOCTL_EPACKET_WRITE:
  684.       NdisAllocateBuffer(pStatus,
  685.                          &pNdisBuffer,
  686.                          pOpen->BufferPool,
  687.                          (PVOID)RESERVED(pPacket)->lpBuffer,
  688.                          pDiocParms->cbInBuffer);
  689.       break;
  690.   }
  691.   
  692.   if (*pStatus == NDIS_STATUS_SUCCESS)
  693.     NdisChainBufferAtFront(pPacket, pNdisBuffer); // Attach buffer to Packet
  694.   else {
  695.     NdisReinitializePacket(pPacket);  // recycle the packet
  696.     NdisFreePacket(pPacket);          // Put the packet on the free queue
  697.     *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0;
  698.   }
  699. }
  700. ///////////////////////////////////////////////////////////////////////////////
  701. DWORD PacketRead(POPEN_INSTANCE     Open,
  702.                  DWORD              dwDDB,
  703.                  DWORD              hDevice,
  704.                  PDIOCPARAMETERS    pDiocParms)
  705. {
  706.   // read a packet
  707.   NDIS_STATUS     Status;
  708.   PNDIS_PACKET    pPacket;
  709.   
  710.   //  Check that the buffer can hold a max length Ethernet packet
  711.   if (pDiocParms->cbOutBuffer < ETHERNET_PACKET_LENGTH) {
  712.     *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0; // Need bigger buffer       
  713.     return NDIS_STATUS_SUCCESS;
  714.   }
  715.   
  716.   PacketAllocatePacketBuffer(&Status, Open, &pPacket, pDiocParms, IOCTL_EPACKET_READ);
  717.   
  718.   if (Status == NDIS_STATUS_SUCCESS) {
  719.     //  Put this packet in a list of pending reads.
  720.     //  The receive indication handler will attempt to remove packets
  721.     //  from this list for use in transfer data calls
  722.     NdisAcquireSpinLock(&Open->RcvQSpinLock); // fixed 6.11.97
  723.     InsertTailList(&Open->RcvList, &RESERVED(pPacket)->ListElement);
  724.     NdisReleaseSpinLock(&Open->RcvQSpinLock);
  725.   }
  726.   return -1;  // This will make DeviceIOControl return ERROR_IO_PENDING
  727. }
  728. ///////////////////////////////////////////////////////////////////////////////
  729. DWORD PacketWrite(POPEN_INSTANCE    Open,
  730.                   DWORD             dwDDB,
  731.                   DWORD             hDevice,
  732.                   PDIOCPARAMETERS   pDiocParms)
  733. {
  734.   // write a packet
  735.   PNDIS_PACKET    pPacket;
  736.   NDIS_STATUS     Status;
  737.   
  738.   PacketAllocatePacketBuffer(&Status, Open, &pPacket, pDiocParms, IOCTL_EPACKET_WRITE);
  739.   if (Status != NDIS_STATUS_SUCCESS)
  740.     return 0;   // This will return immediately with no data written
  741.   
  742.   // Call the MAC
  743.   NdisSend(&Status, Open->AdapterHandle, pPacket);
  744.   if (Status != NDIS_STATUS_PENDING) {
  745.     //  The send didn't pend so call the completion handler now
  746.     PacketSendComplete(Open, pPacket, Status);
  747.   }
  748.   return(-1); // This will make DeviceIOControl return ERROR_IO_PENDING
  749. }
  750. ///////////////////////////////////////////////////////////////////////////////
  751. DWORD _stdcall PacketIOControl(DWORD           dwService,
  752.                                DWORD           dwDDB,
  753.                                DWORD           hDevice,
  754.                                PDIOCPARAMETERS pDiocParms) 
  755. {
  756.   // called from applications
  757.   POPEN_INSTANCE  Open;
  758.   NDIS_STATUS     Status;
  759.   UCHAR           AdapterBuffer[5];
  760.   NDIS_STRING     AdapterName = NDIS_STRING_CONST(AdapterBuffer);
  761.   switch (dwService) {
  762.     case DIOC_OPEN:
  763.       return NDIS_STATUS_SUCCESS;
  764.     
  765.     case DIOC_CLOSEHANDLE:
  766.       if ((Open = GetOpen(hDevice)) != NULL)
  767.         PacketUnbindAdapter(&Status, Open, NULL);
  768.       return NDIS_STATUS_SUCCESS;
  769.     case IOCTL_EPACKET_VERSION:
  770.       if (pDiocParms->cbOutBuffer < 2)
  771.         *(DWORD *)(pDiocParms->lpcbBytesReturned) = 0;
  772.       else {
  773.         ((BYTE *)pDiocParms->lpvOutBuffer)[0] = MAJOR_VERSION;
  774.         ((BYTE *)pDiocParms->lpvOutBuffer)[1] = MINOR_VERSION;
  775.         *(DWORD *)pDiocParms->lpcbBytesReturned = 2;
  776.       }
  777.       return NDIS_STATUS_SUCCESS;
  778.     case IOCTL_EPACKET_BIND:
  779.       memcpy(AdapterName.Buffer, (BYTE *)pDiocParms->lpvInBuffer,
  780.              min(strlen((char *)pDiocParms->lpvInBuffer), sizeof(AdapterBuffer)-1));
  781.       AdapterName.Buffer[sizeof(AdapterBuffer)-1] = '';
  782.       PacketBindAdapter(&Status,
  783.                         GlobalDeviceExtension->NdisProtocolHandle,
  784.                         &AdapterName,
  785.                         (PVOID)hDevice, /* special */
  786.                         NULL);
  787.       // Note: If the above usage of the 4'th arg to PacketBindAdapter
  788.       //       causes problems, use a global variable instead.
  789.       if (Status == NDIS_STATUS_SUCCESS || Status == NDIS_STATUS_PENDING) {
  790.         *(DWORD *)pDiocParms->lpcbBytesReturned = 1;
  791.         return NDIS_STATUS_SUCCESS;
  792.       }
  793.       break;
  794.     case IOCTL_EPACKET_SET_OID:
  795.     case IOCTL_EPACKET_QUERY_OID:
  796.       if ((Open = GetOpen(hDevice)) != NULL)
  797.         return PacketRequest(Open, dwService, dwDDB, hDevice, pDiocParms);
  798.       break;
  799.     
  800.     case IOCTL_EPACKET_READ:
  801.       if ((Open = GetOpen(hDevice)) != NULL)
  802.         return PacketRead(Open, dwDDB, hDevice, pDiocParms);
  803.       break;
  804.     
  805.     case IOCTL_EPACKET_WRITE:
  806.       if ((Open = GetOpen(hDevice)) != NULL)
  807.         return PacketWrite(Open, dwDDB, hDevice, pDiocParms);
  808.       break;
  809.   }
  810.   *(DWORD *)pDiocParms->lpcbBytesReturned = 0;
  811.   return NDIS_STATUS_SUCCESS;
  812. }
  813. // End of File ////////////////////////////////////////////////////////////////