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