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