home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2006 June / PCpro_2006_06.ISO / files / mstools / MSRMesh-VirtualWIFI.MSI / protocol.c < prev    next >
Encoding:
C/C++ Source or Header  |  2005-06-24  |  115.4 KB  |  4,022 lines

  1. /*
  2.  * Author   : Ranveer Chandra
  3.  * Directory: VirtualWiFi_Root\driver
  4.  * File Name: protocol.c
  5.  * Purpose: NDIS Protocol Entry points and utility functions for VirtualWiFi.
  6.  
  7.     The protocol edge binds to Ethernet (NdisMedium802_3) adapters,
  8.     and initiates creation of zero or more Virtual Ethernet LAN (VELAN)
  9.     miniport instances by calling NdisIMInitializeDeviceInstanceEx once
  10.     for each VELAN configured over a lower binding.
  11. */
  12.  
  13.  
  14. #include "precomp.h"
  15. #pragma hdrstop
  16.  
  17.  
  18. #define MODULE_NUMBER           MODULE_PROT
  19.  
  20. VOID
  21. PtBindAdapter(
  22.     OUT PNDIS_STATUS            Status,
  23.     IN  NDIS_HANDLE             BindContext,
  24.     IN  PNDIS_STRING            DeviceName,
  25.     IN  PVOID                   SystemSpecific1,
  26.     IN  PVOID                   SystemSpecific2
  27.     )
  28. /*++
  29.  
  30. Routine Description:
  31.  
  32.     Called by NDIS to bind to a miniport below. This routine
  33.     creates a binding by calling NdisOpenAdapter, and then
  34.     initiates creation of all configured VELANs on this binding.
  35.  
  36. Arguments:
  37.  
  38.     Status            - Return status of bind here.
  39.     BindContext       - Can be passed to NdisCompleteBindAdapter if this 
  40.                         call is pended.
  41.     DeviceName        - Device name to bind to. This is passed to 
  42.                             NdisOpenAdapter.
  43.     SystemSpecific1   - Can be passed to NdisOpenProtocolConfiguration to
  44.                             read per-binding information
  45.     SystemSpecific2   - Unused
  46.  
  47.  
  48. Return Value:
  49.  
  50.     *Status is set to NDIS_STATUS_SUCCESS if no failure occurred
  51.     while handling this call, otherwise an error code.
  52.  
  53. --*/
  54. {
  55.     PADAPT                            pAdapt = NULL;
  56.     NDIS_STATUS                       OpenErrorStatus;
  57.     UINT                              MediumIndex;
  58.     PNDIS_STRING                      pConfigString;
  59.     ULONG                             Length;
  60.  
  61.     pConfigString = (PNDIS_STRING)SystemSpecific1;
  62.     
  63.     DBGPRINT(MUX_LOUD, ("==> Protocol BindAdapter: %ws\n", pConfigString->Buffer));
  64.    
  65.     do
  66.     {
  67.  
  68.         //
  69.         // Allocate memory for Adapter struct plus the config
  70.         // string with two extra WCHARs for NULL termination.
  71.         //
  72.         Length = sizeof(ADAPT) + 
  73.                     pConfigString->MaximumLength + sizeof(WCHAR);
  74.         
  75.         NdisAllocateMemoryWithTag(&pAdapt, Length , TAG);
  76.  
  77.         if (pAdapt == NULL)
  78.         {
  79.             *Status = NDIS_STATUS_RESOURCES;
  80.              break;
  81.         }
  82.         
  83.         //
  84.         // Initialize the adapter structure
  85.         //
  86.         NdisZeroMemory(pAdapt, sizeof(ADAPT));        
  87.  
  88.         (VOID)PtReferenceAdapter(pAdapt, "openadapter");        
  89.         
  90.  
  91.         //
  92.         //  Copy in the Config string - we will use this to open the
  93.         //  registry section for this adapter at a later point.
  94.         //
  95.         pAdapt->ConfigString.MaximumLength = pConfigString->MaximumLength;
  96.         pAdapt->ConfigString.Length = pConfigString->Length;
  97.         pAdapt->ConfigString.Buffer = (PWCHAR)((PUCHAR)pAdapt + 
  98.                             sizeof(ADAPT));
  99.  
  100.         NdisMoveMemory(pAdapt->ConfigString.Buffer,
  101.                        pConfigString->Buffer,
  102.                        pConfigString->Length);
  103.         pAdapt->ConfigString.Buffer[pConfigString->Length/sizeof(WCHAR)] = 
  104.                                     ((WCHAR)0);
  105.  
  106.         NdisInitializeEvent(&pAdapt->Event);
  107.         NdisInitializeListHead(&pAdapt->VElanList);
  108.  
  109.         pAdapt->PtDevicePowerState = NdisDeviceStateD0;
  110.  
  111.         MUX_INIT_ADAPT_RW_LOCK(pAdapt);
  112.  
  113.         //
  114.         // TODO: Allocate a packet pool and buffers for send & receive.
  115.         //
  116.         // Now open the adapter below and complete the initialization
  117.         //
  118.         NdisOpenAdapter(Status,
  119.                           &OpenErrorStatus,
  120.                           &pAdapt->BindingHandle,
  121.                           &MediumIndex,
  122.                           MediumArray,
  123.                           sizeof(MediumArray)/sizeof(NDIS_MEDIUM),
  124.                           ProtHandle,
  125.                           pAdapt,
  126.                           DeviceName,
  127.                           0,
  128.                           NULL);
  129.  
  130.         if (*Status == NDIS_STATUS_PENDING)
  131.         {
  132.               NdisWaitEvent(&pAdapt->Event, 0);
  133.               *Status = pAdapt->Status;
  134.         }
  135.  
  136.         if (*Status != NDIS_STATUS_SUCCESS)
  137.         {
  138.               break;
  139.         }
  140.        
  141.         pAdapt->Medium = MediumArray[MediumIndex];
  142.         pAdapt->CurrentActiveConnection = 0;
  143.         NdisInitializeListHead(&pAdapt->VElanSSIDList);
  144.  
  145.         // Initialize the waiting times per mode for switching
  146.         /*
  147.         g_SwitchingTimeInfra = SWITCHING_PERIOD;
  148.         g_SwitchingTimeAdhoc = SWITCHING_PERIOD;
  149.         g_WaitingTimeInfra = SENDING_PERIOD;
  150.         g_WaitingTimeAdhoc = SENDING_PERIOD;
  151.         */
  152.  
  153.         pAdapt->StartSwitching = FALSE;
  154.         // initialize the timer function for switching
  155.         /*
  156.         NdisInitializeTimer(
  157.             &pAdapt->SwitchingTimer,
  158.             PtSwitchTimerFunction,
  159.             pAdapt);
  160.  
  161.         pAdapt->isTimerFired = FALSE;
  162.         */
  163.         //
  164.         // Add this adapter to the global AdapterList
  165.         //
  166.         MUX_ACQUIRE_MUTEX(&GlobalMutex);
  167.  
  168.         InsertTailList(&AdapterList, &pAdapt->Link);
  169.  
  170.         MUX_RELEASE_MUTEX(&GlobalMutex);
  171.  
  172.         //
  173.         // Get some information from the adapter below.
  174.         //
  175.         PtQueryAdapterInfo(pAdapt);
  176.  
  177.         //
  178.         // Start all VELANS configured on the wireless adapter.
  179.         //
  180.         PtBootStrapVElans(pAdapt);     
  181.     
  182.     } while(FALSE);
  183.  
  184.     if (*Status != NDIS_STATUS_SUCCESS)
  185.     {
  186.         if (pAdapt != NULL)
  187.         {
  188.             PtDereferenceAdapter(pAdapt, "openadapter");
  189.             pAdapt = NULL;
  190.         }
  191.     }
  192.  
  193.  
  194.     DBGPRINT(MUX_INFO, ("<== Protocol BindAdapter: pAdapt %p, Status %x\n", pAdapt, *Status));
  195. }
  196.  
  197.  
  198. VOID
  199. PtOpenAdapterComplete(
  200.     IN  NDIS_HANDLE             ProtocolBindingContext,
  201.     IN  NDIS_STATUS             Status,
  202.     IN  NDIS_STATUS             OpenErrorStatus
  203.     )
  204. /*++
  205.  
  206. Routine Description:
  207.  
  208.     Completion routine for NdisOpenAdapter issued from within the 
  209.     PtBindAdapter. Simply unblock the caller.
  210.  
  211. Arguments:
  212.  
  213.     ProtocolBindingContext    Pointer to the adapter
  214.     Status                    Status of the NdisOpenAdapter call
  215.     OpenErrorStatus            Secondary status(ignored by us).
  216.  
  217. Return Value:
  218.  
  219.     None
  220.  
  221. --*/
  222. {
  223.     PADAPT      pAdapt =(PADAPT)ProtocolBindingContext;
  224.  
  225.     DBGPRINT(MUX_LOUD, ("==> PtOpenAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
  226.     pAdapt->Status = Status;
  227.     NdisSetEvent(&pAdapt->Event);
  228. }
  229.  
  230.  
  231. VOID
  232. PtQueryAdapterInfo(
  233.     IN  PADAPT                  pAdapt
  234.     )
  235. /*++
  236.  
  237. Routine Description:
  238.  
  239.     Query the adapter we are bound to for some standard OID values
  240.     which we cache.
  241.  
  242. Arguments:
  243.  
  244.     pAdapt              Pointer to the adapter
  245.  
  246.  
  247. Return Value:
  248.  
  249.     None
  250. --*/
  251. {
  252.     
  253.     //
  254.     // Get the link speed.
  255.     //
  256.     pAdapt->LinkSpeed = MUX_DEFAULT_LINK_SPEED;
  257.     PtQueryAdapterSync(pAdapt,
  258.                        OID_GEN_LINK_SPEED,
  259.                        &pAdapt->LinkSpeed,
  260.                        sizeof(pAdapt->LinkSpeed));
  261.  
  262.     //
  263.     // Get the max lookahead size.
  264.     //
  265.     pAdapt->MaxLookAhead = MUX_DEFAULT_LOOKAHEAD_SIZE;
  266.     PtQueryAdapterSync(pAdapt,
  267.                        OID_GEN_MAXIMUM_LOOKAHEAD,
  268.                        &pAdapt->MaxLookAhead,
  269.                        sizeof(pAdapt->MaxLookAhead));
  270.  
  271.     //
  272.     // Get the Ethernet MAC address.
  273.     //
  274.     PtQueryAdapterSync(pAdapt,
  275.                        OID_802_3_CURRENT_ADDRESS,
  276.                        &pAdapt->CurrentAddress,
  277.                        sizeof(pAdapt->CurrentAddress));
  278.  
  279.     // 
  280.     // Get the network SSID
  281.     //
  282.     pAdapt->numConnections = 0;
  283.     pAdapt->networkSSID[pAdapt->numConnections].SsidLength = 0;
  284.     pAdapt->isSSIDActive[pAdapt->numConnections] = TRUE;
  285.     PtQueryAdapterSync(pAdapt,
  286.                        OID_802_11_SSID,
  287.                        &pAdapt->networkSSID[pAdapt->numConnections],
  288.                        sizeof(pAdapt->networkSSID[pAdapt->numConnections]));
  289.     PtQueryAdapterSync(pAdapt,
  290.                     OID_802_11_INFRASTRUCTURE_MODE,
  291.                     &pAdapt->networkMode[pAdapt->numConnections],
  292.                     sizeof(pAdapt->networkMode[pAdapt->numConnections]));
  293.  
  294.     // Initialize the send queues for this SSID
  295.     InitializeQueueHeader(&pAdapt->SendWaitQueue[pAdapt->numConnections]);
  296.     pAdapt->nWaitSend[pAdapt->numConnections] = 0;
  297.     pAdapt->nTotalPacketsSeen[pAdapt->numConnections] = 0;
  298.  
  299.     pAdapt->switchingTime[pAdapt->numConnections] = SWITCHING_PERIOD;
  300.     pAdapt->waitingTime[pAdapt->numConnections] = SENDING_PERIOD;
  301.     pAdapt->isAdaptiveScheduling = 1;
  302.  
  303.     pAdapt->CurrentActiveConnection = pAdapt->numConnections;
  304.  
  305.     pAdapt->cardSwitchTime = (Time) 0;
  306.     pAdapt->switchStartTime = (Time) 0;
  307.  
  308.     DBGPRINT(MUX_INFO, ("The %dth network SSID Length is %d\n", 
  309.         pAdapt->numConnections, pAdapt->networkSSID[pAdapt->numConnections].SsidLength));
  310.     //pAdapt->numConnections++;
  311.  
  312.     //
  313.     // Get the Physical Medium.
  314.     //
  315.     pAdapt->PhysicalMedium = NdisPhysicalMediumUnspecified;
  316.     PtQueryAdapterSync(pAdapt,
  317.                        OID_GEN_PHYSICAL_MEDIUM,
  318.                        &pAdapt->PhysicalMedium,
  319.                        sizeof(pAdapt->PhysicalMedium));
  320. }
  321.  
  322.  
  323. VOID
  324. PtQueryAdapterSync(
  325.     IN  PADAPT                      pAdapt,
  326.     IN  NDIS_OID                    Oid,
  327.     IN  PVOID                       InformationBuffer,
  328.     IN  ULONG                       InformationBufferLength
  329.     )
  330. /*++
  331.  
  332. Routine Description:
  333.  
  334.     Utility routine to query the adapter for a single OID value. This
  335.     blocks for the query to complete.
  336.  
  337. Arguments:
  338.  
  339.     pAdapt                      Pointer to the adapter
  340.     Oid                         OID to query for
  341.     InformationBuffer           Place for the result
  342.     InformationBufferLength     Length of the above
  343.  
  344. Return Value:
  345.  
  346.     None.
  347.  
  348. --*/
  349. {
  350.     PMUX_NDIS_REQUEST       pMuxNdisRequest = NULL;
  351.     NDIS_STATUS             Status;
  352.  
  353.     do
  354.     {
  355.         NdisAllocateMemoryWithTag(&pMuxNdisRequest, sizeof(MUX_NDIS_REQUEST), TAG);
  356.         if (pMuxNdisRequest == NULL)
  357.         {
  358.             break;
  359.         }
  360.  
  361.         pMuxNdisRequest->pVElan = NULL; // internal request
  362.  
  363.         //
  364.         // Set up completion routine.
  365.         //
  366.         pMuxNdisRequest->pCallback = PtCompleteBlockingRequest;
  367.         NdisInitializeEvent(&pMuxNdisRequest->Event);
  368.  
  369.         pMuxNdisRequest->Request.RequestType = NdisRequestQueryInformation;
  370.         pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.Oid = Oid;
  371.         pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
  372.                             InformationBuffer;
  373.         pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
  374.                                                 InformationBufferLength;
  375.  
  376.         NdisRequest(&Status,
  377.                     pAdapt->BindingHandle,
  378.                     &pMuxNdisRequest->Request);
  379.         
  380.         if (Status == NDIS_STATUS_PENDING)
  381.         {
  382.             NdisWaitEvent(&pMuxNdisRequest->Event, 0);
  383.             Status = pMuxNdisRequest->Status;
  384.         }
  385.     }
  386.     while (FALSE);
  387.  
  388.     if (NULL != pMuxNdisRequest)
  389.     {
  390.         NdisFreeMemory(pMuxNdisRequest, sizeof(MUX_NDIS_REQUEST), 0);
  391.     }
  392. }
  393.  
  394.  
  395.  
  396. VOID
  397. PtRequestAdapterAsync(
  398.     IN  PADAPT                      pAdapt,
  399.     IN  NDIS_REQUEST_TYPE           RequestType,
  400.     IN  NDIS_OID                    Oid,
  401.     IN  PVOID                       InformationBuffer,
  402.     IN  ULONG                       InformationBufferLength,
  403.     IN  PMUX_REQ_COMPLETE_HANDLER   pCallback
  404.     )
  405. /*++
  406.  
  407. Routine Description:
  408.  
  409.     Utility routine to query the adapter for a single OID value.
  410.     This completes asynchronously, i.e. the calling thread is
  411.     not blocked until the request completes.
  412.  
  413. Arguments:
  414.  
  415.     pAdapt                      Pointer to the adapter
  416.     RequestType                 NDIS request type
  417.     Oid                         OID to set/query
  418.     InformationBuffer           Input/output buffer
  419.     InformationBufferLength     Length of the above
  420.     pCallback                   Function to call on request completion
  421.  
  422. Return Value:
  423.  
  424.     None.
  425.  
  426. --*/
  427. {
  428.     PMUX_NDIS_REQUEST       pMuxNdisRequest = NULL;
  429.     PNDIS_REQUEST           pNdisRequest;
  430.     NDIS_STATUS             Status;
  431.  
  432.     do
  433.     {
  434.         NdisAllocateMemoryWithTag(&pMuxNdisRequest, sizeof(MUX_NDIS_REQUEST), TAG);
  435.         if (pMuxNdisRequest == NULL)
  436.         {
  437.             break;
  438.         }
  439.  
  440.         pMuxNdisRequest->pVElan = NULL; // internal request
  441.  
  442.         //
  443.         // Set up completion routine.
  444.         //
  445.         pMuxNdisRequest->pCallback = pCallback;
  446.  
  447.         pNdisRequest = &pMuxNdisRequest->Request;
  448.  
  449.         pNdisRequest->RequestType = RequestType;
  450.  
  451.         switch (RequestType)
  452.         {
  453.             case NdisRequestQueryInformation:
  454.                 pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
  455.                 pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =
  456.                                     InformationBuffer;
  457.                 pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
  458.                                     InformationBufferLength;
  459.         
  460.                 break;
  461.  
  462.             case NdisRequestSetInformation:
  463.                 pNdisRequest->DATA.SET_INFORMATION.Oid = Oid;
  464.                 pNdisRequest->DATA.SET_INFORMATION.InformationBuffer =
  465.                                     InformationBuffer;
  466.                 pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
  467.                                     InformationBufferLength;
  468.         
  469.                 break;
  470.             
  471.             default:
  472.                 ASSERT(FALSE);
  473.                 break;
  474.         }
  475.  
  476.         NdisRequest(&Status,
  477.                     pAdapt->BindingHandle,
  478.                     pNdisRequest);
  479.         
  480.         if (Status != NDIS_STATUS_PENDING)
  481.         {
  482.             PtRequestComplete(
  483.                 (NDIS_HANDLE)pAdapt,
  484.                 pNdisRequest,
  485.                 Status);
  486.         }
  487.     }
  488.     while (FALSE);
  489. }
  490.  
  491.             
  492. VOID PtUnbindAdapter(
  493.     OUT PNDIS_STATUS            Status,
  494.     IN  NDIS_HANDLE             ProtocolBindingContext,
  495.     IN  NDIS_HANDLE             UnbindContext
  496.     )
  497. /*++
  498.  
  499. Routine Description:
  500.  
  501.     Called by NDIS when we are required to unbind to the adapter below.
  502.     Go through all VELANs on the adapter and shut them down.
  503.  
  504. Arguments:
  505.  
  506.     Status                    Placeholder for return status
  507.     ProtocolBindingContext    Pointer to the adapter structure
  508.     UnbindContext             Context for NdisUnbindComplete() if this pends
  509.  
  510. Return Value:
  511.  
  512.     Status from closing the binding.
  513.  
  514. --*/
  515. {
  516.     PADAPT          pAdapt =(PADAPT)ProtocolBindingContext;
  517.     PLIST_ENTRY     p;
  518.     PVELAN          pVElan = NULL;
  519.     LOCK_STATE      LockState;
  520.     BOOLEAN         CheckCancelled;
  521.     PVElanSSID pVElanSSID;
  522.  
  523.     DBGPRINT(MUX_LOUD, ("==> PtUnbindAdapter: Adapt %p\n", pAdapt));
  524.  
  525.     /*
  526.     MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  527.     NdisCancelTimer(&pAdapt->SwitchingTimer, &CheckCancelled);
  528.     if(pAdapt->isTimerFired && !(CheckCancelled))
  529.     {
  530.         do {
  531.             NdisCancelTimer(&pAdapt->SwitchingTimer, &CheckCancelled);
  532.             NdisMSleep(2000);
  533.         } while(!(CheckCancelled));
  534.     }
  535.     pAdapt->isTimerFired = FALSE;
  536.     MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  537.     */
  538.  
  539.     //
  540.     // Stop all VELANs associated with the adapter.
  541.     // Repeatedly find the first unprocessed VELAN on
  542.     // the adapter, mark it, and stop it.
  543.     //
  544.     MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  545.  
  546.     do
  547.     {
  548.         for (p = pAdapt->VElanList.Flink;
  549.              p != &pAdapt->VElanList;
  550.              p = p->Flink)
  551.         {
  552.             pVElan = CONTAINING_RECORD(p, VELAN, Link);
  553.             if (!pVElan->DeInitializing)
  554.             {
  555.                 pVElan->DeInitializing = TRUE;
  556.                 break;
  557.             }
  558.         }
  559.  
  560.         if (p != &pAdapt->VElanList)
  561.         {
  562.             ASSERT(pVElan == CONTAINING_RECORD(p, VELAN, Link));
  563.  
  564.             //
  565.             // Got a VELAN to stop. Add a temp ref
  566.             // so that the VELAN won't go away when
  567.             // we release the ADAPT lock below.
  568.             //
  569.             PtReferenceVElan(pVElan, "UnbindTemp");
  570.  
  571.             for (p = pAdapt->VElanSSIDList.Flink;
  572.                 p != &pAdapt->VElanSSIDList;
  573.                 )
  574.             {
  575.                 pVElanSSID = CONTAINING_RECORD(p, VElanSSID, Link);
  576.                 p = p->Flink;
  577.                  DBGPRINT(MUX_LOUD, ("PtUnbindAdapter: Removing SSIDElan Adapter %p, ElanKey %ws\n", pAdapt, 
  578.                                                         pVElanSSID->VElanKey.Buffer));
  579.                 RemoveEntryList(&pVElanSSID->Link);
  580.                 NdisFreeMemory(pVElanSSID, 0, 0);
  581.             }
  582.             //
  583.             // Release the read lock because we want to
  584.             // run StopVElan at passive IRQL.
  585.             //
  586.             MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  587.     
  588.             PtStopVElan(pVElan);
  589.     
  590.             PtDereferenceVElan(pVElan, "UnbindTemp");
  591.  
  592.             MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  593.         }
  594.         else
  595.         {
  596.             //
  597.             // No unmarked VELAN, so exit.
  598.             //
  599.             break;
  600.         }
  601.     }
  602.     while (TRUE);
  603.  
  604.     //
  605.     // Wait until all VELANs are unlinked from the adapter.
  606.     // This is so that we don't attempt to forward down packets
  607.     // and/or requests from VELANs after calling NdisCloseAdapter.
  608.     //
  609.     while (!IsListEmpty(&pAdapt->VElanList))
  610.     {
  611.         MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  612.  
  613.         DBGPRINT(MUX_INFO, ("PtUnbindAdapter: pAdapt %p, VELANlist not yet empty\n",
  614.                     pAdapt));
  615.  
  616.         NdisMSleep(2000);
  617.  
  618.         MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  619.     }
  620.     
  621.     
  622.     MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  623.  
  624.     //
  625.     // Close the binding to the lower adapter.
  626.     //
  627.     if (pAdapt->BindingHandle != NULL)
  628.     {
  629.         NdisResetEvent(&pAdapt->Event);
  630.  
  631.         NdisCloseAdapter(Status, pAdapt->BindingHandle);
  632.  
  633.         //
  634.         // Wait for it to complete.
  635.         //
  636.         if (*Status == NDIS_STATUS_PENDING)
  637.         {
  638.              NdisWaitEvent(&pAdapt->Event, 0);
  639.              *Status = pAdapt->Status;
  640.         }
  641.     }
  642.     else
  643.     {
  644.         //
  645.         // Binding Handle should not be NULL.
  646.         //
  647.         *Status = NDIS_STATUS_FAILURE;
  648.         ASSERT(0);
  649.     }
  650.  
  651.     //
  652.     // Remove the adapter from the global AdapterList
  653.     //
  654.     
  655.     MUX_ACQUIRE_MUTEX(&GlobalMutex);
  656.  
  657.     RemoveEntryList(&pAdapt->Link);
  658.  
  659.     MUX_RELEASE_MUTEX(&GlobalMutex);
  660.  
  661.     //
  662.     // Free all the resources associated with this Adapter except the
  663.     // ADAPT struct itself, because that will be freed by 
  664.     // PtDereferenceAdapter call when the reference drops to zero. 
  665.     // Note: Every VELAN associated with this Adapter takes a ref count
  666.     // on it. So the adapter memory wouldn't be freed until all the VELANs
  667.     // are shutdown. 
  668.     //
  669.     
  670.     PtDereferenceAdapter(pAdapt, "Unbind");
  671.     DBGPRINT(MUX_INFO, ("<== PtUnbindAdapter: Adapt %p\n", pAdapt));
  672. }
  673.  
  674.  
  675. VOID
  676. PtCloseAdapterComplete(
  677.     IN    NDIS_HANDLE            ProtocolBindingContext,
  678.     IN    NDIS_STATUS            Status
  679.     )
  680. /*++
  681.  
  682. Routine Description:
  683.  
  684.     Completion for the CloseAdapter call.
  685.  
  686. Arguments:
  687.  
  688.     ProtocolBindingContext    Pointer to the adapter structure
  689.     Status                    Completion status
  690.  
  691. Return Value:
  692.  
  693.     None.
  694.  
  695. --*/
  696. {
  697.     PADAPT      pAdapt =(PADAPT)ProtocolBindingContext;
  698.  
  699.     DBGPRINT(MUX_INFO, ("==> PtCloseAdapterComplete: Adapt %p, Status %x\n", 
  700.                                 pAdapt, Status));
  701.  
  702.     pAdapt->Status = Status;
  703.     NdisSetEvent(&pAdapt->Event);
  704. }
  705.  
  706.  
  707. VOID
  708. PtResetComplete(
  709.     IN  NDIS_HANDLE            ProtocolBindingContext,
  710.     IN  NDIS_STATUS            Status
  711.     )
  712. /*++
  713.  
  714. Routine Description:
  715.  
  716.     Completion for the reset.
  717.  
  718. Arguments:
  719.  
  720.     ProtocolBindingContext    Pointer to the adapter structure
  721.     Status                    Completion status
  722.  
  723. Return Value:
  724.  
  725.     None.
  726.  
  727. --*/
  728. {
  729.     PADAPT    pAdapt =(PADAPT)ProtocolBindingContext;
  730.  
  731.     DBGPRINT(MUX_ERROR, ("==> PtResetComplete: Adapt %p, Status %x\n", 
  732.                                 pAdapt, Status));
  733.  
  734.     //
  735.     // We never issue a reset, so we should not be here.
  736.     //
  737.     ASSERT(0);
  738. }
  739.  
  740.  
  741. VOID
  742. PtRequestComplete(
  743.     IN  NDIS_HANDLE                 ProtocolBindingContext,
  744.     IN  PNDIS_REQUEST               NdisRequest,
  745.     IN  NDIS_STATUS                 Status
  746.     )
  747. /*++
  748.  
  749. Routine Description:
  750.  
  751.     Completion handler for an NDIS request sent to a lower
  752.     miniport.
  753.  
  754. Arguments:
  755.  
  756.     ProtocolBindingContext    Pointer to the adapter structure
  757.     NdisRequest               The completed request
  758.     Status                    Completion status
  759.  
  760. Return Value:
  761.  
  762.     None
  763.  
  764. --*/
  765. {
  766.     PADAPT              pAdapt = (PADAPT)ProtocolBindingContext;
  767.     PMUX_NDIS_REQUEST   pMuxNdisRequest;
  768.  
  769.     pMuxNdisRequest = CONTAINING_RECORD(NdisRequest, MUX_NDIS_REQUEST, Request);
  770.  
  771.     ASSERT(pMuxNdisRequest->pCallback != NULL);
  772.  
  773.     //
  774.     // Completion is handled by the callback routine:
  775.     //
  776.     (*pMuxNdisRequest->pCallback)(pAdapt, 
  777.                                   pMuxNdisRequest,
  778.                                   Status);
  779.  
  780. }
  781.  
  782.  
  783. VOID
  784. PtCompleteForwardedRequest(
  785.     IN PADAPT                       pAdapt,
  786.     IN PMUX_NDIS_REQUEST            pMuxNdisRequest,
  787.     IN NDIS_STATUS                  Status
  788.     )
  789. /*++
  790.  
  791. Routine Description:
  792.  
  793.     Handle completion of an NDIS request that was originally
  794.     submitted to our VELAN miniport and was forwarded down
  795.     to the lower binding.
  796.  
  797.     We do some postprocessing, to cache the results of
  798.     certain queries.
  799.  
  800. Arguments:
  801.  
  802.     pAdapt  - Adapter on which the request was forwarded
  803.     pMuxNdisRequest - super-struct for request
  804.     Status - request completion status
  805.  
  806. Return Value:
  807.  
  808.     None
  809.  
  810. --*/
  811. {
  812.     PVELAN              pVElan = NULL;
  813.     PNDIS_REQUEST       pNdisRequest = &pMuxNdisRequest->Request;
  814.     NDIS_OID            Oid = pNdisRequest->DATA.SET_INFORMATION.Oid;
  815.     
  816.     // DBGPRINT(MUX_WARN, ("=>PtCompleteForwardedReq\n")) 
  817.     //
  818.     // Get the originating VELAN. The VELAN will not be dereferenced
  819.     // away until the pended request is completed.
  820.     //
  821.     pVElan = pMuxNdisRequest->pVElan;
  822.  
  823.     ASSERT(pVElan != NULL);
  824.     ASSERT(pMuxNdisRequest == &pVElan->Request);
  825.     
  826.     if (Status != NDIS_STATUS_SUCCESS)
  827.     {
  828.         DBGPRINT(MUX_WARN, ("PtCompleteForwardedReq: pVElan %p, OID %x, Status %x\n", 
  829.                     pVElan,
  830.                     pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.Oid,
  831.                     Status));
  832.     }
  833.  
  834.     //
  835.     // Complete the original request.
  836.     //
  837.     switch (pNdisRequest->RequestType)
  838.     {
  839.         case NdisRequestQueryInformation:
  840.  
  841.             *pVElan->BytesReadOrWritten = 
  842.                     pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
  843.             *pVElan->BytesNeeded = 
  844.                     pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
  845.  
  846.             //
  847.             // Before completing the request, do any necessary
  848.             // post-processing.
  849.             //
  850.             Oid = pNdisRequest->DATA.QUERY_INFORMATION.Oid;
  851.             if (Status == NDIS_STATUS_SUCCESS)
  852.             {
  853.                 if (Oid == OID_GEN_LINK_SPEED)
  854.                 {
  855.                     pVElan->LinkSpeed = *(PULONG)
  856.                         pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
  857.                 }
  858.                 else if (Oid == OID_PNP_CAPABILITIES)
  859.                 {
  860.                     PtPostProcessPnPCapabilities(pVElan,
  861.                                                  pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
  862.                                                  pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength);
  863.                 }
  864.             }
  865.  
  866.             NdisMQueryInformationComplete(pVElan->MiniportAdapterHandle, Status);
  867.  
  868.             break;
  869.  
  870.         case NdisRequestSetInformation:
  871.  
  872.             *pVElan->BytesReadOrWritten =
  873.                     pNdisRequest->DATA.SET_INFORMATION.BytesRead;
  874.             *pVElan->BytesNeeded =
  875.                     pNdisRequest->DATA.SET_INFORMATION.BytesNeeded;
  876.  
  877.             //
  878.             // Before completing the request, cache relevant information
  879.             // in our structure.
  880.             //
  881.             if (Status == NDIS_STATUS_SUCCESS)
  882.             {
  883.                 Oid = pNdisRequest->DATA.SET_INFORMATION.Oid;
  884.                 switch (Oid)
  885.                 {
  886.                     case OID_GEN_CURRENT_LOOKAHEAD:
  887.                         pVElan->LookAhead = *(PULONG)
  888.                             pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
  889.                         break;
  890.  
  891.                     default:
  892.                         break;
  893.                 }
  894.             }
  895.  
  896.             NdisMSetInformationComplete(pVElan->MiniportAdapterHandle, Status);
  897.  
  898.             break;
  899.  
  900.         default:
  901.             ASSERT(FALSE);
  902.             break;
  903.     }
  904.  
  905.     MUX_DECR_PENDING_SENDS(pVElan);
  906.     //DBGPRINT(MUX_WARN, ("<=PtCompleteForwardedReq\n")) 
  907.  
  908. }
  909.  
  910.  
  911.  
  912. VOID
  913. PtPostProcessPnPCapabilities(
  914.     IN PVELAN                   pVElan,
  915.     IN PVOID                    InformationBuffer,
  916.     IN ULONG                    InformationBufferLength
  917.     )
  918. /*++
  919.  
  920. Routine Description:
  921.  
  922.     Postprocess a successfully completed query for OID_PNP_CAPABILITIES.
  923.     We modify the returned information slightly before completing
  924.     it to the VELAN above.
  925.  
  926. Arguments:
  927.  
  928.     pVElan - Pointer to VELAN
  929.     InformationBuffer - points to buffer for the OID
  930.     InformationBufferLength - byte length of the above.
  931.  
  932. Return Value:
  933.  
  934.     None
  935.  
  936. --*/
  937. {
  938.     PNDIS_PNP_CAPABILITIES          pPNPCapabilities;
  939.     PNDIS_PM_WAKE_UP_CAPABILITIES   pPMstruct;
  940.  
  941.     DBGPRINT(MUX_LOUD, ("=>PtPostProcessPnPCapabilities\n"));
  942.     if (InformationBufferLength >= sizeof(NDIS_PNP_CAPABILITIES))
  943.     {
  944.         pPNPCapabilities = (PNDIS_PNP_CAPABILITIES)InformationBuffer;
  945.  
  946.         //
  947.         // The following fields must be overwritten by an IM driver.
  948.         //
  949.         pPMstruct= &pPNPCapabilities->WakeUpCapabilities;
  950.         pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
  951.         pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
  952.         pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
  953.     }
  954.     DBGPRINT(MUX_LOUD, ("=>PtPostProcessPnPCapabilities\n"));
  955. }
  956.  
  957. VOID
  958. PtCompleteBlockingRequest(
  959.     IN PADAPT                   pAdapt,
  960.     IN PMUX_NDIS_REQUEST        pMuxNdisRequest,
  961.     IN NDIS_STATUS              Status
  962.     )
  963. /*++
  964.  
  965. Routine Description:
  966.  
  967.     Handle completion of an NDIS request that was originated
  968.     by this driver and the calling thread is blocked waiting
  969.     for completion.
  970.  
  971. Arguments:
  972.  
  973.     pAdapt  - Adapter on which the request was forwarded
  974.     pMuxNdisRequest - super-struct for request
  975.     Status - request completion status
  976.  
  977. Return Value:
  978.  
  979.     None
  980.  
  981. --*/
  982. {
  983.     pMuxNdisRequest->Status = Status;
  984.  
  985.     //
  986.     // The request was originated from this driver. Wake up the
  987.     // thread blocked for its completion.
  988.     //
  989.     pMuxNdisRequest->Status = Status;
  990.     NdisSetEvent(&pMuxNdisRequest->Event);
  991. }
  992.  
  993.  
  994. VOID
  995. PtDiscardCompletedRequest(
  996.     IN PADAPT                   pAdapt,
  997.     IN PMUX_NDIS_REQUEST        pMuxNdisRequest,
  998.     IN NDIS_STATUS              Status
  999.     )
  1000. /*++
  1001.  
  1002. Routine Description:
  1003.  
  1004.     Handle completion of an NDIS request that was originated
  1005.     by this driver - the request is to be discarded.
  1006.  
  1007. Arguments:
  1008.  
  1009.     pAdapt  - Adapter on which the request was forwarded
  1010.     pMuxNdisRequest - super-struct for request
  1011.     Status - request completion status
  1012.  
  1013. Return Value:
  1014.  
  1015.     None
  1016.  
  1017. --*/
  1018. {
  1019.     UNREFERENCED_PARAMETER(pAdapt);
  1020.     UNREFERENCED_PARAMETER(Status);
  1021.  
  1022.     NdisFreeMemory(pMuxNdisRequest, sizeof(MUX_NDIS_REQUEST), 0);
  1023. }
  1024.  
  1025.  
  1026. VOID
  1027. PtStatus(
  1028.     IN  NDIS_HANDLE                 ProtocolBindingContext,
  1029.     IN  NDIS_STATUS                 GeneralStatus,
  1030.     IN  PVOID                       StatusBuffer,
  1031.     IN  UINT                        StatusBufferSize
  1032.     )
  1033. /*++
  1034.  
  1035. Routine Description:
  1036.  
  1037.     Handle a status indication on the lower binding (ADAPT).
  1038.     If this is a media status indication, we also pass this
  1039.     on to all associated VELANs.
  1040.  
  1041. Arguments:
  1042.  
  1043.     ProtocolBindingContext      Pointer to the adapter structure
  1044.     GeneralStatus               Status code
  1045.     StatusBuffer                Status buffer
  1046.     StatusBufferSize            Size of the status buffer
  1047.  
  1048. Return Value:
  1049.  
  1050.     None
  1051.  
  1052. --*/
  1053. {
  1054.     PADAPT      pAdapt = (PADAPT)ProtocolBindingContext;
  1055.     PLIST_ENTRY p;
  1056.     PVELAN      pVElan;
  1057.     LOCK_STATE  LockState;
  1058.     Time        now;
  1059.  
  1060.     DBGPRINT(MUX_LOUD, ("==>PtStatus: Adapt %p, Status %x\n", pAdapt, GeneralStatus));
  1061.  
  1062.     do
  1063.     {
  1064.         //
  1065.         // Ignore status indications that we aren't going
  1066.         // to pass up.
  1067.         //
  1068.         
  1069.         if ((GeneralStatus != NDIS_STATUS_MEDIA_CONNECT) && 
  1070.             (GeneralStatus != NDIS_STATUS_MEDIA_DISCONNECT))
  1071.         {
  1072.             break;
  1073.         }
  1074.         
  1075.         if (GeneralStatus == NDIS_STATUS_MEDIA_CONNECT 
  1076.             && pAdapt->switchStartTime > 0) {
  1077.                 pAdapt->cardSwitchTime = KeQueryInterruptTime() - pAdapt->switchStartTime;
  1078.                 pAdapt->switchStartTime    = (Time) 0;    
  1079.                 DBGPRINT(MUX_LOUD, ("PtStatus: Card switch time is %I64d\n", pAdapt->cardSwitchTime));
  1080.             }
  1081.         /*
  1082.         MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1083.  
  1084.         for (p = pAdapt->VElanList.Flink;
  1085.              p != &pAdapt->VElanList;
  1086.              p = p->Flink)
  1087.         {
  1088.             BOOLEAN     bIndicateReceive;
  1089.  
  1090.             pVElan = CONTAINING_RECORD(p, VELAN, Link);
  1091.  
  1092.             MUX_INCR_PENDING_RECEIVES(pVElan);
  1093.  
  1094.             //
  1095.             // Should the indication be sent on this VELAN?
  1096.             //
  1097.             if ((pVElan->MiniportHalting) ||
  1098.                 (pVElan->MiniportAdapterHandle == NULL) ||   
  1099.                 MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState))
  1100.             {
  1101.                 MUX_DECR_PENDING_RECEIVES(pVElan);
  1102.                 if (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState))
  1103.                 {
  1104.                     //
  1105.                     // Keep track of the latest status to indicate when VELAN power is on
  1106.                     // 
  1107.                     ASSERT((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) || (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT));
  1108.                     pVElan->LatestUnIndicateStatus = GeneralStatus;
  1109.                 }
  1110.                 
  1111.                 continue;
  1112.             }
  1113.  
  1114.             //
  1115.             // Save the last indicated status when 
  1116.             pVElan->LastIndicatedStatus = GeneralStatus;
  1117.  
  1118.             
  1119.             NdisMIndicateStatus(pVElan->MiniportAdapterHandle,
  1120.                                 GeneralStatus,
  1121.                                 StatusBuffer,
  1122.                                 StatusBufferSize);
  1123.             
  1124.             //
  1125.             // Mark this so that we forward a status complete
  1126.             // indication as well.
  1127.             //
  1128.             pVElan->IndicateStatusComplete = TRUE;
  1129.  
  1130.             MUX_DECR_PENDING_RECEIVES(pVElan);
  1131.         }
  1132.  
  1133.         MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1134.         */
  1135.     }
  1136.     while (FALSE);
  1137.     DBGPRINT(MUX_LOUD, ("<==PtStatus: Adapt %p, Status %x\n", pAdapt, GeneralStatus));
  1138.  
  1139. }
  1140.  
  1141.  
  1142. VOID
  1143. PtStatusComplete(
  1144.     IN    NDIS_HANDLE            ProtocolBindingContext
  1145.     )
  1146. /*++
  1147.  
  1148. Routine Description:
  1149.  
  1150.     Marks the end of a status indication. Pass it on to
  1151.     associated VELANs if necessary.
  1152.  
  1153. Arguments:
  1154.  
  1155.     ProtocolBindingContext - pointer to ADAPT
  1156.  
  1157. Return Value:
  1158.  
  1159.     None.
  1160.  
  1161. --*/
  1162. {
  1163.     PADAPT      pAdapt = (PADAPT)ProtocolBindingContext;
  1164.     PLIST_ENTRY p;
  1165.     PVELAN      pVElan;
  1166.     LOCK_STATE  LockState;
  1167.  
  1168.     DBGPRINT(MUX_LOUD, ("==>PtStatusComplete: Adapt %p\n", pAdapt));
  1169.     MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1170.  
  1171.     for (p = pAdapt->VElanList.Flink;
  1172.          p != &pAdapt->VElanList;
  1173.          p = p->Flink)
  1174.     {
  1175.         BOOLEAN     bIndicateReceive;
  1176.  
  1177.         pVElan = CONTAINING_RECORD(p, VELAN, Link);
  1178.  
  1179.         MUX_INCR_PENDING_RECEIVES(pVElan);
  1180.  
  1181.         //
  1182.         // Should this indication be sent on this VELAN?
  1183.         //
  1184.         if ((pVElan->MiniportHalting) ||
  1185.             (pVElan->MiniportAdapterHandle == NULL) ||
  1186.             (!pVElan->IndicateStatusComplete) ||
  1187.             (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState)))
  1188.         {
  1189.             MUX_DECR_PENDING_RECEIVES(pVElan);
  1190.             continue;
  1191.         }
  1192.  
  1193.         pVElan->IndicateStatusComplete = FALSE;
  1194.         NdisMIndicateStatusComplete(pVElan->MiniportAdapterHandle);
  1195.         
  1196.         MUX_DECR_PENDING_RECEIVES(pVElan);
  1197.     }
  1198.  
  1199.     MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1200.     if(pAdapt->switchStartTime == 0)
  1201.         PtIoctlSendBufferedPackets(pAdapt);
  1202.     DBGPRINT(MUX_LOUD, ("<==PtStatusComplete: Adapt %p\n", pAdapt));
  1203. }
  1204.  
  1205.  
  1206. VOID
  1207. PtSendComplete(
  1208.     IN  NDIS_HANDLE             ProtocolBindingContext,
  1209.     IN  PNDIS_PACKET            Packet,
  1210.     IN  NDIS_STATUS             Status
  1211.     )
  1212. /*++
  1213.  
  1214. Routine Description:
  1215.  
  1216.     Called by NDIS when the miniport below had completed a send.
  1217.     We complete the corresponding upper-edge send this represents.
  1218.     The packet being completed belongs to our send packet pool,
  1219.     however we store a pointer to the original packet this represents,
  1220.     in the packet's reserved field.
  1221.  
  1222. Arguments:
  1223.  
  1224.     ProtocolBindingContext - Points to ADAPT structure
  1225.     Packet - Packet being completed by the lower miniport
  1226.     Status - status of send
  1227.  
  1228. Return Value:
  1229.  
  1230.     None
  1231.  
  1232. --*/
  1233. {
  1234.     PADAPT              pAdapt = (PADAPT)ProtocolBindingContext;
  1235.     PVELAN              pVElan;
  1236.     PMUX_SEND_RSVD      pSendReserved;
  1237.     PNDIS_PACKET        OriginalPacket;
  1238. #if IEEE_VLAN_SUPPORT
  1239.     NDIS_PACKET_8021Q_INFO      NdisPacket8021qInfo;
  1240.     BOOLEAN                     IsTagInsert;
  1241.     PNDIS_BUFFER                pNdisBuffer;
  1242.     PVOID                       pVa;
  1243.     ULONG                       BufferLength;
  1244. #endif
  1245.     
  1246.     pSendReserved = MUX_RSVD_FROM_SEND_PACKET(Packet);
  1247.     OriginalPacket = pSendReserved->pOriginalPacket;
  1248.     pVElan = pSendReserved->pVElan;
  1249.  
  1250. #if IEEE_VLAN_SUPPORT
  1251.     //
  1252.     // Check if we had inserted a tag header
  1253.     //        
  1254.     IsTagInsert = FALSE;
  1255.     NdisPacket8021qInfo.Value = NDIS_PER_PACKET_INFO_FROM_PACKET(    
  1256.                                         OriginalPacket,
  1257.                                         Ieee8021QInfo);
  1258.     if ((pVElan->VlanId != 0) || (NdisPacket8021qInfo.Value != NULL))
  1259.     {
  1260.         IsTagInsert = TRUE;
  1261.     }
  1262. #endif
  1263.     
  1264.     
  1265. #ifndef WIN9X
  1266.     NdisIMCopySendCompletePerPacketInfo(OriginalPacket, Packet);
  1267. #endif
  1268.  
  1269.     //
  1270.     // Update statistics.
  1271.     //
  1272.     if (Status == NDIS_STATUS_SUCCESS)
  1273.     {
  1274.         MUX_INCR_STATISTICS64(&pVElan->GoodTransmits);
  1275.     }
  1276.     else
  1277.     {
  1278.         MUX_INCR_STATISTICS(&pVElan->TransmitFailuresOther);
  1279.     }
  1280.  
  1281.     //
  1282.     // Complete the original send.
  1283.     //
  1284.     NdisMSendComplete(pVElan->MiniportAdapterHandle,
  1285.                       OriginalPacket,
  1286.                       Status);
  1287.  
  1288. #if IEEE_VLAN_SUPPORT
  1289.     //
  1290.     // If we had inserted a tag header, then remove the header
  1291.     // buffer and free it. We would also have created a new
  1292.     // NDIS buffer to map part of the original packet's header;
  1293.     // free that, too.
  1294.     //
  1295.     if (IsTagInsert)
  1296.     {
  1297.  
  1298.         pNdisBuffer = Packet->Private.Head;
  1299. #ifdef NDIS51_MINIPORT
  1300.         NdisQueryBufferSafe(pNdisBuffer, &pVa, &BufferLength, NormalPagePriority);
  1301. #else
  1302.         NdisQueryBuffer(pNdisBuffer, &pVa, &BufferLength);
  1303. #endif
  1304.         if (pVa != NULL)
  1305.         {
  1306.             NdisFreeToNPagedLookasideList(&pVElan->TagLookaside, pVa);
  1307.         }
  1308.         NdisFreeBuffer(NDIS_BUFFER_LINKAGE(pNdisBuffer));
  1309.         NdisFreeBuffer (pNdisBuffer);
  1310.     }
  1311.                 
  1312. #endif
  1313.  
  1314.     //
  1315.     // Free our packet.
  1316.     //
  1317.     NdisFreePacket(Packet);
  1318.  
  1319.     //
  1320.     // Note down send-completion.
  1321.     //
  1322.     MUX_DECR_PENDING_SENDS(pVElan);
  1323. }       
  1324.  
  1325.  
  1326. VOID
  1327. PtTransferDataComplete(
  1328.     IN  NDIS_HANDLE             ProtocolBindingContext,
  1329.     IN  PNDIS_PACKET            Packet,
  1330.     IN  NDIS_STATUS             Status,
  1331.     IN  UINT                    BytesTransferred 
  1332.     )
  1333. /*++
  1334.  
  1335. Routine Description:
  1336.  
  1337.     Entry point called by NDIS to indicate completion of a call by us
  1338.     to NdisTransferData. We locate the original packet and VELAN on
  1339.     which our TransferData function (see MPTransferData) was called,
  1340.     and complete the original request.
  1341.  
  1342. Arguments:
  1343.  
  1344.     ProtocolBindingContext - lower binding context, pointer to ADAPT
  1345.     Packet - Packet allocated by us
  1346.     Status - Completion status
  1347.     BytesTransferred - Number of bytes copied in
  1348.  
  1349. Return Value:
  1350.  
  1351.     None
  1352.  
  1353. --*/
  1354. {
  1355.     PADAPT          pAdapt = (PADAPT)ProtocolBindingContext;
  1356.     PVELAN          pVElan;
  1357.     PNDIS_PACKET    pOriginalPacket;
  1358.     PMUX_TD_RSVD    pTDReserved;
  1359.  
  1360.     //DBGPRINT(MUX_LOUD, ("=>PtTransferComplete\n"));
  1361.  
  1362.     pTDReserved = MUX_RSVD_FROM_TD_PACKET(Packet);
  1363.     pOriginalPacket = pTDReserved->pOriginalPacket;
  1364.     pVElan = pTDReserved->pVElan;
  1365.  
  1366.     //
  1367.     // Complete the original TransferData request.
  1368.     //
  1369.     NdisMTransferDataComplete(pVElan->MiniportAdapterHandle,
  1370.                               pOriginalPacket,
  1371.                               Status,
  1372.                               BytesTransferred);
  1373.  
  1374.     //
  1375.     // Free our packet.
  1376.     //
  1377.     NdisFreePacket(Packet);
  1378.  
  1379.     //DBGPRINT(MUX_LOUD, ("<=PtTransferComplete\n"));
  1380.  
  1381. }
  1382.  
  1383.  
  1384. BOOLEAN
  1385. PtMulticastMatch(
  1386.     IN PVELAN                       pVElan,
  1387.     IN PUCHAR                       pDstMac
  1388.     )
  1389. /*++
  1390.  
  1391. Routine Description:
  1392.  
  1393.     Check if the given multicast destination MAC address matches
  1394.     any of the multicast address entries set on the VELAN.
  1395.  
  1396.     NOTE: the caller is assumed to hold a READ/WRITE lock
  1397.     to the parent ADAPT structure. This is so that the multicast
  1398.     list on the VELAN is invariant for the duration of this call.
  1399.  
  1400. Arguments:
  1401.  
  1402.     pVElan  - VELAN to look in
  1403.     pDstMac - Destination MAC address to compare
  1404.  
  1405. Return Value:
  1406.  
  1407.     TRUE iff the address matches an entry in the VELAN
  1408.  
  1409. --*/
  1410. {
  1411.     ULONG           i;
  1412.     UINT            AddrCompareResult;
  1413.  
  1414.     for (i = 0; i < pVElan->McastAddrCount; i++)
  1415.     {
  1416.         ETH_COMPARE_NETWORK_ADDRESSES_EQ(pVElan->McastAddrs[i],
  1417.                                          pDstMac,
  1418.                                          &AddrCompareResult);
  1419.         
  1420.         if (AddrCompareResult == 0)
  1421.         {
  1422.             break;
  1423.         }
  1424.     }
  1425.  
  1426.     return (i != pVElan->McastAddrCount);
  1427. }
  1428.  
  1429.  
  1430. BOOLEAN
  1431. PtMatchPacketToVElan(
  1432.     IN PVELAN                       pVElan,
  1433.     IN PUCHAR                       pDstMac,
  1434.     IN BOOLEAN                      bIsMulticast,
  1435.     IN BOOLEAN                      bIsBroadcast
  1436.     )
  1437. /*++
  1438.  
  1439. Routine Description:
  1440.  
  1441.     Check if the destination address of a received packet
  1442.     matches the receive criteria on the specified VELAN.
  1443.  
  1444.     NOTE: the caller is assumed to hold a READ/WRITE lock
  1445.     to the parent ADAPT structure.
  1446.  
  1447. Arguments:
  1448.  
  1449.     pVElan  - VELAN to check on
  1450.     pDstMac - Destination MAC address in received packet
  1451.     bIsMulticast - is this a multicast address
  1452.     bIsBroadcast - is this a broadcast address
  1453.  
  1454. Return Value:
  1455.  
  1456.     TRUE iff this packet should be received on the VELAN
  1457.  
  1458. --*/
  1459. {
  1460.     UINT            AddrCompareResult;
  1461.     ULONG           PacketFilter;
  1462.     BOOLEAN         bPacketMatch;
  1463.  
  1464.     // DBGPRINT(MUX_LOUD, ("=>PtMatchPacketToVElan\n"));
  1465.     PacketFilter = pVElan->PacketFilter;
  1466.  
  1467.     //
  1468.     // Handle the directed packet case first.
  1469.     //
  1470.     if (!bIsMulticast)
  1471.     {
  1472.         //
  1473.         // If the VELAN is not in promisc. mode, check if
  1474.         // the destination MAC address matches the local
  1475.         // address.
  1476.         //
  1477.         if ((PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == 0)
  1478.         {
  1479.             ETH_COMPARE_NETWORK_ADDRESSES_EQ(pVElan->CurrentAddress,
  1480.                                              pDstMac,
  1481.                                              &AddrCompareResult);
  1482.  
  1483.             bPacketMatch = ((AddrCompareResult == 0) &&
  1484.                            ((PacketFilter & NDIS_PACKET_TYPE_DIRECTED) != 0));
  1485.         }
  1486.         else
  1487.         {
  1488.             bPacketMatch = TRUE;
  1489.         }
  1490.      }
  1491.      else
  1492.      {
  1493.         //
  1494.         // Multicast or broadcast packet.
  1495.         //
  1496.  
  1497.         //
  1498.         // Indicate if the filter is set to promisc mode ...
  1499.         //
  1500.         if ((PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
  1501.                 ||
  1502.  
  1503.             //
  1504.             // or if this is a broadcast packet and the filter
  1505.             // is set to receive all broadcast packets...
  1506.             //
  1507.             (bIsBroadcast &&
  1508.              (PacketFilter & NDIS_PACKET_TYPE_BROADCAST))
  1509.                 ||
  1510.  
  1511.             //
  1512.             // or if this is a multicast packet, and the filter is
  1513.             // either set to receive all multicast packets, or
  1514.             // set to receive specific multicast packets. In the
  1515.             // latter case, indicate receive only if the destn
  1516.             // MAC address is present in the list of multicast
  1517.             // addresses set on the VELAN.
  1518.             //
  1519.             (!bIsBroadcast &&
  1520.              ((PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
  1521.               ((PacketFilter & NDIS_PACKET_TYPE_MULTICAST) &&
  1522.                PtMulticastMatch(pVElan, pDstMac))))
  1523.            )
  1524.         {
  1525.             bPacketMatch = TRUE;
  1526.         }
  1527.         else
  1528.         {
  1529.             //
  1530.             // No protocols above are interested in this
  1531.             // multicast/broadcast packet.
  1532.             //
  1533.             bPacketMatch = FALSE;
  1534.         }
  1535.     }
  1536.  
  1537.      //DBGPRINT(MUX_LOUD, ("<=PtMatchPacketToVElan\n"));
  1538.  
  1539.     return (bPacketMatch);
  1540. }
  1541.  
  1542.  
  1543. NDIS_STATUS
  1544. PtReceive(
  1545.     IN  NDIS_HANDLE             ProtocolBindingContext,
  1546.     IN  NDIS_HANDLE             MacReceiveContext,
  1547.     IN  PVOID                   HeaderBuffer,
  1548.     IN  UINT                    HeaderBufferSize,
  1549.     IN  PVOID                   LookAheadBuffer,
  1550.     IN  UINT                    LookAheadBufferSize,
  1551.     IN  UINT                    PacketSize
  1552.     )
  1553. /*++
  1554.  
  1555. Routine Description:
  1556.  
  1557.     Handle receive data indicated up by the miniport below.
  1558.  
  1559.     We forward this up to all VELANs that are eligible to
  1560.     receive this packet:
  1561.  
  1562.     - If this is directed to a broadcast/multicast address,
  1563.       indicate up on all VELANs that have multicast or broadcast
  1564.       or promisc. bits set in their packet filters.
  1565.  
  1566.     - If this is a directed packet, indicate it up on all VELANs
  1567.       that have the a matching MAC address or have the promisc.
  1568.       bit set in their packet filters.
  1569.  
  1570.     We acquire a read lock on the ADAPT structure to ensure
  1571.     that the VELAN list on the adapter is undisturbed.
  1572.  
  1573.     If the miniport below indicates packets, NDIS would more
  1574.     likely call us at our ReceivePacket handler. However we
  1575.     might be called here in certain situations even though
  1576.     the miniport below has indicated a receive packet, e.g.
  1577.     if the miniport had set packet status to NDIS_STATUS_RESOURCES.
  1578.         
  1579. Arguments:
  1580.  
  1581.     <see DDK ref page for ProtocolReceive>
  1582.  
  1583. Return Value:
  1584.  
  1585.     NDIS_STATUS_SUCCESS if we processed the receive successfully,
  1586.     NDIS_STATUS_XXX error code if we discarded it.
  1587.  
  1588. --*/
  1589. {
  1590.     PADAPT          pAdapt =(PADAPT)ProtocolBindingContext;
  1591.     PLIST_ENTRY     p;
  1592.     PVELAN          pVElan, pNextVElan;
  1593.     PNDIS_PACKET    MyPacket, Packet;
  1594.     NDIS_STATUS     Status = NDIS_STATUS_SUCCESS;
  1595.     PUCHAR          pData;
  1596.     PUCHAR          pDstMac;
  1597.     BOOLEAN         bIsMulticast, bIsBroadcast;
  1598.     PMUX_RECV_RSVD  pRecvReserved;
  1599.     LOCK_STATE      LockState;
  1600. #if IEEE_VLAN_SUPPORT
  1601.     VLAN_TAG_HEADER UNALIGNED * pTagHeader;
  1602.     USHORT UNALIGNED *          pTpid;
  1603.     MUX_RCV_CONTEXT             MuxRcvContext;
  1604. #endif
  1605.     
  1606.     //DBGPRINT(MUX_LOUD, ("=>PtReceive\n"));
  1607.  
  1608.     do
  1609.     {
  1610.         if (HeaderBufferSize != ETH_HEADER_SIZE)
  1611.         {
  1612.             Status = NDIS_STATUS_NOT_ACCEPTED;
  1613.             break;
  1614.         }
  1615.  
  1616.         if (pAdapt->PacketFilter == 0)
  1617.         {
  1618.             //
  1619.             // We could get receives in the interval between
  1620.             // initiating a request to set the packet filter on
  1621.             // the binding to 0 and completion of that request.
  1622.             // Drop such packets.
  1623.             //
  1624.             Status = NDIS_STATUS_NOT_ACCEPTED;
  1625.             break;
  1626.         }
  1627.  
  1628.         //
  1629.         // Collect some information from the packet.
  1630.         //
  1631.         pData = (PUCHAR)HeaderBuffer;
  1632.         pDstMac = pData;
  1633.         bIsMulticast = ETH_IS_MULTICAST(pDstMac);
  1634.         bIsBroadcast = ETH_IS_BROADCAST(pDstMac);
  1635.  
  1636.         //
  1637.         // Get at the packet, if any, indicated up by the miniport below.
  1638.         //
  1639.         Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext);
  1640.  
  1641.         //
  1642.         // Lock down the VELAN list on the adapter so that
  1643.         // no insertions/deletions to this list happen while
  1644.         // we loop through it. The packet filter will also not
  1645.         // change during the time we hold the read lock.
  1646.         //
  1647.         MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1648.  
  1649.         for (p = pAdapt->VElanList.Flink;
  1650.              p != &pAdapt->VElanList;
  1651.              p = p->Flink)
  1652.         {
  1653.             BOOLEAN     bIndicateReceive;
  1654.  
  1655.             pVElan = CONTAINING_RECORD(p, VELAN, Link);
  1656.  
  1657.             if (pVElan->NetworkConnection != pAdapt->CurrentActiveConnection )
  1658.             continue;
  1659.     
  1660.             pAdapt->nTotalPacketsSeen[pVElan->NetworkConnection]++;
  1661.             //
  1662.             // Should the packet be indicated up on this VELAN?
  1663.             //
  1664.             bIndicateReceive = PtMatchPacketToVElan(pVElan,
  1665.                                                     pDstMac,
  1666.                                                     bIsMulticast,
  1667.                                                     bIsBroadcast);
  1668.             if (!bIndicateReceive)
  1669.             {
  1670.                 continue;
  1671.             }
  1672.  
  1673.             //
  1674.             // Make sure we don't Halt the VELAN miniport while
  1675.             // we are accessing it here. See MPHalt.
  1676.             //
  1677.             // Also don't indicate receives if the virtual miniport
  1678.             // has been set to a low power state. A specific case
  1679.             // is when the system is resuming from "Stand-by", if
  1680.             // the lower adapter is restored to D0 before the upper
  1681.             // miniports are.
  1682.             //
  1683.             //
  1684.             MUX_INCR_PENDING_RECEIVES(pVElan);
  1685.  
  1686.             if ((pVElan->MiniportHalting) ||
  1687.                 (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState)))
  1688.             {
  1689.                 MUX_DECR_PENDING_RECEIVES(pVElan);
  1690.                 continue;
  1691.             }
  1692.  
  1693.  
  1694.             if (Packet != NULL)
  1695.             {
  1696.                 //
  1697.                 // The miniport below did indicate up a packet. Use information
  1698.                 // from that packet to construct a new packet to indicate up.
  1699.                 //
  1700.  
  1701.                 //
  1702.                 // Get a packet off our receive pool and indicate that up.
  1703.                 //
  1704.                 NdisDprAllocatePacket(&Status,
  1705.                                       &MyPacket,
  1706.                                       pVElan->RecvPacketPoolHandle);
  1707.  
  1708.                 if (Status == NDIS_STATUS_SUCCESS)
  1709.                 {
  1710.                     //
  1711.                     // Make our packet point to data from the original
  1712.                     // packet. NOTE: this works only because we are
  1713.                     // indicating a receive directly from the context of
  1714.                     // our receive indication. If we need to queue this
  1715.                     // packet and indicate it from another thread context,
  1716.                     // we will also have to allocate a new buffer and copy
  1717.                     // over the packet contents, OOB data and per-packet
  1718.                     // information. This is because the packet data
  1719.                     // is available only for the duration of this
  1720.                     // receive indication call.
  1721.                     //
  1722.                     MyPacket->Private.Head = Packet->Private.Head;
  1723.                     MyPacket->Private.Tail = Packet->Private.Tail;
  1724. #if IEEE_VLAN_SUPPORT
  1725.                     Status = PtHandleRcvTagging(pVElan, Packet, MyPacket);
  1726.  
  1727.                     if (Status != NDIS_STATUS_SUCCESS)
  1728.                     {
  1729.                         NdisFreePacket(MyPacket);
  1730.                         MUX_DECR_PENDING_RECEIVES(pVElan);
  1731.                         continue;
  1732.                     }
  1733. #endif               
  1734.                     
  1735.                     //
  1736.                     // Get the original packet (it could be the same packet
  1737.                     // as the one received or a different one based on the
  1738.                     // number of layered miniports below) and set it on the
  1739.                     // indicated packet so the OOB data is visible correctly
  1740.                     // at protocols above.
  1741.                     //
  1742.                     NDIS_SET_ORIGINAL_PACKET(MyPacket,
  1743.                                  NDIS_GET_ORIGINAL_PACKET(Packet));
  1744.  
  1745.                     NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);
  1746.     
  1747.                     //
  1748.                     // Copy packet flags.
  1749.                     //
  1750.                     NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
  1751.  
  1752.                     //
  1753.                     // Force protocols above to make a copy if they want to hang
  1754.                     // on to data in this packet. This is because we are in our
  1755.                     // Receive handler (not ReceivePacket), and the original
  1756.                     // packet can't be accessed after we return from here.
  1757.                     //
  1758.                     NDIS_SET_PACKET_STATUS(MyPacket, NDIS_STATUS_RESOURCES);
  1759.  
  1760.                     //
  1761.                     // Set our context information in the packet. Since
  1762.                     // the original packet from the miniport below is not being
  1763.                     // queued up, set this to NULL:
  1764.                     //
  1765.                     pRecvReserved = MUX_RSVD_FROM_RECV_PACKET(MyPacket);
  1766.                     pRecvReserved->pOriginalPacket = NULL;
  1767.                     
  1768.                     MUX_INCR_STATISTICS64(&pVElan->GoodReceives);
  1769.                     
  1770.                     //
  1771.                     // By setting NDIS_STATUS_RESOURCES, we also know that
  1772.                     // we can reclaim this packet as soon as the call to
  1773.                     // NdisMIndicateReceivePacket returns.
  1774.                     //
  1775.                                         
  1776.                     NdisMIndicateReceivePacket(pVElan->MiniportAdapterHandle,
  1777.                                                &MyPacket,
  1778.                                                1);
  1779.  
  1780.                     //
  1781.                     // Reclaim the indicated packet. Since we had set its status
  1782.                     // to NDIS_STATUS_RESOURCES, we are guaranteed that protocols
  1783.                     // above are done with it. Our ReturnPacket handler will
  1784.                     // not be called for this packet, so call it ourselves.
  1785.                     //
  1786.                     MPReturnPacket((NDIS_HANDLE)pVElan, MyPacket);
  1787.  
  1788.                     //
  1789.                     // Done with this VELAN.
  1790.                     //
  1791.                     continue;
  1792.                 }
  1793.  
  1794.                 //
  1795.                 // else...
  1796.                 //
  1797.                 // Failed to allocate a packet to indicate up - fall through.
  1798.                 // We will still indicate up using the non-packet API, but
  1799.                 // other per-packet/OOB information won't be available
  1800.                 // to protocols above.
  1801.                 //
  1802.             }
  1803.             else
  1804.             {
  1805.                 //
  1806.                 // The miniport below us uses the old-style (not packet)
  1807.                 // receive indication. Fall through.
  1808.                 //
  1809.             }
  1810.  
  1811.             //
  1812.             // Fall through to here if the miniport below us has
  1813.             // either not indicated an NDIS_PACKET or we could not
  1814.             // allocate one.
  1815.             //
  1816.  
  1817.             //
  1818.             // Mark the VELAN so that we will forward up a receive
  1819.             // complete indication.
  1820.             //
  1821.             pVElan->IndicateRcvComplete = TRUE;
  1822.  
  1823. #if IEEE_VLAN_SUPPORT
  1824.             //
  1825.             // Get at the EtherType field.
  1826.             //
  1827.             pTpid = (PUSHORT)((PUCHAR)HeaderBuffer + 2 * ETH_LENGTH_OF_ADDRESS);
  1828.  
  1829.             //
  1830.             // Check if the EtherType indicates presence of a tag header.
  1831.             // 
  1832.             if (*pTpid == TPID)
  1833.             {
  1834.                 pTagHeader = (VLAN_TAG_HEADER UNALIGNED *)LookAheadBuffer;
  1835.                 //
  1836.                 // Drop this frame if it contains Routing information;
  1837.                 // we don't support this.
  1838.                 // 
  1839.                 if (GET_CANONICAL_FORMAT_ID_FROM_TAG(pTagHeader) != 0)
  1840.                 {
  1841.                     Status = NDIS_STATUS_INVALID_PACKET;
  1842.                     MUX_DECR_PENDING_RECEIVES(pVElan);
  1843.                     MUX_INCR_STATISTICS(&pVElan->RcvFormatErrors);
  1844.                     continue;
  1845.                 }
  1846.                 //
  1847.                 // If there is a VLAN ID in this frame, and we have
  1848.                 // a configured VLAN ID for this VELAN, check if they
  1849.                 // are the same - drop if not.
  1850.                 // 
  1851.                 if ((GET_VLAN_ID_FROM_TAG(pTagHeader) != 0) &&
  1852.                      (pVElan->VlanId != 0) &&
  1853.                      (GET_VLAN_ID_FROM_TAG(pTagHeader) != pVElan->VlanId))
  1854.                 {
  1855.                     Status = NDIS_STATUS_NOT_ACCEPTED;
  1856.                     MUX_DECR_PENDING_RECEIVES(pVElan);
  1857.                     MUX_INCR_STATISTICS(&pVElan->RcvVlanIdErrors);
  1858.                     continue;
  1859.                 }
  1860.                 //
  1861.                 // Copy information from the tag header to per-packet
  1862.                 // info fields.
  1863.                 //
  1864.                 MuxRcvContext.NdisPacket8021QInfo.Value = NULL;
  1865.                 COPY_TAG_INFO_FROM_HEADER_TO_PACKET_INFO(
  1866.                     MuxRcvContext.NdisPacket8021QInfo,
  1867.                     pTagHeader);
  1868.                 //
  1869.                 // Prepare for indicating up this frame (the tag
  1870.                 // header must be removed). First, copy in the real
  1871.                 // EtherType value from the tag header.
  1872.                 // 
  1873.                 *pTpid = *((PUSHORT)((PUCHAR)LookAheadBuffer + sizeof(pTagHeader->TagInfo)));
  1874.                 //
  1875.                 // Account for removing the tag header.
  1876.                 //
  1877.                 LookAheadBuffer = (PVOID)((PUCHAR)LookAheadBuffer + VLAN_TAG_HEADER_SIZE); 
  1878.                 LookAheadBufferSize -= VLAN_TAG_HEADER_SIZE;
  1879.                 PacketSize -= VLAN_TAG_HEADER_SIZE;
  1880.                 //
  1881.                 // Use MuxRcvContext to store context for the receive,
  1882.                 // to be used in MpTransferData, if called.
  1883.                 // 
  1884.                 MuxRcvContext.TagHeaderLen = VLAN_TAG_HEADER_SIZE;
  1885.             }
  1886.             else
  1887.             {
  1888.                 MuxRcvContext.TagHeaderLen = 0;
  1889.             }
  1890.  
  1891.             MuxRcvContext.MacRcvContext = MacReceiveContext;
  1892.  
  1893.             //
  1894.             // In order not to change the code a lot
  1895.             // 
  1896.             MacReceiveContext = &MuxRcvContext;
  1897. #endif            
  1898.  
  1899.             MUX_INCR_STATISTICS64(&pVElan->GoodReceives);
  1900.             //
  1901.             // Indicate receive using the non-packet API.
  1902.             //
  1903.             NdisMEthIndicateReceive(pVElan->MiniportAdapterHandle,
  1904.                                     MacReceiveContext,
  1905.                                     HeaderBuffer,
  1906.                                     HeaderBufferSize,
  1907.                                     LookAheadBuffer,
  1908.                                     LookAheadBufferSize,
  1909.                                     PacketSize);
  1910.  
  1911.             MUX_DECR_PENDING_RECEIVES(pVElan);
  1912.  
  1913.         } // for (each VELAN)
  1914.  
  1915.         MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1916.  
  1917.         break;
  1918.  
  1919.     }
  1920.     while(FALSE);
  1921.  
  1922.     //DBGPRINT(MUX_LOUD, ("<=PtReceive\n"));
  1923.  
  1924.     return Status;
  1925. }
  1926.  
  1927.  
  1928. VOID
  1929. PtReceiveComplete(
  1930.     IN    NDIS_HANDLE        ProtocolBindingContext
  1931.     )
  1932. /*++
  1933.  
  1934. Routine Description:
  1935.  
  1936.     Called by the adapter below us when it is done indicating a batch of
  1937.     received packets. We forward this up on all VELANs that need
  1938.     this indication.
  1939.  
  1940. Arguments:
  1941.  
  1942.     ProtocolBindingContext    Pointer to our adapter structure.
  1943.  
  1944. Return Value:
  1945.  
  1946.     None
  1947.  
  1948. --*/
  1949. {
  1950.     PADAPT          pAdapt = (PADAPT)ProtocolBindingContext;
  1951.     PLIST_ENTRY     p;
  1952.     PVELAN          pVElan;
  1953.     LOCK_STATE      LockState;
  1954.  
  1955.     //DBGPRINT(MUX_LOUD, ("=>PtReceiveComplete\n"));
  1956.  
  1957.     MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1958.  
  1959.     for (p = pAdapt->VElanList.Flink;
  1960.          p != &pAdapt->VElanList;
  1961.          p = p->Flink)
  1962.     {
  1963.         pVElan = CONTAINING_RECORD(p, VELAN, Link);
  1964.  
  1965.         if (pVElan->IndicateRcvComplete)
  1966.         {
  1967.             pVElan->IndicateRcvComplete = FALSE;
  1968.             NdisMEthIndicateReceiveComplete(pVElan->MiniportAdapterHandle);
  1969.         }
  1970.     }
  1971.  
  1972.     MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1973.     //DBGPRINT(MUX_LOUD, ("<=PtReceiveComplete\n"));
  1974.  
  1975. }
  1976.  
  1977.  
  1978. INT
  1979. PtReceivePacket(
  1980.     IN    NDIS_HANDLE               ProtocolBindingContext,
  1981.     IN    PNDIS_PACKET              Packet
  1982.     )
  1983. /*++
  1984.  
  1985. Routine Description:
  1986.  
  1987.     ReceivePacket handler. Called by NDIS if the miniport below supports
  1988.     NDIS 4.0 style receives. Re-package the buffer chain in a new packet
  1989.     and indicate the new packet to interested protocols above us.
  1990.  
  1991. Arguments:
  1992.  
  1993.     ProtocolBindingContext - Pointer to our adapter structure.
  1994.     Packet - Pointer to the packet
  1995.  
  1996. Return Value:
  1997.  
  1998.     == 0 -> We are done with the packet
  1999.     != 0 -> We will keep the packet and call NdisReturnPackets() this
  2000.             many times when done.
  2001. --*/
  2002. {
  2003.     PADAPT                  pAdapt = (PADAPT)ProtocolBindingContext;
  2004.     PVELAN                  pVElan;
  2005.     PLIST_ENTRY             p;
  2006.     NDIS_STATUS             Status;
  2007.     PNDIS_PACKET            MyPacket;
  2008.     PUCHAR                  pData;
  2009.     PNDIS_BUFFER            pNdisBuffer;
  2010.     UINT                    FirstBufferLength;
  2011.     UINT                    TotalLength;
  2012.     PUCHAR                  pDstMac;
  2013.     BOOLEAN                 bIsMulticast, bIsBroadcast;
  2014.     PMUX_RECV_RSVD          pRecvReserved;
  2015.     ULONG                   ReturnCount;
  2016.     LOCK_STATE              LockState;
  2017.     
  2018.     
  2019.     DBGPRINT(MUX_LOUD, ("=>PtReceivePacket\n"));
  2020.  
  2021.     ReturnCount = 0;
  2022.  
  2023.     do
  2024.     {
  2025.         if (pAdapt->PacketFilter == 0)
  2026.         {
  2027.             //
  2028.             // We could get receives in the interval between
  2029.             // initiating a request to set the packet filter on
  2030.             // the binding to 0 and completion of that request.
  2031.             // Drop such packets.
  2032.             //
  2033.             break;
  2034.         }
  2035.  
  2036. #ifdef NDIS51
  2037.         //
  2038.         // Collect some information from the packet.
  2039.         //
  2040.         NdisGetFirstBufferFromPacketSafe(Packet,
  2041.                                          &pNdisBuffer,
  2042.                                          &pData,
  2043.                                          &FirstBufferLength,
  2044.                                          &TotalLength,
  2045.                                          NormalPagePriority);
  2046.         if (pNdisBuffer == NULL)
  2047.         {
  2048.             //
  2049.             // Out of system resources. Drop this packet.
  2050.             //
  2051.             break;
  2052.         }
  2053. #else
  2054.         NdisGetFirstBufferFromPacket(Packet,
  2055.                                      &pNdisBuffer,
  2056.                                      &pData,
  2057.                                      &FirstBufferLength,
  2058.                                      &TotalLength);
  2059. #endif
  2060.  
  2061.         pDstMac = pData;
  2062.         bIsMulticast = ETH_IS_MULTICAST(pDstMac);
  2063.         bIsBroadcast = ETH_IS_BROADCAST(pDstMac);
  2064.  
  2065.         //
  2066.         // Lock down the VELAN list on the adapter so that
  2067.         // no insertions/deletions to this list happen while
  2068.         // we loop through it. The packet filter will also not
  2069.         // change during the time we hold the read lock.
  2070.         //
  2071.         MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  2072.  
  2073.         for (p = pAdapt->VElanList.Flink;
  2074.              p != &pAdapt->VElanList;
  2075.              p = p->Flink)
  2076.         {
  2077.             BOOLEAN     bIndicateReceive;
  2078.  
  2079.             pVElan = CONTAINING_RECORD(p, VELAN, Link);
  2080.  
  2081.             //
  2082.             // Should the packet be indicated up on this VELAN?
  2083.             //
  2084.             bIndicateReceive = PtMatchPacketToVElan(pVElan,
  2085.                                                     pDstMac,
  2086.                                                     bIsMulticast,
  2087.                                                     bIsBroadcast);
  2088.             if (!bIndicateReceive)
  2089.             {
  2090.                 continue;
  2091.             }
  2092.  
  2093.             //
  2094.             // Make sure we don't Halt the VELAN miniport while
  2095.             // we are accessing it here. See MPHalt.
  2096.             //
  2097.             // Also don't indicate receives if the virtual miniport
  2098.             // has been set to a low power state. A specific case
  2099.             // is when the system is resuming from "Stand-by", if
  2100.             // the lower adapter is restored to D0 before the upper
  2101.             // miniports are.
  2102.             //
  2103.             MUX_INCR_PENDING_RECEIVES(pVElan);
  2104.  
  2105.             if ((pVElan->MiniportHalting) ||
  2106.                 (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState)))
  2107.             {
  2108.                 MUX_DECR_PENDING_RECEIVES(pVElan);
  2109.                 continue;
  2110.             }
  2111.  
  2112.  
  2113.             //
  2114.             // Get a packet off the pool and indicate that up
  2115.             //
  2116.             NdisDprAllocatePacket(&Status,
  2117.                                   &MyPacket,
  2118.                                   pVElan->RecvPacketPoolHandle);
  2119.  
  2120.             if (Status == NDIS_STATUS_SUCCESS)
  2121.             {
  2122.                 pRecvReserved = MUX_RSVD_FROM_RECV_PACKET(MyPacket);
  2123.                 pRecvReserved->pOriginalPacket = Packet;
  2124.         
  2125.                 MyPacket->Private.Head = Packet->Private.Head;
  2126.                 MyPacket->Private.Tail = Packet->Private.Tail;
  2127.         
  2128.                 //
  2129.                 // Get the original packet (it could be the same
  2130.                 // packet as the one received or a different one
  2131.                 // based on the number of layered miniports below)
  2132.                 // and set it on the indicated packet so the OOB
  2133.                 // data is visible correctly to protocols above us.
  2134.                 //
  2135.                 NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
  2136.         
  2137.                 //
  2138.                 // Copy Packet Flags
  2139.                 //
  2140.                 NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
  2141.         
  2142.                 Status = NDIS_GET_PACKET_STATUS(Packet);
  2143.         
  2144.                 NDIS_SET_PACKET_STATUS(MyPacket, Status);
  2145.                 NDIS_SET_PACKET_HEADER_SIZE(MyPacket, NDIS_GET_PACKET_HEADER_SIZE(Packet));
  2146.  
  2147. #if IEEE_VLAN_SUPPORT
  2148.                 Status = PtHandleRcvTagging(pVElan, Packet, MyPacket);
  2149.  
  2150.                 if (Status != NDIS_STATUS_SUCCESS)
  2151.                 {
  2152.                     NdisFreePacket(MyPacket);
  2153.                     MUX_DECR_PENDING_RECEIVES(pVElan);
  2154.                     continue;
  2155.                 }
  2156. #endif                
  2157.                 MUX_INCR_STATISTICS64(&pVElan->GoodReceives);
  2158.                 
  2159.                 //
  2160.                 // Indicate it up.
  2161.                 //
  2162.                 ReturnCount++;
  2163.                 NdisMIndicateReceivePacket(pVElan->MiniportAdapterHandle,
  2164.                                            &MyPacket,
  2165.                                            1);
  2166.         
  2167.                 //
  2168.                 // Check if we had indicated up the packet with
  2169.                 // status set to NDIS_STATUS_RESOURCES.
  2170.                 //
  2171.                 // NOTE -- do not use NDIS_GET_PACKET_STATUS(MyPacket)
  2172.                 // for this since it might have changed! Use the value
  2173.                 // saved in the local variable.
  2174.                 //
  2175.                 if (Status == NDIS_STATUS_RESOURCES)
  2176.                 {
  2177.                     //
  2178.                     // Our ReturnPackets handler will not be called
  2179.                     // for this packet. We should reclaim it right here.
  2180.                     //
  2181.         
  2182.                     MPReturnPacket((NDIS_HANDLE)pVElan, MyPacket);
  2183.                 }
  2184.             }
  2185.             else
  2186.             {
  2187.                 //
  2188.                 // Failed to allocate a packet.
  2189.                 //
  2190.                 MUX_INCR_STATISTICS(&pVElan->RcvResourceErrors);
  2191.                 MUX_DECR_PENDING_RECEIVES(pVElan);
  2192.             }
  2193.  
  2194.         } // for (loop thru all VELANs)
  2195.  
  2196.         MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  2197.  
  2198.         break;
  2199.     }
  2200.     while (FALSE);
  2201.  
  2202.     DBGPRINT(MUX_LOUD, ("<=PtReceivePacket\n"));
  2203.  
  2204.     //
  2205.     // Return the # of receive indications made for this packet.
  2206.     // We will call NdisReturnPackets for this packet as many
  2207.     // times (see MPReturnPackets).
  2208.     //
  2209.     return (ReturnCount);
  2210.  
  2211. }
  2212.  
  2213.  
  2214.  
  2215. NDIS_STATUS
  2216. PtPnPNetEventSetPower(
  2217.     IN PADAPT                   pAdapt,
  2218.     IN PNET_PNP_EVENT           pNetPnPEvent
  2219.     )
  2220. /*++
  2221. Routine Description:
  2222.  
  2223.     This is a notification to our protocol edge of the power state
  2224.     of the lower miniport. If it is going to a low-power state, we must
  2225.     wait here for all outstanding sends and requests to complete.
  2226.  
  2227. Arguments:
  2228.  
  2229.     pAdapt - Pointer to the adpater structure
  2230.     pNetPnPEvent - The Net Pnp Event. this contains the new device state
  2231.  
  2232. Return Value:
  2233.  
  2234.     NDIS_STATUS_SUCCESS
  2235.  
  2236. --*/
  2237. {
  2238.     PLIST_ENTRY                 p;
  2239.     PVELAN                      pVElan;
  2240.     LOCK_STATE                  LockState;
  2241.     NDIS_STATUS                 Status;
  2242.  
  2243.     //
  2244.     // Store the new power state.
  2245.     //
  2246.     pAdapt->PtDevicePowerState = *(PNDIS_DEVICE_POWER_STATE)pNetPnPEvent->Buffer;
  2247.  
  2248.     DBGPRINT(MUX_LOUD, ("PnPNetEventSetPower: Adapt %p, SetPower to %d\n",
  2249.             pAdapt, pAdapt->PtDevicePowerState));
  2250.  
  2251.     //
  2252.     // Check if the miniport below is going to a low power state.
  2253.     //
  2254.     if (MUX_IS_LOW_POWER_STATE(pAdapt->PtDevicePowerState))
  2255.     {
  2256.         ULONG       i;
  2257.  
  2258.         //
  2259.         // It is going to a low power state. Wait for outstanding
  2260.         // I/O to complete on the adapter.
  2261.         //
  2262.         for (i = 0; i < 10000; i++)
  2263.         {
  2264.             MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  2265.  
  2266.             for (p = pAdapt->VElanList.Flink;
  2267.                  p != &pAdapt->VElanList;
  2268.                  p = p->Flink)
  2269.             {
  2270.                 pVElan = CONTAINING_RECORD(p, VELAN, Link);
  2271.                 if ((pVElan->OutstandingSends != 0) ||
  2272.                     (pVElan->OutstandingReceives != 0))
  2273.                 {
  2274.                     break;
  2275.                 }
  2276.             }
  2277.  
  2278.             MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  2279.  
  2280.             if (p == &pAdapt->VElanList)
  2281.             {
  2282.                 //
  2283.                 // There are no VELANs with pending I/O.
  2284.                 //
  2285.                 break;
  2286.             }
  2287.             
  2288.             DBGPRINT(MUX_INFO, ("SetPower: Adapt %p, waiting for pending IO to complete\n",
  2289.                                 pAdapt));
  2290.  
  2291.             NdisMSleep(1000);
  2292.         }
  2293.  
  2294.     }
  2295.     else
  2296.     {
  2297.         //
  2298.         // The device below is powered on. If we had requests
  2299.         // pending on any VELANs, send them down now.
  2300.         //
  2301.         MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  2302.  
  2303.         for (p = pAdapt->VElanList.Flink;
  2304.              p != &pAdapt->VElanList;
  2305.              p = p->Flink)
  2306.         {
  2307.             pVElan = CONTAINING_RECORD(p, VELAN, Link);
  2308.  
  2309.             if (pVElan->QueuedRequest)
  2310.             {
  2311.                 pVElan->QueuedRequest = FALSE;
  2312.  
  2313.                 NdisRequest(&Status,
  2314.                             pAdapt->BindingHandle,
  2315.                             &pVElan->Request.Request);
  2316.                 
  2317.                 if (Status != NDIS_STATUS_PENDING)
  2318.                 {
  2319.                     PtRequestComplete(pAdapt,
  2320.                                       &pVElan->Request.Request,
  2321.                                       Status);
  2322.                 }
  2323.             }
  2324.         }
  2325.  
  2326.         MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  2327.     }
  2328.  
  2329.     return (NDIS_STATUS_SUCCESS);
  2330. }
  2331.  
  2332.  
  2333. NDIS_STATUS
  2334. PtPNPHandler(
  2335.     IN NDIS_HANDLE              ProtocolBindingContext,
  2336.     IN PNET_PNP_EVENT           pNetPnPEvent
  2337.     )
  2338.  
  2339. /*++
  2340. Routine Description:
  2341.  
  2342.     This is called by NDIS to notify us of a PNP event related to a lower
  2343.     binding. Based on the event, this dispatches to other helper routines.
  2344.  
  2345. Arguments:
  2346.  
  2347.     ProtocolBindingContext - Pointer to our adapter structure. Can be NULL
  2348.                 for "global" notifications
  2349.  
  2350.     pNetPnPEvent - Pointer to the PNP event to be processed.
  2351.  
  2352. Return Value:
  2353.  
  2354.     NDIS_STATUS code indicating status of event processing.
  2355.  
  2356. --*/
  2357. {
  2358.     PADAPT              pAdapt  =(PADAPT)ProtocolBindingContext;
  2359.     NDIS_STATUS         Status  = NDIS_STATUS_SUCCESS;
  2360.     PNOTIFY_CUSTOM_EVENT event = NULL;
  2361.     PVELAN              pVElan = NULL;
  2362.     NDIS_STRING         deviceName;
  2363.     PLIST_ENTRY         p;
  2364.  
  2365.     DBGPRINT(MUX_LOUD, ("PtPnPHandler: Adapt %p, NetPnPEvent %d\n", pAdapt, 
  2366.                             pNetPnPEvent->NetEvent));
  2367.  
  2368.     switch (pNetPnPEvent->NetEvent)
  2369.     {
  2370.         case NetEventSetPower:
  2371.  
  2372.             Status = PtPnPNetEventSetPower(pAdapt, pNetPnPEvent);
  2373.             break;
  2374.  
  2375.         case NetEventReconfigure:
  2376.             //
  2377.             // Rescan configuration and bring up any VELANs that
  2378.             // have been newly added. Make sure that the global
  2379.             // adapter list is undisturbed while we traverse it.
  2380.             //
  2381.             MUX_ACQUIRE_MUTEX(&GlobalMutex);
  2382.  
  2383.             for (p = AdapterList.Flink;
  2384.                  p != &AdapterList;
  2385.                  p = p->Flink)
  2386.             {
  2387.                 pAdapt = CONTAINING_RECORD(p, ADAPT, Link);
  2388.  
  2389.                 PtBootStrapVElans(pAdapt);
  2390.             }
  2391.  
  2392.             MUX_RELEASE_MUTEX(&GlobalMutex);
  2393.                 
  2394.             Status = NDIS_STATUS_SUCCESS;
  2395.             break;
  2396.  
  2397.         default:
  2398.             Status = NDIS_STATUS_SUCCESS;
  2399.  
  2400.             break;
  2401.     }
  2402.     return Status;
  2403. }
  2404.  
  2405. /* This function determines the next active SSID */
  2406. BOOLEAN SetNextActiveConnection(
  2407.      IN PADAPT pAdapt
  2408.      )
  2409. {
  2410.     ULONG i;
  2411.     BOOLEAN flag = FALSE;
  2412.  
  2413.     DBGPRINT(MUX_LOUD, ("SetNextActiveConnection: Previous Active is %d\n", pAdapt->CurrentActiveConnection));
  2414.     // go through all SSIDs from current to MAX
  2415.     for(i=pAdapt->CurrentActiveConnection+1; i<pAdapt->numConnections; i++) {
  2416.         // if there is more than one miniport on that SSID
  2417.         if(pAdapt->NumActiveConnectionsOnSSID[i] > 0) {
  2418.             flag = TRUE;
  2419.             break;
  2420.         }
  2421.     }
  2422.  
  2423.     // if no SSID after the current one has more than one miniport
  2424.     if(!flag)
  2425.     {
  2426.         // go through connections from 0 to current
  2427.         for(i=0; i<pAdapt->CurrentActiveConnection; i++) {
  2428.             // if there is more than one miniport on that SSID
  2429.             if(pAdapt->NumActiveConnectionsOnSSID[i] > 0) {
  2430.                 flag = TRUE;
  2431.                 break;
  2432.             }
  2433.         }
  2434.     }
  2435.  
  2436.     // if there exists another SSID with more than one miniport
  2437.     if(flag) {
  2438.         // if one exists then good
  2439.         if(pAdapt->CurrentActiveConnection != i)
  2440.             pAdapt->CurrentActiveConnection = i;
  2441.         else
  2442.             DBGPRINT(MUX_FATAL, ("Something WRONG in SetNextActiveConnection\n"));
  2443.  
  2444.         DBGPRINT(MUX_LOUD, ("SetNextActiveConnection: New Active is %d\n", pAdapt->CurrentActiveConnection));
  2445.         return TRUE;
  2446.     }
  2447.  
  2448.     return FALSE;
  2449. }
  2450.  
  2451. // Find the total number of SSIDs with more than one miniport
  2452. ULONG NumActiveConnections(
  2453.     IN PADAPT pAdapt
  2454.     )
  2455. {
  2456.     ULONG i = 0;
  2457.     ULONG j;
  2458.  
  2459.     // go through all SSIDs
  2460.     for(j=0; j<pAdapt->numConnections; j++) {
  2461.         DBGPRINT(MUX_LOUD, ("Numactiveconnections on %d ssid is %d\n", j, pAdapt->NumActiveConnectionsOnSSID[j]));
  2462.         // if more than one miniport on that SSID
  2463.         if(pAdapt->NumActiveConnectionsOnSSID[j] > 0)
  2464.             i++;
  2465.     }
  2466.     return i;
  2467. }
  2468.  
  2469. // Called to change the SSID and send buffered packets on that SSID
  2470. VOID SetSSIDAndClearSendPackets( 
  2471.     IN PADAPT pAdapt
  2472.     )
  2473. {
  2474.     LOCK_STATE      LockState;
  2475.  
  2476.     DBGPRINT(MUX_LOUD, ("=>SetSSIDAndClearSendPackets\n"));
  2477.  
  2478.     MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2479.  
  2480.     DBGPRINT(MUX_LOUD, ("=> Switch Timer: Current Active SSID is %d\n", 
  2481.                             pAdapt->CurrentActiveConnection));
  2482.     
  2483.     // Set the mode of the adapter to the required connection
  2484.     PtRequestAdapterAsync(pAdapt,
  2485.         NdisRequestSetInformation,
  2486.         OID_802_11_INFRASTRUCTURE_MODE,
  2487.         &pAdapt->networkMode[pAdapt->CurrentActiveConnection],
  2488.         sizeof(pAdapt->networkMode[pAdapt->CurrentActiveConnection]),
  2489.         PtDiscardCompletedRequest);
  2490.  
  2491.     // Set the SSID of the adapter to the required connection
  2492.     PtRequestAdapterAsync(pAdapt,
  2493.         NdisRequestSetInformation,
  2494.         OID_802_11_SSID,
  2495.         &pAdapt->networkSSID[pAdapt->CurrentActiveConnection],
  2496.         sizeof(pAdapt->networkSSID[pAdapt->CurrentActiveConnection]),
  2497.         PtDiscardCompletedRequest);
  2498.  
  2499.     // Set the last Action as Switched, 
  2500.     // so that the next time the timer goes off, it should send the buffered packets 
  2501.     // pAdapt->LastActionSwitched = TRUE;
  2502.  
  2503.     // Send the buffered packets
  2504.     PtIoctlSendBufferedPackets(pAdapt);
  2505.  
  2506.     MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2507.  
  2508.     DBGPRINT(MUX_LOUD, ("<=SetSSIDAndClearSendPackets\n"));
  2509. }
  2510.  
  2511. // This function is called every time the timer goes off
  2512. /*
  2513. VOID PtSwitchTimerFunction(
  2514.     IN  PVOID                      SystemSpecific1,  // not used
  2515.     IN  PVOID                       FunctionContext,  // adapter
  2516.     IN  PVOID                      SystemSpecific2,  // not used
  2517.     IN  PVOID                      SystemSpecific3   // not used
  2518.     )
  2519. {
  2520.     PADAPT pAdapt = (PADAPT)FunctionContext;
  2521.     LOCK_STATE       LockState;
  2522.     NDIS_STATUS      Status;
  2523.  
  2524.     DBGPRINT(MUX_LOUD, ("=> Switch Timer: Adapter %p\n", 
  2525.                             pAdapt));
  2526.  
  2527.     if(!pAdapt->StartSwitching) {
  2528.         NdisSetTimer(&pAdapt->SwitchingTimer, g_WaitingTimeInfra);
  2529.         return;
  2530.     }
  2531.  
  2532.     MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2533.     pAdapt->isTimerFired = FALSE;
  2534.  
  2535.     // if the last action was not a switch, then it should switch the adapter now
  2536.     if(!pAdapt->LastActionSwitched)
  2537.     {
  2538.         // Find the network to switch to
  2539.         if(SetNextActiveConnection(pAdapt))
  2540.         {    
  2541.             DBGPRINT(MUX_LOUD, ("=> Switch Timer: Current Active SSID is %d\n", 
  2542.                                     pAdapt->CurrentActiveConnection));
  2543.  
  2544.             // change the mode of the adapter
  2545.             PtRequestAdapterAsync(pAdapt,
  2546.                 NdisRequestSetInformation,
  2547.                 OID_802_11_INFRASTRUCTURE_MODE,
  2548.                 &pAdapt->networkMode[pAdapt->CurrentActiveConnection],
  2549.                 sizeof(pAdapt->networkMode[pAdapt->CurrentActiveConnection]),
  2550.                 PtDiscardCompletedRequest);
  2551.  
  2552.             // change the SSID of the adapter
  2553.             PtRequestAdapterAsync(pAdapt,
  2554.                 NdisRequestSetInformation,
  2555.                 OID_802_11_SSID,
  2556.                 &pAdapt->networkSSID[pAdapt->CurrentActiveConnection],
  2557.                 sizeof(pAdapt->networkSSID[pAdapt->CurrentActiveConnection]),
  2558.                 PtDiscardCompletedRequest);
  2559.  
  2560.             // if there is more than one active SSID, then set the timer again
  2561.             if(NumActiveConnections(pAdapt) > 1)
  2562.             {
  2563.                 // if the network is infrastructure
  2564.                 if(pAdapt->networkMode[pAdapt->CurrentActiveConnection])
  2565.                     NdisSetTimer(&pAdapt->SwitchingTimer, g_SwitchingTimeInfra);
  2566.                 else // if ad hoc
  2567.                     NdisSetTimer(&pAdapt->SwitchingTimer, g_SwitchingTimeAdhoc);
  2568.                 pAdapt->isTimerFired = TRUE;
  2569.                 pAdapt->LastActionSwitched = TRUE;
  2570.             }
  2571.         }
  2572.     }
  2573.     else  // if the last action was a switch, then keep the network active for some time
  2574.     {
  2575.         // Send all the buffered packets
  2576.         while(!IsQueueEmpty(&pAdapt->SendWaitQueue[pAdapt->CurrentActiveConnection]))
  2577.         {
  2578.             PVELAN           pVElan;
  2579.             PMUX_SEND_RSVD   pSendReserved;
  2580.             PNDIS_PACKET     MyPacket;
  2581.             PQUEUE_ENTRY     pEntry = RemoveHeadQueue(&pAdapt->SendWaitQueue[pAdapt->CurrentActiveConnection]);
  2582.  
  2583.             ASSERT(pEntry);
  2584.  
  2585.             DBGPRINT(MUX_LOUD, ("Dequeueing packet for SSID %d\n", pAdapt->CurrentActiveConnection));
  2586.  
  2587.             // decrement the number of buffered packets
  2588.             pAdapt->nWaitSend[pAdapt->CurrentActiveConnection]--;
  2589.             MyPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
  2590.  
  2591.             pSendReserved = MUX_RSVD_FROM_SEND_PACKET(MyPacket);
  2592.             pVElan = pSendReserved->pVElan;
  2593.  
  2594.             MUX_INCR_PENDING_SENDS(pVElan);
  2595.  
  2596.             NdisSend(&Status,
  2597.                     pAdapt->BindingHandle,
  2598.                     MyPacket);
  2599.  
  2600.             if (Status != NDIS_STATUS_PENDING)
  2601.             {
  2602.                 PtSendComplete((NDIS_HANDLE)pAdapt,
  2603.                             MyPacket,
  2604.                             Status);
  2605.             }
  2606.         }
  2607.  
  2608.         // Fire the next timer to switch after waiting for some period
  2609.         if(pAdapt->networkMode[pAdapt->CurrentActiveConnection])
  2610.             NdisSetTimer(&pAdapt->SwitchingTimer, g_WaitingTimeInfra);
  2611.         else
  2612.             NdisSetTimer(&pAdapt->SwitchingTimer, g_WaitingTimeAdhoc);
  2613.  
  2614.         pAdapt->isTimerFired = TRUE;
  2615.         pAdapt->LastActionSwitched = FALSE;
  2616.     }
  2617.  
  2618.     MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2619.     DBGPRINT(MUX_LOUD, ("<= Switch Timer: Adapter %p\n", 
  2620.                             pAdapt));
  2621. }
  2622. */
  2623.  
  2624. // Called by an Ioctl to Set the SSID to the next network
  2625. VOID PtIoctlSetAdapterSSID(
  2626.     IN PADAPT pAdapt
  2627. )
  2628. {
  2629.     LOCK_STATE       LockState;
  2630.     NDIS_STATUS      Status;
  2631.  
  2632.     DBGPRINT(MUX_LOUD, ("=> PtIoctlSetAdapterSSID %p\n", 
  2633.                             pAdapt));
  2634.  
  2635.     MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2636.  
  2637.     // Find the network to switch to
  2638.     if(SetNextActiveConnection(pAdapt))
  2639.     {    
  2640.         DBGPRINT(MUX_LOUD, ("=> PtIoctlSetAdapterSSID: Current Active SSID is %d\n", 
  2641.                                 pAdapt->CurrentActiveConnection));
  2642.  
  2643.         pAdapt->nTotalPacketsSeen[pAdapt->CurrentActiveConnection] = 0;
  2644.         pAdapt->switchStartTime = KeQueryInterruptTime();
  2645.  
  2646.         // change the mode of the adapter to either AH or IS
  2647.         PtRequestAdapterAsync(pAdapt,
  2648.             NdisRequestSetInformation,
  2649.             OID_802_11_INFRASTRUCTURE_MODE,
  2650.             &pAdapt->networkMode[pAdapt->CurrentActiveConnection],
  2651.             sizeof(pAdapt->networkMode[pAdapt->CurrentActiveConnection]),
  2652.             PtDiscardCompletedRequest);
  2653.  
  2654.         // change the SSID of the adapter to the required SSID
  2655.         PtRequestAdapterAsync(pAdapt,
  2656.             NdisRequestSetInformation,
  2657.             OID_802_11_SSID,
  2658.             &pAdapt->networkSSID[pAdapt->CurrentActiveConnection],
  2659.             sizeof(pAdapt->networkSSID[pAdapt->CurrentActiveConnection]),
  2660.             PtDiscardCompletedRequest);
  2661.  
  2662.     }
  2663.  
  2664.     MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2665.     DBGPRINT(MUX_LOUD, ("<= PtIoctlSetAdapterSSID: Adapter %p\n", 
  2666.                             pAdapt));
  2667. }
  2668.  
  2669. // Called by an Ioctl to buffer packets on the currently active SSID
  2670. VOID PtIoctlStartBufferingPackets(
  2671.     IN PADAPT pAdapt
  2672. )
  2673. {
  2674.     LOCK_STATE       LockState;
  2675.     NDIS_STATUS      Status;
  2676.  
  2677.     DBGPRINT(MUX_LOUD, ("=> PtIoctlStartBufferingPackets %p\n", 
  2678.                             pAdapt));
  2679.  
  2680.     MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2681.  
  2682.     pAdapt->isSSIDActive[pAdapt->CurrentActiveConnection] = FALSE;
  2683.  
  2684.     MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2685.     DBGPRINT(MUX_LOUD, ("<= PtIoctlStartBufferingPackets: Adapter %p\n", 
  2686.                             pAdapt));
  2687. }
  2688.  
  2689. // Called by an Ioctl to Send the Buffered Packets
  2690. VOID PtIoctlSendBufferedPackets(
  2691.     IN PADAPT pAdapt
  2692. )
  2693. {
  2694.     LOCK_STATE       LockState;
  2695.     NDIS_STATUS      Status;
  2696.  
  2697.     DBGPRINT(MUX_LOUD, ("=> PtIoctlSendBufferedPackets %p\n", 
  2698.                             pAdapt));
  2699.  
  2700.     MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2701.  
  2702.     pAdapt->isSSIDActive[pAdapt->CurrentActiveConnection] = TRUE;
  2703.  
  2704.     // Send all the buffered packets
  2705.     while(!IsQueueEmpty(&pAdapt->SendWaitQueue[pAdapt->CurrentActiveConnection]))
  2706.     {
  2707.         PVELAN           pVElan;
  2708.         PMUX_SEND_RSVD   pSendReserved;
  2709.         PNDIS_PACKET     MyPacket;
  2710.         PQUEUE_ENTRY     pEntry = RemoveHeadQueue(&pAdapt->SendWaitQueue[pAdapt->CurrentActiveConnection]);
  2711.  
  2712.         ASSERT(pEntry);
  2713.  
  2714.         DBGPRINT(MUX_LOUD, ("Dequeueing packet for SSID %d\n", pAdapt->CurrentActiveConnection));
  2715.  
  2716.         // decrement the number of buffered packets
  2717.         pAdapt->nWaitSend[pAdapt->CurrentActiveConnection]--;
  2718.         MyPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
  2719.  
  2720.         pSendReserved = MUX_RSVD_FROM_SEND_PACKET(MyPacket);
  2721.         pVElan = pSendReserved->pVElan;
  2722.  
  2723.         MUX_INCR_PENDING_SENDS(pVElan);
  2724.  
  2725.         NdisSend(&Status,
  2726.                 pAdapt->BindingHandle,
  2727.                 MyPacket);
  2728.  
  2729.         if (Status != NDIS_STATUS_PENDING)
  2730.         {
  2731.             PtSendComplete((NDIS_HANDLE)pAdapt,
  2732.                         MyPacket,
  2733.                         Status);
  2734.         }
  2735.     }
  2736.  
  2737.     MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2738.     DBGPRINT(MUX_LOUD, ("<= PtIoctlSendBufferedPackets: Adapter %p\n", 
  2739.                             pAdapt));
  2740. }
  2741.  
  2742.  
  2743. NDIS_STATUS
  2744. PtCreateAndStartVElan(
  2745.     IN  PADAPT                      pAdapt,
  2746.     IN  PNDIS_STRING                pVElanKey
  2747. )
  2748. /*++
  2749.  
  2750. Routine Description:
  2751.  
  2752.     Create and start a VELAN with the given key name. Check if a VELAN
  2753.     with this key name already exists; if so do nothing.
  2754.  
  2755.     ASSUMPTION: this is called from either the BindAdapter handler for
  2756.     the underlying adapter, or from the PNP reconfig handler. Both these
  2757.     routines are protected by NDIS against pre-emption by UnbindAdapter.
  2758.     If this routine will be called from any other context, it should
  2759.     be protected against a simultaneous call to our UnbindAdapter handler.
  2760.     
  2761. Arguments:
  2762.  
  2763.     pAdapt        - Pointer to Adapter structure
  2764.     pVElanKey     - Points to a Unicode string naming the VELAN to create. 
  2765.     
  2766. Return Value:
  2767.  
  2768.     NDIS_STATUS_SUCCESS if we either found a duplicate VELAN or
  2769.     successfully initiated a new ELAN with the given key.
  2770.  
  2771.     NDIS_STATUS_XXX error code otherwise (failure initiating a new VELAN).
  2772.  
  2773. --*/
  2774. {
  2775.     NDIS_STATUS             Status;
  2776.     PVELAN                  pVElan;
  2777.     ULONG                   count, count1;
  2778.     BOOLEAN                 flag = FALSE;
  2779.     LOCK_STATE              LockState;
  2780.     ULONG                   NetworkConnection;
  2781.     ULONG                    ssidNumber;
  2782.  
  2783.     Status = NDIS_STATUS_SUCCESS;
  2784.     pVElan = NULL;
  2785.  
  2786.     DBGPRINT(MUX_LOUD, ("=> Create VElan: Adapter %p, ElanKey %ws\n", 
  2787.                             pAdapt, pVElanKey->Buffer));
  2788.  
  2789.     do
  2790.     {
  2791.         //
  2792.         //  Weed out duplicates.
  2793.         //
  2794.         if (pVElanKey != NULL)
  2795.         {
  2796.  
  2797.             pVElan = PtFindVElan(pAdapt, pVElanKey);
  2798.  
  2799.             if (NULL != pVElan)
  2800.             {
  2801.                 //
  2802.                 // Duplicate - bail out silently.
  2803.                 //
  2804.                 DBGPRINT(MUX_WARN, ("CreateElan: found duplicate pVElan %x\n", pVElan));
  2805.  
  2806.                 Status = NDIS_STATUS_SUCCESS;
  2807.                 pVElan = NULL;
  2808.                 break;
  2809.             }
  2810.         }
  2811.  
  2812.         ssidNumber = PtFindVElanSSID(pAdapt, pVElanKey);
  2813.  
  2814.         // this will add a new SSID to the list of current SSIDs
  2815.         MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2816.  
  2817.         DBGPRINT(MUX_LOUD, ("Numconnections is %d\n", pAdapt->numConnections));
  2818.  
  2819.         if(ssidNumber > MAX_NETWORK_CONNECTIONS) {
  2820.             // initialize the SSID field
  2821.             pAdapt->isSSIDActive[pAdapt->numConnections] = TRUE;
  2822.     
  2823.             /*
  2824.             pAdapt->networkSSID[pAdapt->numConnections].SsidLength = 0;
  2825.             // query the SSID
  2826.             PtQueryAdapterSync(pAdapt,
  2827.                             OID_802_11_SSID,
  2828.                             &pAdapt->networkSSID[pAdapt->numConnections],
  2829.                             sizeof(pAdapt->networkSSID[pAdapt->numConnections]));
  2830.     
  2831.             // query the mode
  2832.             PtQueryAdapterSync(pAdapt,
  2833.                             OID_802_11_INFRASTRUCTURE_MODE,
  2834.                             &pAdapt->networkMode[pAdapt->numConnections],
  2835.                             sizeof(pAdapt->networkMode[pAdapt->numConnections]));
  2836.             */
  2837.  
  2838.             // set the number of active connections on that SSID
  2839.             pAdapt->NumActiveConnectionsOnSSID[pAdapt->numConnections] = 1;
  2840.     
  2841.             // This is used to inform the service of the wait and switch periods
  2842.             // Really not the best way to do it, but works
  2843.             pAdapt->switchingTime[pAdapt->numConnections] = SWITCHING_PERIOD;
  2844.             pAdapt->waitingTime[pAdapt->numConnections] = SENDING_PERIOD;
  2845.             pAdapt->isAdaptiveScheduling = 1;    
  2846.  
  2847.             // find whether this SSID existed
  2848.             for (count=0; count<pAdapt->numConnections; count++)
  2849.             {
  2850.                 DBGPRINT(MUX_LOUD, ("Trying SSID %d of length %d\n", count, pAdapt->networkSSID[count].SsidLength));
  2851.                 // if the SSID lengths do not match, look for another one
  2852.                 if (pAdapt->networkSSID[pAdapt->numConnections].SsidLength != pAdapt->networkSSID[count].SsidLength)
  2853.                     continue;
  2854.  
  2855.                 // if modes do not match
  2856.                 if (pAdapt->networkMode[pAdapt->numConnections] != pAdapt->networkMode[count])
  2857.                     continue;
  2858.  
  2859.                 // check whether SSIDs match
  2860.                 for (count1=0; count1<pAdapt->networkSSID[pAdapt->numConnections].SsidLength; count1++)
  2861.                 {
  2862.                     if(pAdapt->networkSSID[pAdapt->numConnections].Ssid[count1] != pAdapt->networkSSID[count].Ssid[count1])
  2863.                         break;
  2864.                     if(count1 == (pAdapt->networkSSID[pAdapt->numConnections].SsidLength -1))
  2865.                     {
  2866.                         // this SSID existed before
  2867.                         flag = TRUE;
  2868.                     }
  2869.                 }
  2870.  
  2871.                 // the SSID already exists
  2872.                 if (flag) 
  2873.                 {
  2874.                     // increment the number of active connections on that SSID
  2875.                     pAdapt->NumActiveConnectionsOnSSID[count]++;
  2876.                     NetworkConnection = count;
  2877.                     DBGPRINT(MUX_LOUD, ("Number of connections on %d ssid is %d\n", count, pAdapt->NumActiveConnectionsOnSSID[count]));
  2878.                     DBGPRINT(MUX_LOUD, ("Number of active connections is %d\n", NumActiveConnections(pAdapt)));
  2879.  
  2880.                     // if the number of active connections on the adapter in greater than 1
  2881.                     if(NumActiveConnections(pAdapt)>1)
  2882.                     {
  2883.                         DBGPRINT(MUX_LOUD, ("The timer is off, will switch it on"));
  2884.                         // set the current connection as the active connection
  2885.                         pAdapt->CurrentActiveConnection = NetworkConnection;
  2886.                     }
  2887.                     break;
  2888.                 }
  2889.             }
  2890.         }
  2891.         else {
  2892.                 pAdapt->NumActiveConnectionsOnSSID[ssidNumber]++;
  2893.                 NetworkConnection = ssidNumber;
  2894.                 flag = TRUE;
  2895.                 DBGPRINT(MUX_LOUD, ("FOUND AN INSTANCE OF THIS VELAN\n"));
  2896.                 DBGPRINT(MUX_LOUD, ("Number of connections on %d ssid is %d\n", ssidNumber, pAdapt->NumActiveConnectionsOnSSID[ssidNumber]));
  2897.                 DBGPRINT(MUX_LOUD, ("Number of active connections is %d\n", NumActiveConnections(pAdapt)));
  2898.         }
  2899.         // the ssid does not exist
  2900.         if (!flag)
  2901.         {
  2902.             NetworkConnection = pAdapt->numConnections;
  2903.  
  2904.             // Initialize the send queues for this SSID
  2905.             InitializeQueueHeader(&pAdapt->SendWaitQueue[pAdapt->numConnections]);
  2906.             pAdapt->nWaitSend[pAdapt->numConnections] = 0;
  2907.             pAdapt->nTotalPacketsSeen[pAdapt->numConnections] = 0;
  2908.  
  2909.             DBGPRINT(MUX_INFO, ("The %dth network SSID Length is %d\n", 
  2910.                 pAdapt->numConnections, pAdapt->networkSSID[pAdapt->numConnections].SsidLength));
  2911.             pAdapt->numConnections++;
  2912.  
  2913.             // if there is more than one active connection on the adapter
  2914.             if(NumActiveConnections(pAdapt) > 0)
  2915.             {
  2916.                 pAdapt->CurrentActiveConnection = NetworkConnection;
  2917.             }
  2918.         }
  2919.         
  2920.         MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2921.  
  2922.         pVElan = PtAllocateAndInitializeVElan(pAdapt, pVElanKey, NetworkConnection);
  2923.  
  2924.         if (pVElan == NULL)
  2925.         {
  2926.             Status = NDIS_STATUS_RESOURCES;
  2927.             break;
  2928.         }
  2929.         //
  2930.         // Request NDIS to initialize the virtual miniport. Set
  2931.         // the flag below just in case an unbind occurs before
  2932.         // MiniportInitialize is called.
  2933.         //
  2934.         pVElan->MiniportInitPending = TRUE;
  2935.         pVElan->NetworkConnection = NetworkConnection;
  2936.         NdisInitializeEvent(&pVElan->MiniportInitEvent);
  2937.     
  2938.         
  2939.         Status = NdisIMInitializeDeviceInstanceEx(DriverHandle,
  2940.                                                   &pVElan->CfgDeviceName,
  2941.                                                   pVElan);
  2942.  
  2943.         
  2944.  
  2945.         if (Status != NDIS_STATUS_SUCCESS)
  2946.         {
  2947.             PtUnlinkVElanFromAdapter(pVElan);   // IMInit failed
  2948.             pVElan = NULL;
  2949.             break;
  2950.         }
  2951.         else
  2952.             pVElan->NetworkConnection = NetworkConnection;
  2953.     
  2954.     }
  2955.     while (FALSE);
  2956.  
  2957.     DBGPRINT(MUX_INFO, ("<= Create VElan: Adapter %p, VELAN %p\n", pAdapt, pVElan));
  2958.  
  2959.     return Status;
  2960. }
  2961.  
  2962.  
  2963. PVELAN
  2964. PtAllocateAndInitializeVElan(
  2965.     IN PADAPT                       pAdapt,
  2966.     IN PNDIS_STRING                 pVElanKey,
  2967.     IN ULONG                        NetworkConnection
  2968.     )
  2969. /*++
  2970.  
  2971. Routine Description:
  2972.  
  2973.     Allocates and initializes a VELAN structure. Also links it to
  2974.     the specified ADAPT.
  2975.  
  2976. Arguments:
  2977.  
  2978.     pAdapt - Adapter to link VELAN to
  2979.     pVElanKey - Key to the VELAN
  2980.  
  2981. Return Value:
  2982.  
  2983.     Pointer to VELAN structure if successful, NULL otherwise.
  2984.  
  2985. --*/
  2986. {
  2987.     PVELAN          pVElan;
  2988.     ULONG           Length;
  2989.     NDIS_STATUS     Status;
  2990.     LOCK_STATE      LockState;
  2991.     PVElanSSID      pVElanSSID;
  2992.  
  2993.     pVElan = NULL;
  2994.     Status = NDIS_STATUS_SUCCESS;
  2995.  
  2996.     do
  2997.     {
  2998.         Length = sizeof(VELAN) + pVElanKey->Length + sizeof(WCHAR);
  2999.         
  3000.         //
  3001.         // Allocate a VELAN data structure.
  3002.         //
  3003.         NdisAllocateMemoryWithTag(&pVElan, Length, TAG);
  3004.         NdisAllocateMemoryWithTag(&pVElanSSID, sizeof(VElanSSID) + pVElanKey->Length + sizeof(WCHAR), TAG);
  3005.  
  3006.         if (pVElan == NULL)
  3007.         {
  3008.             DBGPRINT(MUX_FATAL, ("AllocateVElan: Failed to allocate %d bytes for VELAN\n",
  3009.                                  Length));
  3010.             Status = NDIS_STATUS_RESOURCES;
  3011.             break;
  3012.         }
  3013.  
  3014.         if (pVElanSSID == NULL)
  3015.         {
  3016.             DBGPRINT(MUX_FATAL, ("AllocateVElanSSID: Failed to allocate %d bytes for VELAN\n",
  3017.                                  Length));
  3018.             Status = NDIS_STATUS_RESOURCES;
  3019.             break;
  3020.         }
  3021.         //
  3022.         // Initialize it.
  3023.         //
  3024.         NdisZeroMemory(pVElan, Length);
  3025.         NdisInitializeListHead(&pVElan->Link);
  3026.         NdisInitializeListHead(&pVElanSSID->Link);
  3027.         
  3028.         //
  3029.         // Initialize the built-in request structure to signify
  3030.         // that it is used to forward NDIS requests.
  3031.         //
  3032.         pVElan->Request.pVElan = pVElan;
  3033.         NdisInitializeEvent(&pVElan->Request.Event);
  3034.        
  3035.         //
  3036.         // Store in the key name.
  3037.         //
  3038.         pVElan->CfgDeviceName.Length = 0;
  3039.         pVElan->CfgDeviceName.Buffer = (PWCHAR)((PUCHAR)pVElan + 
  3040.                     sizeof(VELAN));       
  3041.         pVElan->CfgDeviceName.MaximumLength = 
  3042.                 pVElanKey->MaximumLength + sizeof(WCHAR);
  3043.         (VOID)NdisUpcaseUnicodeString(&pVElan->CfgDeviceName, pVElanKey);
  3044.         pVElan->CfgDeviceName.Buffer[pVElanKey->Length/sizeof(WCHAR)] =
  3045.                         ((WCHAR)0);
  3046.  
  3047.         // also for the VELANSSID structure
  3048.         pVElanSSID->VElanKey.Length = 0;
  3049.         pVElanSSID->VElanKey.Buffer = (PWCHAR)((PUCHAR)pVElanSSID + sizeof(VElanSSID));
  3050.         pVElanSSID->VElanKey.MaximumLength = pVElanKey->MaximumLength + sizeof(WCHAR);
  3051.         (VOID)NdisUpcaseUnicodeString(&pVElanSSID->VElanKey, pVElanKey);
  3052.         pVElanSSID->VElanKey.Buffer[pVElanKey->Length/sizeof(WCHAR)] = ((WCHAR)0);
  3053.         pVElanSSID->ssidNumber = NetworkConnection;
  3054.         
  3055.  
  3056.         // 
  3057.         // Initialize LastIndicatedStatus to media connect
  3058.         //
  3059.         pVElan->LastIndicatedStatus = NDIS_STATUS_MEDIA_CONNECT;
  3060.  
  3061.         //
  3062.         // Set power state of virtual miniport to D0.
  3063.         //
  3064.         pVElan->MPDevicePowerState = NdisDeviceStateD0;
  3065.  
  3066.         //
  3067.         // Cache the binding handle for quick reference.
  3068.         //
  3069.         pVElan->BindingHandle = pAdapt->BindingHandle;
  3070.         pVElan->pAdapt = pAdapt;
  3071.  
  3072.         //
  3073.         // Copy in some adapter parameters.
  3074.         //
  3075.         pVElan->LookAhead = pAdapt->MaxLookAhead;
  3076.         pVElan->LinkSpeed = pAdapt->LinkSpeed;
  3077.         NdisMoveMemory(pVElan->PermanentAddress,
  3078.                        pAdapt->CurrentAddress,
  3079.                        sizeof(pVElan->PermanentAddress));
  3080.  
  3081.         NdisMoveMemory(pVElan->CurrentAddress,
  3082.                        pAdapt->CurrentAddress,
  3083.                        sizeof(pVElan->CurrentAddress));
  3084.  
  3085.         DBGPRINT(MUX_LOUD, ("Alloced VELAN %p, MAC addr %s\n",
  3086.                     pVElan, MacAddrToString(pVElan->CurrentAddress)));
  3087. #if IEEE_VLAN_SUPPORT
  3088.         //
  3089.         // Allocate lookaside list for tag headers.
  3090.         // 
  3091.         NdisInitializeNPagedLookasideList (
  3092.                 &pVElan->TagLookaside,
  3093.                 NULL,
  3094.                 NULL,
  3095.                 0,
  3096.                 ETH_HEADER_SIZE + VLAN_TAG_HEADER_SIZE,
  3097.                 'TxuM',
  3098.                 0);
  3099.         
  3100. #endif
  3101.         //
  3102.         // Allocate a packet pool for sends.
  3103.         //
  3104.         NdisAllocatePacketPoolEx(&Status,
  3105.                                  &pVElan->SendPacketPoolHandle,
  3106.                                  MIN_PACKET_POOL_SIZE,
  3107.                                  MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
  3108.                                  sizeof(MUX_SEND_RSVD));
  3109.  
  3110.         if (Status != NDIS_STATUS_SUCCESS)
  3111.         {
  3112.             DBGPRINT(MUX_FATAL, ("PtAllocateVElan: failed to allocate send packet pool\n"));
  3113.             break;
  3114.         }
  3115.  
  3116.         //
  3117.         // NOTE: this sample driver does not -originate- packets in the
  3118.         // send or receive directions. If the driver must originate packets,
  3119.         // here is a good place to allocate NDIS buffer pool(s) for
  3120.         // this purpose.
  3121.         //
  3122. #if IEEE_VLAN_SUPPORT
  3123.         //
  3124.         // Allocate a buffer pool for tag headers.
  3125.         //
  3126.         NdisAllocateBufferPool (&Status,
  3127.                                 &pVElan->BufferPoolHandle,
  3128.                                 MIN_PACKET_POOL_SIZE);
  3129.  
  3130.         ASSERT(Status == NDIS_STATUS_SUCCESS);
  3131.         
  3132. #endif
  3133.         
  3134.         //
  3135.         // Allocate a packet pool for receives.
  3136.         //
  3137.         NdisAllocatePacketPoolEx(&Status,
  3138.                                  &pVElan->RecvPacketPoolHandle,
  3139.                                  MIN_PACKET_POOL_SIZE,
  3140.                                  MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
  3141.                                  PROTOCOL_RESERVED_SIZE_IN_PACKET);
  3142.  
  3143.         if (Status != NDIS_STATUS_SUCCESS)
  3144.         {
  3145.             DBGPRINT(MUX_FATAL, ("PtAllocateVElan: failed to allocate receive packet pool\n"));
  3146.             break;
  3147.         }
  3148.  
  3149.         //
  3150.         // Finally link this VELAN to the Adapter's VELAN list. 
  3151.         //
  3152.         PtReferenceVElan(pVElan, "adapter");        
  3153.  
  3154.         MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  3155.  
  3156.         PtReferenceAdapter(pAdapt, "VElan");
  3157.         InsertTailList(&pAdapt->VElanList, &pVElan->Link);
  3158.         pAdapt->VElanCount++;
  3159.         pVElan->VElanNumber = NdisInterlockedIncrement(&NextVElanNumber);
  3160.  
  3161.          DBGPRINT(MUX_LOUD, ("InsertSSIDElan: Adapter %p, ElanKey %ws, ssid number %d\n", pAdapt, 
  3162.                                                 pVElanSSID->VElanKey.Buffer, pVElanSSID->ssidNumber));
  3163.         InsertTailList(&pAdapt->VElanSSIDList, &pVElanSSID->Link);
  3164.         MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  3165.     }
  3166.     while (FALSE);
  3167.  
  3168.     if (Status != NDIS_STATUS_SUCCESS)
  3169.     {
  3170.         if (pVElan)
  3171.         {
  3172.             PtDeallocateVElan(pVElan);
  3173.             pVElan = NULL;
  3174.         }
  3175.     }
  3176.  
  3177.     return (pVElan);
  3178. }
  3179.  
  3180.  
  3181. VOID
  3182. PtDeallocateVElan(
  3183.     IN PVELAN                   pVElan
  3184.     )
  3185. /*++
  3186.  
  3187. Routine Description:
  3188.  
  3189.     Free up all resources allocated to a VELAN, and then the VELAN
  3190.     structure itself.
  3191.  
  3192. Arguments:
  3193.  
  3194.     pVElan - Pointer to VELAN to be deallocated.
  3195.  
  3196. Return Value:
  3197.  
  3198.     None
  3199.  
  3200. --*/
  3201. {
  3202.     DBGPRINT(MUX_LOUD, ("=>PtDeallocateVElan\n"));
  3203.     if (pVElan->SendPacketPoolHandle != NULL)
  3204.     {
  3205.         NdisFreePacketPool(pVElan->SendPacketPoolHandle);
  3206.     }
  3207.  
  3208.     if (pVElan->RecvPacketPoolHandle != NULL)
  3209.     {
  3210.         NdisFreePacketPool(pVElan->RecvPacketPoolHandle);
  3211.     }
  3212. #if IEEE_VLAN_SUPPORT 
  3213.     NdisFreeBufferPool(pVElan->BufferPoolHandle);
  3214.     NdisDeleteNPagedLookasideList(&pVElan->TagLookaside);
  3215. #endif    
  3216.     NdisFreeMemory(pVElan, 0, 0);
  3217.     DBGPRINT(MUX_LOUD, ("<=PtDeallocateVElan\n"));
  3218. }
  3219.  
  3220.  
  3221. VOID
  3222. PtStopVElan(
  3223.     IN  PVELAN            pVElan
  3224. )
  3225. /*++
  3226.  
  3227. Routine Description:
  3228.  
  3229.     Stop a VELAN by requesting NDIS to halt the virtual miniport.
  3230.     The caller has a reference on the VELAN, so it won't go away
  3231.     while we are executing in this routine.
  3232.  
  3233.     ASSUMPTION: this is only called in the context of unbinding
  3234.     from the underlying miniport. If it may be called from elsewhere,
  3235.     this should protect itself from re-entrancy.
  3236.     
  3237. Arguments:
  3238.  
  3239.     pVElan      - Pointer to VELAN to be stopped.
  3240.     
  3241. Return Value:
  3242.  
  3243.     None
  3244.  
  3245. --*/
  3246. {
  3247.     NDIS_STATUS             Status;
  3248.     NDIS_HANDLE             MiniportAdapterHandle;
  3249.     BOOLEAN                 bMiniportInitCancelled = FALSE;
  3250.  
  3251.     DBGPRINT(MUX_LOUD, ("=> StopVElan: VELAN %p, Adapt %p\n", pVElan, pVElan->pAdapt));
  3252.  
  3253.     //
  3254.     // We make blocking calls below.
  3255.     //
  3256.     ASSERT_AT_PASSIVE();
  3257.  
  3258.     //
  3259.     // If there was a queued request on this VELAN, fail it now.
  3260.     //
  3261.     if (pVElan->QueuedRequest)
  3262.     {
  3263.         pVElan->QueuedRequest = FALSE;
  3264.  
  3265.         PtRequestComplete(pVElan->pAdapt,
  3266.                           &pVElan->Request.Request,
  3267.                           NDIS_STATUS_FAILURE);
  3268.     }
  3269.  
  3270.     //
  3271.     // Check if we had called NdisIMInitializeDeviceInstanceEx and
  3272.     // we are awaiting a call to MiniportInitialize.
  3273.     //
  3274.     if (pVElan->MiniportInitPending)
  3275.     {
  3276.         //
  3277.         // Attempt to cancel miniport init.
  3278.         //
  3279.         Status = NdisIMCancelInitializeDeviceInstance(
  3280.                     DriverHandle,
  3281.                     &pVElan->CfgDeviceName);
  3282.  
  3283.         if (Status == NDIS_STATUS_SUCCESS)
  3284.         {
  3285.             //
  3286.             // Successfully cancelled IM initialization; our
  3287.             // Miniport Init routine will not be called for this
  3288.             // VELAN miniport.
  3289.             //
  3290.             pVElan->MiniportInitPending = FALSE;
  3291.             ASSERT(pVElan->MiniportAdapterHandle == NULL);
  3292.             bMiniportInitCancelled = TRUE;
  3293.         }
  3294.         else
  3295.         {
  3296.             //
  3297.             // Our Miniport Initialize routine will be called
  3298.             // (may be running on another thread at this time).
  3299.             // Wait for it to finish.
  3300.             //
  3301.             NdisWaitEvent(&pVElan->MiniportInitEvent, 0);
  3302.             ASSERT(pVElan->MiniportInitPending == FALSE);
  3303.         }
  3304.     }
  3305.  
  3306.     //
  3307.     // Check if Miniport Init has run. If so, deinitialize the virtual
  3308.     // miniport. This will result in a call to our Miniport Halt routine,
  3309.     // where the VELAN will be cleaned up.
  3310.     //
  3311.     MiniportAdapterHandle = pVElan->MiniportAdapterHandle;
  3312.  
  3313.     if ((NULL != MiniportAdapterHandle) &&
  3314.         (!pVElan->MiniportHalting))
  3315.     {
  3316.         //
  3317.         // The miniport was initialized, and has not yet halted.
  3318.         //
  3319.         ASSERT(bMiniportInitCancelled == FALSE);
  3320.         (VOID)NdisIMDeInitializeDeviceInstance(MiniportAdapterHandle);
  3321.     }
  3322.     else
  3323.     {
  3324.         if (bMiniportInitCancelled)
  3325.         {
  3326.             //
  3327.             // No NDIS events can come to this VELAN since it
  3328.             // was never initialized as a miniport. We need to unlink
  3329.             // it explicitly here.
  3330.             //
  3331.             PtUnlinkVElanFromAdapter(pVElan);
  3332.         }
  3333.     }
  3334.     DBGPRINT(MUX_LOUD, ("=> StopVElan\n"));
  3335. }
  3336.  
  3337.  
  3338. VOID
  3339. PtUnlinkVElanFromAdapter(
  3340.     IN PVELAN               pVElan
  3341. )
  3342. /*++
  3343.  
  3344. Routine Description:
  3345.  
  3346.     Utility routine to unlink a VELAN from its parent ADAPT structure.
  3347.     
  3348. Arguments:
  3349.  
  3350.     pVElan      - Pointer to VELAN to be unlinked.
  3351.     
  3352. Return Value:
  3353.  
  3354.     None
  3355.  
  3356. --*/
  3357. {
  3358.     PADAPT pAdapt = pVElan->pAdapt;    
  3359.     LOCK_STATE      LockState;
  3360.     
  3361.     ASSERT(pAdapt != NULL);
  3362.  
  3363.     DBGPRINT(MUX_LOUD, ("=>PtUnlinkVElanFromAdapter\n"));
  3364.     //
  3365.     // Remove this VELAN from the Adapter list
  3366.     //
  3367.     MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  3368.  
  3369.     RemoveEntryList(&pVElan->Link);
  3370.     pAdapt->VElanCount--;
  3371.         
  3372.     MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  3373.     pVElan->pAdapt = NULL;
  3374.     PtDereferenceVElan(pVElan, "adapter");
  3375.  
  3376.     PtDereferenceAdapter(pAdapt, "VElan");
  3377.     DBGPRINT(MUX_LOUD, ("<=PtUnlinkVElanFromAdapter\n"));
  3378.  
  3379. }
  3380.  
  3381. ULONG
  3382. PtFindVElanSSID(
  3383.     IN    PADAPT                pAdapt,
  3384.     IN    PNDIS_STRING          pVElanKey
  3385. )
  3386. /*++
  3387.  
  3388. Routine Description:
  3389.  
  3390.     Find an ELAN by bind name/key
  3391.  
  3392. Arguments:
  3393.  
  3394.     pAdapt     -    Pointer to an adapter struct.
  3395.     pVElanKey  -    The VELAN's device name
  3396.  
  3397. Return Value:
  3398.  
  3399.     ssid number if found, else MAX_NETWORK_CONNECTIONS if not found.
  3400.     
  3401. --*/
  3402. {
  3403.     PLIST_ENTRY         p;
  3404.     PVElanSSID          pVElanSSID;
  3405.     BOOLEAN             Found;
  3406.     NDIS_STRING         VElanKeyName;
  3407.     LOCK_STATE          LockState;
  3408.  
  3409.     ASSERT_AT_PASSIVE();
  3410.  
  3411.     DBGPRINT(MUX_LOUD, ("FindSSIDElan: Adapter %p, ElanKey %ws\n", pAdapt, 
  3412.                                         pVElanKey->Buffer));
  3413.  
  3414.     pVElanSSID = NULL;
  3415.     Found = FALSE;
  3416.     VElanKeyName.Buffer = NULL;
  3417.  
  3418.     do
  3419.     {
  3420.         //
  3421.         // Make an up-cased copy of the given string.
  3422.         //
  3423.         NdisAllocateMemoryWithTag(&VElanKeyName.Buffer, 
  3424.                                 pVElanKey->MaximumLength, TAG);
  3425.         if (VElanKeyName.Buffer == NULL)
  3426.         {
  3427.             break;
  3428.         }
  3429.  
  3430.         VElanKeyName.Length = pVElanKey->Length;
  3431.         VElanKeyName.MaximumLength = pVElanKey->MaximumLength;
  3432.  
  3433.         (VOID)NdisUpcaseUnicodeString(&VElanKeyName, pVElanKey);
  3434.  
  3435.         //
  3436.         // Go through all VELANs on the ADAPT structure, looking
  3437.         // for a VELAN that has a matching device name.
  3438.         //
  3439.         MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  3440.  
  3441.         if(IsListEmpty(&pAdapt->VElanSSIDList))
  3442.             DBGPRINT(MUX_LOUD, ("FindSSIDElan Check: The list is empty\n"));
  3443.         p = pAdapt->VElanSSIDList.Flink;
  3444.  
  3445.         while (p != &pAdapt->VElanSSIDList)
  3446.         {
  3447.             pVElanSSID = CONTAINING_RECORD(p, VElanSSID, Link);
  3448.  
  3449.             DBGPRINT(MUX_LOUD, ("FindSSIDElan Check: Adapter %p, ElanKey %ws\n", pAdapt, 
  3450.                                                     pVElanSSID->VElanKey.Buffer));
  3451.             if ((VElanKeyName.Length == pVElanSSID->VElanKey.Length) &&
  3452.                 (memcmp(VElanKeyName.Buffer, pVElanSSID->VElanKey.Buffer, 
  3453.                 VElanKeyName.Length) == 0))
  3454.             {
  3455.                 Found = TRUE;
  3456.                 break;
  3457.             }
  3458.         
  3459.             p = p->Flink;
  3460.         }
  3461.  
  3462.         MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  3463.  
  3464.     }
  3465.     while (FALSE);
  3466.  
  3467.     if (!Found)
  3468.     {
  3469.         DBGPRINT(MUX_INFO, ( "FindElanSSID: No match found!\n"));
  3470.         pVElanSSID = NULL;
  3471.     }
  3472.  
  3473.     if (VElanKeyName.Buffer)
  3474.     {
  3475.         NdisFreeMemory(VElanKeyName.Buffer, VElanKeyName.Length, 0);
  3476.     }
  3477.  
  3478.     if(Found)
  3479.         return pVElanSSID->ssidNumber;
  3480.     else
  3481.         return MAX_NETWORK_CONNECTIONS+1;
  3482. }
  3483.  
  3484.  
  3485. PVELAN
  3486. PtFindVElan(
  3487.     IN    PADAPT                pAdapt,
  3488.     IN    PNDIS_STRING          pVElanKey
  3489. )
  3490. /*++
  3491.  
  3492. Routine Description:
  3493.  
  3494.     Find an ELAN by bind name/key
  3495.  
  3496. Arguments:
  3497.  
  3498.     pAdapt     -    Pointer to an adapter struct.
  3499.     pVElanKey  -    The VELAN's device name
  3500.  
  3501. Return Value:
  3502.  
  3503.     Pointer to matching VELAN or NULL if not found.
  3504.     
  3505. --*/
  3506. {
  3507.     PLIST_ENTRY         p;
  3508.     PVELAN              pVElan;
  3509.     BOOLEAN             Found;
  3510.     NDIS_STRING         VElanKeyName;
  3511.     LOCK_STATE          LockState;
  3512.  
  3513.     ASSERT_AT_PASSIVE();
  3514.  
  3515.     DBGPRINT(MUX_LOUD, ("FindElan: Adapter %p, ElanKey %ws\n", pAdapt, 
  3516.                                         pVElanKey->Buffer));
  3517.  
  3518.     pVElan = NULL;
  3519.     Found = FALSE;
  3520.     VElanKeyName.Buffer = NULL;
  3521.  
  3522.     do
  3523.     {
  3524.         //
  3525.         // Make an up-cased copy of the given string.
  3526.         //
  3527.         NdisAllocateMemoryWithTag(&VElanKeyName.Buffer, 
  3528.                                 pVElanKey->MaximumLength, TAG);
  3529.         if (VElanKeyName.Buffer == NULL)
  3530.         {
  3531.             break;
  3532.         }
  3533.  
  3534.         VElanKeyName.Length = pVElanKey->Length;
  3535.         VElanKeyName.MaximumLength = pVElanKey->MaximumLength;
  3536.  
  3537.         (VOID)NdisUpcaseUnicodeString(&VElanKeyName, pVElanKey);
  3538.  
  3539.         //
  3540.         // Go through all VELANs on the ADAPT structure, looking
  3541.         // for a VELAN that has a matching device name.
  3542.         //
  3543.         MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  3544.  
  3545.         p = pAdapt->VElanList.Flink;
  3546.         while (p != &pAdapt->VElanList)
  3547.         {
  3548.             pVElan = CONTAINING_RECORD(p, VELAN, Link);
  3549.  
  3550.             if ((VElanKeyName.Length == pVElan->CfgDeviceName.Length) &&
  3551.                 (memcmp(VElanKeyName.Buffer, pVElan->CfgDeviceName.Buffer, 
  3552.                 VElanKeyName.Length) == 0))
  3553.             {
  3554.                 Found = TRUE;
  3555.                 break;
  3556.             }
  3557.         
  3558.             p = p->Flink;
  3559.         }
  3560.  
  3561.         MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  3562.  
  3563.     }
  3564.     while (FALSE);
  3565.  
  3566.     if (!Found)
  3567.     {
  3568.         DBGPRINT(MUX_INFO, ( "FindElan: No match found!\n"));
  3569.         pVElan = NULL;
  3570.     }
  3571.  
  3572.     if (VElanKeyName.Buffer)
  3573.     {
  3574.         NdisFreeMemory(VElanKeyName.Buffer, VElanKeyName.Length, 0);
  3575.     }
  3576.  
  3577.     return pVElan;
  3578. }
  3579.  
  3580.  
  3581. VOID
  3582. PtBootStrapVElans(
  3583.     IN  PADAPT            pAdapt
  3584. )
  3585. /*++
  3586.  
  3587. Routine Description:
  3588.  
  3589.     Start up the VELANs configured for an adapter.
  3590.  
  3591. Arguments:
  3592.  
  3593.     pAdapt    - Pointer to ATMLANE Adapter structure
  3594.  
  3595. Return Value:
  3596.  
  3597.     None
  3598.  
  3599. --*/
  3600. {
  3601.     NDIS_STATUS                     Status;
  3602.     NDIS_HANDLE                     AdapterConfigHandle;
  3603.     PVELAN                          pVElan;
  3604.     PNDIS_CONFIGURATION_PARAMETER   Param;
  3605.     NDIS_STRING                     DeviceStr = NDIS_STRING_CONST("UpperBindings");
  3606.     PWSTR                           buffer;
  3607.  
  3608.     //
  3609.     //  Initialize.
  3610.     //
  3611.     Status = NDIS_STATUS_SUCCESS;
  3612.     AdapterConfigHandle = NULL;
  3613.     
  3614.     do
  3615.     {
  3616.         DBGPRINT(MUX_LOUD, ("BootStrapElans: Starting ELANs on adapter %x\n", pAdapt));
  3617.  
  3618.         //
  3619.         //  Open the protocol configuration section for this adapter.
  3620.         //
  3621.  
  3622.         NdisOpenProtocolConfiguration(&Status,
  3623.                                        &AdapterConfigHandle,
  3624.                                        &pAdapt->ConfigString);
  3625.  
  3626.         if (NDIS_STATUS_SUCCESS != Status)
  3627.         {
  3628.             AdapterConfigHandle = NULL;
  3629.             DBGPRINT(MUX_ERROR, ("BootStrapElans: OpenProtocolConfiguration failed\n"));
  3630.             Status = NDIS_STATUS_OPEN_FAILED;
  3631.             break;
  3632.         }
  3633.         
  3634.         //
  3635.         // Read the "UpperBindings" reserved key that contains a list
  3636.         // of device names representing our miniport instances corresponding
  3637.         // to this lower binding. The UpperBindings is a 
  3638.         // MULTI_SZ containing a list of device names. We will loop through
  3639.         // this list and initialize the virtual miniports.
  3640.         //
  3641.         NdisReadConfiguration(&Status,
  3642.                               &Param,
  3643.                                 AdapterConfigHandle,
  3644.                                 &DeviceStr,
  3645.                                 NdisParameterMultiString);
  3646.         if (NDIS_STATUS_SUCCESS != Status)
  3647.         {
  3648.             DBGPRINT(MUX_ERROR, ("BootStrapElans: NdisReadConfiguration failed\n"));
  3649.               break;
  3650.         }
  3651.  
  3652.         //
  3653.         // Parse the Multi_sz string to extract the device name of each VELAN.
  3654.         // This is used as the key name for the VELAN.
  3655.         //
  3656.         buffer = (PWSTR)Param->ParameterData.StringData.Buffer;
  3657.         while(*buffer != L'\0')
  3658.         {
  3659.             NDIS_STRING     DeviceName;
  3660.             
  3661.             NdisInitUnicodeString(&DeviceName, buffer);
  3662.            
  3663.             
  3664.             Status = PtCreateAndStartVElan(pAdapt, &DeviceName); 
  3665.             if (NDIS_STATUS_SUCCESS != Status)
  3666.             {
  3667.                 DBGPRINT(MUX_ERROR, ("BootStrapElans: CreateVElan failed\n"));
  3668.                 break;
  3669.             }
  3670.             buffer = (PWSTR)((PUCHAR)buffer + DeviceName.Length + sizeof(WCHAR));
  3671.         };
  3672.           
  3673.     } while (FALSE);
  3674.  
  3675.     //
  3676.     //    Close config handles
  3677.     //        
  3678.     if (NULL != AdapterConfigHandle)
  3679.     {
  3680.         NdisCloseConfiguration(AdapterConfigHandle);
  3681.     }
  3682.     return;
  3683. }
  3684.  
  3685. VOID
  3686. PtReferenceVElan(
  3687.     IN    PVELAN            pVElan,
  3688.     IN    PUCHAR            String
  3689.     )
  3690. /*++
  3691.  
  3692. Routine Description:
  3693.  
  3694.     Add a references to an Elan structure.
  3695.  
  3696. Arguments:
  3697.  
  3698.     pElan    -    Pointer to the Elan structure.
  3699.  
  3700.  
  3701. Return Value:
  3702.  
  3703.     None.
  3704.  
  3705. --*/
  3706. {
  3707.     
  3708.     NdisInterlockedIncrement(&pVElan->RefCount);
  3709.     
  3710.     DBGPRINT(MUX_LOUD, ("ReferenceElan: Elan %p (%s) new count %d\n",
  3711.              pVElan, String, pVElan->RefCount));
  3712.  
  3713.     return;
  3714. }
  3715.  
  3716. ULONG
  3717. PtDereferenceVElan(
  3718.     IN    PVELAN            pVElan,
  3719.     IN    PUCHAR            String
  3720.     )
  3721. /*++
  3722.  
  3723. Routine Description:
  3724.  
  3725.     Subtract a reference from an VElan structure. 
  3726.     If the reference count becomes zero, deallocate it.
  3727.  
  3728. Arguments:
  3729.  
  3730.     pElan    -    Pointer to an VElan structure.
  3731.  
  3732.  
  3733. Return Value:
  3734.  
  3735.     None.
  3736.  
  3737. --*/
  3738. {
  3739.     ULONG        rc;
  3740.  
  3741.     ASSERT(pVElan->RefCount > 0);
  3742.  
  3743.     rc = NdisInterlockedDecrement(&pVElan->RefCount);
  3744.  
  3745.     if (rc == 0)
  3746.     {
  3747.         //
  3748.         // Free memory if there is no outstanding reference.
  3749.         // Note: Length field is not required if the memory 
  3750.         // is allocated with NdisAllocateMemoryWithTag.
  3751.         //
  3752.         PtDeallocateVElan(pVElan);
  3753.     }
  3754.     
  3755.     DBGPRINT(MUX_LOUD, ("DereferenceElan: VElan %p (%s) new count %d\n", 
  3756.                                     pVElan, String, rc));
  3757.     return (rc);
  3758. }
  3759.  
  3760.  
  3761. BOOLEAN
  3762. PtReferenceAdapter(
  3763.     IN    PADAPT            pAdapt,
  3764.     IN    PUCHAR            String
  3765.     )
  3766. /*++
  3767.  
  3768. Routine Description:
  3769.  
  3770.     Add a references to an Adapter structure.
  3771.  
  3772. Arguments:
  3773.  
  3774.     pAdapt    -    Pointer to the Adapter structure.
  3775.  
  3776. Return Value:
  3777.  
  3778.     None.
  3779.  
  3780. --*/
  3781. {
  3782.     NdisInterlockedIncrement(&pAdapt->RefCount);
  3783.     
  3784.     DBGPRINT(MUX_LOUD, ("ReferenceAdapter: Adapter %x (%s) new count %d\n",
  3785.                     pAdapt, String, pAdapt->RefCount));
  3786.  
  3787.     return TRUE;
  3788. }
  3789.  
  3790. ULONG
  3791. PtDereferenceAdapter(
  3792.     IN    PADAPT    pAdapt,
  3793.     IN    PUCHAR    String
  3794.     )
  3795. /*++
  3796.  
  3797. Routine Description:
  3798.  
  3799.     Subtract a reference from an Adapter structure. 
  3800.     If the reference count becomes zero, deallocate it.
  3801.  
  3802. Arguments:
  3803.  
  3804.     pAdapt    -    Pointer to an adapter structure.
  3805.  
  3806.  
  3807. Return Value:
  3808.  
  3809.     None.
  3810.  
  3811. --*/
  3812. {
  3813.     ULONG        rc;
  3814.  
  3815.     ASSERT(pAdapt->RefCount > 0);
  3816.  
  3817.  
  3818.     rc = NdisInterlockedDecrement (&pAdapt->RefCount);
  3819.  
  3820.     if (rc == 0)
  3821.     {
  3822.         //
  3823.         // Free memory if there is no outstanding reference.
  3824.         // Note: Length field is not required if the memory 
  3825.         // is allocated with NdisAllocateMemoryWithTag.
  3826.         //
  3827.         NdisFreeMemory(pAdapt, 0, 0);
  3828.     }
  3829.  
  3830.     DBGPRINT(MUX_LOUD, ("DereferenceAdapter: Adapter %x (%s) new count %d\n", 
  3831.                         pAdapt, String, rc));
  3832.  
  3833.     return (rc);
  3834. }
  3835.  
  3836.  
  3837. #if IEEE_VLAN_SUPPORT
  3838. NDIS_STATUS
  3839. PtHandleRcvTagging(
  3840.     IN  PVELAN              pVElan,
  3841.     IN  PNDIS_PACKET        Packet,
  3842.     IN  OUT PNDIS_PACKET    MyPacket
  3843.     )
  3844. /*++
  3845.  
  3846. Routine Description:
  3847.  
  3848.     Parse a received Ethernet frame for 802.1Q tag information.
  3849.     If a tag header is present, copy in relevant field values to
  3850.     per-packet information to the new packet (MyPacket) used to
  3851.     indicate up this frame.
  3852.  
  3853. Arguments:
  3854.  
  3855.     pVElan   -    Pointer to the VELAN structure.
  3856.     Packet   -    Pointer to the indicated packet from the lower miniport
  3857.     MyPacket -    Pointer to the new allocated packet
  3858.     
  3859. Return Value:
  3860.  
  3861.     NDIS_STATUS_SUCCESS if the frame was successfully parsed
  3862.     and hence should be indicated up this VELAN. NDIS_STATUS_XXX
  3863.     otherwise.
  3864.  
  3865. --*/
  3866. {
  3867.     VLAN_TAG_HEADER UNALIGNED * pTagHeader;
  3868.     USHORT UNALIGNED *          pTpid;
  3869.     PVOID                       pVa;
  3870.     ULONG                       BufferLength;
  3871.     PNDIS_BUFFER                pNdisBuffer;
  3872.     NDIS_PACKET_8021Q_INFO      NdisPacket8021qInfo;
  3873.     PVOID                       pDst;
  3874.     BOOLEAN                     OnlyOneBuffer = FALSE;
  3875.     NDIS_STATUS                 Status;
  3876.     
  3877.     Status = NDIS_STATUS_SUCCESS;
  3878.  
  3879.     do
  3880.     {
  3881.         pNdisBuffer = Packet->Private.Head;
  3882.  
  3883. #ifdef NDIS51_MINIPORT
  3884.         NdisQueryBufferSafe(pNdisBuffer, &pVa, &BufferLength, NormalPagePriority );
  3885.         if (pVa == NULL)
  3886.         {
  3887.             Status = NDIS_STATUS_RESOURCES;
  3888.             MUX_INCR_STATISTICS(&pVElan->RcvResourceErrors);
  3889.             break;
  3890.         }
  3891. #else
  3892.         NdisQueryBuffer(pNdisBuffer, &pVa, &BufferLength);
  3893. #endif
  3894.     
  3895.         //
  3896.         // The first NDIS buffer (lookahead) must be longer than
  3897.         // ETH_HEADER_SIZE + VLAN_TAG_HEADER_SIZE
  3898.         // 
  3899.         ASSERT(BufferLength >= ETH_HEADER_SIZE + VLAN_TAG_HEADER_SIZE);
  3900.  
  3901.         //
  3902.         // Get at the EtherType field.
  3903.         //
  3904.         pTpid = (USHORT UNALIGNED *)((PUCHAR)pVa + 2 * ETH_LENGTH_OF_ADDRESS);
  3905.                     
  3906.         //
  3907.         // Check if a tag header is present.
  3908.         //
  3909.         if (*pTpid != TPID)
  3910.         {
  3911.             //
  3912.             // No tag header exists - nothing more to do here.
  3913.             // 
  3914.             NDIS_PER_PACKET_INFO_FROM_PACKET(MyPacket, Ieee8021QInfo) = 0;                  
  3915.             break;
  3916.         }
  3917.  
  3918.         //
  3919.         // We do have a tag header. Parse it further.
  3920.         //
  3921.         //
  3922.         // If E-RIF is present, discard the packet - we don't
  3923.         // support this variation.
  3924.         //
  3925.         pTagHeader = (VLAN_TAG_HEADER UNALIGNED *)(pTpid + 1);
  3926.         if (GET_CANONICAL_FORMAT_ID_FROM_TAG(pTagHeader) != 0)
  3927.         {
  3928.             //
  3929.             // Drop the packet
  3930.             // 
  3931.             Status = NDIS_STATUS_NOT_ACCEPTED;
  3932.             MUX_INCR_STATISTICS(&pVElan->RcvFormatErrors);
  3933.             break;
  3934.         }
  3935.  
  3936.         //
  3937.         // If there is a VLAN ID in this frame, and we have
  3938.         // a configured VLAN ID for this VELAN, check if they
  3939.         // are the same - drop if not.
  3940.         // 
  3941.         if ((GET_VLAN_ID_FROM_TAG(pTagHeader) != 0) &&
  3942.              (pVElan->VlanId != 0) &&
  3943.              (GET_VLAN_ID_FROM_TAG(pTagHeader) != pVElan->VlanId))
  3944.         {
  3945.             Status = NDIS_STATUS_NOT_ACCEPTED;
  3946.             MUX_INCR_STATISTICS(&pVElan->RcvVlanIdErrors);
  3947.             break;
  3948.         }
  3949.  
  3950.         //
  3951.         // Parsed this frame successfully. Copy in relevant
  3952.         // parts of the tag header to per-packet information.
  3953.         //
  3954.         NdisPacket8021qInfo.Value = NULL; // initialize
  3955.  
  3956.         COPY_TAG_INFO_FROM_HEADER_TO_PACKET_INFO(NdisPacket8021qInfo, pTagHeader);
  3957.  
  3958.         NDIS_PER_PACKET_INFO_FROM_PACKET(MyPacket, Ieee8021QInfo) = 
  3959.                                     NdisPacket8021qInfo.Value;
  3960.  
  3961.         //
  3962.         // Strip off the tag header "in place":
  3963.         // 
  3964.         pDst = (PVOID)((PUCHAR)pVa + VLAN_TAG_HEADER_SIZE);
  3965.         RtlMoveMemory(pDst, pVa, 2 * ETH_LENGTH_OF_ADDRESS);
  3966.  
  3967.         //
  3968.         // Allocate a new buffer to describe the new first
  3969.         // buffer in the packet. This could very well be the
  3970.         // only buffer in the packet.
  3971.         // 
  3972.         NdisAllocateBuffer(&Status,
  3973.                             &pNdisBuffer,
  3974.                             pVElan->BufferPoolHandle,
  3975.                             pDst,
  3976.                             BufferLength - VLAN_TAG_HEADER_SIZE);
  3977.  
  3978.         if (Status != NDIS_STATUS_SUCCESS)
  3979.         {
  3980.             //
  3981.             // Drop the packet 
  3982.             // 
  3983.             Status = NDIS_STATUS_RESOURCES;
  3984.             MUX_INCR_STATISTICS(&pVElan->RcvResourceErrors);
  3985.             break;
  3986.         }
  3987.  
  3988.         //
  3989.         // Prepare the new packet to be indicated up: this consists
  3990.         // of the buffer chain starting with the second buffer,
  3991.         // appended to the first buffer set up in the previous step.
  3992.         //
  3993.         MyPacket->Private.Head = NDIS_BUFFER_LINKAGE(Packet->Private.Head);
  3994.  
  3995.         //
  3996.         // Only one buffer in the packet
  3997.         // 
  3998.         if (MyPacket->Private.Head == NULL)
  3999.         {
  4000.             OnlyOneBuffer = TRUE;
  4001.         }
  4002.  
  4003.         NdisChainBufferAtFront(MyPacket, pNdisBuffer);
  4004.  
  4005.         if (OnlyOneBuffer)
  4006.         {
  4007.             MyPacket->Private.Tail = MyPacket->Private.Head;
  4008.         }
  4009.         else
  4010.         {
  4011.             MyPacket->Private.Tail = Packet->Private.Tail;
  4012.         }
  4013.  
  4014.         break;
  4015.     }
  4016.     while (FALSE);
  4017.                     
  4018.     return Status;
  4019. }
  4020. #endif  // IEEE_VLAN_SUPPORT        
  4021.  
  4022.