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