Home | History | Annotate | Download | only in SnpDxe
      1 /** @file
      2     Implementation of managing the multicast receive filters of a network
      3     interface.
      4 
      5 Copyright (c) 2004 - 2007, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials are licensed and made available under the
      7 terms and conditions of the BSD License which accompanies this distribution. The
      8 full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 
     17 
     18 #include "Snp.h"
     19 
     20 /**
     21   Call undi to enable the receive filters.
     22 
     23   @param  Snp                Pointer to snp driver structure.
     24   @param  EnableFlags        Bit mask for enabling the receive filters.
     25   @param  MCastAddressCount  Multicast address count for a new multicast address
     26                              list.
     27   @param  MCastAddressList   List of new multicast addresses.
     28 
     29   @retval EFI_SUCCESS           The multicast receive filter list was updated.
     30   @retval EFI_INVALID_PARAMETER Invalid UNDI command.
     31   @retval EFI_UNSUPPORTED       Command is not supported by UNDI.
     32   @retval EFI_DEVICE_ERROR      Fail to execute UNDI command.
     33 
     34 **/
     35 EFI_STATUS
     36 PxeRecvFilterEnable (
     37   SNP_DRIVER      *Snp,
     38   UINT32          EnableFlags,
     39   UINTN           MCastAddressCount,
     40   EFI_MAC_ADDRESS *MCastAddressList
     41   )
     42 {
     43   Snp->Cdb.OpCode     = PXE_OPCODE_RECEIVE_FILTERS;
     44   Snp->Cdb.OpFlags    = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE;
     45   Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
     46   Snp->Cdb.DBsize     = PXE_DBSIZE_NOT_USED;
     47   Snp->Cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;
     48   Snp->Cdb.DBaddr     = PXE_DBADDR_NOT_USED;
     49   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
     50   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
     51   Snp->Cdb.IFnum      = Snp->IfNum;
     52   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
     53 
     54   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
     55     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
     56   }
     57 
     58   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
     59     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
     60   }
     61 
     62   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
     63     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
     64   }
     65 
     66   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
     67     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
     68   }
     69 
     70   if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
     71     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
     72   }
     73 
     74   if (MCastAddressCount != 0) {
     75     Snp->Cdb.CPBsize  = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS));
     76     Snp->Cdb.CPBaddr  = (UINT64)(UINTN)Snp->Cpb;
     77     CopyMem (Snp->Cpb, MCastAddressList, Snp->Cdb.CPBsize);
     78   }
     79   //
     80   // Issue UNDI command and check result.
     81   //
     82   DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));
     83 
     84   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
     85 
     86   if (Snp->Cdb.StatCode != EFI_SUCCESS) {
     87     //
     88     // UNDI command failed.  Return UNDI status to caller.
     89     //
     90     DEBUG (
     91       (EFI_D_ERROR,
     92       "\nsnp->undi.receive_filters()  %xh:%xh\n",
     93       Snp->Cdb.StatFlags,
     94       Snp->Cdb.StatCode)
     95       );
     96 
     97     switch (Snp->Cdb.StatCode) {
     98     case PXE_STATCODE_INVALID_CDB:
     99     case PXE_STATCODE_INVALID_CPB:
    100     case PXE_STATCODE_INVALID_PARAMETER:
    101       return EFI_INVALID_PARAMETER;
    102 
    103     case PXE_STATCODE_UNSUPPORTED:
    104       return EFI_UNSUPPORTED;
    105     }
    106 
    107     return EFI_DEVICE_ERROR;
    108   }
    109 
    110   return EFI_SUCCESS;
    111 }
    112 
    113 /**
    114   Call undi to disable the receive filters.
    115 
    116   @param  Snp             Pointer to snp driver structure
    117   @param  DisableFlags    Bit mask for disabling the receive filters
    118   @param  ResetMCastList  Boolean flag to reset/delete the multicast filter
    119                           list.
    120 
    121   @retval EFI_SUCCESS           The multicast receive filter list was updated.
    122   @retval EFI_DEVICE_ERROR      Fail to execute UNDI command.
    123 
    124 **/
    125 EFI_STATUS
    126 PxeRecvFilterDisable (
    127   SNP_DRIVER *Snp,
    128   UINT32     DisableFlags,
    129   BOOLEAN    ResetMCastList
    130   )
    131 {
    132   Snp->Cdb.OpCode     = PXE_OPCODE_RECEIVE_FILTERS;
    133   Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
    134   Snp->Cdb.DBsize     = PXE_DBSIZE_NOT_USED;
    135   Snp->Cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;
    136   Snp->Cdb.DBaddr     = PXE_DBADDR_NOT_USED;
    137   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
    138   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
    139   Snp->Cdb.IFnum      = Snp->IfNum;
    140   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
    141 
    142   Snp->Cdb.OpFlags    = (UINT16) ((DisableFlags != 0) ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED);
    143 
    144   if (ResetMCastList) {
    145     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST;
    146   }
    147 
    148   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
    149     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
    150   }
    151 
    152   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
    153     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
    154   }
    155 
    156   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
    157     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
    158   }
    159 
    160   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
    161     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
    162   }
    163 
    164   if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
    165     Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
    166   }
    167   //
    168   // Issue UNDI command and check result.
    169   //
    170   DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));
    171 
    172   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
    173 
    174   if (Snp->Cdb.StatCode != EFI_SUCCESS) {
    175     //
    176     // UNDI command failed.  Return UNDI status to caller.
    177     //
    178     DEBUG (
    179       (EFI_D_ERROR,
    180       "\nsnp->undi.receive_filters()  %xh:%xh\n",
    181       Snp->Cdb.StatFlags,
    182       Snp->Cdb.StatCode)
    183       );
    184 
    185     return EFI_DEVICE_ERROR;
    186   }
    187 
    188   return EFI_SUCCESS;
    189 }
    190 
    191 /**
    192   Call undi to read the receive filters.
    193 
    194   @param  Snp                Pointer to snp driver structure.
    195 
    196   @retval EFI_SUCCESS           The receive filter was read.
    197   @retval EFI_DEVICE_ERROR      Fail to execute UNDI command.
    198 
    199 **/
    200 EFI_STATUS
    201 PxeRecvFilterRead (
    202   SNP_DRIVER *Snp
    203   )
    204 {
    205   Snp->Cdb.OpCode   = PXE_OPCODE_RECEIVE_FILTERS;
    206   Snp->Cdb.OpFlags  = PXE_OPFLAGS_RECEIVE_FILTER_READ;
    207   Snp->Cdb.CPBsize  = PXE_CPBSIZE_NOT_USED;
    208   Snp->Cdb.DBsize   = (UINT16) (Snp->Mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS));
    209   Snp->Cdb.CPBaddr  = PXE_CPBADDR_NOT_USED;
    210   if (Snp->Cdb.DBsize == 0) {
    211     Snp->Cdb.DBaddr = (UINT64)(UINTN) NULL;
    212   } else {
    213     Snp->Cdb.DBaddr = (UINT64)(UINTN) Snp->Db;
    214     ZeroMem (Snp->Db, Snp->Cdb.DBsize);
    215   }
    216 
    217   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
    218   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
    219   Snp->Cdb.IFnum      = Snp->IfNum;
    220   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
    221 
    222   DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters()  "));
    223 
    224   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
    225 
    226   if (Snp->Cdb.StatCode != EFI_SUCCESS) {
    227     //
    228     // UNDI command failed.  Return UNDI status to caller.
    229     //
    230     DEBUG (
    231       (EFI_D_ERROR,
    232       "\nsnp->undi.receive_filters()  %xh:%xh\n",
    233       Snp->Cdb.StatFlags,
    234       Snp->Cdb.StatCode)
    235       );
    236 
    237     return EFI_DEVICE_ERROR;
    238   }
    239   //
    240   // Convert UNDI32 StatFlags to EFI SNP filter flags.
    241   //
    242   Snp->Mode.ReceiveFilterSetting = 0;
    243 
    244   if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) {
    245     Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
    246   }
    247 
    248   if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) {
    249     Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
    250   }
    251 
    252   if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) {
    253     Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
    254   }
    255 
    256   if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) {
    257     Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
    258   }
    259 
    260   if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
    261     Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
    262   }
    263 
    264   CopyMem (Snp->Mode.MCastFilter, Snp->Db, Snp->Cdb.DBsize);
    265 
    266   //
    267   // Count number of active entries in multicast filter list.
    268   //
    269   {
    270     EFI_MAC_ADDRESS ZeroMacAddr;
    271 
    272     SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0);
    273 
    274     for (Snp->Mode.MCastFilterCount = 0;
    275          Snp->Mode.MCastFilterCount < Snp->Mode.MaxMCastFilterCount;
    276          Snp->Mode.MCastFilterCount++
    277         ) {
    278       if (CompareMem (
    279             &Snp->Mode.MCastFilter[Snp->Mode.MCastFilterCount],
    280             &ZeroMacAddr,
    281             sizeof ZeroMacAddr
    282             ) == 0) {
    283         break;
    284       }
    285     }
    286   }
    287 
    288   return EFI_SUCCESS;
    289 }
    290 
    291 
    292 /**
    293   Manages the multicast receive filters of a network interface.
    294 
    295   This function is used enable and disable the hardware and software receive
    296   filters for the underlying network device.
    297   The receive filter change is broken down into three steps:
    298   * The filter mask bits that are set (ON) in the Enable parameter are added to
    299     the current receive filter settings.
    300   * The filter mask bits that are set (ON) in the Disable parameter are subtracted
    301     from the updated receive filter settings.
    302   * If the resulting receive filter setting is not supported by the hardware a
    303     more liberal setting is selected.
    304   If the same bits are set in the Enable and Disable parameters, then the bits
    305   in the Disable parameter takes precedence.
    306   If the ResetMCastFilter parameter is TRUE, then the multicast address list
    307   filter is disabled (irregardless of what other multicast bits are set in the
    308   Enable and Disable parameters). The SNP->Mode->MCastFilterCount field is set
    309   to zero. The Snp->Mode->MCastFilter contents are undefined.
    310   After enabling or disabling receive filter settings, software should verify
    311   the new settings by checking the Snp->Mode->ReceiveFilterSettings,
    312   Snp->Mode->MCastFilterCount and Snp->Mode->MCastFilter fields.
    313   Note: Some network drivers and/or devices will automatically promote receive
    314     filter settings if the requested setting can not be honored. For example, if
    315     a request for four multicast addresses is made and the underlying hardware
    316     only supports two multicast addresses the driver might set the promiscuous
    317     or promiscuous multicast receive filters instead. The receiving software is
    318     responsible for discarding any extra packets that get through the hardware
    319     receive filters.
    320     Note: Note: To disable all receive filter hardware, the network driver must
    321       be Shutdown() and Stopped(). Calling ReceiveFilters() with Disable set to
    322       Snp->Mode->ReceiveFilterSettings will make it so no more packets are
    323       returned by the Receive() function, but the receive hardware may still be
    324       moving packets into system memory before inspecting and discarding them.
    325       Unexpected system errors, reboots and hangs can occur if an OS is loaded
    326       and the network devices are not Shutdown() and Stopped().
    327   If ResetMCastFilter is TRUE, then the multicast receive filter list on the
    328   network interface will be reset to the default multicast receive filter list.
    329   If ResetMCastFilter is FALSE, and this network interface allows the multicast
    330   receive filter list to be modified, then the MCastFilterCnt and MCastFilter
    331   are used to update the current multicast receive filter list. The modified
    332   receive filter list settings can be found in the MCastFilter field of
    333   EFI_SIMPLE_NETWORK_MODE. If the network interface does not allow the multicast
    334   receive filter list to be modified, then EFI_INVALID_PARAMETER will be returned.
    335   If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
    336   If the receive filter mask and multicast receive filter list have been
    337   successfully updated on the network interface, EFI_SUCCESS will be returned.
    338 
    339   @param This             A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
    340   @param Enable           A bit mask of receive filters to enable on the network
    341                           interface.
    342   @param Disable          A bit mask of receive filters to disable on the network
    343                           interface. For backward compatibility with EFI 1.1
    344                           platforms, the EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit
    345                           must be set when the ResetMCastFilter parameter is TRUE.
    346   @param ResetMCastFilter Set to TRUE to reset the contents of the multicast
    347                           receive filters on the network interface to their
    348                           default values.
    349   @param MCastFilterCnt   Number of multicast HW MAC addresses in the new MCastFilter
    350                           list. This value must be less than or equal to the
    351                           MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE.
    352                           This field is optional if ResetMCastFilter is TRUE.
    353   @param MCastFilter      A pointer to a list of new multicast receive filter HW
    354                           MAC addresses. This list will replace any existing
    355                           multicast HW MAC address list. This field is optional
    356                           if ResetMCastFilter is TRUE.
    357 
    358   @retval EFI_SUCCESS            The multicast receive filter list was updated.
    359   @retval EFI_NOT_STARTED        The network interface has not been started.
    360   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
    361                                  * This is NULL
    362                                  * There are bits set in Enable that are not set
    363                                    in Snp->Mode->ReceiveFilterMask
    364                                  * There are bits set in Disable that are not set
    365                                    in Snp->Mode->ReceiveFilterMask
    366                                  * Multicast is being enabled (the
    367                                    EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is
    368                                    set in Enable, it is not set in Disable, and
    369                                    ResetMCastFilter is FALSE) and MCastFilterCount
    370                                    is zero
    371                                  * Multicast is being enabled and MCastFilterCount
    372                                    is greater than Snp->Mode->MaxMCastFilterCount
    373                                  * Multicast is being enabled and MCastFilter is NULL
    374                                  * Multicast is being enabled and one or more of
    375                                    the addresses in the MCastFilter list are not
    376                                    valid multicast MAC addresses
    377   @retval EFI_DEVICE_ERROR       One or more of the following conditions is TRUE:
    378                                  * The network interface has been started but has
    379                                    not been initialized
    380                                  * An unexpected error was returned by the
    381                                    underlying network driver or device
    382   @retval EFI_UNSUPPORTED        This function is not supported by the network
    383                                  interface.
    384 
    385 **/
    386 EFI_STATUS
    387 EFIAPI
    388 SnpUndi32ReceiveFilters (
    389   IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
    390   IN UINT32                      Enable,
    391   IN UINT32                      Disable,
    392   IN BOOLEAN                     ResetMCastFilter,
    393   IN UINTN                       MCastFilterCnt,  OPTIONAL
    394   IN EFI_MAC_ADDRESS             *MCastFilter     OPTIONAL
    395   )
    396 {
    397   SNP_DRIVER  *Snp;
    398   EFI_STATUS  Status;
    399   EFI_TPL     OldTpl;
    400 
    401   if (This == NULL) {
    402     return EFI_INVALID_PARAMETER;
    403   }
    404 
    405   Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
    406 
    407   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    408 
    409   switch (Snp->Mode.State) {
    410   case EfiSimpleNetworkInitialized:
    411     break;
    412 
    413   case EfiSimpleNetworkStopped:
    414     Status = EFI_NOT_STARTED;
    415     goto ON_EXIT;
    416 
    417   default:
    418     Status = EFI_DEVICE_ERROR;
    419     goto ON_EXIT;
    420   }
    421   //
    422   // check if we are asked to enable or disable something that the UNDI
    423   // does not even support!
    424   //
    425   if (((Enable &~Snp->Mode.ReceiveFilterMask) != 0) ||
    426     ((Disable &~Snp->Mode.ReceiveFilterMask) != 0)) {
    427     Status = EFI_INVALID_PARAMETER;
    428     goto ON_EXIT;
    429   }
    430 
    431   if (ResetMCastFilter) {
    432 
    433     Disable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & Snp->Mode.ReceiveFilterMask;
    434     MCastFilterCnt = 0;
    435     MCastFilter    = NULL;
    436   } else {
    437     if (MCastFilterCnt != 0) {
    438       if ((MCastFilterCnt > Snp->Mode.MaxMCastFilterCount) ||
    439           (MCastFilter == NULL)) {
    440 
    441         Status = EFI_INVALID_PARAMETER;
    442         goto ON_EXIT;
    443       }
    444     }
    445   }
    446 
    447   if (Enable == 0 && Disable == 0 && !ResetMCastFilter && MCastFilterCnt == 0) {
    448     Status = EFI_SUCCESS;
    449     goto ON_EXIT;
    450   }
    451 
    452   if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastFilterCnt == 0) {
    453     Status = EFI_INVALID_PARAMETER;
    454     goto ON_EXIT;
    455   }
    456 
    457   if ((Enable != 0) || (MCastFilterCnt != 0)) {
    458     Status = PxeRecvFilterEnable (
    459                Snp,
    460                Enable,
    461                MCastFilterCnt,
    462                MCastFilter
    463                );
    464 
    465     if (EFI_ERROR (Status)) {
    466       goto ON_EXIT;
    467     }
    468   }
    469 
    470   if ((Disable != 0) || ResetMCastFilter) {
    471     Status = PxeRecvFilterDisable (Snp, Disable, ResetMCastFilter);
    472 
    473     if (EFI_ERROR (Status)) {
    474       goto ON_EXIT;
    475     }
    476   }
    477 
    478   Status = PxeRecvFilterRead (Snp);
    479 
    480 ON_EXIT:
    481   gBS->RestoreTPL (OldTpl);
    482 
    483   return Status;
    484 }
    485