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
PxeGetStnAddr(SNP_DRIVER * Snp)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
PxeSetStnAddr(SNP_DRIVER * Snp,EFI_MAC_ADDRESS * NewMacAddr)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
SnpUndi32StationAddress(IN EFI_SIMPLE_NETWORK_PROTOCOL * This,IN BOOLEAN Reset,IN EFI_MAC_ADDRESS * New OPTIONAL)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