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