]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/UefiPxeBcDxe/PxeBcSupport.c
Add NetworkPkg (P.UDK2010.UP3.Network.P1)
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcSupport.c
1 /** @file
2 Support functions implementation for UefiPxeBc Driver.
3
4 Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "PxeBcImpl.h"
17
18
19
20 /**
21 This function returns SMBIOS string given the string number.
22
23 @param[in] Smbios The pointer to the SMBIOS structure
24 @param[in] StringNumber String number to return. 0 is used to skip all
25 strings and point to the next SMBIOS structure.
26
27 @return String The pointer to the next SMBIOS structure if
28 StringNumber == 0.
29
30 **/
31 CHAR8 *
32 PxeBcGetSmbiosString (
33 IN SMBIOS_STRUCTURE_POINTER *Smbios,
34 IN UINT16 StringNumber
35 )
36 {
37 UINT16 Index;
38 CHAR8 *String;
39
40 //
41 // Skip over formatted section.
42 //
43 String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length);
44
45 //
46 // Look through unformated section.
47 //
48 for (Index = 1; Index <= StringNumber || StringNumber == 0; Index++) {
49 if (StringNumber == Index) {
50 return String;
51 }
52
53 //
54 // Skip zero string.
55 //
56 while (*String != 0) {
57 String++;
58 }
59 String++;
60
61 if (*String == 0) {
62 //
63 // If double NULL then we are done.
64 // Return pointer to next structure in Smbios.
65 // if you pass in a 0 you will always get here
66 //
67 Smbios->Raw = (UINT8 *)++String;
68 return NULL;
69 }
70 }
71
72 return NULL;
73 }
74
75
76 /**
77 This function obtains the system guid and the serial number from the smbios table.
78
79 @param[out] SystemGuid The pointer of the returned system guid.
80
81 @retval EFI_SUCCESS Successfully obtained the system guid.
82 @retval EFI_NOT_FOUND Did not find the SMBIOS table.
83
84 **/
85 EFI_STATUS
86 PxeBcGetSystemGuid (
87 OUT EFI_GUID *SystemGuid
88 )
89 {
90 EFI_STATUS Status;
91 SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;
92 SMBIOS_STRUCTURE_POINTER Smbios;
93 SMBIOS_STRUCTURE_POINTER SmbiosEnd;
94 UINT16 Index;
95
96 SmbiosTable = NULL;
97 Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);
98
99 if (EFI_ERROR (Status) || SmbiosTable == NULL) {
100 return EFI_NOT_FOUND;
101 }
102
103 Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress;
104 SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength);
105
106 for (Index = 0; Index < SmbiosTable->TableLength; Index++) {
107 if (Smbios.Hdr->Type == 1) {
108 if (Smbios.Hdr->Length < 0x19) {
109 //
110 // Older version did not support Guid and Serial number
111 //
112 continue;
113 }
114 //
115 // SMBIOS tables are byte packed so we need to do a byte copy to
116 // prevend alignment faults on Itanium-based platform.
117 //
118 CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));
119 PxeBcGetSmbiosString (&Smbios, Smbios.Type1->SerialNumber);
120
121 return EFI_SUCCESS;
122 }
123 //
124 // Make Smbios point to the next record
125 //
126 PxeBcGetSmbiosString (&Smbios, 0);
127
128 if (Smbios.Raw >= SmbiosEnd.Raw) {
129 //
130 // SMBIOS 2.1 incorrectly stated the length of SmbiosTable as 0x1e.
131 // given this we must double check against the length of the structure.
132 //
133 return EFI_SUCCESS;
134 }
135 }
136
137 return EFI_NOT_FOUND;
138 }
139
140
141 /**
142 Flush the previous configration using the new station Ip address.
143
144 @param[in] Private The pointer to the PxeBc private data.
145 @param[in] StationIp The pointer to the station Ip address.
146 @param[in] SubnetMask The pointer to the subnet mask address for v4.
147
148 @retval EFI_SUCCESS Successfully flushed the previous configuration.
149 @retval Others Failed to flush using the new station Ip.
150
151 **/
152 EFI_STATUS
153 PxeBcFlushStaionIp (
154 PXEBC_PRIVATE_DATA *Private,
155 EFI_IP_ADDRESS *StationIp,
156 EFI_IP_ADDRESS *SubnetMask OPTIONAL
157 )
158 {
159 EFI_PXE_BASE_CODE_MODE *Mode;
160 EFI_STATUS Status;
161
162 ASSERT (StationIp != NULL);
163
164 Mode = Private->PxeBc.Mode;
165 Status = EFI_SUCCESS;
166
167 if (Mode->UsingIpv6) {
168
169 CopyMem (&Private->Udp6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
170 CopyMem (&Private->Ip6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
171
172 //
173 // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address.
174 //
175 Private->Ip6->Cancel (Private->Ip6, &Private->Icmp6Token);
176 Private->Ip6->Configure (Private->Ip6, NULL);
177
178 Status = Private->Ip6->Configure (Private->Ip6, &Private->Ip6CfgData);
179 if (EFI_ERROR (Status)) {
180 goto ON_EXIT;
181 }
182
183 Status = Private->Ip6->Receive (Private->Ip6, &Private->Icmp6Token);
184 if (EFI_ERROR (Status)) {
185 goto ON_EXIT;
186 }
187
188 } else {
189 ASSERT (SubnetMask != NULL);
190 CopyMem (&Private->Udp4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));
191 CopyMem (&Private->Udp4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));
192 CopyMem (&Private->Ip4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));
193 CopyMem (&Private->Ip4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));
194
195 //
196 // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
197 //
198 Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken);
199 Private->Ip4->Configure (Private->Ip4, NULL);
200
201 Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4CfgData);
202 if (EFI_ERROR (Status)) {
203 goto ON_EXIT;
204 }
205
206 Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpToken);
207 if (EFI_ERROR (Status)) {
208 goto ON_EXIT;
209 }
210
211 }
212
213 ON_EXIT:
214 return Status;
215 }
216
217
218 /**
219 Notify the callback function when an event is triggered.
220
221 @param[in] Event The triggered event.
222 @param[in] Context The opaque parameter to the function.
223
224 **/
225 VOID
226 EFIAPI
227 PxeBcCommonNotify (
228 IN EFI_EVENT Event,
229 IN VOID *Context
230 )
231 {
232 *((BOOLEAN *) Context) = TRUE;
233 }
234
235
236 /**
237 Do arp resolution from arp cache in PxeBcMode.
238
239 @param Mode The pointer to EFI_PXE_BASE_CODE_MODE.
240 @param Ip4Addr The Ip4 address for resolution.
241 @param MacAddress The resoluted MAC address if the resolution is successful.
242 The value is undefined if the resolution fails.
243
244 @retval TRUE Found an matched entry.
245 @retval FALSE Did not find a matched entry.
246
247 **/
248 BOOLEAN
249 PxeBcCheckArpCache (
250 IN EFI_PXE_BASE_CODE_MODE *Mode,
251 IN EFI_IPv4_ADDRESS *Ip4Addr,
252 OUT EFI_MAC_ADDRESS *MacAddress
253 )
254 {
255 UINT32 Index;
256
257 ASSERT (!Mode->UsingIpv6);
258
259 //
260 // Check whether the current Arp cache in mode data contains this information or not.
261 //
262 for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {
263 if (EFI_IP4_EQUAL (&Mode->ArpCache[Index].IpAddr.v4, Ip4Addr)) {
264 CopyMem (
265 MacAddress,
266 &Mode->ArpCache[Index].MacAddr,
267 sizeof (EFI_MAC_ADDRESS)
268 );
269 return TRUE;
270 }
271 }
272
273 return FALSE;
274 }
275
276
277 /**
278 Update the arp cache periodically.
279
280 @param Event The pointer to EFI_PXE_BC_PROTOCOL.
281 @param Context Context of the timer event.
282
283 **/
284 VOID
285 EFIAPI
286 PxeBcArpCacheUpdate (
287 IN EFI_EVENT Event,
288 IN VOID *Context
289 )
290 {
291 PXEBC_PRIVATE_DATA *Private;
292 EFI_PXE_BASE_CODE_MODE *Mode;
293 EFI_ARP_FIND_DATA *ArpEntry;
294 UINT32 EntryLength;
295 UINT32 EntryCount;
296 UINT32 Index;
297 EFI_STATUS Status;
298
299 Private = (PXEBC_PRIVATE_DATA *) Context;
300 Mode = Private->PxeBc.Mode;
301
302 ASSERT (!Mode->UsingIpv6);
303
304 //
305 // Get the current Arp cache from Arp driver.
306 //
307 Status = Private->Arp->Find (
308 Private->Arp,
309 TRUE,
310 NULL,
311 &EntryLength,
312 &EntryCount,
313 &ArpEntry,
314 TRUE
315 );
316 if (EFI_ERROR (Status)) {
317 return;
318 }
319
320 //
321 // Update the Arp cache in mode data.
322 //
323 Mode->ArpCacheEntries = MIN (EntryCount, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES);
324
325 for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {
326 CopyMem (
327 &Mode->ArpCache[Index].IpAddr,
328 ArpEntry + 1,
329 ArpEntry->SwAddressLength
330 );
331 CopyMem (
332 &Mode->ArpCache[Index].MacAddr,
333 (UINT8 *) (ArpEntry + 1) + ArpEntry->SwAddressLength,
334 ArpEntry->HwAddressLength
335 );
336 ArpEntry = (EFI_ARP_FIND_DATA *) ((UINT8 *) ArpEntry + EntryLength);
337 }
338 }
339
340
341 /**
342 Notify function to handle the received ICMP message in DPC.
343
344 @param Context The PXEBC private data.
345
346 **/
347 VOID
348 EFIAPI
349 PxeBcIcmpErrorDpcHandle (
350 IN VOID *Context
351 )
352 {
353 EFI_STATUS Status;
354 EFI_IP4_RECEIVE_DATA *RxData;
355 EFI_IP4_PROTOCOL *Ip4;
356 PXEBC_PRIVATE_DATA *Private;
357 EFI_PXE_BASE_CODE_MODE *Mode;
358 UINT8 Type;
359 UINTN Index;
360 UINT32 CopiedLen;
361 UINT8 *IcmpError;
362
363 Private = (PXEBC_PRIVATE_DATA *) Context;
364 Mode = &Private->Mode;
365 Status = Private->IcmpToken.Status;
366 RxData = Private->IcmpToken.Packet.RxData;
367 Ip4 = Private->Ip4;
368
369 ASSERT (!Mode->UsingIpv6);
370
371 if (Status == EFI_ABORTED) {
372 //
373 // It's triggered by user cancellation.
374 //
375 return;
376 }
377
378 if (RxData == NULL) {
379 goto ON_EXIT;
380 }
381
382 if (Status != EFI_ICMP_ERROR) {
383 //
384 // The return status should be recognized as EFI_ICMP_ERROR.
385 //
386 gBS->SignalEvent (RxData->RecycleSignal);
387 goto ON_EXIT;
388 }
389
390 if (EFI_IP4 (RxData->Header->SourceAddress) != 0 &&
391 !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {
392 //
393 // The source address of the received packet should be a valid unicast address.
394 //
395 gBS->SignalEvent (RxData->RecycleSignal);
396 goto ON_EXIT;
397 }
398
399 if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {
400 //
401 // The destination address of the received packet should be equal to the host address.
402 //
403 gBS->SignalEvent (RxData->RecycleSignal);
404 goto ON_EXIT;
405 }
406
407 if (RxData->Header->Protocol != EFI_IP_PROTO_ICMP) {
408 //
409 // The protocol value in the header of the receveid packet should be EFI_IP_PROTO_ICMP.
410 //
411 gBS->SignalEvent (RxData->RecycleSignal);
412 goto ON_EXIT;
413 }
414
415 Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer);
416
417 if (Type != ICMP_DEST_UNREACHABLE &&
418 Type != ICMP_SOURCE_QUENCH &&
419 Type != ICMP_REDIRECT &&
420 Type != ICMP_TIME_EXCEEDED &&
421 Type != ICMP_PARAMETER_PROBLEM) {
422 //
423 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
424 //
425 gBS->SignalEvent (RxData->RecycleSignal);
426 goto ON_EXIT;
427 }
428
429 //
430 // Copy the right ICMP error message into mode data.
431 //
432 CopiedLen = 0;
433 IcmpError = (UINT8 *) &Mode->IcmpError;
434
435 for (Index = 0; Index < RxData->FragmentCount; Index++) {
436 CopiedLen += RxData->FragmentTable[Index].FragmentLength;
437 if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
438 CopyMem (
439 IcmpError,
440 RxData->FragmentTable[Index].FragmentBuffer,
441 RxData->FragmentTable[Index].FragmentLength
442 );
443 } else {
444 CopyMem (
445 IcmpError,
446 RxData->FragmentTable[Index].FragmentBuffer,
447 CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
448 );
449 }
450 IcmpError += CopiedLen;
451 }
452
453 ON_EXIT:
454 Private->IcmpToken.Status = EFI_NOT_READY;
455 Ip4->Receive (Ip4, &Private->IcmpToken);
456 }
457
458
459 /**
460 Callback function to update the latest ICMP6 error message.
461
462 @param Event The event signalled.
463 @param Context The context passed in using the event notifier.
464
465 **/
466 VOID
467 EFIAPI
468 PxeBcIcmpErrorUpdate (
469 IN EFI_EVENT Event,
470 IN VOID *Context
471 )
472 {
473 QueueDpc (TPL_CALLBACK, PxeBcIcmpErrorDpcHandle, Context);
474 }
475
476
477 /**
478 Notify function to handle the received ICMP6 message in DPC.
479
480 @param Context The PXEBC private data.
481
482 **/
483 VOID
484 EFIAPI
485 PxeBcIcmp6ErrorDpcHandle (
486 IN VOID *Context
487 )
488 {
489 PXEBC_PRIVATE_DATA *Private;
490 EFI_IP6_RECEIVE_DATA *RxData;
491 EFI_IP6_PROTOCOL *Ip6;
492 EFI_PXE_BASE_CODE_MODE *Mode;
493 EFI_STATUS Status;
494 UINTN Index;
495 UINT8 Type;
496 UINT32 CopiedLen;
497 UINT8 *Icmp6Error;
498
499 Private = (PXEBC_PRIVATE_DATA *) Context;
500 Mode = &Private->Mode;
501 Status = Private->Icmp6Token.Status;
502 RxData = Private->Icmp6Token.Packet.RxData;
503 Ip6 = Private->Ip6;
504
505 ASSERT (Mode->UsingIpv6);
506
507 if (Status == EFI_ABORTED) {
508 //
509 // It's triggered by user cancellation.
510 //
511 return;
512 }
513
514 if (RxData == NULL) {
515 goto ON_EXIT;
516 }
517
518 if (Status != EFI_ICMP_ERROR) {
519 //
520 // The return status should be recognized as EFI_ICMP_ERROR.
521 //
522 gBS->SignalEvent (RxData->RecycleSignal);
523 goto ON_EXIT;
524 }
525
526 if (!NetIp6IsValidUnicast (&RxData->Header->SourceAddress)) {
527 //
528 // The source address of the received packet should be a valid unicast address.
529 //
530 gBS->SignalEvent (RxData->RecycleSignal);
531 goto ON_EXIT;
532 }
533
534 if (!NetIp6IsUnspecifiedAddr (&Mode->StationIp.v6) &&
535 !EFI_IP6_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v6)) {
536 //
537 // The destination address of the received packet should be equal to the host address.
538 //
539 gBS->SignalEvent (RxData->RecycleSignal);
540 goto ON_EXIT;
541 }
542
543 if (RxData->Header->NextHeader != IP6_ICMP) {
544 //
545 // The nextheader in the header of the receveid packet should be IP6_ICMP.
546 //
547 gBS->SignalEvent (RxData->RecycleSignal);
548 goto ON_EXIT;
549 }
550
551 Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer);
552
553 if (Type != ICMP_V6_DEST_UNREACHABLE &&
554 Type != ICMP_V6_PACKET_TOO_BIG &&
555 Type != ICMP_V6_PACKET_TOO_BIG &&
556 Type != ICMP_V6_PARAMETER_PROBLEM) {
557 //
558 // The type of the receveid packet should be an ICMP6 error message.
559 //
560 gBS->SignalEvent (RxData->RecycleSignal);
561 goto ON_EXIT;
562 }
563
564 //
565 // Copy the right ICMP6 error message into mode data.
566 //
567 CopiedLen = 0;
568 Icmp6Error = (UINT8 *) &Mode->IcmpError;
569
570 for (Index = 0; Index < RxData->FragmentCount; Index++) {
571 CopiedLen += RxData->FragmentTable[Index].FragmentLength;
572 if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
573 CopyMem (
574 Icmp6Error,
575 RxData->FragmentTable[Index].FragmentBuffer,
576 RxData->FragmentTable[Index].FragmentLength
577 );
578 } else {
579 CopyMem (
580 Icmp6Error,
581 RxData->FragmentTable[Index].FragmentBuffer,
582 CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
583 );
584 }
585 Icmp6Error += CopiedLen;
586 }
587
588 ON_EXIT:
589 Private->Icmp6Token.Status = EFI_NOT_READY;
590 Ip6->Receive (Ip6, &Private->Icmp6Token);
591 }
592
593
594 /**
595 Callback function to update the latest ICMP6 error message.
596
597 @param Event The event signalled.
598 @param Context The context passed in using the event notifier.
599
600 **/
601 VOID
602 EFIAPI
603 PxeBcIcmp6ErrorUpdate (
604 IN EFI_EVENT Event,
605 IN VOID *Context
606 )
607 {
608 QueueDpc (TPL_CALLBACK, PxeBcIcmp6ErrorDpcHandle, Context);
609 }
610
611
612 /**
613 This function is to configure a UDPv4 instance for UdpWrite.
614
615 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
616 @param[in] StationIp The pointer to the station address.
617 @param[in] SubnetMask The pointer to the subnet mask.
618 @param[in] Gateway The pointer to the gateway address.
619 @param[in, out] SrcPort The pointer to the source port.
620 @param[in] DoNotFragment If TRUE, fragment is not enabled.
621 Otherwise, fragment is enabled.
622
623 @retval EFI_SUCCESS Successfully configured this instance.
624 @retval Others Failed to configure this instance.
625
626 **/
627 EFI_STATUS
628 PxeBcConfigUdp4Write (
629 IN EFI_UDP4_PROTOCOL *Udp4,
630 IN EFI_IPv4_ADDRESS *StationIp,
631 IN EFI_IPv4_ADDRESS *SubnetMask,
632 IN EFI_IPv4_ADDRESS *Gateway,
633 IN OUT UINT16 *SrcPort,
634 IN BOOLEAN DoNotFragment
635 )
636 {
637 EFI_UDP4_CONFIG_DATA Udp4CfgData;
638 EFI_STATUS Status;
639
640 ZeroMem (&Udp4CfgData, sizeof (Udp4CfgData));
641
642 Udp4CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME;
643 Udp4CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;
644 Udp4CfgData.TypeOfService = DEFAULT_ToS;
645 Udp4CfgData.TimeToLive = DEFAULT_TTL;
646 Udp4CfgData.AllowDuplicatePort = TRUE;
647 Udp4CfgData.DoNotFragment = DoNotFragment;
648
649 CopyMem (&Udp4CfgData.StationAddress, StationIp, sizeof (*StationIp));
650 CopyMem (&Udp4CfgData.SubnetMask, SubnetMask, sizeof (*SubnetMask));
651
652 Udp4CfgData.StationPort = *SrcPort;
653
654 //
655 // Reset the UDPv4 instance.
656 //
657 Udp4->Configure (Udp4, NULL);
658
659 Status = Udp4->Configure (Udp4, &Udp4CfgData);
660 if (!EFI_ERROR (Status) && !EFI_IP4_EQUAL (Gateway, &mZeroIp4Addr)) {
661 //
662 // The basic configuration is OK, need to add the default route entry
663 //
664 Status = Udp4->Routes (Udp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, Gateway);
665 if (EFI_ERROR (Status)) {
666 Udp4->Configure (Udp4, NULL);
667 }
668 }
669
670 if (!EFI_ERROR (Status) && *SrcPort == 0) {
671 Udp4->GetModeData (Udp4, &Udp4CfgData, NULL, NULL, NULL);
672 *SrcPort = Udp4CfgData.StationPort;
673 }
674
675 return Status;
676 }
677
678
679 /**
680 This function is to configure a UDPv6 instance for UdpWrite.
681
682 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
683 @param[in] StationIp The pointer to the station address.
684 @param[in, out] SrcPort The pointer to the source port.
685
686 @retval EFI_SUCCESS Successfully configured this instance.
687 @retval Others Failed to configure this instance.
688
689 **/
690 EFI_STATUS
691 PxeBcConfigUdp6Write (
692 IN EFI_UDP6_PROTOCOL *Udp6,
693 IN EFI_IPv6_ADDRESS *StationIp,
694 IN OUT UINT16 *SrcPort
695 )
696 {
697 EFI_UDP6_CONFIG_DATA CfgData;
698 EFI_STATUS Status;
699
700 ZeroMem (&CfgData, sizeof (EFI_UDP6_CONFIG_DATA));
701
702 CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;
703 CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME;
704 CfgData.HopLimit = PXEBC_DEFAULT_HOPLIMIT;
705 CfgData.AllowDuplicatePort = TRUE;
706 CfgData.StationPort = *SrcPort;
707
708 CopyMem (&CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
709
710 //
711 // Reset the UDPv6 instance.
712 //
713 Udp6->Configure (Udp6, NULL);
714
715 Status = Udp6->Configure (Udp6, &CfgData);
716 if (EFI_ERROR (Status)) {
717 return Status;
718 }
719
720 if (!EFI_ERROR (Status) && *SrcPort == 0) {
721 Udp6->GetModeData (Udp6, &CfgData, NULL, NULL, NULL);
722 *SrcPort = CfgData.StationPort;
723 }
724
725 return Status;
726 }
727
728
729 /**
730 This function is to configure a UDPv4 instance for UdpWrite.
731
732 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
733 @param[in] Session The pointer to the UDP4 session data.
734 @param[in] TimeoutEvent The event for timeout.
735 @param[in] Gateway The pointer to the gateway address.
736 @param[in] HeaderSize An optional field which may be set to the length of a header
737 at HeaderPtr to be prefixed to the data at BufferPtr.
738 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
739 prefixed to the data at BufferPtr.
740 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
741 @param[in] BufferPtr A pointer to the data to be written.
742
743 @retval EFI_SUCCESS Successfully send out data using Udp4Write.
744 @retval Others Failed to send out data.
745
746 **/
747 EFI_STATUS
748 PxeBcUdp4Write (
749 IN EFI_UDP4_PROTOCOL *Udp4,
750 IN EFI_UDP4_SESSION_DATA *Session,
751 IN EFI_EVENT TimeoutEvent,
752 IN EFI_IPv4_ADDRESS *Gateway OPTIONAL,
753 IN UINTN *HeaderSize OPTIONAL,
754 IN VOID *HeaderPtr OPTIONAL,
755 IN UINTN *BufferSize,
756 IN VOID *BufferPtr
757 )
758 {
759 EFI_UDP4_COMPLETION_TOKEN Token;
760 EFI_UDP4_TRANSMIT_DATA *TxData;
761 UINT32 TxLength;
762 UINT32 FragCount;
763 UINT32 DataLength;
764 BOOLEAN IsDone;
765 EFI_STATUS Status;
766
767 //
768 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
769 //
770 FragCount = (HeaderSize != NULL) ? 2 : 1;
771 TxLength = sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA);
772 TxData = (EFI_UDP4_TRANSMIT_DATA *) AllocateZeroPool (TxLength);
773 if (TxData == NULL) {
774 return EFI_OUT_OF_RESOURCES;
775 }
776
777 TxData->FragmentCount = FragCount;
778 TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;
779 TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
780 DataLength = (UINT32) *BufferSize;
781
782 if (HeaderSize != NULL) {
783 TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;
784 TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
785 DataLength += (UINT32) *HeaderSize;
786 }
787
788 if (Gateway != NULL) {
789 TxData->GatewayAddress = Gateway;
790 }
791
792 TxData->UdpSessionData = Session;
793 TxData->DataLength = DataLength;
794 Token.Packet.TxData = TxData;
795 Token.Status = EFI_NOT_READY;
796 IsDone = FALSE;
797
798 Status = gBS->CreateEvent (
799 EVT_NOTIFY_SIGNAL,
800 TPL_NOTIFY,
801 PxeBcCommonNotify,
802 &IsDone,
803 &Token.Event
804 );
805 if (EFI_ERROR (Status)) {
806 goto ON_EXIT;
807 }
808
809 Status = Udp4->Transmit (Udp4, &Token);
810 if (EFI_ERROR (Status)) {
811 goto ON_EXIT;
812 }
813
814 //
815 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
816 //
817 while (!IsDone &&
818 Token.Status == EFI_NOT_READY &&
819 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
820 Udp4->Poll (Udp4);
821 }
822
823 Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;
824
825 ON_EXIT:
826 if (Token.Event != NULL) {
827 gBS->CloseEvent (Token.Event);
828 }
829 FreePool (TxData);
830
831 return Status;
832 }
833
834
835 /**
836 This function is to configure a UDPv4 instance for UdpWrite.
837
838 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
839 @param[in] Session The pointer to the UDP6 session data.
840 @param[in] TimeoutEvent The event for timeout.
841 @param[in] HeaderSize An optional field which may be set to the length of a header
842 at HeaderPtr to be prefixed to the data at BufferPtr.
843 @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a header to be
844 prefixed to the data at BufferPtr.
845 @param[in] BufferSize A pointer to the size of the data at BufferPtr.
846 @param[in] BufferPtr A pointer to the data to be written.
847
848 @retval EFI_SUCCESS Successfully sent out data using Udp6Write.
849 @retval Others Failed to send out data.
850
851 **/
852 EFI_STATUS
853 PxeBcUdp6Write (
854 IN EFI_UDP6_PROTOCOL *Udp6,
855 IN EFI_UDP6_SESSION_DATA *Session,
856 IN EFI_EVENT TimeoutEvent,
857 IN UINTN *HeaderSize OPTIONAL,
858 IN VOID *HeaderPtr OPTIONAL,
859 IN UINTN *BufferSize,
860 IN VOID *BufferPtr
861 )
862 {
863 EFI_UDP6_COMPLETION_TOKEN Token;
864 EFI_UDP6_TRANSMIT_DATA *TxData;
865 UINT32 TxLength;
866 UINT32 FragCount;
867 UINT32 DataLength;
868 BOOLEAN IsDone;
869 EFI_STATUS Status;
870
871 //
872 // Arrange one fragment buffer for data, and another fragment buffer for header if has.
873 //
874 FragCount = (HeaderSize != NULL) ? 2 : 1;
875 TxLength = sizeof (EFI_UDP6_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP6_FRAGMENT_DATA);
876 TxData = (EFI_UDP6_TRANSMIT_DATA *) AllocateZeroPool (TxLength);
877 if (TxData == NULL) {
878 return EFI_OUT_OF_RESOURCES;
879 }
880
881 TxData->FragmentCount = FragCount;
882 TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;
883 TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
884 DataLength = (UINT32) *BufferSize;
885
886 if (HeaderSize != NULL) {
887 TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;
888 TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
889 DataLength += (UINT32) *HeaderSize;
890 }
891
892 TxData->UdpSessionData = Session;
893 TxData->DataLength = DataLength;
894 Token.Packet.TxData = TxData;
895 Token.Status = EFI_NOT_READY;
896 IsDone = FALSE;
897
898 Status = gBS->CreateEvent (
899 EVT_NOTIFY_SIGNAL,
900 TPL_NOTIFY,
901 PxeBcCommonNotify,
902 &IsDone,
903 &Token.Event
904 );
905 if (EFI_ERROR (Status)) {
906 goto ON_EXIT;
907 }
908
909 Status = Udp6->Transmit (Udp6, &Token);
910 if (EFI_ERROR (Status)) {
911 goto ON_EXIT;
912 }
913
914 //
915 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
916 //
917 while (!IsDone &&
918 Token.Status == EFI_NOT_READY &&
919 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
920 Udp6->Poll (Udp6);
921 }
922
923 Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;
924
925 ON_EXIT:
926 if (Token.Event != NULL) {
927 gBS->CloseEvent (Token.Event);
928 }
929 FreePool (TxData);
930
931 return Status;
932 }
933
934
935 /**
936 Check the received packet using the Ip filter.
937
938 @param[in] Mode The pointer to the mode data of PxeBc.
939 @param[in] Session The pointer to the current UDPv4 session.
940 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
941
942 @retval TRUE Passed the Ip filter successfully.
943 @retval FALSE Failed to pass the Ip filter.
944
945 **/
946 BOOLEAN
947 PxeBcCheckByIpFilter (
948 IN EFI_PXE_BASE_CODE_MODE *Mode,
949 IN VOID *Session,
950 IN UINT16 OpFlags
951 )
952 {
953 EFI_IP_ADDRESS DestinationIp;
954 UINTN Index;
955
956 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) == 0) {
957 return TRUE;
958 }
959
960 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) {
961 return TRUE;
962 }
963
964 //
965 // Convert the destination address in session data to host order.
966 //
967 if (Mode->UsingIpv6) {
968 CopyMem (
969 &DestinationIp,
970 &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,
971 sizeof (EFI_IPv6_ADDRESS)
972 );
973 NTOHLLL (&DestinationIp.v6);
974 } else {
975 ZeroMem (&DestinationIp, sizeof (EFI_IP_ADDRESS));
976 CopyMem (
977 &DestinationIp,
978 &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,
979 sizeof (EFI_IPv4_ADDRESS)
980 );
981 EFI_NTOHL (DestinationIp);
982 }
983
984 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0 &&
985 (IP4_IS_MULTICAST (DestinationIp.Addr[0]) ||
986 IP6_IS_MULTICAST (&DestinationIp))) {
987 return TRUE;
988 }
989
990 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0 &&
991 IP4_IS_LOCAL_BROADCAST (DestinationIp.Addr[0])) {
992 ASSERT (!Mode->UsingIpv6);
993 return TRUE;
994 }
995
996 if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 &&
997 (EFI_IP4_EQUAL (&Mode->StationIp.v4, &DestinationIp) ||
998 EFI_IP6_EQUAL (&Mode->StationIp.v6, &DestinationIp))) {
999 //
1000 // Matched if the dest address is equal to the station address.
1001 //
1002 return TRUE;
1003 }
1004
1005 for (Index = 0; Index < Mode->IpFilter.IpCnt; Index++) {
1006 ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT);
1007 if (EFI_IP4_EQUAL (&Mode->IpFilter.IpList[Index].v4, &DestinationIp) ||
1008 EFI_IP6_EQUAL (&Mode->IpFilter.IpList[Index].v6, &DestinationIp)) {
1009 //
1010 // Matched if the dest address is equal to any of address in the filter list.
1011 //
1012 return TRUE;
1013 }
1014 }
1015
1016 return FALSE;
1017 }
1018
1019
1020 /**
1021 Filter the received packet using the destination Ip.
1022
1023 @param[in] Mode The pointer to the mode data of PxeBc.
1024 @param[in] Session The pointer to the current UDPv4 session.
1025 @param[in, out] DestIp The pointer to the destination Ip address.
1026 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1027
1028 @retval TRUE Passed the IPv4 filter successfully.
1029 @retval FALSE Failed to pass the IPv4 filter.
1030
1031 **/
1032 BOOLEAN
1033 PxeBcCheckByDestIp (
1034 IN EFI_PXE_BASE_CODE_MODE *Mode,
1035 IN VOID *Session,
1036 IN OUT EFI_IP_ADDRESS *DestIp,
1037 IN UINT16 OpFlags
1038 )
1039 {
1040 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) != 0) {
1041 //
1042 // Copy the destination address from the received packet if accept any.
1043 //
1044 if (DestIp != NULL) {
1045 if (Mode->UsingIpv6) {
1046 CopyMem (
1047 DestIp,
1048 &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress,
1049 sizeof (EFI_IPv6_ADDRESS)
1050 );
1051 } else {
1052 ZeroMem (DestIp, sizeof (EFI_IP_ADDRESS));
1053 CopyMem (
1054 DestIp,
1055 &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress,
1056 sizeof (EFI_IPv4_ADDRESS)
1057 );
1058 }
1059
1060 }
1061 return TRUE;
1062 } else if (DestIp != NULL &&
1063 (EFI_IP4_EQUAL (DestIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||
1064 EFI_IP6_EQUAL (DestIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress))) {
1065 //
1066 // The destination address in the received packet is matched if present.
1067 //
1068 return TRUE;
1069 } else if (EFI_IP4_EQUAL (&Mode->StationIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||
1070 EFI_IP6_EQUAL (&Mode->StationIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress)) {
1071 //
1072 // The destination address in the received packet is equal to the host address.
1073 //
1074 return TRUE;
1075 }
1076
1077 return FALSE;
1078 }
1079
1080
1081 /**
1082 Check the received packet using the destination port.
1083
1084 @param[in] PxeBcMode The pointer to the mode data of PxeBc.
1085 @param[in] Session The pointer to the current UDPv4 session.
1086 @param[in, out] DestPort The pointer to the destination port.
1087 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1088
1089 @retval TRUE Passed the IPv4 filter successfully.
1090 @retval FALSE Failed to pass the IPv4 filter.
1091
1092 **/
1093 BOOLEAN
1094 PxeBcCheckByDestPort (
1095 IN EFI_PXE_BASE_CODE_MODE *Mode,
1096 IN VOID *Session,
1097 IN OUT UINT16 *DestPort,
1098 IN UINT16 OpFlags
1099 )
1100 {
1101 UINT16 Port;
1102
1103 if (Mode->UsingIpv6) {
1104 Port = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;
1105 } else {
1106 Port = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;
1107 }
1108
1109 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0) {
1110 //
1111 // Return the destination port in the received packet if accept any.
1112 //
1113 if (DestPort != NULL) {
1114 *DestPort = Port;
1115 }
1116 return TRUE;
1117 } else if (DestPort != NULL && *DestPort == Port) {
1118 //
1119 // The destination port in the received packet is matched if present.
1120 //
1121 return TRUE;
1122 }
1123
1124 return FALSE;
1125 }
1126
1127
1128 /**
1129 Filter the received packet using the source Ip.
1130
1131 @param[in] Mode The pointer to the mode data of PxeBc.
1132 @param[in] Session The pointer to the current UDPv4 session.
1133 @param[in, out] SrcIp The pointer to the source Ip address.
1134 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1135
1136 @retval TRUE Passed the IPv4 filter successfully.
1137 @retval FALSE Failed to pass the IPv4 filter.
1138
1139 **/
1140 BOOLEAN
1141 PxeBcFilterBySrcIp (
1142 IN EFI_PXE_BASE_CODE_MODE *Mode,
1143 IN VOID *Session,
1144 IN OUT EFI_IP_ADDRESS *SrcIp,
1145 IN UINT16 OpFlags
1146 )
1147 {
1148 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0) {
1149 //
1150 // Copy the source address from the received packet if accept any.
1151 //
1152 if (SrcIp != NULL) {
1153 if (Mode->UsingIpv6) {
1154 CopyMem (
1155 SrcIp,
1156 &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress,
1157 sizeof (EFI_IPv6_ADDRESS)
1158 );
1159 } else {
1160 ZeroMem (SrcIp, sizeof (EFI_IP_ADDRESS));
1161 CopyMem (
1162 SrcIp,
1163 &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress,
1164 sizeof (EFI_IPv4_ADDRESS)
1165 );
1166 }
1167
1168 }
1169 return TRUE;
1170 } else if (SrcIp != NULL &&
1171 (EFI_IP4_EQUAL (SrcIp, &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress) ||
1172 EFI_IP6_EQUAL (SrcIp, &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress))) {
1173 //
1174 // The source address in the received packet is matched if present.
1175 //
1176 return TRUE;
1177 }
1178
1179 return FALSE;
1180 }
1181
1182
1183 /**
1184 Filter the received packet using the source port.
1185
1186 @param[in] Mode The pointer to the mode data of PxeBc.
1187 @param[in] Session The pointer to the current UDPv4 session.
1188 @param[in, out] SrcPort The pointer to the source port.
1189 @param[in] OpFlags Operation flag for UdpRead/UdpWrite.
1190
1191 @retval TRUE Passed the IPv4 filter successfully.
1192 @retval FALSE Failed to pass the IPv4 filter.
1193
1194 **/
1195 BOOLEAN
1196 PxeBcFilterBySrcPort (
1197 IN EFI_PXE_BASE_CODE_MODE *Mode,
1198 IN VOID *Session,
1199 IN OUT UINT16 *SrcPort,
1200 IN UINT16 OpFlags
1201 )
1202 {
1203 UINT16 Port;
1204
1205 if (Mode->UsingIpv6) {
1206 Port = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;
1207 } else {
1208 Port = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;
1209 }
1210
1211 if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0) {
1212 //
1213 // Return the source port in the received packet if accept any.
1214 //
1215 if (SrcPort != NULL) {
1216 *SrcPort = Port;
1217 }
1218 return TRUE;
1219 } else if (SrcPort != NULL && *SrcPort == Port) {
1220 //
1221 // The source port in the received packet is matched if present.
1222 //
1223 return TRUE;
1224 }
1225
1226 return FALSE;
1227 }
1228
1229
1230 /**
1231 This function is to receive packet using Udp4Read.
1232
1233 @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL.
1234 @param[in] Token The pointer to EFI_UDP4_COMPLETION_TOKEN.
1235 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1236 @param[in] TimeoutEvent The event for timeout.
1237 @param[in] OpFlags The UDP operation flags.
1238 @param[in] IsDone The pointer to the IsDone flag.
1239 @param[out] IsMatched The pointer to the IsMatched flag.
1240 @param[in, out] DestIp The pointer to the destination address.
1241 @param[in, out] DestPort The pointer to the destination port.
1242 @param[in, out] SrcIp The pointer to the source address.
1243 @param[in, out] SrcPort The pointer to the source port.
1244
1245 @retval EFI_SUCCESS Successfully read the data using Udp4.
1246 @retval Others Failed to send out data.
1247
1248 **/
1249 EFI_STATUS
1250 PxeBcUdp4Read (
1251 IN EFI_UDP4_PROTOCOL *Udp4,
1252 IN EFI_UDP4_COMPLETION_TOKEN *Token,
1253 IN EFI_PXE_BASE_CODE_MODE *Mode,
1254 IN EFI_EVENT TimeoutEvent,
1255 IN UINT16 OpFlags,
1256 IN BOOLEAN *IsDone,
1257 OUT BOOLEAN *IsMatched,
1258 IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL,
1259 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL,
1260 IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL,
1261 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL
1262 )
1263 {
1264 EFI_UDP4_RECEIVE_DATA *RxData;
1265 EFI_UDP4_SESSION_DATA *Session;
1266 EFI_STATUS Status;
1267
1268 Token->Status = EFI_NOT_READY;
1269 *IsDone = FALSE;
1270
1271 Status = Udp4->Receive (Udp4, Token);
1272 if (EFI_ERROR (Status)) {
1273 return Status;
1274 }
1275
1276 //
1277 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1278 //
1279 while (!(*IsDone) &&
1280 Token->Status == EFI_NOT_READY &&
1281 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
1282 //
1283 // Poll the token utill reply/ICMPv6 error message received or timeout.
1284 //
1285 Udp4->Poll (Udp4);
1286 if (Token->Status == EFI_ICMP_ERROR ||
1287 Token->Status == EFI_NETWORK_UNREACHABLE ||
1288 Token->Status == EFI_HOST_UNREACHABLE ||
1289 Token->Status == EFI_PROTOCOL_UNREACHABLE ||
1290 Token->Status == EFI_PORT_UNREACHABLE) {
1291 break;
1292 }
1293 }
1294
1295 Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;
1296
1297 if (!EFI_ERROR (Status)) {
1298 //
1299 // check whether this packet matches the filters
1300 //
1301 RxData = Token->Packet.RxData;
1302 Session = &RxData->UdpSession;
1303
1304 *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);
1305
1306 if (*IsMatched) {
1307 *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);
1308 }
1309
1310 if (*IsMatched) {
1311 *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);
1312 }
1313
1314 if (*IsMatched) {
1315 *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);
1316 }
1317
1318 if (*IsMatched) {
1319 *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);
1320 }
1321
1322 if (!(*IsMatched)) {
1323 //
1324 // Recycle the receiving buffer if not matched.
1325 //
1326 gBS->SignalEvent (RxData->RecycleSignal);
1327 }
1328 }
1329
1330 return Status;
1331 }
1332
1333
1334 /**
1335 This function is to receive packets using Udp6Read.
1336
1337 @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL.
1338 @param[in] Token The pointer to EFI_UDP6_COMPLETION_TOKEN.
1339 @param[in] Mode The pointer to EFI_PXE_BASE_CODE_MODE.
1340 @param[in] TimeoutEvent The event for timeout.
1341 @param[in] OpFlags The UDP operation flags.
1342 @param[in] IsDone The pointer to the IsDone flag.
1343 @param[out] IsMatched The pointer to the IsMatched flag.
1344 @param[in, out] DestIp The pointer to the destination address.
1345 @param[in, out] DestPort The pointer to the destination port.
1346 @param[in, out] SrcIp The pointer to the source address.
1347 @param[in, out] SrcPort The pointer to the source port.
1348
1349 @retval EFI_SUCCESS Successfully read data using Udp6.
1350 @retval Others Failed to send out data.
1351
1352 **/
1353 EFI_STATUS
1354 PxeBcUdp6Read (
1355 IN EFI_UDP6_PROTOCOL *Udp6,
1356 IN EFI_UDP6_COMPLETION_TOKEN *Token,
1357 IN EFI_PXE_BASE_CODE_MODE *Mode,
1358 IN EFI_EVENT TimeoutEvent,
1359 IN UINT16 OpFlags,
1360 IN BOOLEAN *IsDone,
1361 OUT BOOLEAN *IsMatched,
1362 IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL,
1363 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL,
1364 IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL,
1365 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL
1366 )
1367 {
1368 EFI_UDP6_RECEIVE_DATA *RxData;
1369 EFI_UDP6_SESSION_DATA *Session;
1370 EFI_STATUS Status;
1371
1372 Token->Status = EFI_NOT_READY;
1373 *IsDone = FALSE;
1374
1375 Status = Udp6->Receive (Udp6, Token);
1376 if (EFI_ERROR (Status)) {
1377 return Status;
1378 }
1379
1380 //
1381 // Poll the UDPv6 read instance if no packet received and no timeout triggered.
1382 //
1383 while (!(*IsDone) &&
1384 Token->Status == EFI_NOT_READY &&
1385 EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
1386 //
1387 // Poll the token utill reply/ICMPv6 error message received or timeout.
1388 //
1389 Udp6->Poll (Udp6);
1390 if (Token->Status == EFI_ICMP_ERROR ||
1391 Token->Status == EFI_NETWORK_UNREACHABLE ||
1392 Token->Status == EFI_HOST_UNREACHABLE ||
1393 Token->Status == EFI_PROTOCOL_UNREACHABLE ||
1394 Token->Status == EFI_PORT_UNREACHABLE) {
1395 break;
1396 }
1397 }
1398
1399 Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;
1400
1401 if (!EFI_ERROR (Status)) {
1402 //
1403 // check whether this packet matches the filters
1404 //
1405 RxData = Token->Packet.RxData;
1406 Session = &RxData->UdpSession;
1407
1408 *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);
1409
1410 if (*IsMatched) {
1411 *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);
1412 }
1413
1414 if (*IsMatched) {
1415 *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);
1416 }
1417
1418 if (*IsMatched) {
1419 *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);
1420 }
1421
1422 if (*IsMatched) {
1423 *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);
1424 }
1425
1426 if (!(*IsMatched)) {
1427 //
1428 // Recycle the receiving buffer if not matched.
1429 //
1430 gBS->SignalEvent (RxData->RecycleSignal);
1431 }
1432 }
1433
1434 return Status;
1435 }
1436
1437
1438 /**
1439 This function is to display the IPv4 address.
1440
1441 @param[in] Ip The pointer to the IPv4 address.
1442
1443 **/
1444 VOID
1445 PxeBcShowIp4Addr (
1446 IN EFI_IPv4_ADDRESS *Ip
1447 )
1448 {
1449 UINTN Index;
1450
1451 for (Index = 0; Index < 4; Index++) {
1452 AsciiPrint ("%d", Ip->Addr[Index]);
1453 if (Index < 3) {
1454 AsciiPrint (".");
1455 }
1456 }
1457 }
1458
1459
1460 /**
1461 This function is to display the IPv6 address.
1462
1463 @param[in] Ip The pointer to the IPv6 address.
1464
1465 **/
1466 VOID
1467 PxeBcShowIp6Addr (
1468 IN EFI_IPv6_ADDRESS *Ip
1469 )
1470 {
1471 UINTN Index;
1472
1473 for (Index = 0; Index < 16; Index++) {
1474
1475 if (Ip->Addr[Index] != 0) {
1476 AsciiPrint ("%x", Ip->Addr[Index]);
1477 }
1478 Index++;
1479 if (Index > 15) {
1480 return;
1481 }
1482 if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {
1483 AsciiPrint ("0");
1484 }
1485 AsciiPrint ("%x", Ip->Addr[Index]);
1486 if (Index < 15) {
1487 AsciiPrint (":");
1488 }
1489 }
1490 }
1491
1492
1493 /**
1494 This function is to convert UINTN to ASCII string with the required formatting.
1495
1496 @param[in] Number Numeric value to be converted.
1497 @param[in] Buffer The pointer to the buffer for ASCII string.
1498 @param[in] Length The length of the required format.
1499
1500 **/
1501 VOID
1502 PxeBcUintnToAscDecWithFormat (
1503 IN UINTN Number,
1504 IN UINT8 *Buffer,
1505 IN INTN Length
1506 )
1507 {
1508 UINTN Remainder;
1509
1510 while (Length > 0) {
1511 Length--;
1512 Remainder = Number % 10;
1513 Number /= 10;
1514 Buffer[Length] = (UINT8) ('0' + Remainder);
1515 }
1516 }
1517
1518
1519 /**
1520 This function is to convert a UINTN to a ASCII string, and return the
1521 actual length of the buffer.
1522
1523 @param[in] Number Numeric value to be converted.
1524 @param[in] Buffer The pointer to the buffer for ASCII string.
1525
1526 @return Length The actual length of the ASCII string.
1527
1528 **/
1529 UINTN
1530 PxeBcUintnToAscDec (
1531 IN UINTN Number,
1532 IN UINT8 *Buffer
1533 )
1534 {
1535 UINTN Index;
1536 UINTN Length;
1537 CHAR8 TempStr[64];
1538
1539 Index = 63;
1540 TempStr[Index] = 0;
1541
1542 do {
1543 Index--;
1544 TempStr[Index] = (CHAR8) ('0' + (Number % 10));
1545 Number = (UINTN) (Number / 10);
1546 } while (Number != 0);
1547
1548 AsciiStrCpy ((CHAR8 *) Buffer, &TempStr[Index]);
1549
1550 Length = AsciiStrLen ((CHAR8 *) Buffer);
1551
1552 return Length;
1553 }
1554
1555
1556 /**
1557 This function is to convert unicode hex number to a UINT8.
1558
1559 @param[out] Digit The converted UINT8 for output.
1560 @param[in] Char The unicode hex number to be converted.
1561
1562 @retval EFI_SUCCESS Successfully converted the unicode hex.
1563 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.
1564
1565 **/
1566 EFI_STATUS
1567 PxeBcUniHexToUint8 (
1568 OUT UINT8 *Digit,
1569 IN CHAR16 Char
1570 )
1571 {
1572 if ((Char >= L'0') && (Char <= L'9')) {
1573 *Digit = (UINT8) (Char - L'0');
1574 return EFI_SUCCESS;
1575 }
1576
1577 if ((Char >= L'A') && (Char <= L'F')) {
1578 *Digit = (UINT8) (Char - L'A' + 0x0A);
1579 return EFI_SUCCESS;
1580 }
1581
1582 if ((Char >= L'a') && (Char <= L'f')) {
1583 *Digit = (UINT8) (Char - L'a' + 0x0A);
1584 return EFI_SUCCESS;
1585 }
1586
1587 return EFI_INVALID_PARAMETER;
1588 }