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