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