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