]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c
NetworkPkg: Clean up source files
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDhcp4.c
1 /** @file
2 Functions implementation related with DHCPv4 for UefiPxeBc Driver.
3
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The 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 #include "PxeBcImpl.h"
17
18 //
19 // This is a map from the interested DHCP4 option tags' index to the tag value.
20 //
21 UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] = {
22 DHCP4_TAG_BOOTFILE_LEN,
23 DHCP4_TAG_VENDOR,
24 DHCP4_TAG_OVERLOAD,
25 DHCP4_TAG_MSG_TYPE,
26 DHCP4_TAG_SERVER_ID,
27 DHCP4_TAG_VENDOR_CLASS_ID,
28 DHCP4_TAG_BOOTFILE
29 };
30
31 //
32 // There are 4 times retries with the value of 4, 8, 16 and 32, refers to PXE2.1 spec.
33 //
34 UINT32 mPxeDhcpTimeout[4] = {4, 8, 16, 32};
35
36
37 /**
38 Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.
39
40 @param[in] Buffer Pointer to the option buffer.
41 @param[in] Length Length of the option buffer.
42 @param[in] OptTag Tag of the required option.
43
44 @retval NULL Failed to find the required option.
45 @retval Others The position of the required option.
46
47 **/
48 EFI_DHCP4_PACKET_OPTION *
49 PxeBcParseDhcp4Options (
50 IN UINT8 *Buffer,
51 IN UINT32 Length,
52 IN UINT8 OptTag
53 )
54 {
55 EFI_DHCP4_PACKET_OPTION *Option;
56 UINT32 Offset;
57
58 Option = (EFI_DHCP4_PACKET_OPTION *) Buffer;
59 Offset = 0;
60
61 while (Offset < Length && Option->OpCode != DHCP4_TAG_EOP) {
62
63 if (Option->OpCode == OptTag) {
64 //
65 // Found the required option.
66 //
67 return Option;
68 }
69
70 //
71 // Skip the current option to the next.
72 //
73 if (Option->OpCode == DHCP4_TAG_PAD) {
74 Offset++;
75 } else {
76 Offset += Option->Length + 2;
77 }
78
79 Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);
80 }
81
82 return NULL;
83 }
84
85
86 /**
87 Parse the PXE vender options and extract the information from them.
88
89 @param[in] Dhcp4Option Pointer to vendor options in buffer.
90 @param[in] VendorOption Pointer to structure to store information in vendor options.
91
92 **/
93 VOID
94 PxeBcParseVendorOptions (
95 IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option,
96 IN PXEBC_VENDOR_OPTION *VendorOption
97 )
98 {
99 UINT32 *BitMap;
100 UINT8 VendorOptionLen;
101 EFI_DHCP4_PACKET_OPTION *PxeOption;
102 UINT8 Offset;
103
104 BitMap = VendorOption->BitMap;
105 VendorOptionLen = Dhcp4Option->Length;
106 PxeOption = (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0];
107 Offset = 0;
108
109 ASSERT (PxeOption != NULL);
110
111 while ((Offset < VendorOptionLen) && (PxeOption->OpCode != DHCP4_TAG_EOP)) {
112 //
113 // Parse all the interesting PXE vendor options one by one.
114 //
115 switch (PxeOption->OpCode) {
116
117 case PXEBC_VENDOR_TAG_MTFTP_IP:
118
119 CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
120 break;
121
122 case PXEBC_VENDOR_TAG_MTFTP_CPORT:
123
124 CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));
125 break;
126
127 case PXEBC_VENDOR_TAG_MTFTP_SPORT:
128
129 CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));
130 break;
131
132 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:
133
134 VendorOption->MtftpTimeout = *PxeOption->Data;
135 break;
136
137 case PXEBC_VENDOR_TAG_MTFTP_DELAY:
138
139 VendorOption->MtftpDelay = *PxeOption->Data;
140 break;
141
142 case PXEBC_VENDOR_TAG_DISCOVER_CTRL:
143
144 VendorOption->DiscoverCtrl = *PxeOption->Data;
145 break;
146
147 case PXEBC_VENDOR_TAG_DISCOVER_MCAST:
148
149 CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
150 break;
151
152 case PXEBC_VENDOR_TAG_BOOT_SERVERS:
153
154 VendorOption->BootSvrLen = PxeOption->Length;
155 VendorOption->BootSvr = (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Data;
156 break;
157
158 case PXEBC_VENDOR_TAG_BOOT_MENU:
159
160 VendorOption->BootMenuLen = PxeOption->Length;
161 VendorOption->BootMenu = (PXEBC_BOOT_MENU_ENTRY *) PxeOption->Data;
162 break;
163
164 case PXEBC_VENDOR_TAG_MENU_PROMPT:
165
166 VendorOption->MenuPromptLen = PxeOption->Length;
167 VendorOption->MenuPrompt = (PXEBC_MENU_PROMPT *) PxeOption->Data;
168 break;
169
170 case PXEBC_VENDOR_TAG_MCAST_ALLOC:
171
172 CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
173 CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));
174 CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));
175 break;
176
177 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:
178
179 VendorOption->CredTypeLen = PxeOption->Length;
180 VendorOption->CredType = (UINT32 *) PxeOption->Data;
181 break;
182
183 case PXEBC_VENDOR_TAG_BOOT_ITEM:
184
185 CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));
186 CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));
187 break;
188
189 default:
190 //
191 // Not interesting PXE vendor options.
192 //
193 break;
194 }
195
196 //
197 // Set the bit map for the special PXE options.
198 //
199 SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);
200
201 //
202 // Continue to the next option.
203 //
204 if (PxeOption->OpCode == DHCP4_TAG_PAD) {
205 Offset++;
206 } else {
207 Offset = (UINT8) (Offset + PxeOption->Length + 2);
208 }
209
210 PxeOption = (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset);
211 }
212 }
213
214
215 /**
216 Build the options buffer for the DHCPv4 request packet.
217
218 @param[in] Private Pointer to PxeBc private data.
219 @param[out] OptList Pointer to the option pointer array.
220 @param[in] Buffer Pointer to the buffer to contain the option list.
221 @param[in] NeedMsgType If TRUE, it is necessary to include the Msg type option.
222 Otherwise, it is not necessary.
223
224 @return Index The count of the built-in options.
225
226 **/
227 UINT32
228 PxeBcBuildDhcp4Options (
229 IN PXEBC_PRIVATE_DATA *Private,
230 OUT EFI_DHCP4_PACKET_OPTION **OptList,
231 IN UINT8 *Buffer,
232 IN BOOLEAN NeedMsgType
233 )
234 {
235 UINT32 Index;
236 PXEBC_DHCP4_OPTION_ENTRY OptEnt;
237 UINT16 Value;
238
239 Index = 0;
240 OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Buffer;
241
242 if (NeedMsgType) {
243 //
244 // Append message type.
245 //
246 OptList[Index]->OpCode = DHCP4_TAG_MSG_TYPE;
247 OptList[Index]->Length = 1;
248 OptEnt.Mesg = (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]->Data;
249 OptEnt.Mesg->Type = PXEBC_DHCP4_MSG_TYPE_REQUEST;
250 Index++;
251 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
252
253 //
254 // Append max message size.
255 //
256 OptList[Index]->OpCode = DHCP4_TAG_MAXMSG;
257 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);
258 OptEnt.MaxMesgSize = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptList[Index]->Data;
259 Value = NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE);
260 CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));
261 Index++;
262 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
263 }
264
265 //
266 // Append parameter request list option.
267 //
268 OptList[Index]->OpCode = DHCP4_TAG_PARA_LIST;
269 OptList[Index]->Length = 35;
270 OptEnt.Para = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data;
271 OptEnt.Para->ParaList[0] = DHCP4_TAG_NETMASK;
272 OptEnt.Para->ParaList[1] = DHCP4_TAG_TIME_OFFSET;
273 OptEnt.Para->ParaList[2] = DHCP4_TAG_ROUTER;
274 OptEnt.Para->ParaList[3] = DHCP4_TAG_TIME_SERVER;
275 OptEnt.Para->ParaList[4] = DHCP4_TAG_NAME_SERVER;
276 OptEnt.Para->ParaList[5] = DHCP4_TAG_DNS_SERVER;
277 OptEnt.Para->ParaList[6] = DHCP4_TAG_HOSTNAME;
278 OptEnt.Para->ParaList[7] = DHCP4_TAG_BOOTFILE_LEN;
279 OptEnt.Para->ParaList[8] = DHCP4_TAG_DOMAINNAME;
280 OptEnt.Para->ParaList[9] = DHCP4_TAG_ROOTPATH;
281 OptEnt.Para->ParaList[10] = DHCP4_TAG_EXTEND_PATH;
282 OptEnt.Para->ParaList[11] = DHCP4_TAG_EMTU;
283 OptEnt.Para->ParaList[12] = DHCP4_TAG_TTL;
284 OptEnt.Para->ParaList[13] = DHCP4_TAG_BROADCAST;
285 OptEnt.Para->ParaList[14] = DHCP4_TAG_NIS_DOMAIN;
286 OptEnt.Para->ParaList[15] = DHCP4_TAG_NIS_SERVER;
287 OptEnt.Para->ParaList[16] = DHCP4_TAG_NTP_SERVER;
288 OptEnt.Para->ParaList[17] = DHCP4_TAG_VENDOR;
289 OptEnt.Para->ParaList[18] = DHCP4_TAG_REQUEST_IP;
290 OptEnt.Para->ParaList[19] = DHCP4_TAG_LEASE;
291 OptEnt.Para->ParaList[20] = DHCP4_TAG_SERVER_ID;
292 OptEnt.Para->ParaList[21] = DHCP4_TAG_T1;
293 OptEnt.Para->ParaList[22] = DHCP4_TAG_T2;
294 OptEnt.Para->ParaList[23] = DHCP4_TAG_VENDOR_CLASS_ID;
295 OptEnt.Para->ParaList[24] = DHCP4_TAG_TFTP;
296 OptEnt.Para->ParaList[25] = DHCP4_TAG_BOOTFILE;
297 OptEnt.Para->ParaList[26] = DHCP4_TAG_UUID;
298 OptEnt.Para->ParaList[27] = 0x80;
299 OptEnt.Para->ParaList[28] = 0x81;
300 OptEnt.Para->ParaList[29] = 0x82;
301 OptEnt.Para->ParaList[30] = 0x83;
302 OptEnt.Para->ParaList[31] = 0x84;
303 OptEnt.Para->ParaList[32] = 0x85;
304 OptEnt.Para->ParaList[33] = 0x86;
305 OptEnt.Para->ParaList[34] = 0x87;
306 Index++;
307 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
308
309 //
310 // Append UUID/Guid-based client identifier option
311 //
312 OptList[Index]->OpCode = DHCP4_TAG_UUID;
313 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UUID);
314 OptEnt.Uuid = (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->Data;
315 OptEnt.Uuid->Type = 0;
316 Index++;
317 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
318
319 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) {
320 //
321 // Zero the Guid to indicate NOT programable if failed to get system Guid.
322 //
323 DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));
324 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));
325 }
326
327 //
328 // Append client network device interface option
329 //
330 OptList[Index]->OpCode = DHCP4_TAG_UNDI;
331 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UNDI);
332 OptEnt.Undi = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data;
333
334 if (Private->Nii != NULL) {
335 OptEnt.Undi->Type = Private->Nii->Type;
336 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;
337 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;
338 } else {
339 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;
340 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;
341 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;
342 }
343
344 Index++;
345 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
346
347 //
348 // Append client system architecture option
349 //
350 OptList[Index]->OpCode = DHCP4_TAG_ARCH;
351 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_ARCH);
352 OptEnt.Arch = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data;
353 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);
354 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
355 Index++;
356 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
357
358 //
359 // Append vendor class identify option
360 //
361 OptList[Index]->OpCode = DHCP4_TAG_VENDOR_CLASS_ID;
362 OptList[Index]->Length = (UINT8) sizeof (PXEBC_DHCP4_OPTION_CLID);
363 OptEnt.Clid = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data;
364 CopyMem (
365 OptEnt.Clid,
366 DEFAULT_CLASS_ID_DATA,
367 sizeof (PXEBC_DHCP4_OPTION_CLID)
368 );
369 PxeBcUintnToAscDecWithFormat (
370 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,
371 OptEnt.Clid->ArchitectureType,
372 sizeof (OptEnt.Clid->ArchitectureType)
373 );
374
375 if (Private->Nii != NULL) {
376 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));
377 PxeBcUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));
378 PxeBcUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));
379 }
380
381 Index++;
382
383 return Index;
384 }
385
386
387 /**
388 Create a template DHCPv4 packet as a seed.
389
390 @param[out] Seed Pointer to the seed packet.
391 @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL.
392
393 **/
394 VOID
395 PxeBcSeedDhcp4Packet (
396 OUT EFI_DHCP4_PACKET *Seed,
397 IN EFI_UDP4_PROTOCOL *Udp4
398 )
399 {
400 EFI_SIMPLE_NETWORK_MODE Mode;
401 EFI_DHCP4_HEADER *Header;
402
403 //
404 // Get IfType and HwAddressSize from SNP mode data.
405 //
406 Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode);
407
408 Seed->Size = sizeof (EFI_DHCP4_PACKET);
409 Seed->Length = sizeof (Seed->Dhcp4);
410 Header = &Seed->Dhcp4.Header;
411 ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
412 Header->OpCode = PXEBC_DHCP4_OPCODE_REQUEST;
413 Header->HwType = Mode.IfType;
414 Header->HwAddrLen = (UINT8) Mode.HwAddressSize;
415 CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);
416
417 Seed->Dhcp4.Magik = PXEBC_DHCP4_MAGIC;
418 Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;
419 }
420
421
422 /**
423 Cache the DHCPv4 packet.
424
425 @param[in] Dst Pointer to the cache buffer for DHCPv4 packet.
426 @param[in] Src Pointer to the DHCPv4 packet to be cached.
427
428 @retval EFI_SUCCESS Packet is copied.
429 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
430
431 **/
432 EFI_STATUS
433 PxeBcCacheDhcp4Packet (
434 IN EFI_DHCP4_PACKET *Dst,
435 IN EFI_DHCP4_PACKET *Src
436 )
437 {
438 if (Dst->Size < Src->Length) {
439 return EFI_BUFFER_TOO_SMALL;
440 }
441
442 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);
443 Dst->Length = Src->Length;
444
445 return EFI_SUCCESS;
446 }
447
448
449 /**
450 Parse the cached DHCPv4 packet, including all the options.
451
452 @param[in] Cache4 Pointer to cached DHCPv4 packet.
453
454 @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully.
455 @retval EFI_DEVICE_ERROR Failed to parse and invalid packet.
456
457 **/
458 EFI_STATUS
459 PxeBcParseDhcp4Packet (
460 IN PXEBC_DHCP4_PACKET_CACHE *Cache4
461 )
462 {
463 EFI_DHCP4_PACKET *Offer;
464 EFI_DHCP4_PACKET_OPTION **Options;
465 EFI_DHCP4_PACKET_OPTION *Option;
466 PXEBC_OFFER_TYPE OfferType;
467 UINTN Index;
468 BOOLEAN IsProxyOffer;
469 BOOLEAN IsPxeOffer;
470 UINT8 *Ptr8;
471 BOOLEAN FileFieldOverloaded;
472
473 IsProxyOffer = FALSE;
474 IsPxeOffer = FALSE;
475 FileFieldOverloaded = FALSE;
476
477 ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));
478 ZeroMem (&Cache4->VendorOpt, sizeof (Cache4->VendorOpt));
479
480 Offer = &Cache4->Packet.Offer;
481 Options = Cache4->OptList;
482
483 //
484 // Parse DHCPv4 options in this offer, and store the pointers.
485 // First, try to parse DHCPv4 options from the DHCP optional parameters field.
486 //
487 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
488 Options[Index] = PxeBcParseDhcp4Options (
489 Offer->Dhcp4.Option,
490 GET_OPTION_BUFFER_LEN (Offer),
491 mInterestedDhcp4Tags[Index]
492 );
493 }
494 //
495 // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
496 // If yes, try to parse options from the BootFileName field, then ServerName field.
497 //
498 Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];
499 if (Option != NULL) {
500 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) {
501 FileFieldOverloaded = TRUE;
502 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
503 if (Options[Index] == NULL) {
504 Options[Index] = PxeBcParseDhcp4Options (
505 (UINT8 *) Offer->Dhcp4.Header.BootFileName,
506 sizeof (Offer->Dhcp4.Header.BootFileName),
507 mInterestedDhcp4Tags[Index]
508 );
509 }
510 }
511 }
512 if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) != 0) {
513 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
514 if (Options[Index] == NULL) {
515 Options[Index] = PxeBcParseDhcp4Options (
516 (UINT8 *) Offer->Dhcp4.Header.ServerName,
517 sizeof (Offer->Dhcp4.Header.ServerName),
518 mInterestedDhcp4Tags[Index]
519 );
520 }
521 }
522 }
523 }
524
525 //
526 // The offer with zero "yiaddr" is a proxy offer.
527 //
528 if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {
529 IsProxyOffer = TRUE;
530 }
531
532 //
533 // The offer with "PXEClient" is a PXE offer.
534 //
535 Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];
536 if ((Option != NULL) && (Option->Length >= 9) &&
537 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {
538 IsPxeOffer = TRUE;
539 }
540
541 //
542 // Parse PXE vendor options in this offer, and store the contents/pointers.
543 //
544 Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR];
545 if (IsPxeOffer && Option != NULL) {
546 PxeBcParseVendorOptions (Option, &Cache4->VendorOpt);
547 }
548
549 //
550 // Parse PXE boot file name:
551 // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.
552 // Otherwise, read from boot file field in DHCP header.
553 //
554 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
555 //
556 // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
557 // terminated string. So force to append null terminated character at the end of string.
558 //
559 Ptr8 = (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];
560 Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length;
561 if (*(Ptr8 - 1) != '\0') {
562 *Ptr8 = '\0';
563 }
564 } else if (!FileFieldOverloaded && Offer->Dhcp4.Header.BootFileName[0] != 0) {
565 //
566 // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.
567 // Do not count dhcp option header here, or else will destroy the serverhostname.
568 //
569 Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)
570 (&Offer->Dhcp4.Header.BootFileName[0] -
571 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));
572
573 }
574
575 //
576 // Determine offer type of the DHCPv4 packet.
577 //
578 Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];
579 if (Option == NULL || Option->Data[0] == 0) {
580 //
581 // It's a Bootp offer.
582 //
583 OfferType = PxeOfferTypeBootp;
584
585 Option = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];
586 if (Option == NULL) {
587 //
588 // If the Bootp offer without bootfilename, discard it.
589 //
590 return EFI_DEVICE_ERROR;
591 }
592 } else {
593
594 if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
595 //
596 // It's a PXE10 offer with PXEClient and discover vendor option.
597 //
598 OfferType = IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDhcpPxe10;
599 } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
600 //
601 // It's a WFM11a offer with PXEClient and mtftp vendor option.
602 // But multi-cast download is not supported currently, so discard it.
603 //
604 return EFI_DEVICE_ERROR;
605 } else if (IsPxeOffer) {
606 //
607 // It's a BINL offer only with PXEClient.
608 //
609 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;
610 } else {
611 //
612 // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.
613 //
614 OfferType = PxeOfferTypeDhcpOnly;
615 }
616 }
617
618 Cache4->OfferType = OfferType;
619
620 return EFI_SUCCESS;
621 }
622
623
624 /**
625 Cache the DHCPv4 ack packet, and parse it on demand.
626
627 @param[in] Private Pointer to PxeBc private data.
628 @param[in] Ack Pointer to the DHCPv4 ack packet.
629 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
630
631 @retval EFI_SUCCESS Cache and parse the packet successfully.
632 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
633
634 **/
635 EFI_STATUS
636 PxeBcCopyDhcp4Ack (
637 IN PXEBC_PRIVATE_DATA *Private,
638 IN EFI_DHCP4_PACKET *Ack,
639 IN BOOLEAN Verified
640 )
641 {
642 EFI_PXE_BASE_CODE_MODE *Mode;
643 EFI_STATUS Status;
644
645 Mode = Private->PxeBc.Mode;
646
647 Status = PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack);
648 if (EFI_ERROR (Status)) {
649 return Status;
650 }
651
652 if (Verified) {
653 //
654 // Parse the ack packet and store it into mode data if needed.
655 //
656 PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4);
657 CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length);
658 Mode->DhcpAckReceived = TRUE;
659 }
660
661 return EFI_SUCCESS;
662 }
663
664
665 /**
666 Cache the DHCPv4 proxy offer packet according to the received order.
667
668 @param[in] Private Pointer to PxeBc private data.
669 @param[in] OfferIndex The received order of offer packets.
670
671 @retval EFI_SUCCESS Cache and parse the packet successfully.
672 @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet.
673
674 **/
675 EFI_STATUS
676 PxeBcCopyProxyOffer (
677 IN PXEBC_PRIVATE_DATA *Private,
678 IN UINT32 OfferIndex
679 )
680 {
681 EFI_PXE_BASE_CODE_MODE *Mode;
682 EFI_DHCP4_PACKET *Offer;
683 EFI_STATUS Status;
684
685 ASSERT (OfferIndex < Private->OfferNum);
686 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);
687
688 Mode = Private->PxeBc.Mode;
689 Offer = &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer;
690
691 //
692 // Cache the proxy offer packet and parse it.
693 //
694 Status = PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer);
695 if (EFI_ERROR(Status)) {
696 return Status;
697 }
698
699 PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4);
700
701 //
702 // Store this packet into mode data.
703 //
704 CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length);
705 Mode->ProxyOfferReceived = TRUE;
706
707 return EFI_SUCCESS;
708 }
709
710
711 /**
712 Retry to request bootfile name by the BINL offer.
713
714 @param[in] Private Pointer to PxeBc private data.
715 @param[in] Index The received order of offer packets.
716
717 @retval EFI_SUCCESS Successfully retried to request bootfile name.
718 @retval EFI_DEVICE_ERROR Failed to retry bootfile name.
719
720 **/
721 EFI_STATUS
722 PxeBcRetryBinlOffer (
723 IN PXEBC_PRIVATE_DATA *Private,
724 IN UINT32 Index
725 )
726 {
727 EFI_DHCP4_PACKET *Offer;
728 EFI_IP_ADDRESS ServerIp;
729 EFI_STATUS Status;
730 PXEBC_DHCP4_PACKET_CACHE *Cache4;
731 EFI_DHCP4_PACKET *Reply;
732
733 ASSERT (Index < PXEBC_OFFER_MAX_NUM);
734 ASSERT (Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpBinl ||
735 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeProxyBinl);
736
737 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
738
739 //
740 // Prefer to siaddr in header as next server address. If it's zero, then use option 54.
741 //
742 if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) {
743 CopyMem (
744 &ServerIp.Addr[0],
745 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
746 sizeof (EFI_IPv4_ADDRESS)
747 );
748 } else {
749 CopyMem (
750 &ServerIp.Addr[0],
751 &Offer->Dhcp4.Header.ServerAddr,
752 sizeof (EFI_IPv4_ADDRESS)
753 );
754 }
755
756 Private->IsDoDiscover = FALSE;
757 Cache4 = &Private->ProxyOffer.Dhcp4;
758 Reply = &Cache4->Packet.Offer;
759
760 //
761 // Send another request packet for bootfile name.
762 //
763 Status = PxeBcDhcp4Discover (
764 Private,
765 0,
766 NULL,
767 FALSE,
768 &ServerIp,
769 0,
770 NULL
771 );
772 if (EFI_ERROR (Status)) {
773 return Status;
774 }
775
776 //
777 // Parse the reply for the last request packet.
778 //
779 Status = PxeBcParseDhcp4Packet (Cache4);
780 if (EFI_ERROR (Status)) {
781 return Status;
782 }
783
784 if (Cache4->OfferType != PxeOfferTypeProxyPxe10 &&
785 Cache4->OfferType != PxeOfferTypeProxyWfm11a &&
786 Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
787 //
788 // This BINL ack doesn't have discovery option set or multicast option set
789 // or bootfile name specified.
790 //
791 return EFI_DEVICE_ERROR;
792 }
793
794 //
795 // Store the reply into mode data.
796 //
797 Private->PxeBc.Mode->ProxyOfferReceived = TRUE;
798 CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->Length);
799
800 return EFI_SUCCESS;
801 }
802
803
804 /**
805 Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
806
807 @param[in] Private Pointer to PxeBc private data.
808 @param[in] RcvdOffer Pointer to the received offer packet.
809
810 @retval EFI_SUCCESS Cache and parse the packet successfully.
811 @retval Others Operation failed.
812
813 **/
814 EFI_STATUS
815 PxeBcCacheDhcp4Offer (
816 IN PXEBC_PRIVATE_DATA *Private,
817 IN EFI_DHCP4_PACKET *RcvdOffer
818 )
819 {
820 PXEBC_DHCP4_PACKET_CACHE *Cache4;
821 EFI_DHCP4_PACKET *Offer;
822 PXEBC_OFFER_TYPE OfferType;
823 EFI_STATUS Status;
824
825 ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM);
826 Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;
827 Offer = &Cache4->Packet.Offer;
828
829 //
830 // Cache the content of DHCPv4 packet firstly.
831 //
832 Status = PxeBcCacheDhcp4Packet (Offer, RcvdOffer);
833 if (EFI_ERROR(Status)) {
834 return Status;
835 }
836
837 //
838 // Validate the DHCPv4 packet, and parse the options and offer type.
839 //
840 if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) {
841 return EFI_ABORTED;
842 }
843
844 //
845 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
846 //
847 OfferType = Cache4->OfferType;
848 ASSERT (OfferType < PxeOfferTypeMax);
849
850 if (OfferType == PxeOfferTypeBootp) {
851 //
852 // It's a Bootp offer, only cache the first one, and discard the others.
853 //
854 if (Private->OfferCount[OfferType] == 0) {
855 Private->OfferIndex[OfferType][0] = Private->OfferNum;
856 Private->OfferCount[OfferType] = 1;
857 } else {
858 return EFI_ABORTED;
859 }
860 } else {
861 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);
862 if (IS_PROXY_DHCP_OFFER (Offer)) {
863 //
864 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
865 //
866 Private->IsProxyRecved = TRUE;
867
868 if (OfferType == PxeOfferTypeProxyBinl) {
869 //
870 // Cache all proxy BINL offers.
871 //
872 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
873 Private->OfferCount[OfferType]++;
874 } else if ((OfferType == PxeOfferTypeProxyPxe10 || OfferType == PxeOfferTypeProxyWfm11a) &&
875 Private->OfferCount[OfferType] < 1) {
876 //
877 // Only cache the first PXE10/WFM11a offer, and discard the others.
878 //
879 Private->OfferIndex[OfferType][0] = Private->OfferNum;
880 Private->OfferCount[OfferType] = 1;
881 } else {
882 return EFI_ABORTED;
883 }
884 } else {
885 //
886 // It's a DHCPv4 offer with yiaddr, and cache them all.
887 //
888 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
889 Private->OfferCount[OfferType]++;
890 }
891 }
892
893 Private->OfferNum++;
894
895 return EFI_SUCCESS;
896 }
897
898
899 /**
900 Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.
901
902 @param[in] Private Pointer to PxeBc private data.
903
904 **/
905 VOID
906 PxeBcSelectDhcp4Offer (
907 IN PXEBC_PRIVATE_DATA *Private
908 )
909 {
910 UINT32 Index;
911 UINT32 OfferIndex;
912 EFI_DHCP4_PACKET *Offer;
913
914 Private->SelectIndex = 0;
915
916 if (Private->IsOfferSorted) {
917 //
918 // Select offer by default policy.
919 //
920 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {
921 //
922 // 1. DhcpPxe10 offer
923 //
924 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;
925
926 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {
927 //
928 // 2. DhcpWfm11a offer
929 //
930 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;
931
932 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
933 Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) {
934 //
935 // 3. DhcpOnly offer and ProxyPxe10 offer.
936 //
937 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
938 Private->SelectProxyType = PxeOfferTypeProxyPxe10;
939
940 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
941 Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) {
942 //
943 // 4. DhcpOnly offer and ProxyWfm11a offer.
944 //
945 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
946 Private->SelectProxyType = PxeOfferTypeProxyWfm11a;
947
948 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {
949 //
950 // 5. DhcpBinl offer.
951 //
952 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;
953
954 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
955 Private->OfferCount[PxeOfferTypeProxyBinl] > 0) {
956 //
957 // 6. DhcpOnly offer and ProxyBinl offer.
958 //
959 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
960 Private->SelectProxyType = PxeOfferTypeProxyBinl;
961
962 } else {
963 //
964 // 7. DhcpOnly offer with bootfilename.
965 //
966 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {
967 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];
968 if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
969 Private->SelectIndex = OfferIndex + 1;
970 break;
971 }
972 }
973 //
974 // 8. Bootp offer with bootfilename.
975 //
976 OfferIndex = Private->OfferIndex[PxeOfferTypeBootp][0];
977 if (Private->SelectIndex == 0 &&
978 Private->OfferCount[PxeOfferTypeBootp] > 0 &&
979 Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
980 Private->SelectIndex = OfferIndex + 1;
981 }
982 }
983 } else {
984 //
985 // Select offer by received order.
986 //
987 for (Index = 0; Index < Private->OfferNum; Index++) {
988
989 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
990
991 if (IS_PROXY_DHCP_OFFER (Offer)) {
992 //
993 // Skip proxy offers
994 //
995 continue;
996 }
997
998 if (!Private->IsProxyRecved &&
999 Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpOnly &&
1000 Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
1001 //
1002 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1003 //
1004 continue;
1005 }
1006
1007 //
1008 // Record the index of the select offer.
1009 //
1010 Private->SelectIndex = Index + 1;
1011 break;
1012 }
1013 }
1014 }
1015
1016
1017 /**
1018 Handle the DHCPv4 offer packet.
1019
1020 @param[in] Private Pointer to PxeBc private data.
1021
1022 @retval EFI_SUCCESS Handled the DHCPv4 offer packet successfully.
1023 @retval EFI_NO_RESPONSE No response to the following request packet.
1024 @retval EFI_NOT_FOUND No boot filename received.
1025 @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.
1026
1027 **/
1028 EFI_STATUS
1029 PxeBcHandleDhcp4Offer (
1030 IN PXEBC_PRIVATE_DATA *Private
1031 )
1032 {
1033 PXEBC_DHCP4_PACKET_CACHE *Cache4;
1034 EFI_DHCP4_PACKET_OPTION **Options;
1035 UINT32 Index;
1036 EFI_DHCP4_PACKET *Offer;
1037 PXEBC_OFFER_TYPE OfferType;
1038 UINT32 ProxyIndex;
1039 UINT32 SelectIndex;
1040 EFI_STATUS Status;
1041 EFI_PXE_BASE_CODE_MODE *Mode;
1042 EFI_DHCP4_PACKET *Ack;
1043
1044 ASSERT (Private->SelectIndex > 0);
1045 SelectIndex = (UINT32) (Private->SelectIndex - 1);
1046 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);
1047 Cache4 = &Private->OfferBuffer[SelectIndex].Dhcp4;
1048 Options = Cache4->OptList;
1049 Status = EFI_SUCCESS;
1050
1051 if (Cache4->OfferType == PxeOfferTypeDhcpBinl) {
1052 //
1053 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1054 //
1055 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) {
1056 Status = EFI_NO_RESPONSE;
1057 }
1058 } else if (Cache4->OfferType == PxeOfferTypeDhcpOnly) {
1059
1060 if (Private->IsProxyRecved) {
1061 //
1062 // DhcpOnly offer is selected, so need try to request bootfile name.
1063 //
1064 ProxyIndex = 0;
1065 if (Private->IsOfferSorted) {
1066 //
1067 // The proxy offer should be determined if select by default policy.
1068 // IsOfferSorted means all offers are labeled by OfferIndex.
1069 //
1070 ASSERT (Private->SelectProxyType < PxeOfferTypeMax);
1071 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);
1072
1073 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {
1074 //
1075 // Try all the cached ProxyBinl offer one by one to request bootfile name.
1076 //
1077 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {
1078 ASSERT (Index < PXEBC_OFFER_MAX_NUM);
1079 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];
1080 if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) {
1081 break;
1082 }
1083 }
1084 if (Index == Private->OfferCount[Private->SelectProxyType]) {
1085 Status = EFI_NO_RESPONSE;
1086 }
1087 } else {
1088 //
1089 // For other proxy offers, only one is buffered.
1090 //
1091 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
1092 }
1093 } else {
1094 //
1095 // The proxy offer should not be determined if select by received order.
1096 //
1097 Status = EFI_NO_RESPONSE;
1098
1099 for (Index = 0; Index < Private->OfferNum; Index++) {
1100 ASSERT (Index < PXEBC_OFFER_MAX_NUM);
1101 Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
1102 OfferType = Private->OfferBuffer[Index].Dhcp4.OfferType;
1103 if (!IS_PROXY_DHCP_OFFER (Offer)) {
1104 //
1105 // Skip non proxy DHCPv4 offers.
1106 //
1107 continue;
1108 }
1109
1110 if (OfferType == PxeOfferTypeProxyBinl) {
1111 //
1112 // Try all the cached ProxyBinl offer one by one to request bootfile name.
1113 //
1114 if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) {
1115 continue;
1116 }
1117 }
1118
1119 Private->SelectProxyType = OfferType;
1120 ProxyIndex = Index;
1121 Status = EFI_SUCCESS;
1122 break;
1123 }
1124 }
1125
1126 if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) {
1127 //
1128 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1129 //
1130 Status = PxeBcCopyProxyOffer (Private, ProxyIndex);
1131 }
1132 } else {
1133 //
1134 // Othewise, the bootfile name must be included in DhcpOnly offer.
1135 //
1136 if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
1137 Status = EFI_NOT_FOUND;
1138 }
1139 }
1140 }
1141
1142 if (!EFI_ERROR (Status)) {
1143 //
1144 // All PXE boot information is ready by now.
1145 //
1146 Mode = Private->PxeBc.Mode;
1147 Offer = &Cache4->Packet.Offer;
1148 Ack = &Private->DhcpAck.Dhcp4.Packet.Ack;
1149 if (Cache4->OfferType == PxeOfferTypeBootp) {
1150 //
1151 // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply
1152 // should be taken as ack.
1153 //
1154 Ack = Offer;
1155 }
1156
1157 Status = PxeBcCopyDhcp4Ack (Private, Ack, TRUE);
1158 if (EFI_ERROR (Status)) {
1159 return Status;
1160 }
1161 Mode->DhcpDiscoverValid = TRUE;
1162 }
1163
1164 return Status;
1165 }
1166
1167
1168 /**
1169 EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
1170 to intercept events that occurred in the configuration process.
1171
1172 @param[in] This Pointer to the EFI DHCPv4 Protocol.
1173 @param[in] Context Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
1174 @param[in] CurrentState The current operational state of the EFI DHCPv4 Protocol driver.
1175 @param[in] Dhcp4Event The event that occurs in the current state, which usually means a
1176 state transition.
1177 @param[in] Packet The DHCPv4 packet that is going to be sent or already received.
1178 @param[out] NewPacket The packet that is used to replace the above Packet.
1179
1180 @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
1181 @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
1182 driver will continue to wait for more DHCPOFFER packets until the
1183 retry timeout expires.
1184 @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process
1185 and return to the Dhcp4Init or Dhcp4InitReboot state.
1186
1187 **/
1188 EFI_STATUS
1189 EFIAPI
1190 PxeBcDhcp4CallBack (
1191 IN EFI_DHCP4_PROTOCOL *This,
1192 IN VOID *Context,
1193 IN EFI_DHCP4_STATE CurrentState,
1194 IN EFI_DHCP4_EVENT Dhcp4Event,
1195 IN EFI_DHCP4_PACKET *Packet OPTIONAL,
1196 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL
1197 )
1198 {
1199 PXEBC_PRIVATE_DATA *Private;
1200 EFI_PXE_BASE_CODE_MODE *Mode;
1201 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;
1202 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;
1203 UINT16 Value;
1204 EFI_STATUS Status;
1205 BOOLEAN Received;
1206
1207 if ((Dhcp4Event != Dhcp4RcvdOffer) &&
1208 (Dhcp4Event != Dhcp4SelectOffer) &&
1209 (Dhcp4Event != Dhcp4SendDiscover) &&
1210 (Dhcp4Event != Dhcp4RcvdAck)) {
1211 return EFI_SUCCESS;
1212 }
1213
1214 ASSERT (Packet != NULL);
1215
1216 Private = (PXEBC_PRIVATE_DATA *) Context;
1217 Mode = Private->PxeBc.Mode;
1218 Callback = Private->PxeBcCallback;
1219
1220 //
1221 // Override the Maximum DHCP Message Size.
1222 //
1223 MaxMsgSize = PxeBcParseDhcp4Options (
1224 Packet->Dhcp4.Option,
1225 GET_OPTION_BUFFER_LEN (Packet),
1226 DHCP4_TAG_MAXMSG
1227 );
1228 if (MaxMsgSize != NULL) {
1229 Value = HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE);
1230 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));
1231 }
1232
1233 //
1234 // Callback to user if any packets sent or received.
1235 //
1236 if (Dhcp4Event != Dhcp4SelectOffer && Callback != NULL) {
1237 Received = (BOOLEAN) (Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);
1238 Status = Callback->Callback (
1239 Callback,
1240 Private->Function,
1241 Received,
1242 Packet->Length,
1243 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4
1244 );
1245 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
1246 return EFI_ABORTED;
1247 }
1248 }
1249
1250 Status = EFI_SUCCESS;
1251
1252 switch (Dhcp4Event) {
1253
1254 case Dhcp4SendDiscover:
1255 if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
1256 //
1257 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1258 //
1259 Status = EFI_ABORTED;
1260 break;
1261 }
1262
1263 //
1264 // Cache the DHCPv4 discover packet to mode data directly.
1265 // It need to check SendGuid as well as Dhcp4SendRequest.
1266 //
1267 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length);
1268
1269 case Dhcp4SendRequest:
1270 if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
1271 //
1272 // If the to be sent packet exceeds the maximum length, abort the DHCP process.
1273 //
1274 Status = EFI_ABORTED;
1275 break;
1276 }
1277
1278 if (Mode->SendGUID) {
1279 //
1280 // Send the system Guid instead of the MAC address as the hardware address if required.
1281 //
1282 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Packet->Dhcp4.Header.ClientHwAddr))) {
1283 //
1284 // Zero the Guid to indicate NOT programable if failed to get system Guid.
1285 //
1286 DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));
1287 ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
1288 }
1289 Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID);
1290 }
1291 break;
1292
1293 case Dhcp4RcvdOffer:
1294 Status = EFI_NOT_READY;
1295 if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
1296 //
1297 // Ignore the incoming packets which exceed the maximum length.
1298 //
1299 break;
1300 }
1301 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {
1302 //
1303 // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
1304 // the OfferIndex and OfferCount.
1305 // If error happens, just ignore this packet and continue to wait more offer.
1306 //
1307 PxeBcCacheDhcp4Offer (Private, Packet);
1308 }
1309 break;
1310
1311 case Dhcp4SelectOffer:
1312 ASSERT (NewPacket != NULL);
1313
1314 //
1315 // Select offer by the default policy or by order, and record the SelectIndex
1316 // and SelectProxyType.
1317 //
1318 PxeBcSelectDhcp4Offer (Private);
1319
1320 if (Private->SelectIndex == 0) {
1321 Status = EFI_ABORTED;
1322 } else {
1323 *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;
1324 }
1325 break;
1326
1327 case Dhcp4RcvdAck:
1328 //
1329 // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data
1330 // without verification.
1331 //
1332 ASSERT (Private->SelectIndex != 0);
1333
1334 Status = PxeBcCopyDhcp4Ack (Private, Packet, FALSE);
1335 if (EFI_ERROR (Status)) {
1336 Status = EFI_ABORTED;
1337 }
1338 break;
1339
1340 default:
1341 break;
1342 }
1343
1344 return Status;
1345 }
1346
1347
1348 /**
1349 Build and send out the request packet for the bootfile, and parse the reply.
1350
1351 @param[in] Private Pointer to PxeBc private data.
1352 @param[in] Type PxeBc option boot item type.
1353 @param[in] Layer Pointer to option boot item layer.
1354 @param[in] UseBis Use BIS or not.
1355 @param[in] DestIp Pointer to the server address.
1356 @param[in] IpCount The total count of the server address.
1357 @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
1358
1359 @retval EFI_SUCCESS Successfully discovered boot file.
1360 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
1361 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1362 @retval Others Failed to discover boot file.
1363
1364 **/
1365 EFI_STATUS
1366 PxeBcDhcp4Discover (
1367 IN PXEBC_PRIVATE_DATA *Private,
1368 IN UINT16 Type,
1369 IN UINT16 *Layer,
1370 IN BOOLEAN UseBis,
1371 IN EFI_IP_ADDRESS *DestIp,
1372 IN UINT16 IpCount,
1373 IN EFI_PXE_BASE_CODE_SRVLIST *SrvList
1374 )
1375 {
1376 EFI_PXE_BASE_CODE_UDP_PORT Sport;
1377 EFI_PXE_BASE_CODE_MODE *Mode;
1378 EFI_DHCP4_PROTOCOL *Dhcp4;
1379 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;
1380 BOOLEAN IsBCast;
1381 EFI_STATUS Status;
1382 UINT16 RepIndex;
1383 UINT16 SrvIndex;
1384 UINT16 TryIndex;
1385 EFI_DHCP4_LISTEN_POINT ListenPoint;
1386 EFI_DHCP4_PACKET *Response;
1387 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
1388 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
1389 UINT32 OptCount;
1390 EFI_DHCP4_PACKET_OPTION *PxeOpt;
1391 PXEBC_OPTION_BOOT_ITEM *PxeBootItem;
1392 UINT8 VendorOptLen;
1393 UINT32 Xid;
1394
1395 Mode = Private->PxeBc.Mode;
1396 Dhcp4 = Private->Dhcp4;
1397 Status = EFI_SUCCESS;
1398
1399 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
1400
1401 //
1402 // Use broadcast if destination address not specified.
1403 //
1404 if (DestIp == NULL) {
1405 Sport = PXEBC_DHCP4_S_PORT;
1406 IsBCast = TRUE;
1407 } else {
1408 Sport = PXEBC_BS_DISCOVER_PORT;
1409 IsBCast = FALSE;
1410 }
1411
1412 if (!UseBis && Layer != NULL) {
1413 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
1414 }
1415
1416 //
1417 // Build all the options for the request packet.
1418 //
1419 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE);
1420
1421 if (Private->IsDoDiscover) {
1422 //
1423 // Add vendor option of PXE_BOOT_ITEM
1424 //
1425 VendorOptLen = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);
1426 OptList[OptCount] = AllocateZeroPool (VendorOptLen);
1427 if (OptList[OptCount] == NULL) {
1428 return EFI_OUT_OF_RESOURCES;
1429 }
1430
1431 OptList[OptCount]->OpCode = DHCP4_TAG_VENDOR;
1432 OptList[OptCount]->Length = (UINT8) (VendorOptLen - 2);
1433 PxeOpt = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;
1434 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM;
1435 PxeOpt->Length = (UINT8) sizeof (PXEBC_OPTION_BOOT_ITEM);
1436 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;
1437 PxeBootItem->Type = HTONS (Type);
1438 PxeOpt->Data[PxeOpt->Length] = DHCP4_TAG_EOP;
1439
1440 if (Layer != NULL) {
1441 PxeBootItem->Layer = HTONS (*Layer);
1442 }
1443
1444 OptCount++;
1445 }
1446
1447 //
1448 // Build the request packet with seed packet and option list.
1449 //
1450 Status = Dhcp4->Build (
1451 Dhcp4,
1452 &Private->SeedPacket,
1453 0,
1454 NULL,
1455 OptCount,
1456 OptList,
1457 &Token.Packet
1458 );
1459 //
1460 // Free the vendor option of PXE_BOOT_ITEM.
1461 //
1462 if (Private->IsDoDiscover) {
1463 FreePool (OptList[OptCount - 1]);
1464 }
1465
1466 if (EFI_ERROR (Status)) {
1467 return Status;
1468 }
1469
1470 if (Mode->SendGUID) {
1471 if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Token.Packet->Dhcp4.Header.ClientHwAddr))) {
1472 //
1473 // Zero the Guid to indicate NOT programable if failed to get system Guid.
1474 //
1475 DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));
1476 ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
1477 }
1478 Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID);
1479 }
1480
1481 //
1482 // Set fields of the token for the request packet.
1483 //
1484 Xid = NET_RANDOM (NetRandomInitSeed ());
1485 Token.Packet->Dhcp4.Header.Xid = HTONL (Xid);
1486 Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16) ((IsBCast) ? 0x8000 : 0x0));
1487 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1488
1489 Token.RemotePort = Sport;
1490
1491 if (IsBCast) {
1492 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
1493 } else {
1494 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
1495 }
1496
1497 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
1498
1499 if (!IsBCast) {
1500 Token.ListenPointCount = 1;
1501 Token.ListenPoints = &ListenPoint;
1502 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT;
1503 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));
1504 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));
1505 }
1506
1507 //
1508 // Send out the request packet to discover the bootfile.
1509 //
1510 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {
1511
1512 Token.TimeoutValue = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);
1513 Token.Packet->Dhcp4.Header.Seconds = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));
1514
1515 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
1516 if (Token.Status != EFI_TIMEOUT) {
1517 break;
1518 }
1519 }
1520
1521 if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {
1522 //
1523 // No server response our PXE request
1524 //
1525 Status = EFI_TIMEOUT;
1526 }
1527
1528 if (!EFI_ERROR (Status)) {
1529
1530 RepIndex = 0;
1531 SrvIndex = 0;
1532 Response = Token.ResponseList;
1533 //
1534 // Find the right PXE Reply according to server address.
1535 //
1536 while (RepIndex < Token.ResponseCount) {
1537 if (Response->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
1538 SrvIndex = 0;
1539 RepIndex++;
1540 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);
1541 continue;
1542 }
1543
1544 while (SrvIndex < IpCount) {
1545 if (SrvList[SrvIndex].AcceptAnyResponse) {
1546 break;
1547 }
1548 if ((SrvList[SrvIndex].Type == Type) &&
1549 EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr)) {
1550 break;
1551 }
1552 SrvIndex++;
1553 }
1554
1555 if ((IpCount != SrvIndex) || (IpCount == 0)) {
1556 break;
1557 }
1558
1559 SrvIndex = 0;
1560 RepIndex++;
1561 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);
1562 }
1563
1564 if (RepIndex < Token.ResponseCount) {
1565 //
1566 // Cache the right PXE reply packet here, set valid flag later.
1567 // Especially for PXE discover packet, store it into mode data here.
1568 //
1569 if (Private->IsDoDiscover) {
1570 Status = PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response);
1571 if (EFI_ERROR(Status)) {
1572 goto ON_EXIT;
1573 }
1574 CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length);
1575 } else {
1576 Status = PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response);
1577 if (EFI_ERROR(Status)) {
1578 goto ON_EXIT;
1579 }
1580 }
1581 } else {
1582 //
1583 // Not found the right PXE reply packet.
1584 //
1585 Status = EFI_NOT_FOUND;
1586 }
1587 }
1588 ON_EXIT:
1589
1590 if (Token.ResponseList != NULL) {
1591 FreePool (Token.ResponseList);
1592 }
1593 if (Token.Packet != NULL) {
1594 FreePool (Token.Packet);
1595 }
1596 return Status;
1597 }
1598
1599 /**
1600 Switch the Ip4 policy to static.
1601
1602 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1603
1604 @retval EFI_SUCCESS The policy is already configured to static.
1605 @retval Others Other error as indicated..
1606
1607 **/
1608 EFI_STATUS
1609 PxeBcSetIp4Policy (
1610 IN PXEBC_PRIVATE_DATA *Private
1611 )
1612 {
1613 EFI_STATUS Status;
1614 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
1615 EFI_IP4_CONFIG2_POLICY Policy;
1616 UINTN DataSize;
1617
1618 Ip4Config2 = Private->Ip4Config2;
1619 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
1620 Status = Ip4Config2->GetData (
1621 Ip4Config2,
1622 Ip4Config2DataTypePolicy,
1623 &DataSize,
1624 &Policy
1625 );
1626 if (EFI_ERROR (Status)) {
1627 return Status;
1628 }
1629
1630 if (Policy != Ip4Config2PolicyStatic) {
1631 Policy = Ip4Config2PolicyStatic;
1632 Status= Ip4Config2->SetData (
1633 Ip4Config2,
1634 Ip4Config2DataTypePolicy,
1635 sizeof (EFI_IP4_CONFIG2_POLICY),
1636 &Policy
1637 );
1638 if (EFI_ERROR (Status)) {
1639 return Status;
1640 }
1641 }
1642
1643 return EFI_SUCCESS;
1644 }
1645
1646 /**
1647 Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.
1648
1649 @param[in] Private Pointer to PxeBc private data.
1650 @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL
1651
1652 @retval EFI_SUCCESS The D.O.R.A process successfully finished.
1653 @retval Others Failed to finish the D.O.R.A process.
1654
1655 **/
1656 EFI_STATUS
1657 PxeBcDhcp4Dora (
1658 IN PXEBC_PRIVATE_DATA *Private,
1659 IN EFI_DHCP4_PROTOCOL *Dhcp4
1660 )
1661 {
1662 EFI_PXE_BASE_CODE_MODE *PxeMode;
1663 EFI_DHCP4_CONFIG_DATA Config;
1664 EFI_DHCP4_MODE_DATA Mode;
1665 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
1666 UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
1667 UINT32 OptCount;
1668 EFI_STATUS Status;
1669
1670 ASSERT (Dhcp4 != NULL);
1671
1672 Status = EFI_SUCCESS;
1673 PxeMode = Private->PxeBc.Mode;
1674
1675 //
1676 // Build option list for the request packet.
1677 //
1678 OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE);
1679 ASSERT (OptCount> 0);
1680
1681 ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA));
1682 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1683
1684 Config.OptionCount = OptCount;
1685 Config.OptionList = OptList;
1686 Config.Dhcp4Callback = PxeBcDhcp4CallBack;
1687 Config.CallbackContext = Private;
1688 Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;
1689 Config.DiscoverTimeout = mPxeDhcpTimeout;
1690
1691 //
1692 // Configure the DHCPv4 instance for PXE boot.
1693 //
1694 Status = Dhcp4->Configure (Dhcp4, &Config);
1695 if (EFI_ERROR (Status)) {
1696 goto ON_EXIT;
1697 }
1698
1699 //
1700 // Initialize the record fields for DHCPv4 offer in private data.
1701 //
1702 Private->IsProxyRecved = FALSE;
1703 Private->OfferNum = 0;
1704 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
1705 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
1706
1707 Status = Dhcp4->Start (Dhcp4, NULL);
1708 if (EFI_ERROR (Status)) {
1709 if (Status == EFI_ICMP_ERROR) {
1710 PxeMode->IcmpErrorReceived = TRUE;
1711 }
1712
1713 if (Status == EFI_TIMEOUT && Private->OfferNum > 0) {
1714 Status = EFI_NO_RESPONSE;
1715 }
1716
1717 goto ON_EXIT;
1718 }
1719
1720 //
1721 // Get the acquired IPv4 address and store them.
1722 //
1723 Status = Dhcp4->GetModeData (Dhcp4, &Mode);
1724 if (EFI_ERROR (Status)) {
1725 goto ON_EXIT;
1726 }
1727
1728 ASSERT (Mode.State == Dhcp4Bound);
1729
1730 CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
1731 CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1732 CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
1733 CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
1734 CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
1735
1736 Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask);
1737 if (EFI_ERROR (Status)) {
1738 goto ON_EXIT;
1739 }
1740
1741 //
1742 // Check the selected offer whether BINL retry is needed.
1743 //
1744 Status = PxeBcHandleDhcp4Offer (Private);
1745
1746 AsciiPrint ("\n Station IP address is ");
1747
1748 PxeBcShowIp4Addr (&Private->StationIp.v4);
1749 AsciiPrint ("\n");
1750
1751 ON_EXIT:
1752 if (EFI_ERROR (Status)) {
1753 Dhcp4->Stop (Dhcp4);
1754 Dhcp4->Configure (Dhcp4, NULL);
1755 } else {
1756 ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
1757 Dhcp4->Configure (Dhcp4, &Config);
1758 Private->IsAddressOk = TRUE;
1759 }
1760
1761 return Status;
1762 }