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