]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/UefiPxeBcDxe/PxeBcSupport.c
NetworkPkg: Remove redundant check 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 gBS->SignalEvent (RxData->RecycleSignal);
261 goto ON_EXIT;
262 }
263
264 if (EFI_IP4 (RxData->Header->SourceAddress) != 0 &&
265 (NTOHL (Mode->SubnetMask.Addr[0]) != 0) &&
266 IP4_NET_EQUAL (NTOHL(Mode->StationIp.Addr[0]), EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0])) &&
267 !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0]))) {
268 //
269 // The source address of the received packet should be a valid unicast address.
270 //
271 gBS->SignalEvent (RxData->RecycleSignal);
272 goto ON_EXIT;
273 }
274
275 if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {
276 //
277 // The destination address of the received packet should be equal to the host address.
278 //
279 gBS->SignalEvent (RxData->RecycleSignal);
280 goto ON_EXIT;
281 }
282
283 //
284 // The protocol has been configured to only receive ICMP packet.
285 //
286 ASSERT (RxData->Header->Protocol == EFI_IP_PROTO_ICMP);
287
288 Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer);
289
290 if (Type != ICMP_DEST_UNREACHABLE &&
291 Type != ICMP_SOURCE_QUENCH &&
292 Type != ICMP_REDIRECT &&
293 Type != ICMP_TIME_EXCEEDED &&
294 Type != ICMP_PARAMETER_PROBLEM) {
295 //
296 // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
297 //
298 gBS->SignalEvent (RxData->RecycleSignal);
299 goto ON_EXIT;
300 }
301
302 //
303 // Copy the right ICMP error message into mode data.
304 //
305 CopiedLen = 0;
306 IcmpError = (UINT8 *) &Mode->IcmpError;
307
308 for (Index = 0; Index < RxData->FragmentCount; Index++) {
309 CopiedLen += RxData->FragmentTable[Index].FragmentLength;
310 if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
311 CopyMem (
312 IcmpError,
313 RxData->FragmentTable[Index].FragmentBuffer,
314 RxData->FragmentTable[Index].FragmentLength
315 );
316 } else {
317 CopyMem (
318 IcmpError,
319 RxData->FragmentTable[Index].FragmentBuffer,
320 CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
321 );
322 }
323 IcmpError += CopiedLen;
324 }
325
326 ON_EXIT:
327 Private->IcmpToken.Status = EFI_NOT_READY;
328 Ip4->Receive (Ip4, &Private->IcmpToken);
329 }
330
331
332 /**
333 Callback function to update the latest ICMP6 error message.
334
335 @param Event The event signalled.
336 @param Context The context passed in using the event notifier.
337
338 **/
339 VOID
340 EFIAPI
341 PxeBcIcmpErrorUpdate (
342 IN EFI_EVENT Event,
343 IN VOID *Context
344 )
345 {
346 QueueDpc (TPL_CALLBACK, PxeBcIcmpErrorDpcHandle, Context);
347 }
348
349
350 /**
351 Notify function to handle the received ICMP6 message in DPC.
352
353 @param Context The PXEBC private data.
354
355 **/
356 VOID
357 EFIAPI
358 PxeBcIcmp6ErrorDpcHandle (
359 IN VOID *Context
360 )
361 {
362 PXEBC_PRIVATE_DATA *Private;
363 EFI_IP6_RECEIVE_DATA *RxData;
364 EFI_IP6_PROTOCOL *Ip6;
365 EFI_PXE_BASE_CODE_MODE *Mode;
366 EFI_STATUS Status;
367 UINTN Index;
368 UINT8 Type;
369 UINT32 CopiedLen;
370 UINT8 *Icmp6Error;
371
372 Private = (PXEBC_PRIVATE_DATA *) Context;
373 Mode = &Private->Mode;
374 Status = Private->Icmp6Token.Status;
375 RxData = Private->Icmp6Token.Packet.RxData;
376 Ip6 = Private->Ip6;
377
378 ASSERT (Mode->UsingIpv6);
379
380 if (Status == EFI_ABORTED) {
381 //
382 // It's triggered by user cancellation.
383 //
384 return;
385 }
386
387 if (RxData == NULL) {
388 goto ON_EXIT;
389 }
390
391 if (Status != EFI_ICMP_ERROR) {
392 //
393 // The return status should be recognized as EFI_ICMP_ERROR.
394 //
395 gBS->SignalEvent (RxData->RecycleSignal);
396 goto ON_EXIT;
397 }
398
399 if (!NetIp6IsValidUnicast (&RxData->Header->SourceAddress)) {
400 //
401 // The source address of the received packet should be a valid unicast address.
402 //
403 gBS->SignalEvent (RxData->RecycleSignal);
404 goto ON_EXIT;
405 }
406
407 if (!NetIp6IsUnspecifiedAddr (&Mode->StationIp.v6) &&
408 !EFI_IP6_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v6)) {
409 //
410 // The destination address of the received packet should be equal to the host address.
411 //
412 gBS->SignalEvent (RxData->RecycleSignal);
413 goto ON_EXIT;
414 }
415
416 //
417 // The protocol has been configured to only receive ICMP packet.
418 //
419 ASSERT (RxData->Header->NextHeader == IP6_ICMP);
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_TIME_EXCEEDED &&
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 for (; Length > 0; Length--) {
1385 Remainder = Number % 10;
1386 Number /= 10;
1387 Buffer[Length - 1] = (UINT8) ('0' + Remainder);
1388 }
1389 }
1390
1391
1392 /**
1393 This function is to convert a UINTN to a ASCII string, and return the
1394 actual length of the buffer.
1395
1396 @param[in] Number Numeric value to be converted.
1397 @param[in] Buffer The pointer to the buffer for ASCII string.
1398 @param[in] BufferSize The maxsize of the buffer.
1399
1400 @return Length The actual length of the ASCII string.
1401
1402 **/
1403 UINTN
1404 PxeBcUintnToAscDec (
1405 IN UINTN Number,
1406 IN UINT8 *Buffer,
1407 IN UINTN BufferSize
1408 )
1409 {
1410 UINTN Index;
1411 UINTN Length;
1412 CHAR8 TempStr[64];
1413
1414 Index = 63;
1415 TempStr[Index] = 0;
1416
1417 do {
1418 Index--;
1419 TempStr[Index] = (CHAR8) ('0' + (Number % 10));
1420 Number = (UINTN) (Number / 10);
1421 } while (Number != 0);
1422
1423 AsciiStrCpyS ((CHAR8 *) Buffer, BufferSize, &TempStr[Index]);
1424
1425 Length = AsciiStrLen ((CHAR8 *) Buffer);
1426
1427 return Length;
1428 }
1429
1430
1431 /**
1432 This function is to convert unicode hex number to a UINT8.
1433
1434 @param[out] Digit The converted UINT8 for output.
1435 @param[in] Char The unicode hex number to be converted.
1436
1437 @retval EFI_SUCCESS Successfully converted the unicode hex.
1438 @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex.
1439
1440 **/
1441 EFI_STATUS
1442 PxeBcUniHexToUint8 (
1443 OUT UINT8 *Digit,
1444 IN CHAR16 Char
1445 )
1446 {
1447 if ((Char >= L'0') && (Char <= L'9')) {
1448 *Digit = (UINT8) (Char - L'0');
1449 return EFI_SUCCESS;
1450 }
1451
1452 if ((Char >= L'A') && (Char <= L'F')) {
1453 *Digit = (UINT8) (Char - L'A' + 0x0A);
1454 return EFI_SUCCESS;
1455 }
1456
1457 if ((Char >= L'a') && (Char <= L'f')) {
1458 *Digit = (UINT8) (Char - L'a' + 0x0A);
1459 return EFI_SUCCESS;
1460 }
1461
1462 return EFI_INVALID_PARAMETER;
1463 }
1464
1465 /**
1466 Calculate the elapsed time.
1467
1468 @param[in] Private The pointer to PXE private data
1469
1470 **/
1471 VOID
1472 CalcElapsedTime (
1473 IN PXEBC_PRIVATE_DATA *Private
1474 )
1475 {
1476 EFI_TIME Time;
1477 UINT64 CurrentStamp;
1478 UINT64 ElapsedTimeValue;
1479
1480 //
1481 // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.
1482 //
1483 ZeroMem (&Time, sizeof (EFI_TIME));
1484 gRT->GetTime (&Time, NULL);
1485 CurrentStamp = (UINT64)
1486 (
1487 ((((((Time.Year - 1900) * 360 +
1488 (Time.Month - 1)) * 30 +
1489 (Time.Day - 1)) * 24 + Time.Hour) * 60 +
1490 Time.Minute) * 60 + Time.Second) * 100
1491 + DivU64x32(Time.Nanosecond, 10000000)
1492 );
1493
1494 //
1495 // Sentinel value of 0 means that this is the first DHCP packet that we are
1496 // sending and that we need to initialize the value. First DHCP Solicit
1497 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
1498 //
1499 if (Private->ElapsedTime == 0) {
1500 Private->ElapsedTime = CurrentStamp;
1501 } else {
1502 ElapsedTimeValue = CurrentStamp - Private->ElapsedTime;
1503
1504 //
1505 // If elapsed time cannot fit in two bytes, set it to 0xffff.
1506 //
1507 if (ElapsedTimeValue > 0xffff) {
1508 ElapsedTimeValue = 0xffff;
1509 }
1510 //
1511 // Save the elapsed time
1512 //
1513 Private->ElapsedTime = ElapsedTimeValue;
1514 }
1515 }
1516