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