OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
Ip4Config2Nv.c
Go to the documentation of this file.
1
14#include "NetworkBootInternal.h"
15
16STATIC
17VOID
19 IN OUT IP4_CONFIG2_VARIABLE *Variable,
20 IN EFI_IP4_CONFIG2_DATA_TYPE DataType,
21 IN VOID *Data,
22 IN UINTN DataSize,
23 IN OUT CHAR8 **Heap
24 )
25{
26 *Heap -= DataSize;
27 CopyMem (*Heap, Data, DataSize);
28
29 Variable->DataRecord[Variable->DataRecordCount].Offset = (UINT16)(*Heap - (CHAR8 *)Variable);
30 Variable->DataRecord[Variable->DataRecordCount].DataSize = (UINT32)DataSize;
31 Variable->DataRecord[Variable->DataRecordCount].DataType = DataType;
32
33 ++Variable->DataRecordCount;
34}
35
36//
37// Performs the same job as
38// https://github.com/tianocore/edk2/blob/e99d532fd7224e68026543834ed9c0fe3cfaf88c/NetworkPkg/Ip4Dxe/Ip4Config2Impl.c#L303
39// but in order to avoid initialising unnecessary data structures we work directly
40// from the config data which is in fact acccepted there.
41//
42STATIC
43EFI_STATUS
45 IN CHAR16 *VarName,
46 EFI_IP4_CONFIG2_POLICY Policy,
47 EFI_IP4_CONFIG2_MANUAL_ADDRESS *ManualAddress,
48 EFI_IP_ADDRESS *Gateway,
49 EFI_IPv4_ADDRESS *DnsAddress,
50 UINTN DnsCount
51 )
52{
53 EFI_STATUS Status;
54
55 IP4_CONFIG2_VARIABLE *Variable;
56 UINTN VarSize;
57 UINT16 DataRecordCount;
58 CHAR8 *Heap;
59
60 DataRecordCount = 0;
61 VarSize = sizeof (*Variable);
62 {
63 ++DataRecordCount;
64 VarSize += sizeof (Policy);
65 }
66 if (ManualAddress != NULL) {
67 ++DataRecordCount;
68 VarSize += sizeof (*ManualAddress);
69 }
70
71 if (Gateway != NULL) {
72 ++DataRecordCount;
73 VarSize += sizeof (Gateway->v4);
74 }
75
76 if (DnsAddress != NULL) {
77 ASSERT (DnsCount != 0);
78 ++DataRecordCount;
79 VarSize += DnsCount * sizeof (*DnsAddress);
80 }
81
82 VarSize += sizeof (Variable->DataRecord[0]) * DataRecordCount;
83
84 Variable = AllocatePool (VarSize);
85
86 if (Variable == NULL) {
87 return EFI_OUT_OF_RESOURCES;
88 }
89
90 Heap = (CHAR8 *)Variable + VarSize;
91
92 Variable->DataRecordCount = 0;
93
94 AddDataRecord (Variable, Ip4Config2DataTypePolicy, &Policy, sizeof (Policy), &Heap);
95 if (ManualAddress != NULL) {
96 AddDataRecord (Variable, Ip4Config2DataTypeManualAddress, ManualAddress, sizeof (*ManualAddress), &Heap);
97 }
98
99 if (Gateway != NULL) {
100 AddDataRecord (Variable, Ip4Config2DataTypeGateway, &Gateway->v4, sizeof (Gateway->v4), &Heap);
101 }
102
103 if (DnsAddress != NULL) {
104 AddDataRecord (Variable, Ip4Config2DataTypeDnsServer, DnsAddress, sizeof (*DnsAddress) * DnsCount, &Heap);
105 }
106
107 ASSERT (Variable->DataRecordCount == DataRecordCount);
108 ASSERT (Heap == (CHAR8 *)&Variable->DataRecord[DataRecordCount]);
109
110 Variable->Checksum = 0;
111 Variable->Checksum = (UINT16) ~NetblockChecksum ((UINT8 *)Variable, (UINT32)VarSize);
112
113 Status = gRT->SetVariable (
114 VarName,
115 &gEfiIp4Config2ProtocolGuid,
117 VarSize,
118 Variable
119 );
120
121 FreePool (Variable);
122
123 return Status;
124}
125
126EFI_STATUS
128 IN CHAR16 *VarName,
129 IN IP4_CONFIG2_OC_CONFIG_DATA *ConfigData
130 )
131{
132 EFI_STATUS Status;
133 UINTN Index;
134
135 EFI_IP4_CONFIG2_POLICY Policy;
136 EFI_IP4_CONFIG2_MANUAL_ADDRESS ManualAddress;
137 EFI_IP_ADDRESS StationAddress;
138 EFI_IP_ADDRESS SubnetMask;
139 EFI_IP_ADDRESS Gateway;
140 IP4_ADDR Ip;
141 EFI_IPv4_ADDRESS *DnsAddress;
142 UINTN DnsCount;
143
144 //
145 // cf Ip4Config2ConvertIfrNvDataToConfigNvData
146 // REF: https://github.com/tianocore/edk2/blob/e99d532fd7224e68026543834ed9c0fe3cfaf88c/NetworkPkg/Ip4Dxe/Ip4Config2Nv.c#L551
147 //
148 Policy = Ip4Config2PolicyStatic;
149
150 Status = Ip4Config2StrToIp (ConfigData->SubnetMask, &SubnetMask.v4);
151 if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
152 DEBUG ((DEBUG_WARN, "NETB: Invalid subnet mask %s\n", ConfigData->SubnetMask));
153 return EFI_INVALID_PARAMETER;
154 }
155
156 Status = Ip4Config2StrToIp (ConfigData->StationAddress, &StationAddress.v4);
157 if (EFI_ERROR (Status) ||
158 ((SubnetMask.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (StationAddress.Addr[0]), NTOHL (SubnetMask.Addr[0]))) ||
159 !Ip4StationAddressValid (NTOHL (StationAddress.Addr[0]), NTOHL (SubnetMask.Addr[0])))
160 {
161 DEBUG ((DEBUG_WARN, "NETB: Invalid IP address %s\n", ConfigData->StationAddress));
162 return EFI_INVALID_PARAMETER;
163 }
164
165 Status = Ip4Config2StrToIp (ConfigData->GatewayAddress, &Gateway.v4);
166 if (EFI_ERROR (Status) ||
167 ((Gateway.Addr[0] != 0) && (SubnetMask.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL (SubnetMask.Addr[0]))))
168 {
169 DEBUG ((DEBUG_WARN, "NETB: Invalid gateway %s\n", ConfigData->GatewayAddress));
170 return EFI_INVALID_PARAMETER;
171 }
172
173 Status = Ip4Config2StrToIpList (ConfigData->DnsAddress, &DnsAddress, &DnsCount);
174 if (!EFI_ERROR (Status) && (DnsCount > 0)) {
175 for (Index = 0; Index < DnsCount; Index++) {
176 CopyMem (&Ip, &DnsAddress[Index], sizeof (IP4_ADDR));
177 if (IP4_IS_UNSPECIFIED (NTOHL (Ip)) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {
178 DEBUG ((
179 DEBUG_WARN,
180 "NETB: Invalid DNS address %d.%d.%d.%d\n",
181 DnsAddress[Index].Addr[0],
182 DnsAddress[Index].Addr[1],
183 DnsAddress[Index].Addr[2],
184 DnsAddress[Index].Addr[3]
185 ));
186 FreePool (DnsAddress);
187 return EFI_INVALID_PARAMETER;
188 }
189 }
190 } else {
191 if (EFI_ERROR (Status)) {
192 DEBUG ((DEBUG_WARN, "NETB: Invalid DNS server list %s\n", ConfigData->DnsAddress));
193 //
194 // Unlike Ip4Config2ConvertIfrNvDataToConfigNvData we abort if unparseable DNS list.
195 //
196 return EFI_INVALID_PARAMETER;
197 }
198 }
199
200 CopyMem (&ManualAddress.Address, &StationAddress.v4, sizeof (EFI_IPv4_ADDRESS));
201 CopyMem (&ManualAddress.SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS));
202
203 Status = Ip4Config2WriteConfigData (VarName, Policy, &ManualAddress, &Gateway, DnsAddress, DnsCount);
204
205 DEBUG ((
206 DEBUG_INFO,
207 "NETB: Adding %a %s - %r\n",
208 "IPv4 NVRAM config for MAC address",
209 VarName,
210 Status
211 ));
212
213 if (DnsAddress != NULL) {
214 FreePool (DnsAddress);
215 }
216
217 return Status;
218}
219
220//
221// cf Ip4Config2ReadConfigData
222// REF: https://github.com/tianocore/edk2/blob/e99d532fd7224e68026543834ed9c0fe3cfaf88c/NetworkPkg/Ip4Dxe/Ip4Config2Impl.c#L188
223//
224EFI_STATUS
226 IN CHAR16 *VarName
227 )
228{
229 EFI_STATUS Status;
230 UINTN VarSize;
231 IP4_CONFIG2_VARIABLE *Variable;
232 UINTN Index;
233 IP4_CONFIG2_DATA_RECORD *DataRecord;
234
235 EFI_IP4_CONFIG2_POLICY Policy;
236
237 BOOLEAN FoundStaticPolicy;
238 BOOLEAN FoundManualAddress;
239
240 VarSize = 0;
241 Status = gRT->GetVariable (
242 VarName,
243 &gEfiIp4Config2ProtocolGuid,
244 NULL,
245 &VarSize,
246 NULL
247 );
248
249 if (Status != EFI_BUFFER_TOO_SMALL) {
250 return Status;
251 }
252
253 Variable = AllocatePool (VarSize);
254 if (Variable == NULL) {
255 return EFI_OUT_OF_RESOURCES;
256 }
257
258 Status = gRT->GetVariable (
259 VarName,
260 &gEfiIp4Config2ProtocolGuid,
261 NULL,
262 &VarSize,
263 Variable
264 );
265 if (EFI_ERROR (Status) || ((UINT16)(~NetblockChecksum ((UINT8 *)Variable, (UINT32)VarSize)) != 0)) {
266 FreePool (Variable);
267
268 //
269 // Unlike Ip4Config2ReadConfigData it is not our job to resolve existing problematic variable,
270 // just warn and return EFI_NOT_FOUND.
271 //
272 DEBUG ((
273 DEBUG_INFO,
274 "NETB: %a, %a %a %s - %r\n",
275 "Invalid variable",
276 "not removing",
277 "IPv4 NVRAM config for MAC address",
278 VarName,
279 Status
280 ));
281
282 return EFI_NOT_FOUND;
283 }
284
285 //
286 // In order to avoid fighting with PXE and HTTP boot over the variable value,
287 // only remove valid static IP settings.
288 //
289 FoundStaticPolicy = FALSE;
290 FoundManualAddress = FALSE;
291
292 for (Index = 0; Index < Variable->DataRecordCount; Index++) {
293 DataRecord = &Variable->DataRecord[Index];
294 if ( (DataRecord->DataType == Ip4Config2DataTypePolicy)
295 && (DataRecord->DataSize == sizeof (Policy)))
296 {
297 CopyMem (&Policy, (CHAR8 *)Variable + DataRecord->Offset, DataRecord->DataSize);
298 if (Policy == Ip4Config2PolicyStatic) {
299 FoundStaticPolicy = TRUE;
300 }
301 } else if ( (DataRecord->DataType == Ip4Config2DataTypeManualAddress)
302 && (DataRecord->DataSize == sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS)))
303 {
304 FoundManualAddress = TRUE;
305 }
306 }
307
308 if (FoundStaticPolicy && FoundManualAddress) {
309 //
310 // We may be called after Ip4Dxe has run (e.g. OpenNetworkBoot loaded by OpenCore, with native network stack).
311 // Since this variable is boot services access only we should not just delete it, as this may leave one boot
312 // where the OS could set it. Instead reinitialise the variable to the value to which Ip4Dxe initialises it.
313 // For initial values, see:
314 // https://github.com/tianocore/edk2/blob/e99d532fd7224e68026543834ed9c0fe3cfaf88c/NetworkPkg/Ip4Dxe/Ip4Config2Impl.c#L1985-L2015
315 //
316 Policy = Ip4Config2PolicyStatic;
317 Status = Ip4Config2WriteConfigData (VarName, Policy, NULL, NULL, NULL, 0);
318
319 DEBUG ((
320 DEBUG_INFO,
321 "NETB: Removing %a %s - %r\n",
322 "IPv4 NVRAM config for MAC address",
323 VarName,
324 Status
325 ));
326 } else {
327 DEBUG ((
328 DEBUG_INFO,
329 "NETB: %a, %a %a %s\n",
330 "No static IP",
331 "not removing",
332 "IPv4 NVRAM config for MAC address",
333 VarName
334 ));
335 Status = EFI_NOT_FOUND;
336 }
337
338 FreePool (Variable);
339 return Status;
340}
EFI_STATUS Ip4Config2ConvertOcConfigDataToNvData(IN CHAR16 *VarName, IN IP4_CONFIG2_OC_CONFIG_DATA *ConfigData)
STATIC EFI_STATUS Ip4Config2WriteConfigData(IN CHAR16 *VarName, EFI_IP4_CONFIG2_POLICY Policy, EFI_IP4_CONFIG2_MANUAL_ADDRESS *ManualAddress, EFI_IP_ADDRESS *Gateway, EFI_IPv4_ADDRESS *DnsAddress, UINTN DnsCount)
EFI_STATUS Ip4Config2DeleteStaticIpNvData(IN CHAR16 *VarName)
STATIC VOID AddDataRecord(IN OUT IP4_CONFIG2_VARIABLE *Variable, IN EFI_IP4_CONFIG2_DATA_TYPE DataType, IN VOID *Data, IN UINTN DataSize, IN OUT CHAR8 **Heap)
EFI_STATUS Ip4Config2StrToIpList(IN CHAR16 *Str, OUT EFI_IPv4_ADDRESS **PtrIpList, OUT UINTN *IpCount)
Definition Ip4Utils.c:173
BOOLEAN Ip4StationAddressValid(IN IP4_ADDR Ip, IN IP4_ADDR Netmask)
Definition Ip4Utils.c:27
UINT8 GetSubnetMaskPrefixLength(IN EFI_IPv4_ADDRESS *SubnetMask)
Definition Ip4Utils.c:66
EFI_STATUS Ip4Config2StrToIp(IN CHAR16 *Str, OUT EFI_IPv4_ADDRESS *Ip)
Definition Ip4Utils.c:108
#define IP4_CONFIG2_VARIABLE_ATTRIBUTE
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
EFI_RUNTIME_SERVICES * gRT
#define ASSERT(x)
Definition coder.h:55
EFI_IP4_CONFIG2_DATA_TYPE DataType
IP4_CONFIG2_DATA_RECORD DataRecord[]