Home | History | Annotate | Download | only in SnpDxe
      1 /** @file
      2     Implementation of reading the MAC address of a network adapter.
      3 
      4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials are licensed
      6 and made available under the terms and conditions of the BSD License which
      7 accompanies this distribution. The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "Snp.h"
     16 
     17 
     18 /**
     19   Call UNDI to read the MAC address of the NIC and update the mode structure
     20   with the address.
     21 
     22   @param  Snp         Pointer to snp driver structure.
     23 
     24   @retval EFI_SUCCESS       The MAC address of the NIC is read successfully.
     25   @retval EFI_DEVICE_ERROR  Failed to read the MAC address of the NIC.
     26 
     27 **/
     28 EFI_STATUS
     29 PxeGetStnAddr (
     30   SNP_DRIVER *Snp
     31   )
     32 {
     33   PXE_DB_STATION_ADDRESS  *Db;
     34 
     35   Db                  = Snp->Db;
     36   Snp->Cdb.OpCode     = PXE_OPCODE_STATION_ADDRESS;
     37   Snp->Cdb.OpFlags    = PXE_OPFLAGS_STATION_ADDRESS_READ;
     38 
     39   Snp->Cdb.CPBaddr    = PXE_CPBADDR_NOT_USED;
     40   Snp->Cdb.CPBsize    = PXE_CPBSIZE_NOT_USED;
     41 
     42   Snp->Cdb.DBsize     = (UINT16) sizeof (PXE_DB_STATION_ADDRESS);
     43   Snp->Cdb.DBaddr     = (UINT64)(UINTN) Db;
     44 
     45   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
     46   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
     47   Snp->Cdb.IFnum      = Snp->IfNum;
     48   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
     49 
     50   //
     51   // Issue UNDI command and check result.
     52   //
     53   DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr()  "));
     54 
     55   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
     56 
     57   if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
     58     DEBUG (
     59       (EFI_D_ERROR,
     60       "\nsnp->undi.station_addr()  %xh:%xh\n",
     61       Snp->Cdb.StatFlags,
     62       Snp->Cdb.StatCode)
     63       );
     64 
     65     return EFI_DEVICE_ERROR;
     66   }
     67   //
     68   // Set new station address in SNP->Mode structure and return success.
     69   //
     70   CopyMem (
     71     &(Snp->Mode.CurrentAddress),
     72     &Db->StationAddr,
     73     Snp->Mode.HwAddressSize
     74     );
     75 
     76   CopyMem (
     77     &Snp->Mode.BroadcastAddress,
     78     &Db->BroadcastAddr,
     79     Snp->Mode.HwAddressSize
     80     );
     81 
     82   CopyMem (
     83     &Snp->Mode.PermanentAddress,
     84     &Db->PermanentAddr,
     85     Snp->Mode.HwAddressSize
     86     );
     87 
     88   return EFI_SUCCESS;
     89 }
     90 
     91 
     92 /**
     93   Call UNDI to set a new MAC address for the NIC.
     94 
     95   @param  Snp         Pointer to Snp driver structure.
     96   @param  NewMacAddr  Pointer to a MAC address to be set for the NIC, if this is
     97                       NULL then this routine resets the mac address to the NIC's
     98                       original address.
     99 
    100 
    101 **/
    102 EFI_STATUS
    103 PxeSetStnAddr (
    104   SNP_DRIVER      *Snp,
    105   EFI_MAC_ADDRESS *NewMacAddr
    106   )
    107 {
    108   PXE_CPB_STATION_ADDRESS *Cpb;
    109   PXE_DB_STATION_ADDRESS  *Db;
    110 
    111   Cpb             = Snp->Cpb;
    112   Db              = Snp->Db;
    113   Snp->Cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;
    114 
    115   if (NewMacAddr == NULL) {
    116     Snp->Cdb.OpFlags  = PXE_OPFLAGS_STATION_ADDRESS_RESET;
    117     Snp->Cdb.CPBsize  = PXE_CPBSIZE_NOT_USED;
    118     Snp->Cdb.CPBaddr  = PXE_CPBADDR_NOT_USED;
    119   } else {
    120     Snp->Cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_WRITE;
    121     //
    122     // Supplying a new address in the CPB will make undi change the mac address to the new one.
    123     //
    124     CopyMem (&Cpb->StationAddr, NewMacAddr, Snp->Mode.HwAddressSize);
    125 
    126     Snp->Cdb.CPBsize  = (UINT16) sizeof (PXE_CPB_STATION_ADDRESS);
    127     Snp->Cdb.CPBaddr  = (UINT64)(UINTN) Cpb;
    128   }
    129 
    130   Snp->Cdb.DBsize     = (UINT16) sizeof (PXE_DB_STATION_ADDRESS);
    131   Snp->Cdb.DBaddr     = (UINT64)(UINTN) Db;
    132 
    133   Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
    134   Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
    135   Snp->Cdb.IFnum      = Snp->IfNum;
    136   Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;
    137 
    138   //
    139   // Issue UNDI command and check result.
    140   //
    141   DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr()  "));
    142 
    143   (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
    144 
    145   if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
    146     DEBUG (
    147       (EFI_D_ERROR,
    148       "\nsnp->undi.station_addr()  %xh:%xh\n",
    149       Snp->Cdb.StatFlags,
    150       Snp->Cdb.StatCode)
    151       );
    152 
    153     //
    154     // UNDI command failed.  Return UNDI status to caller.
    155     //
    156     return EFI_DEVICE_ERROR;
    157   }
    158   //
    159   // read the changed address and save it in SNP->Mode structure
    160   //
    161   PxeGetStnAddr (Snp);
    162 
    163   return EFI_SUCCESS;
    164 }
    165 
    166 
    167 /**
    168   Modifies or resets the current station address, if supported.
    169 
    170   This function modifies or resets the current station address of a network
    171   interface, if supported. If Reset is TRUE, then the current station address is
    172   set to the network interface's permanent address. If Reset is FALSE, and the
    173   network interface allows its station address to be modified, then the current
    174   station address is changed to the address specified by New. If the network
    175   interface does not allow its station address to be modified, then
    176   EFI_INVALID_PARAMETER will be returned. If the station address is successfully
    177   updated on the network interface, EFI_SUCCESS will be returned. If the driver
    178   has not been initialized, EFI_DEVICE_ERROR will be returned.
    179 
    180   @param This  A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
    181   @param Reset Flag used to reset the station address to the network interface's
    182                permanent address.
    183   @param New   New station address to be used for the network interface.
    184 
    185 
    186   @retval EFI_SUCCESS           The network interface's station address was updated.
    187   @retval EFI_NOT_STARTED       The Simple Network Protocol interface has not been
    188                                 started by calling Start().
    189   @retval EFI_INVALID_PARAMETER The New station address was not accepted by the NIC.
    190   @retval EFI_INVALID_PARAMETER Reset is FALSE and New is NULL.
    191   @retval EFI_DEVICE_ERROR      The Simple Network Protocol interface has not
    192                                 been initialized by calling Initialize().
    193   @retval EFI_DEVICE_ERROR      An error occurred attempting to set the new
    194                                 station address.
    195   @retval EFI_UNSUPPORTED       The NIC does not support changing the network
    196                                 interface's station address.
    197 
    198 **/
    199 EFI_STATUS
    200 EFIAPI
    201 SnpUndi32StationAddress (
    202   IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
    203   IN BOOLEAN                     Reset,
    204   IN EFI_MAC_ADDRESS             *New OPTIONAL
    205   )
    206 {
    207   SNP_DRIVER  *Snp;
    208   EFI_STATUS  Status;
    209   EFI_TPL     OldTpl;
    210 
    211   //
    212   // Check for invalid parameter combinations.
    213   //
    214   if ((This == NULL) ||
    215     (!Reset && (New == NULL))) {
    216     return EFI_INVALID_PARAMETER;
    217   }
    218 
    219   Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
    220 
    221   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    222 
    223   //
    224   // Return error if the SNP is not initialized.
    225   //
    226   switch (Snp->Mode.State) {
    227   case EfiSimpleNetworkInitialized:
    228     break;
    229 
    230   case EfiSimpleNetworkStopped:
    231     Status = EFI_NOT_STARTED;
    232     goto ON_EXIT;
    233 
    234   default:
    235     Status = EFI_DEVICE_ERROR;
    236     goto ON_EXIT;
    237   }
    238 
    239   if (Reset) {
    240     Status = PxeSetStnAddr (Snp, NULL);
    241   } else {
    242     Status = PxeSetStnAddr (Snp, New);
    243   }
    244 
    245 ON_EXIT:
    246   gBS->RestoreTPL (OldTpl);
    247 
    248   return Status;
    249 }
    250