]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/PxeDhcp4Dxe/PxeDhcp4InitSelect.c
Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeDhcp4Dxe / PxeDhcp4InitSelect.c
1 /** @file
2
3 Copyright (c) 2004, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13 PxeDhcp4InitSelect.c
14
15 Abstract:
16
17
18 **/
19
20
21 #include "PxeDhcp4.h"
22
23 #define DebugPrint(x)
24 //
25 // #define DebugPrint(x) Aprint x
26 //
27
28 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
29
30 /**
31
32 **/
33 STATIC
34 INTN
35 offer_verify (
36 IN PXE_DHCP4_PRIVATE_DATA *Private,
37 IN DHCP4_PACKET *tx_pkt,
38 IN DHCP4_PACKET *rx_pkt,
39 IN UINTN rx_pkt_size
40 )
41 {
42 EFI_STATUS EfiStatus;
43 DHCP4_PACKET *tmp;
44 DHCP4_OP *msg_type_op;
45 DHCP4_OP *srvid_op;
46 UINT32 magik;
47
48 //
49 // Verify parameters. Touch unused parameters to keep
50 // compiler happy.
51 //
52 ASSERT (Private);
53 ASSERT (rx_pkt);
54
55 if (Private == NULL || rx_pkt == NULL) {
56 return -2;
57 }
58
59 tx_pkt = tx_pkt;
60 rx_pkt_size = rx_pkt_size;
61
62 //
63 // This may be a BOOTP Reply or DHCP Offer packet.
64 // If there is no DHCP magik number, assume that
65 // this is a BOOTP Reply packet.
66 //
67 magik = htonl (DHCP4_MAGIK_NUMBER);
68
69 while (!CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {
70 //
71 // If there is no DHCP message type option, assume
72 // this is a BOOTP reply packet and cache it.
73 //
74 EfiStatus = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);
75
76 if (EFI_ERROR (EfiStatus)) {
77 break;
78 }
79 //
80 // If there is a DHCP message type option, it must be a
81 // DHCP offer packet
82 //
83 if (msg_type_op->len != 1) {
84 return -1;
85 }
86
87 if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) {
88 return -1;
89 }
90 //
91 // There must be a server identifier option.
92 //
93 EfiStatus = find_opt (
94 rx_pkt,
95 DHCP4_SERVER_IDENTIFIER,
96 0,
97 &srvid_op
98 );
99
100 if (EFI_ERROR (EfiStatus)) {
101 return -1;
102 }
103
104 if (srvid_op->len != 4) {
105 return -1;
106 }
107 //
108 // Good DHCP offer packet.
109 //
110 break;
111 }
112 //
113 // Good DHCP (or BOOTP) packet. Cache it!
114 //
115 EfiStatus = gBS->AllocatePool (
116 EfiBootServicesData,
117 (Private->offers + 1) * sizeof (DHCP4_PACKET),
118 (VOID **) &tmp
119 );
120
121 if (EFI_ERROR (EfiStatus)) {
122 return -2;
123 }
124
125 ASSERT (tmp);
126
127 if (Private->offers != 0) {
128 CopyMem (
129 tmp,
130 Private->offer_list,
131 Private->offers * sizeof (DHCP4_PACKET)
132 );
133
134 gBS->FreePool (Private->offer_list);
135 }
136
137 CopyMem (&tmp[Private->offers++], rx_pkt, sizeof (DHCP4_PACKET));
138
139 Private->offer_list = tmp;
140
141 return 0;
142 }
143
144 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
145
146 /**
147
148 **/
149 STATIC
150 INTN
151 acknak_verify (
152 IN PXE_DHCP4_PRIVATE_DATA *Private,
153 IN DHCP4_PACKET *tx_pkt,
154 IN DHCP4_PACKET *rx_pkt,
155 IN UINTN rx_pkt_size
156 )
157 {
158 EFI_STATUS EfiStatus;
159 DHCP4_OP *msg_type_op;
160 DHCP4_OP *srvid_op;
161 DHCP4_OP *renew_op;
162 DHCP4_OP *rebind_op;
163 DHCP4_OP *lease_time_op;
164 UINT32 magik;
165
166 //
167 // Verify parameters. Touch unused parameters to
168 // keep compiler happy.
169 //
170 ASSERT (Private);
171 ASSERT (rx_pkt);
172
173 if (Private == NULL || rx_pkt == NULL) {
174 return -2;
175 }
176
177 tx_pkt = tx_pkt;
178 rx_pkt_size = rx_pkt_size;
179
180 //
181 // This must be a DHCP Ack message.
182 //
183 magik = htonl (DHCP4_MAGIK_NUMBER);
184
185 if (CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {
186 return -1;
187 }
188
189 EfiStatus = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);
190
191 if (EFI_ERROR (EfiStatus)) {
192 return -1;
193 }
194
195 if (msg_type_op->len != 1) {
196 return -1;
197 }
198
199 if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_ACK) {
200 return -1;
201 }
202 //
203 // There must be a server identifier.
204 //
205 EfiStatus = find_opt (rx_pkt, DHCP4_SERVER_IDENTIFIER, 0, &srvid_op);
206
207 if (EFI_ERROR (EfiStatus)) {
208 return -1;
209 }
210
211 if (srvid_op->len != 4) {
212 return -1;
213 }
214 //
215 // There should be a renewal time.
216 // If there is not, we will default to the 7/8 of the rebinding time.
217 //
218 EfiStatus = find_opt (rx_pkt, DHCP4_RENEWAL_TIME, 0, &renew_op);
219
220 if (EFI_ERROR (EfiStatus)) {
221 renew_op = NULL;
222 } else if (renew_op->len != 4) {
223 renew_op = NULL;
224 }
225 //
226 // There should be a rebinding time.
227 // If there is not, we will default to 7/8 of the lease time.
228 //
229 EfiStatus = find_opt (rx_pkt, DHCP4_REBINDING_TIME, 0, &rebind_op);
230
231 if (EFI_ERROR (EfiStatus)) {
232 rebind_op = NULL;
233 } else if (rebind_op->len != 4) {
234 rebind_op = NULL;
235 }
236 //
237 // There should be a lease time.
238 // If there is not, we will default to one week.
239 //
240 EfiStatus = find_opt (rx_pkt, DHCP4_LEASE_TIME, 0, &lease_time_op);
241
242 if (EFI_ERROR (EfiStatus)) {
243 lease_time_op = NULL;
244 } else if (lease_time_op->len != 4) {
245 lease_time_op = NULL;
246 }
247 //
248 // Packet looks good. Double check the renew, rebind and lease times.
249 //
250 CopyMem (&Private->ServerIp, srvid_op->data, 4);
251
252 if (renew_op != NULL) {
253 CopyMem (&Private->RenewTime, renew_op->data, 4);
254 Private->RenewTime = htonl (Private->RenewTime);
255 } else {
256 Private->RenewTime = 0;
257 }
258
259 if (rebind_op != NULL) {
260 CopyMem (&Private->RebindTime, rebind_op->data, 4);
261 Private->RebindTime = htonl (Private->RebindTime);
262 } else {
263 Private->RebindTime = 0;
264 }
265
266 if (lease_time_op != NULL) {
267 CopyMem (&Private->LeaseTime, lease_time_op->data, 4);
268 Private->LeaseTime = htonl (Private->LeaseTime);
269 } else {
270 Private->LeaseTime = 0;
271 }
272
273 if (Private->LeaseTime < 60) {
274 Private->LeaseTime = 7 * 86400;
275 }
276
277 if (Private->RebindTime < 52 || Private->RebindTime >= Private->LeaseTime) {
278 Private->RebindTime = Private->LeaseTime / 2 + Private->LeaseTime / 4 + Private->LeaseTime / 8;
279 }
280
281 if (Private->RenewTime < 45 || Private->RenewTime >= Private->RebindTime) {
282 Private->RenewTime = Private->RebindTime / 2 + Private->RebindTime / 4 + Private->RebindTime / 8;
283 }
284
285 return 1;
286 }
287
288 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
289 EFI_STATUS
290 EFIAPI
291 PxeDhcp4Init (
292 IN EFI_PXE_DHCP4_PROTOCOL *This,
293 IN UINTN seconds_timeout,
294 OUT UINTN *Offers,
295 OUT DHCP4_PACKET **OfferList
296 )
297 {
298 PXE_DHCP4_PRIVATE_DATA *Private;
299 DHCP4_PACKET offer;
300 EFI_IP_ADDRESS bcast_ip;
301 EFI_STATUS EfiStatus;
302
303 //
304 // Verify parameters and protocol state.
305 //
306 if (This == NULL ||
307 seconds_timeout < DHCP4_MIN_SECONDS ||
308 seconds_timeout > DHCP4_MAX_SECONDS ||
309 Offers == NULL ||
310 OfferList == NULL
311 ) {
312 //
313 // Return parameters are not initialized when
314 // parameters are invalid!
315 //
316 return EFI_INVALID_PARAMETER;
317 }
318
319 *Offers = 0;
320 *OfferList = NULL;
321
322 //
323 // Check protocol state.
324 //
325 if (This->Data == NULL) {
326 return EFI_NOT_STARTED;
327 }
328
329 if (!This->Data->SetupCompleted) {
330 return EFI_NOT_READY;
331 }
332
333 #if 0
334 if (!is_good_discover (&This->Data->Discover)) {
335 //
336 // %%TBD - check discover packet fields
337 //
338 }
339 #endif
340 //
341 // Get pointer to our instance data.
342 //
343 Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
344
345 if (Private == NULL) {
346 return EFI_INVALID_PARAMETER;
347 }
348
349 if (Private->PxeBc == NULL) {
350 return EFI_DEVICE_ERROR;
351 }
352 //
353 // Setup variables...
354 //
355 Private->offers = 0;
356 Private->offer_list = NULL;
357
358 EfiStatus = gBS->HandleProtocol (
359 Private->Handle,
360 &gEfiPxeDhcp4CallbackProtocolGuid,
361 (VOID *) &Private->callback
362 );
363
364 if (EFI_ERROR (EfiStatus)) {
365 Private->callback = NULL;
366 }
367
368 Private->function = EFI_PXE_DHCP4_FUNCTION_INIT;
369
370 //
371 // Increment the transaction ID.
372 //
373 {
374 UINT32 xid;
375
376 CopyMem (&xid, &This->Data->Discover.dhcp4.xid, sizeof (UINT32));
377
378 xid = htonl (htonl (xid) + 1);
379
380 CopyMem (&This->Data->Discover.dhcp4.xid, &xid, sizeof (UINT32));
381 }
382 //
383 // Transmit discover and wait for offers...
384 //
385 SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
386
387 EfiStatus = tx_rx_udp (
388 Private,
389 &bcast_ip,
390 NULL,
391 NULL,
392 NULL,
393 &This->Data->Discover,
394 &offer,
395 &offer_verify,
396 seconds_timeout
397 );
398
399 if (EFI_ERROR (EfiStatus)) {
400 if (Private->offer_list) {
401 gBS->FreePool (Private->offer_list);
402 }
403
404 Private->offers = 0;
405 Private->offer_list = NULL;
406 Private->callback = NULL;
407
408 DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
409 return EfiStatus;
410 }
411
412 *Offers = Private->offers;
413 *OfferList = Private->offer_list;
414
415 Private->offers = 0;
416 Private->offer_list = NULL;
417 Private->callback = NULL;
418
419 This->Data->InitCompleted = TRUE;
420 This->Data->SelectCompleted = FALSE;
421 This->Data->IsBootp = FALSE;
422 This->Data->IsAck = FALSE;
423
424 return EFI_SUCCESS;
425 }
426
427 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
428 EFI_STATUS
429 EFIAPI
430 PxeDhcp4Select (
431 IN EFI_PXE_DHCP4_PROTOCOL *This,
432 IN UINTN seconds_timeout,
433 IN DHCP4_PACKET *Offer
434 )
435 {
436 PXE_DHCP4_PRIVATE_DATA *Private;
437 EFI_STATUS EfiStatus;
438 DHCP4_PACKET request;
439 DHCP4_PACKET acknak;
440 EFI_IP_ADDRESS bcast_ip;
441 EFI_IP_ADDRESS zero_ip;
442 EFI_IP_ADDRESS local_ip;
443 DHCP4_OP *srvid;
444 DHCP4_OP *op;
445 UINT32 dhcp4_magik;
446 UINT8 buf[16];
447 BOOLEAN is_bootp;
448
449 //
450 // Verify parameters.
451 //
452 if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS || Offer == NULL) {
453 return EFI_INVALID_PARAMETER;
454 }
455 //
456 // Check protocol state.
457 //
458 if (This->Data == NULL) {
459 return EFI_NOT_STARTED;
460 }
461
462 if (!This->Data->SetupCompleted) {
463 return EFI_NOT_READY;
464 }
465 //
466 // Get pointer to instance data.
467 //
468 Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
469
470 if (Private == NULL) {
471 return EFI_INVALID_PARAMETER;
472 }
473
474 if (Private->PxeBc == NULL) {
475 return EFI_DEVICE_ERROR;
476 }
477
478 #if 0
479 if (!is_good_discover (&This->Data->Discover)) {
480 //
481 // %%TBD - check discover packet fields
482 //
483 }
484 #endif
485 //
486 // Setup useful variables...
487 //
488 SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
489
490 ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));
491
492 ZeroMem (&local_ip, sizeof (EFI_IP_ADDRESS));
493 local_ip.v4.Addr[0] = 127;
494 local_ip.v4.Addr[3] = 1;
495
496 This->Data->SelectCompleted = FALSE;
497 This->Data->IsBootp = FALSE;
498 This->Data->IsAck = FALSE;
499
500 EfiStatus = gBS->HandleProtocol (
501 Private->Handle,
502 &gEfiPxeDhcp4CallbackProtocolGuid,
503 (VOID *) &Private->callback
504 );
505
506 if (EFI_ERROR (EfiStatus)) {
507 Private->callback = NULL;
508 }
509
510 Private->function = EFI_PXE_DHCP4_FUNCTION_SELECT;
511
512 //
513 // Verify offer packet fields.
514 //
515 if (Offer->dhcp4.op != BOOTP_REPLY) {
516 Private->callback = NULL;
517 return EFI_INVALID_PARAMETER;
518 }
519
520 if (Offer->dhcp4.htype != This->Data->Discover.dhcp4.htype) {
521 Private->callback = NULL;
522 return EFI_INVALID_PARAMETER;
523 }
524
525 if (Offer->dhcp4.hlen != This->Data->Discover.dhcp4.hlen) {
526 Private->callback = NULL;
527 return EFI_INVALID_PARAMETER;
528 }
529
530 if (CompareMem (&Offer->dhcp4.xid, &This->Data->Discover.dhcp4.xid, 4)) {
531 Private->callback = NULL;
532 return EFI_INVALID_PARAMETER;
533 }
534
535 if (!CompareMem (&Offer->dhcp4.yiaddr, &bcast_ip, 4)) {
536 Private->callback = NULL;
537 return EFI_INVALID_PARAMETER;
538 }
539
540 if (!CompareMem (&Offer->dhcp4.yiaddr, &zero_ip, 4)) {
541 Private->callback = NULL;
542 return EFI_INVALID_PARAMETER;
543 }
544
545 if (!CompareMem (&Offer->dhcp4.yiaddr, &local_ip, 4)) {
546 Private->callback = NULL;
547 return EFI_INVALID_PARAMETER;
548 }
549
550 if (CompareMem (
551 &Offer->dhcp4.chaddr,
552 &This->Data->Discover.dhcp4.chaddr,
553 16
554 )) {
555 Private->callback = NULL;
556 return EFI_INVALID_PARAMETER;
557 }
558 //
559 // DHCP option checks
560 //
561 dhcp4_magik = htonl (DHCP4_MAGIK_NUMBER);
562 is_bootp = TRUE;
563
564 if (!CompareMem (&Offer->dhcp4.magik, &dhcp4_magik, 4)) {
565 //
566 // If present, DHCP message type must be offer.
567 //
568 EfiStatus = find_opt (Offer, DHCP4_MESSAGE_TYPE, 0, &op);
569
570 if (!EFI_ERROR (EfiStatus)) {
571 if (op->len != 1 || op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) {
572 Private->callback = NULL;
573 return EFI_INVALID_PARAMETER;
574 }
575
576 is_bootp = FALSE;
577 }
578 //
579 // If present, DHCP max message size must be valid.
580 //
581 EfiStatus = find_opt (Offer, DHCP4_MAX_MESSAGE_SIZE, 0, &op);
582
583 if (!EFI_ERROR (EfiStatus)) {
584 if (op->len != 2 || ((op->data[0] << 8) | op->data[1]) < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) {
585 Private->callback = NULL;
586 return EFI_INVALID_PARAMETER;
587 }
588 }
589 //
590 // If present, DHCP server identifier must be valid.
591 //
592 EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &op);
593
594 if (!EFI_ERROR (EfiStatus)) {
595 if (op->len != 4 || !CompareMem (op->data, &bcast_ip, 4) || !CompareMem (op->data, &zero_ip, 4)) {
596 Private->callback = NULL;
597 return EFI_INVALID_PARAMETER;
598 }
599 }
600 //
601 // If present, DHCP subnet mask must be valid.
602 //
603 EfiStatus = find_opt (
604 Offer,
605 DHCP4_SUBNET_MASK,
606 0,
607 &op
608 );
609
610 if (!EFI_ERROR (EfiStatus)) {
611 if (op->len != 4) {
612 Private->callback = NULL;
613 return EFI_INVALID_PARAMETER;
614 }
615 }
616 }
617 //
618 // Early out for BOOTP.
619 //
620 This->Data->IsBootp = is_bootp;
621 if (is_bootp) {
622 //
623 // Copy offer packet to instance data.
624 //
625 CopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET));
626
627 //
628 // Copy discover to request and offer to acknak.
629 //
630 CopyMem (
631 &This->Data->Request,
632 &This->Data->Discover,
633 sizeof (DHCP4_PACKET)
634 );
635
636 CopyMem (
637 &This->Data->AckNak,
638 &This->Data->Offer,
639 sizeof (DHCP4_PACKET)
640 );
641
642 //
643 // Set state flags.
644 //
645 This->Data->SelectCompleted = TRUE;
646 This->Data->IsAck = TRUE;
647
648 Private->callback = NULL;
649 return EFI_SUCCESS;
650 }
651 //
652 // Copy discover packet contents to request packet.
653 //
654 CopyMem (&request, &This->Data->Discover, sizeof (DHCP4_PACKET));
655
656 This->Data->IsAck = FALSE;
657
658 //
659 // Change DHCP message type from discover to request.
660 //
661 EfiStatus = find_opt (&request, DHCP4_MESSAGE_TYPE, 0, &op);
662
663 if (EFI_ERROR (EfiStatus) && EfiStatus != EFI_NOT_FOUND) {
664 Private->callback = NULL;
665 return EFI_INVALID_PARAMETER;
666 }
667
668 if (EfiStatus == EFI_NOT_FOUND) {
669 EfiStatus = find_opt (&request, DHCP4_END, 0, &op);
670
671 if (EFI_ERROR (EfiStatus)) {
672 Private->callback = NULL;
673 return EFI_INVALID_PARAMETER;
674 }
675
676 op->op = DHCP4_MESSAGE_TYPE;
677 op->len = 1;
678
679 op->data[1] = DHCP4_END;
680 }
681
682 op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST;
683
684 //
685 // Copy server identifier option from offer to request.
686 //
687 EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &srvid);
688
689 if (EFI_ERROR (EfiStatus)) {
690 Private->callback = NULL;
691 return EFI_INVALID_PARAMETER;
692 }
693
694 if (srvid->len != 4) {
695 Private->callback = NULL;
696 return EFI_INVALID_PARAMETER;
697 }
698
699 EfiStatus = add_opt (&request, srvid);
700
701 if (EFI_ERROR (EfiStatus)) {
702 DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
703 Private->callback = NULL;
704 return EfiStatus;
705 }
706 //
707 // Add requested IP address option to request packet.
708 //
709 op = (DHCP4_OP *) buf;
710 op->op = DHCP4_REQUESTED_IP_ADDRESS;
711 op->len = 4;
712 CopyMem (op->data, &Offer->dhcp4.yiaddr, 4);
713
714 EfiStatus = add_opt (&request, op);
715
716 if (EFI_ERROR (EfiStatus)) {
717 DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
718 Private->callback = NULL;
719 return EfiStatus;
720 }
721 //
722 // Transimit DHCP request and wait for DHCP ack...
723 //
724 SetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
725
726 EfiStatus = tx_rx_udp (
727 Private,
728 &bcast_ip,
729 NULL,
730 NULL,
731 NULL,
732 &request,
733 &acknak,
734 &acknak_verify,
735 seconds_timeout
736 );
737
738 if (EFI_ERROR (EfiStatus)) {
739 DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
740 Private->callback = NULL;
741 return EfiStatus;
742 }
743 //
744 // Set Data->IsAck and return.
745 //
746 EfiStatus = find_opt (&acknak, DHCP4_MESSAGE_TYPE, 0, &op);
747
748 if (EFI_ERROR (EfiStatus)) {
749 Private->callback = NULL;
750 return EFI_DEVICE_ERROR;
751 }
752
753 if (op->len != 1) {
754 Private->callback = NULL;
755 return EFI_DEVICE_ERROR;
756 }
757
758 switch (op->data[0]) {
759 case DHCP4_MESSAGE_TYPE_ACK:
760 This->Data->IsAck = TRUE;
761 break;
762
763 case DHCP4_MESSAGE_TYPE_NAK:
764 This->Data->IsAck = FALSE;
765 break;
766
767 default:
768 Private->callback = NULL;
769 return EFI_DEVICE_ERROR;
770 }
771 //
772 // Copy packets into instance data...
773 //
774 CopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET));
775 CopyMem (&This->Data->Request, &request, sizeof (DHCP4_PACKET));
776 CopyMem (&This->Data->AckNak, &acknak, sizeof (DHCP4_PACKET));
777
778 This->Data->SelectCompleted = TRUE;
779
780 Private->callback = NULL;
781 return EFI_SUCCESS;
782 }
783
784 /* eof - PxeDhcp4InitSelect.c */