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