]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/PxeDhcp4Dxe/Support.c
sync comments, fix function header, rename variable name to follow coding style.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeDhcp4Dxe / Support.c
1 /** @file
2
3 Copyright (c) 2004 - 2005, 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 support.c
14
15 Abstract:
16 Miscellaneous support routines for PxeDhcp4 protocol.
17
18
19 **/
20
21
22 #include "PxeDhcp4.h"
23
24 #define DebugPrint(x)
25 //
26 // #define DebugPrint(x) Aprint x
27 //
28
29 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
30 UINT16
31 htons (
32 UINTN n
33 )
34 {
35 return (UINT16) ((n >> 8) | (n << 8));
36 }
37
38 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
39 UINT32
40 htonl (
41 UINTN n
42 )
43 {
44 return (UINT32) ((n >> 24) | ((n >> 8) & 0xFF00) | ((n & 0xFF00) << 8) | (n << 24));
45 }
46
47 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
48 VOID
49 EFIAPI
50 timeout_notify (
51 IN EFI_EVENT Event,
52 IN VOID *Context
53 )
54 {
55 ASSERT (Context);
56
57 if (Context != NULL) {
58 ((PXE_DHCP4_PRIVATE_DATA *) Context)->TimeoutOccurred = TRUE;
59 }
60 }
61
62 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
63 VOID
64 EFIAPI
65 periodic_notify (
66 IN EFI_EVENT Event,
67 IN VOID *Context
68 )
69 {
70 ASSERT (Context);
71
72 if (Context != NULL) {
73 ((PXE_DHCP4_PRIVATE_DATA *) Context)->PeriodicOccurred = TRUE;
74 }
75 }
76
77 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
78
79 /**
80
81 @return EFI_SUCCESS := Option was found
82 @return EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL
83 @return EFI_INVALID_PARAMETER := OpCode == DHCP4_PAD
84 @return EFI_INVALID_PARAMETER := OpCode == DHCP4_END && Skip != 0
85 @return EFI_INVALID_PARAMETER := DHCP magik number in Packet is not valid
86 @return EFI_NOT_FOUND := op-code was not found in packet
87 @return EFI_INVALID_PARAMETER := If present, DHCP_MAX_MESSAGE_SIZE option
88 @return does not have a valid value.
89
90 **/
91 EFI_STATUS
92 find_opt (
93 IN DHCP4_PACKET *Packet,
94 IN UINT8 OpCode,
95 IN UINTN Skip,
96 OUT DHCP4_OP **OpPtr
97 )
98 {
99 UINTN msg_size;
100 UINTN buf_len;
101 UINTN n;
102 UINT8 *buf;
103 UINT8 *end_ptr;
104 UINT8 overload;
105
106 //
107 // Verify parameters.
108 //
109 if (Packet == NULL || OpPtr == NULL || OpCode == DHCP4_PAD || (OpCode == DHCP4_END && Skip != 0)) {
110 return EFI_INVALID_PARAMETER;
111 }
112
113 if (Packet->dhcp4.magik != htonl (DHCP4_MAGIK_NUMBER)) {
114 return EFI_INVALID_PARAMETER;
115 }
116 //
117 // Initialize search variables.
118 //
119 *OpPtr = NULL;
120
121 msg_size = DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);
122
123 overload = 0;
124 end_ptr = NULL;
125
126 buf = Packet->dhcp4.options;
127 buf_len = msg_size - (Packet->dhcp4.options - Packet->raw);
128
129 //
130 // Start searching for requested option.
131 //
132 for (n = 0;;) {
133 //
134 // If match is found, decrement skip count and return
135 // when desired match is found.
136 //
137 if (buf[n] == OpCode) {
138 *OpPtr = (DHCP4_OP *) &buf[n];
139
140 if (Skip-- == 0) {
141 return EFI_SUCCESS;
142 }
143 }
144 //
145 // Skip past current option. Check for option overload
146 // and message size options since these will affect the
147 // amount of data to be searched.
148 //
149 switch (buf[n]) {
150 case DHCP4_PAD:
151 //
152 // Remember the first pad byte of a group. This
153 // could be the end of a badly formed packet.
154 //
155 if (end_ptr == NULL) {
156 end_ptr = &buf[n];
157 }
158
159 ++n;
160 break;
161
162 case DHCP4_END:
163 //
164 // If we reach the end we are done.
165 //
166 end_ptr = NULL;
167 return EFI_NOT_FOUND;
168
169 case DHCP4_OPTION_OVERLOAD:
170 //
171 // Remember the option overload value since it
172 // could cause the search to continue into
173 // the fname and sname fields.
174 //
175 end_ptr = NULL;
176
177 if (buf[n + 1] == 1) {
178 overload = buf[n + 2];
179 }
180
181 n += 2 + buf[n + 1];
182 break;
183
184 case DHCP4_MAX_MESSAGE_SIZE:
185 //
186 // Remember the message size value since it could
187 // change the amount of option buffer to search.
188 //
189 end_ptr = NULL;
190
191 if (buf[n + 1] == 2 && buf == Packet->dhcp4.options) {
192 msg_size = ((buf[n + 2] << 8) | buf[n + 3]) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);
193
194 if (msg_size < 328) {
195 return EFI_INVALID_PARAMETER;
196 }
197
198 buf_len = msg_size - (Packet->dhcp4.options - Packet->raw);
199
200 if (n + 2 + buf[n + 1] > buf_len) {
201 return EFI_INVALID_PARAMETER;
202 }
203 }
204
205 /* fall thru */
206 default:
207 end_ptr = NULL;
208
209 n += 2 + buf[n + 1];
210 }
211 //
212 // Keep searching until the end of the buffer is reached.
213 //
214 if (n < buf_len) {
215 continue;
216 }
217 //
218 // Reached end of current buffer. Check if we are supposed
219 // to search the fname and sname buffers.
220 //
221 if (buf == Packet->dhcp4.options &&
222 (overload == DHCP4_OVERLOAD_FNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)
223 ) {
224 buf = Packet->dhcp4.fname;
225 buf_len = 128;
226 n = 0;
227 continue;
228 }
229
230 if (buf != Packet->dhcp4.sname && (overload == DHCP4_OVERLOAD_SNAME || overload == DHCP4_OVERLOAD_FNAME_AND_SNAME)) {
231 buf = Packet->dhcp4.sname;
232 buf_len = 64;
233 n = 0;
234 continue;
235 }
236 //
237 // End of last buffer reached. If this was a search
238 // for the end of the options, go back to the start
239 // of the current pad block.
240 //
241 if (OpCode == DHCP4_END && end_ptr != NULL) {
242 *OpPtr = (DHCP4_OP *) end_ptr;
243 return EFI_SUCCESS;
244 }
245
246 return EFI_NOT_FOUND;
247 }
248 }
249
250 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
251
252 /**
253
254 @return EFI_INVALID_PARAMETER := Packet == NULL || OpPtr == NULL
255 @return EFI_INVALID_PARAMETER := OpPtr->op == DHCP4_PAD || OpPtr->op == DHCP4_END
256 @return EFI_INVALID_PARAMETER := DHCP magik number in DHCP packet is not valid
257 @return EFI_INVALID_PARAMETER := If DHCP_MAX_MESSAGE_SIZE option is present and
258 @return is not valid
259 @return EFI_INVALID_PARAMETER := If DHCP_OPTION_OVERLOAD option is present and
260 @return is not valid
261 @return EFI_DEVICE_ERROR := Cannot determine end of packet
262 @return EFI_BUFFER_TOO_SMALL := Not enough room in packet to add option
263 @return EFI_SUCCESS := Option added to DHCP packet
264
265 **/
266 EFI_STATUS
267 add_opt (
268 IN DHCP4_PACKET *Packet,
269 IN DHCP4_OP *OpPtr
270 )
271 {
272 EFI_STATUS efi_status;
273 DHCP4_OP *msg_size_op;
274 DHCP4_OP *overload_op;
275 DHCP4_OP *op;
276 UINTN msg_size;
277 UINTN buf_len;
278 UINT32 magik;
279 UINT8 *buf;
280
281 //
282 // Verify parameters.
283 //
284 ASSERT (Packet);
285 ASSERT (OpPtr);
286
287 if (Packet == NULL || OpPtr == NULL) {
288 return EFI_INVALID_PARAMETER;
289 }
290
291 switch (OpPtr->op) {
292 case DHCP4_PAD:
293 case DHCP4_END:
294 //
295 // No adding PAD or END.
296 //
297 return EFI_INVALID_PARAMETER;
298 }
299 //
300 // Check the DHCP magik number.
301 //
302 CopyMem (&magik, &Packet->dhcp4.magik, 4);
303
304 if (magik != htonl (DHCP4_MAGIK_NUMBER)) {
305 return EFI_INVALID_PARAMETER;
306 }
307 //
308 // Find the DHCP message size option.
309 //
310 msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE;
311
312 efi_status = find_opt (
313 Packet,
314 DHCP4_MAX_MESSAGE_SIZE,
315 0,
316 &msg_size_op
317 );
318
319 if (EFI_ERROR (efi_status)) {
320 if (efi_status != EFI_NOT_FOUND) {
321 DebugPrint (
322 ("%s:%d:%r\n",
323 __FILE__,
324 __LINE__,
325 efi_status)
326 );
327 return efi_status;
328 }
329
330 msg_size_op = NULL;
331 } else {
332 CopyMem (&msg_size, msg_size_op->data, 2);
333 msg_size = htons (msg_size);
334
335 if (msg_size < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) {
336 return EFI_INVALID_PARAMETER;
337 }
338 }
339 //
340 // Find the DHCP option overload option.
341 //
342 efi_status = find_opt (
343 Packet,
344 DHCP4_OPTION_OVERLOAD,
345 0,
346 &overload_op
347 );
348
349 if (EFI_ERROR (efi_status)) {
350 if (efi_status != EFI_NOT_FOUND) {
351 DebugPrint (
352 ("%s:%d:%r\n",
353 __FILE__,
354 __LINE__,
355 efi_status)
356 );
357 return efi_status;
358 }
359
360 overload_op = NULL;
361 } else {
362 if (overload_op->len != 1) {
363 return EFI_INVALID_PARAMETER;
364 }
365
366 switch (overload_op->data[0]) {
367 case 1:
368 case 2:
369 case 3:
370 break;
371
372 default:
373 return EFI_INVALID_PARAMETER;
374 }
375 }
376 //
377 // Find the end of the packet.
378 //
379 efi_status = find_opt (Packet, DHCP4_END, 0, &op);
380
381 if (EFI_ERROR (efi_status)) {
382 return EFI_INVALID_PARAMETER;
383 }
384 //
385 // Find which buffer the end is in.
386 //
387 if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.options)) {
388 buf_len = (msg_size - ((UINT8 *) &Packet->dhcp4.options - (UINT8 *) &Packet->raw)) - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE);
389 } else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.fname)) {
390 buf_len = 128;
391 } else if ((UINTN) op >= (UINTN) (buf = Packet->dhcp4.sname)) {
392 buf_len = 64;
393 } else {
394 return EFI_DEVICE_ERROR;
395 }
396 //
397 // Add option to current buffer if there is no overlow.
398 //
399 if ((UINTN) ((&op->op - buf) + 3 + op->len) < buf_len) {
400 CopyMem (op, OpPtr, OpPtr->len + 2);
401
402 op->data[op->len] = DHCP4_END;
403
404 return EFI_SUCCESS;
405 }
406 //
407 // Error if there is no space for option.
408 //
409 return EFI_BUFFER_TOO_SMALL;
410 }
411
412 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
413
414 /**
415
416 @return EFI_INVALID_PARAMETER := Private == NULL || Private->PxeBc == NULL
417 @return EFI_INVALID_PARAMETER := Only one of StationIp and SubnetMask is given
418 @return EFI_SUCCESS := UDP stack is ready
419 @return other := Error from PxeBc->SetIpFilter() or PxeBc->SetStationIp()
420
421 **/
422 EFI_STATUS
423 start_udp (
424 IN PXE_DHCP4_PRIVATE_DATA *Private,
425 IN OPTIONAL EFI_IP_ADDRESS *StationIp,
426 IN OPTIONAL EFI_IP_ADDRESS *SubnetMask
427 )
428 {
429 EFI_PXE_BASE_CODE_IP_FILTER bcast_filter;
430 EFI_STATUS efi_status;
431
432 //
433 //
434 //
435 ASSERT (Private);
436 ASSERT (Private->PxeBc);
437
438 if (Private == NULL) {
439 return EFI_INVALID_PARAMETER;
440 }
441
442 if (Private->PxeBc == NULL) {
443 return EFI_INVALID_PARAMETER;
444 }
445
446 if (StationIp != NULL && SubnetMask == NULL) {
447 return EFI_INVALID_PARAMETER;
448 }
449
450 if (StationIp == NULL && SubnetMask != NULL) {
451 return EFI_INVALID_PARAMETER;
452 }
453 //
454 // Setup broadcast receive filter...
455 //
456 ZeroMem (&bcast_filter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
457
458 bcast_filter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST;
459 bcast_filter.IpCnt = 0;
460
461 efi_status = Private->PxeBc->SetIpFilter (
462 Private->PxeBc,
463 &bcast_filter
464 );
465
466 if (EFI_ERROR (efi_status)) {
467 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
468 return efi_status;
469 }
470 //
471 // Configure station IP address and subnet mask...
472 //
473 efi_status = Private->PxeBc->SetStationIp (
474 Private->PxeBc,
475 StationIp,
476 SubnetMask
477 );
478
479 if (EFI_ERROR (efi_status)) {
480 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
481 }
482
483 return efi_status;
484 }
485
486 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
487 VOID
488 stop_udp (
489 IN PXE_DHCP4_PRIVATE_DATA *Private
490 )
491 {
492 //
493 //
494 //
495 ASSERT (Private);
496 ASSERT (Private->PxeBc);
497 }
498
499 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
500
501 /**
502
503
504 **/
505 EFI_STATUS
506 start_receive_events (
507 IN PXE_DHCP4_PRIVATE_DATA *Private,
508 IN UINTN SecondsTimeout
509 )
510 {
511 EFI_STATUS efi_status;
512 UINTN random;
513
514 //
515 //
516 //
517 ASSERT (Private);
518 ASSERT (SecondsTimeout);
519
520 if (Private == NULL || SecondsTimeout == 0) {
521 return EFI_INVALID_PARAMETER;
522 }
523 //
524 // Need a bettern randomizer...
525 // For now adjust the timeout value by the least significant
526 // digit in the MAC address.
527 //
528 random = 0;
529
530 if (Private->PxeDhcp4.Data != NULL) {
531 if (Private->PxeDhcp4.Data->Discover.dhcp4.hlen != 0 && Private->PxeDhcp4.Data->Discover.dhcp4.hlen <= 16) {
532 random = 0xFFF & Private->PxeDhcp4.Data->Discover.dhcp4.chaddr[Private->PxeDhcp4.Data->Discover.dhcp4.hlen - 1];
533 }
534 }
535 //
536 // Setup timeout event and start timer.
537 //
538 efi_status = gBS->CreateEvent (
539 EVT_TIMER | EVT_NOTIFY_SIGNAL,
540 TPL_NOTIFY,
541 &timeout_notify,
542 Private,
543 &Private->TimeoutEvent
544 );
545
546 if (EFI_ERROR (efi_status)) {
547 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
548 return efi_status;
549 }
550
551 efi_status = gBS->SetTimer (
552 Private->TimeoutEvent,
553 TimerRelative,
554 SecondsTimeout * 10000000 + random
555 );
556
557 if (EFI_ERROR (efi_status)) {
558 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
559 gBS->CloseEvent (Private->TimeoutEvent);
560 return efi_status;
561 }
562
563 Private->TimeoutOccurred = FALSE;
564
565 //
566 // Setup periodic event for callbacks
567 //
568 efi_status = gBS->CreateEvent (
569 EVT_TIMER | EVT_NOTIFY_SIGNAL,
570 TPL_NOTIFY,
571 &periodic_notify,
572 Private,
573 &Private->PeriodicEvent
574 );
575
576 if (EFI_ERROR (efi_status)) {
577 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
578 gBS->CloseEvent (Private->TimeoutEvent);
579 return efi_status;
580 }
581
582 efi_status = gBS->SetTimer (
583 Private->PeriodicEvent,
584 TimerPeriodic,
585 1000000
586 ); /* 1/10th second */
587
588 if (EFI_ERROR (efi_status)) {
589 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
590 gBS->CloseEvent (Private->TimeoutEvent);
591 gBS->CloseEvent (Private->PeriodicEvent);
592 return efi_status;
593 }
594
595 Private->PeriodicOccurred = FALSE;
596
597 return EFI_SUCCESS;
598 }
599
600 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
601 VOID
602 stop_receive_events (
603 IN PXE_DHCP4_PRIVATE_DATA *Private
604 )
605 {
606 //
607 //
608 //
609 ASSERT (Private);
610
611 if (Private == NULL) {
612 return ;
613 }
614 //
615 //
616 //
617 gBS->CloseEvent (Private->TimeoutEvent);
618 Private->TimeoutOccurred = FALSE;
619
620 //
621 //
622 //
623 gBS->CloseEvent (Private->PeriodicEvent);
624 Private->PeriodicOccurred = FALSE;
625 }
626
627 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
628
629 /**
630
631 @return EFI_INVALID_PARAMETER := Private == NULL || dest_ip == NULL ||
632 @return buffer == NULL || BufferSize < 300 || Private->PxeBc == NULL
633 @return EFI_SUCCESS := Buffer was transmitted
634 @return other := Return from PxeBc->UdpWrite()
635
636 **/
637 EFI_STATUS
638 tx_udp (
639 IN PXE_DHCP4_PRIVATE_DATA *Private,
640 IN EFI_IP_ADDRESS *dest_ip,
641 IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,
642 IN EFI_IP_ADDRESS *src_ip,
643 IN VOID *buffer,
644 IN UINTN BufferSize
645 )
646 {
647 EFI_PXE_BASE_CODE_UDP_PORT dest_port;
648 EFI_PXE_BASE_CODE_UDP_PORT src_port;
649 EFI_IP_ADDRESS zero_ip;
650
651 //
652 //
653 //
654 ASSERT (Private);
655 ASSERT (dest_ip);
656 ASSERT (buffer);
657 ASSERT (BufferSize >= 300);
658
659 if (Private == NULL || dest_ip == NULL || buffer == NULL || BufferSize < 300) {
660 return EFI_INVALID_PARAMETER;
661 }
662
663 ASSERT (Private->PxeBc);
664
665 if (Private->PxeBc == NULL) {
666 return EFI_INVALID_PARAMETER;
667 }
668 //
669 // Transmit DHCP discover packet...
670 //
671 ZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));
672
673 if (src_ip == NULL) {
674 src_ip = &zero_ip;
675 }
676
677 dest_port = DHCP4_SERVER_PORT;
678 src_port = DHCP4_CLIENT_PORT;
679
680 return Private->PxeBc->UdpWrite (
681 Private->PxeBc,
682 EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT,
683 dest_ip,
684 &dest_port,
685 gateway_ip,
686 src_ip,
687 &src_port,
688 NULL,
689 NULL,
690 &BufferSize,
691 buffer
692 );
693 }
694
695 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
696
697 /**
698
699 @return EFI_INVALID_PARAMETER :=
700 @return EFI_SUCCESS := Packet received
701 @return other := Return from PxeBc->UdpRead()
702
703 **/
704 EFI_STATUS
705 rx_udp (
706 IN PXE_DHCP4_PRIVATE_DATA *Private,
707 OUT VOID *buffer,
708 IN OUT UINTN *BufferSize,
709 IN OUT EFI_IP_ADDRESS *dest_ip,
710 IN OUT EFI_IP_ADDRESS *src_ip,
711 IN UINT16 op_flags
712 )
713 {
714 EFI_PXE_BASE_CODE_UDP_PORT dest_port;
715 EFI_PXE_BASE_CODE_UDP_PORT src_port;
716
717 //
718 //
719 //
720 ASSERT (Private);
721 ASSERT (buffer);
722 ASSERT (dest_ip);
723 ASSERT (src_ip);
724
725 if (Private == NULL || buffer == NULL || dest_ip == NULL || src_ip == NULL || BufferSize == NULL) {
726 return EFI_INVALID_PARAMETER;
727 }
728
729 ASSERT (Private->PxeBc);
730
731 if (Private->PxeBc == NULL) {
732 return EFI_INVALID_PARAMETER;
733 }
734 //
735 // Check for packet
736 //
737 *BufferSize = sizeof (DHCP4_PACKET);
738
739 dest_port = DHCP4_CLIENT_PORT;
740 src_port = DHCP4_SERVER_PORT;
741
742 return Private->PxeBc->UdpRead (
743 Private->PxeBc,
744 op_flags,
745 dest_ip,
746 &dest_port,
747 src_ip,
748 &src_port,
749 NULL,
750 NULL,
751 BufferSize,
752 buffer
753 );
754 }
755
756 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
757 EFI_STATUS
758 tx_rx_udp (
759 IN PXE_DHCP4_PRIVATE_DATA *Private,
760 IN OUT EFI_IP_ADDRESS *ServerIp,
761 IN OPTIONAL EFI_IP_ADDRESS *gateway_ip,
762 IN OPTIONAL EFI_IP_ADDRESS *client_ip,
763 IN OPTIONAL EFI_IP_ADDRESS *SubnetMask,
764 IN DHCP4_PACKET *tx_pkt,
765 OUT DHCP4_PACKET *rx_pkt,
766 IN INTN (*rx_vfy)(
767 IN PXE_DHCP4_PRIVATE_DATA *Private,
768 IN DHCP4_PACKET *tx_pkt,
769 IN DHCP4_PACKET *rx_pkt,
770 IN UINTN rx_pkt_size
771 ),
772 IN UINTN SecondsTimeout
773 )
774 /*++
775 Routine description:
776 Transmit DHCP packet and wait for replies.
777
778 Parameters:
779 Private := Pointer to PxeDhcp4 private data
780 ServerIp := Pointer to server IP address
781 gateway_ip := Pointer to gateway IP address or NULL
782 client_ip := Pointer to client IP address or NULL
783 SubnetMask := Pointer to subnet mask or NULL
784 tx_pkt := Pointer to DHCP packet to transmit
785 rx_pkt := Pointer to DHCP packet receive buffer
786 rx_vfy := Pointer to DHCP packet receive verification routine
787 SecondsTimeout := Number of seconds until timeout
788
789 Returns:
790 EFI_INVALID_PARAMETER := Private == NULL || ServerIp == NULL ||
791 tx_pkt == NULL || rx_pkt == NULL || rx_vfy == NULL || Private->PxeBc == NULL
792 EFI_ABORTED := Receive aborted
793 EFI_TIMEOUT := No packets received
794 EFI_SUCCESS := Packet(s) received
795 other := Returns from other PxeDhcp4 support routines
796 --*/
797 {
798 EFI_PXE_DHCP4_CALLBACK_STATUS CallbackStatus;
799 EFI_IP_ADDRESS dest_ip;
800 EFI_IP_ADDRESS src_ip;
801 EFI_STATUS efi_status;
802 DHCP4_OP *msg_size_op;
803 UINTN pkt_size;
804 UINTN n;
805 UINT16 msg_size;
806 UINT16 op_flags;
807 BOOLEAN done_flag;
808 BOOLEAN got_packet;
809
810 //
811 // Bad programmer check...
812 //
813 ASSERT (Private);
814 ASSERT (ServerIp);
815 ASSERT (tx_pkt);
816 ASSERT (rx_pkt);
817 ASSERT (rx_vfy);
818
819 if (Private == NULL || ServerIp == NULL || tx_pkt == NULL || rx_pkt == NULL || rx_vfy == NULL) {
820 return EFI_INVALID_PARAMETER;
821 }
822
823 ASSERT (Private->PxeBc);
824
825 if (Private->PxeBc == NULL) {
826 return EFI_INVALID_PARAMETER;
827 }
828 //
829 // Enable UDP...
830 //
831 efi_status = start_udp (Private, client_ip, SubnetMask);
832
833 if (EFI_ERROR (efi_status)) {
834 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
835 return efi_status;
836 }
837 //
838 // Get length of transmit packet...
839 //
840 msg_size = DHCP4_DEFAULT_MAX_MESSAGE_SIZE;
841
842 efi_status = find_opt (
843 tx_pkt,
844 DHCP4_MAX_MESSAGE_SIZE,
845 0,
846 &msg_size_op
847 );
848
849 if (!EFI_ERROR (efi_status)) {
850 CopyMem (&msg_size, msg_size_op->data, 2);
851
852 if ((msg_size = htons (msg_size)) < 328) {
853 msg_size = 328;
854 }
855 }
856 //
857 // Transmit packet...
858 //
859 efi_status = tx_udp (
860 Private,
861 ServerIp,
862 gateway_ip,
863 client_ip,
864 tx_pkt,
865 msg_size - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE)
866 );
867
868 if (EFI_ERROR (efi_status)) {
869 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
870 stop_udp (Private);
871 return efi_status;
872 }
873 //
874 // Enable periodic and timeout events...
875 //
876 efi_status = start_receive_events (Private, SecondsTimeout);
877
878 if (EFI_ERROR (efi_status)) {
879 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
880 stop_udp (Private);
881 return efi_status;
882 }
883 //
884 // Wait for packet(s)...
885 //
886
887 done_flag = FALSE;
888 got_packet = FALSE;
889
890 while (!done_flag) {
891 //
892 // Check for timeout event...
893 //
894 if (Private->TimeoutOccurred) {
895 efi_status = EFI_SUCCESS;
896 break;
897 }
898 //
899 // Check for periodic event...
900 //
901 if (Private->PeriodicOccurred && Private->callback != NULL) {
902 CallbackStatus = EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE;
903
904 if (Private->callback->Callback != NULL) {
905 CallbackStatus = (Private->callback->Callback) (&Private->PxeDhcp4, Private->function, 0, NULL);
906 }
907
908 switch (CallbackStatus) {
909 case EFI_PXE_DHCP4_CALLBACK_STATUS_CONTINUE:
910 break;
911
912 case EFI_PXE_DHCP4_CALLBACK_STATUS_ABORT:
913 default:
914 stop_receive_events (Private);
915 stop_udp (Private);
916 return EFI_ABORTED;
917 }
918
919 Private->PeriodicOccurred = FALSE;
920 }
921 //
922 // Check for packet...
923 //
924 if (client_ip == NULL) {
925 SetMem (&dest_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
926 } else {
927 CopyMem (&dest_ip, client_ip, sizeof (EFI_IP_ADDRESS));
928 }
929
930 SetMem (&src_ip, sizeof (EFI_IP_ADDRESS), 0xFF);
931
932 if (CompareMem (&src_ip, &ServerIp, sizeof (EFI_IP_ADDRESS))) {
933 ZeroMem (&src_ip, sizeof (EFI_IP_ADDRESS));
934 op_flags = EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP;
935 } else {
936 op_flags = 0;
937 }
938
939 efi_status = rx_udp (
940 Private,
941 rx_pkt,
942 &pkt_size,
943 &dest_ip,
944 &src_ip,
945 op_flags
946 );
947
948 if (efi_status == EFI_TIMEOUT) {
949 efi_status = EFI_SUCCESS;
950 continue;
951 }
952
953 if (EFI_ERROR (efi_status)) {
954 break;
955 }
956 //
957 // Some basic packet sanity checks..
958 //
959 if (pkt_size < 300) {
960 continue;
961 }
962
963 if (rx_pkt->dhcp4.op != BOOTP_REPLY) {
964 continue;
965 }
966
967 if (tx_pkt->dhcp4.htype != rx_pkt->dhcp4.htype) {
968 continue;
969 }
970
971 if ((n = tx_pkt->dhcp4.hlen) != rx_pkt->dhcp4.hlen) {
972 continue;
973 }
974
975 if (CompareMem (&tx_pkt->dhcp4.xid, &rx_pkt->dhcp4.xid, 4)) {
976 continue;
977 }
978
979 if (n != 0) {
980 if (n >= 16) {
981 n = 16;
982 }
983
984 if (CompareMem (tx_pkt->dhcp4.chaddr, rx_pkt->dhcp4.chaddr, n)) {
985 continue;
986 }
987 }
988 //
989 // Internal callback packet verification...
990 //
991 switch ((*rx_vfy) (Private, tx_pkt, rx_pkt, pkt_size)) {
992 case -2: /* ignore and stop */
993 stop_receive_events (Private);
994 stop_udp (Private);
995 return EFI_ABORTED;
996
997 case -1: /* ignore and wait */
998 continue;
999
1000 case 0: /* accept and wait */
1001 break;
1002
1003 case 1: /* accept and stop */
1004 done_flag = TRUE;
1005 break;
1006
1007 default:
1008 ASSERT (0);
1009 }
1010 //
1011 // External callback packet verification...
1012 //
1013 CallbackStatus = EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE;
1014
1015 if (Private->callback != NULL) {
1016 if (Private->callback->Callback != NULL) {
1017 CallbackStatus = (Private->callback->Callback) (&Private->PxeDhcp4, Private->function, (UINT32) pkt_size, rx_pkt);
1018 }
1019 }
1020
1021 switch (CallbackStatus) {
1022 case EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_CONTINUE:
1023 continue;
1024
1025 case EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_ABORT:
1026 done_flag = TRUE;
1027 break;
1028
1029 case EFI_PXE_DHCP4_CALLBACK_STATUS_IGNORE_ABORT:
1030 stop_receive_events (Private);
1031 stop_udp (Private);
1032 return EFI_ABORTED;
1033
1034 case EFI_PXE_DHCP4_CALLBACK_STATUS_KEEP_CONTINUE:
1035 default:
1036 break;
1037 }
1038 //
1039 // We did! We did get a packet!
1040 //
1041 got_packet = TRUE;
1042 }
1043 //
1044 //
1045 //
1046 stop_receive_events (Private);
1047 stop_udp (Private);
1048
1049 if (EFI_ERROR (efi_status)) {
1050 DebugPrint (("%s:%d:%r\n", __FILE__, __LINE__, efi_status));
1051 return efi_status;
1052 }
1053
1054 if (got_packet) {
1055 return EFI_SUCCESS;
1056 } else {
1057 return EFI_TIMEOUT;
1058 }
1059 }
1060
1061 /* eof - support.c */