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