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