1 /** @file
2   Udp6 driver's whole implementation.
3 
4   Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "Udp6Impl.h"
11 
12 UINT16  mUdp6RandomPort;
13 
14 /**
15   This function checks and timeouts the I/O datagrams holding by the corresponding
16   service context.
17 
18   @param[in]  Event              The event this function is registered to.
19   @param[in]  Context            The context data registered during the creation of
20                                  the Event.
21 
22 **/
23 VOID
24 EFIAPI
25 Udp6CheckTimeout (
26   IN EFI_EVENT  Event,
27   IN VOID       *Context
28   );
29 
30 /**
31   This function finds the udp instance by the specified <Address, Port> pair.
32 
33   @param[in]  InstanceList       Pointer to the head of the list linking the udp
34                                  instances.
35   @param[in]  Address            Pointer to the specified IPv6 address.
36   @param[in]  Port               The udp port number.
37 
38   @retval TRUE     The specified <Address, Port> pair is found.
39   @retval FALSE    Otherwise.
40 
41 **/
42 BOOLEAN
43 Udp6FindInstanceByPort (
44   IN LIST_ENTRY        *InstanceList,
45   IN EFI_IPv6_ADDRESS  *Address,
46   IN UINT16            Port
47   );
48 
49 /**
50   This function is the packet transmitting notify function registered to the IpIo
51   interface. It's called to signal the udp TxToken when the IpIo layer completes
52   transmitting of the udp datagram.
53 
54   If Context is NULL, then ASSERT().
55   If NotifyData is NULL, then ASSERT().
56 
57   @param[in]  Status            The completion status of the output udp datagram.
58   @param[in]  Context           Pointer to the context data.
59   @param[in]  Sender            Specify a EFI_IP6_PROTOCOL for sending.
60   @param[in]  NotifyData        Pointer to the notify data.
61 
62 **/
63 VOID
64 EFIAPI
65 Udp6DgramSent (
66   IN EFI_STATUS        Status,
67   IN VOID              *Context,
68   IN IP_IO_IP_PROTOCOL Sender,
69   IN VOID              *NotifyData
70   );
71 
72 /**
73   This function processes the received datagram passed up by the IpIo layer.
74 
75   If NetSession is NULL, then ASSERT().
76   If Packet is NULL, then ASSERT().
77   If Context is NULL, then ASSERT().
78 
79   @param[in]  Status            The status of this udp datagram.
80   @param[in]  IcmpError         The IcmpError code, only available when Status is
81                                 EFI_ICMP_ERROR.
82   @param[in]  NetSession        Pointer to the EFI_NET_SESSION_DATA.
83   @param[in]  Packet            Pointer to the NET_BUF containing the received udp
84                                 datagram.
85   @param[in]  Context           Pointer to the context data.
86 
87 **/
88 VOID
89 EFIAPI
90 Udp6DgramRcvd (
91   IN EFI_STATUS            Status,
92   IN UINT8                 IcmpError,
93   IN EFI_NET_SESSION_DATA  *NetSession,
94   IN NET_BUF               *Packet,
95   IN VOID                  *Context
96   );
97 
98 /**
99   This function cancel the token specified by Arg in the Map.
100 
101   @param[in]  Map             Pointer to the NET_MAP.
102   @param[in]  Item            Pointer to the NET_MAP_ITEM.
103   @param[in]  Arg             Pointer to the token to be cancelled, if NULL, all
104                               the tokens in this Map will be cancelled.
105                               This parameter is optional and may be NULL.
106 
107   @retval EFI_SUCCESS         The token is cancelled if Arg is NULL or the token
108                               is not the same as that in the Item if Arg is not
109                               NULL.
110   @retval EFI_ABORTED         Arg is not NULL, and the token specified by Arg is
111                               cancelled.
112 
113 **/
114 EFI_STATUS
115 EFIAPI
116 Udp6CancelTokens (
117   IN NET_MAP       *Map,
118   IN NET_MAP_ITEM  *Item,
119   IN VOID          *Arg OPTIONAL
120   );
121 
122 /**
123   This function check if the received udp datagram matches with the Instance.
124 
125   @param[in]  Instance           Pointer to the udp instance context data.
126   @param[in]  Udp6Session        Pointer to the EFI_UDP6_SESSION_DATA abstracted
127                                  from the received udp datagram.
128 
129   @retval TRUE     The udp datagram matches the receiving requirements of the Instance.
130   @retval FALSE    The udp datagram doe not match the receiving requirements of the Instance.
131 
132 **/
133 BOOLEAN
134 Udp6MatchDgram (
135   IN UDP6_INSTANCE_DATA     *Instance,
136   IN EFI_UDP6_SESSION_DATA  *Udp6Session
137   );
138 
139 /**
140   This function removes the Wrap specified by Context and releases relevant resources.
141 
142   @param[in]  Event                  The Event this notify function is registered to.
143   @param[in]  Context                Pointer to the context data.
144 
145 **/
146 VOID
147 EFIAPI
148 Udp6RecycleRxDataWrap (
149   IN EFI_EVENT  Event,
150   IN VOID       *Context
151   );
152 
153 /**
154   This function wraps the Packet into RxData.
155 
156   @param[in]  Instance           Pointer to the instance context data.
157   @param[in]  Packet             Pointer to the buffer containing the received
158                                  datagram.
159   @param[in]  RxData             Pointer to the EFI_UDP6_RECEIVE_DATA of this
160                                  datagram.
161 
162   @return Pointer to the structure wrapping the RxData and the Packet. NULL will
163           be returned if any error occurs.
164 
165 **/
166 UDP6_RXDATA_WRAP *
167 Udp6WrapRxData (
168   IN UDP6_INSTANCE_DATA     *Instance,
169   IN NET_BUF                *Packet,
170   IN EFI_UDP6_RECEIVE_DATA  *RxData
171   );
172 
173 /**
174   This function enqueues the received datagram into the instances' receiving queues.
175 
176   @param[in]  Udp6Service        Pointer to the udp service context data.
177   @param[in]  Packet             Pointer to the buffer containing the received
178                                  datagram.
179   @param[in]  RxData             Pointer to the EFI_UDP6_RECEIVE_DATA of this
180                                  datagram.
181 
182   @return The times this datagram is enqueued.
183 
184 **/
185 UINTN
186 Udp6EnqueueDgram (
187   IN UDP6_SERVICE_DATA      *Udp6Service,
188   IN NET_BUF                *Packet,
189   IN EFI_UDP6_RECEIVE_DATA  *RxData
190   );
191 
192 /**
193   This function delivers the datagrams enqueued in the instances.
194 
195   @param[in]  Udp6Service            Pointer to the udp service context data.
196 
197 **/
198 VOID
199 Udp6DeliverDgram (
200   IN UDP6_SERVICE_DATA  *Udp6Service
201   );
202 
203 /**
204   This function demultiplexes the received udp datagram to the appropriate instances.
205 
206   @param[in]  Udp6Service        Pointer to the udp service context data.
207   @param[in]  NetSession         Pointer to the EFI_NET_SESSION_DATA abstracted from
208                                  the received datagram.
209   @param[in]  Packet             Pointer to the buffer containing the received udp
210                                  datagram.
211 
212 **/
213 VOID
214 Udp6Demultiplex (
215   IN UDP6_SERVICE_DATA     *Udp6Service,
216   IN EFI_NET_SESSION_DATA  *NetSession,
217   IN NET_BUF               *Packet
218   );
219 
220 /**
221   This function handles the received Icmp Error message and demultiplexes it to the
222   instance.
223 
224   @param[in]       Udp6Service        Pointer to the udp service context data.
225   @param[in]       IcmpError          The icmp error code.
226   @param[in]       NetSession         Pointer to the EFI_NET_SESSION_DATA abstracted
227                                       from the received Icmp Error packet.
228   @param[in, out]  Packet             Pointer to the Icmp Error packet.
229 
230 **/
231 VOID
232 Udp6IcmpHandler (
233   IN UDP6_SERVICE_DATA     *Udp6Service,
234   IN UINT8                 IcmpError,
235   IN EFI_NET_SESSION_DATA  *NetSession,
236   IN OUT NET_BUF           *Packet
237   );
238 
239 /**
240   This function builds and sends out a icmp port unreachable message.
241 
242   @param[in]  IpIo               Pointer to the IP_IO instance.
243   @param[in]  NetSession         Pointer to the EFI_NET_SESSION_DATA of the packet
244                                  causes this icmp error message.
245   @param[in]  Udp6Header         Pointer to the udp header of the datagram causes
246                                  this icmp error message.
247 
248 **/
249 VOID
250 Udp6SendPortUnreach (
251   IN IP_IO                 *IpIo,
252   IN EFI_NET_SESSION_DATA  *NetSession,
253   IN VOID                  *Udp6Header
254   );
255 
256 /**
257   Find the key in the netmap
258 
259   @param[in]  Map                    The netmap to search within.
260   @param[in]  Key                    The key to search.
261 
262   @return The point to the item contains the Key, or NULL if Key isn't in the map.
263 
264 **/
265 NET_MAP_ITEM *
266 Udp6MapMultiCastAddr (
267   IN  NET_MAP               *Map,
268   IN  VOID                  *Key
269   );
270 
271 /**
272   Create the Udp service context data.
273 
274   @param[in]  Udp6Service        Pointer to the UDP6_SERVICE_DATA.
275   @param[in]  ImageHandle        The image handle of this udp6 driver.
276   @param[in]  ControllerHandle   The controller handle this udp6 driver binds on.
277 
278   @retval EFI_SUCCESS            The udp6 service context data was created and
279                                  initialized.
280   @retval EFI_OUT_OF_RESOURCES   Cannot allocate memory.
281   @retval Others                 An error condition occurred.
282 
283 **/
284 EFI_STATUS
Udp6CreateService(IN UDP6_SERVICE_DATA * Udp6Service,IN EFI_HANDLE ImageHandle,IN EFI_HANDLE ControllerHandle)285 Udp6CreateService (
286   IN UDP6_SERVICE_DATA  *Udp6Service,
287   IN EFI_HANDLE         ImageHandle,
288   IN EFI_HANDLE         ControllerHandle
289   )
290 {
291   EFI_STATUS       Status;
292   IP_IO_OPEN_DATA  OpenData;
293 
294   ZeroMem (Udp6Service, sizeof (UDP6_SERVICE_DATA));
295 
296   Udp6Service->Signature        = UDP6_SERVICE_DATA_SIGNATURE;
297   Udp6Service->ServiceBinding   = mUdp6ServiceBinding;
298   Udp6Service->ImageHandle      = ImageHandle;
299   Udp6Service->ControllerHandle = ControllerHandle;
300   Udp6Service->ChildrenNumber   = 0;
301 
302   InitializeListHead (&Udp6Service->ChildrenList);
303 
304   //
305   // Create the IpIo for this service context.
306   //
307   Udp6Service->IpIo = IpIoCreate (ImageHandle, ControllerHandle, IP_VERSION_6);
308   if (Udp6Service->IpIo == NULL) {
309     return EFI_OUT_OF_RESOURCES;
310   }
311 
312   //
313   // Set the OpenData used to open the IpIo.
314   //
315   CopyMem (
316     &OpenData.IpConfigData.Ip6CfgData,
317     &mIp6IoDefaultIpConfigData,
318     sizeof (EFI_IP6_CONFIG_DATA)
319     );
320   OpenData.RcvdContext           = (VOID *) Udp6Service;
321   OpenData.SndContext            = NULL;
322   OpenData.PktRcvdNotify         = Udp6DgramRcvd;
323   OpenData.PktSentNotify         = Udp6DgramSent;
324 
325   //
326   // Configure and start the IpIo.
327   //
328   Status = IpIoOpen (Udp6Service->IpIo, &OpenData);
329   if (EFI_ERROR (Status)) {
330     goto ON_ERROR;
331   }
332 
333   //
334   // Create the event for Udp timeout checking.
335   //
336   Status = gBS->CreateEvent (
337                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
338                   TPL_CALLBACK,
339                   Udp6CheckTimeout,
340                   Udp6Service,
341                   &Udp6Service->TimeoutEvent
342                   );
343   if (EFI_ERROR (Status)) {
344     goto ON_ERROR;
345   }
346 
347   //
348   // Start the timeout timer event.
349   //
350   Status = gBS->SetTimer (
351                   Udp6Service->TimeoutEvent,
352                   TimerPeriodic,
353                   UDP6_TIMEOUT_INTERVAL
354                   );
355   if (EFI_ERROR (Status)) {
356     goto ON_ERROR;
357   }
358 
359   return EFI_SUCCESS;
360 
361 ON_ERROR:
362 
363   if (Udp6Service->TimeoutEvent != NULL) {
364     gBS->CloseEvent (Udp6Service->TimeoutEvent);
365   }
366 
367   IpIoDestroy (Udp6Service->IpIo);
368   Udp6Service->IpIo = NULL;
369 
370   return Status;
371 }
372 
373 
374 /**
375   Clean the Udp service context data.
376 
377   @param[in, out]  Udp6Service      Pointer to the UDP6_SERVICE_DATA.
378 
379 **/
380 VOID
Udp6CleanService(IN OUT UDP6_SERVICE_DATA * Udp6Service)381 Udp6CleanService (
382   IN OUT UDP6_SERVICE_DATA  *Udp6Service
383   )
384 {
385   //
386   // Close the TimeoutEvent timer.
387   //
388   gBS->CloseEvent (Udp6Service->TimeoutEvent);
389 
390   //
391   // Destroy the IpIo.
392   //
393   IpIoDestroy (Udp6Service->IpIo);
394   Udp6Service->IpIo = NULL;
395 
396   ZeroMem (Udp6Service, sizeof (UDP6_SERVICE_DATA));
397 }
398 
399 
400 /**
401   This function checks and times out the I/O datagrams listed in the
402   UDP6_SERVICE_DATA which is specified by the input parameter Context.
403 
404 
405   @param[in]  Event              The event this function registered to.
406   @param[in]  Context            The context data registered during the creation of
407                                  the Event.
408 
409 **/
410 VOID
411 EFIAPI
Udp6CheckTimeout(IN EFI_EVENT Event,IN VOID * Context)412 Udp6CheckTimeout (
413   IN EFI_EVENT  Event,
414   IN VOID       *Context
415   )
416 {
417   UDP6_SERVICE_DATA   *Udp6Service;
418   LIST_ENTRY          *Entry;
419   UDP6_INSTANCE_DATA  *Instance;
420   LIST_ENTRY          *WrapEntry;
421   LIST_ENTRY          *NextEntry;
422   UDP6_RXDATA_WRAP    *Wrap;
423 
424   Udp6Service = (UDP6_SERVICE_DATA *) Context;
425   NET_CHECK_SIGNATURE (Udp6Service, UDP6_SERVICE_DATA_SIGNATURE);
426 
427   NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) {
428     //
429     // Iterate all the instances belonging to this service context.
430     //
431     Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link);
432     NET_CHECK_SIGNATURE (Instance, UDP6_INSTANCE_DATA_SIGNATURE);
433 
434     if (!Instance->Configured || (Instance->ConfigData.ReceiveTimeout == 0)) {
435       //
436       // Skip this instance if it's not configured or no receive timeout.
437       //
438       continue;
439     }
440 
441     NET_LIST_FOR_EACH_SAFE (WrapEntry, NextEntry, &Instance->RcvdDgramQue) {
442       //
443       // Iterate all the rxdatas belonging to this udp instance.
444       //
445       Wrap = NET_LIST_USER_STRUCT (WrapEntry, UDP6_RXDATA_WRAP, Link);
446 
447       if (Wrap->TimeoutTick < UDP6_TIMEOUT_INTERVAL / 10) {
448         //
449         // Remove this RxData if it timeouts.
450         //
451         Udp6RecycleRxDataWrap (NULL, (VOID *) Wrap);
452       } else {
453         Wrap->TimeoutTick -= UDP6_TIMEOUT_INTERVAL / 10;
454       }
455     }
456   }
457 }
458 
459 
460 /**
461   This function initializes the new created udp instance.
462 
463   @param[in]       Udp6Service      Pointer to the UDP6_SERVICE_DATA.
464   @param[in, out]  Instance         Pointer to the un-initialized UDP6_INSTANCE_DATA.
465 
466 **/
467 VOID
Udp6InitInstance(IN UDP6_SERVICE_DATA * Udp6Service,IN OUT UDP6_INSTANCE_DATA * Instance)468 Udp6InitInstance (
469   IN UDP6_SERVICE_DATA       *Udp6Service,
470   IN OUT UDP6_INSTANCE_DATA  *Instance
471   )
472 {
473   //
474   // Set the signature.
475   //
476   Instance->Signature = UDP6_INSTANCE_DATA_SIGNATURE;
477 
478   //
479   // Init the lists.
480   //
481   InitializeListHead (&Instance->Link);
482   InitializeListHead (&Instance->RcvdDgramQue);
483   InitializeListHead (&Instance->DeliveredDgramQue);
484 
485   //
486   // Init the NET_MAPs.
487   //
488   NetMapInit (&Instance->TxTokens);
489   NetMapInit (&Instance->RxTokens);
490   NetMapInit (&Instance->McastIps);
491 
492   //
493   // Save the pointer to the UDP6_SERVICE_DATA, and initialize other members.
494   //
495   Instance->Udp6Service = Udp6Service;
496   CopyMem (&Instance->Udp6Proto, &mUdp6Protocol, sizeof (EFI_UDP6_PROTOCOL));
497   Instance->IcmpError   = EFI_SUCCESS;
498   Instance->Configured  = FALSE;
499   Instance->IsNoMapping = FALSE;
500   Instance->InDestroy   = FALSE;
501 }
502 
503 
504 /**
505   This function cleans the udp instance.
506 
507   @param[in, out]  Instance       Pointer to the UDP6_INSTANCE_DATA to clean.
508 
509 **/
510 VOID
Udp6CleanInstance(IN OUT UDP6_INSTANCE_DATA * Instance)511 Udp6CleanInstance (
512   IN OUT UDP6_INSTANCE_DATA  *Instance
513   )
514 {
515   NetMapClean (&Instance->McastIps);
516   NetMapClean (&Instance->RxTokens);
517   NetMapClean (&Instance->TxTokens);
518 }
519 
520 
521 /**
522   This function finds the udp instance by the specified <Address, Port> pair.
523 
524   @param[in]  InstanceList       Pointer to the head of the list linking the udp
525                                  instances.
526   @param[in]  Address            Pointer to the specified IPv6 address.
527   @param[in]  Port               The udp port number.
528 
529   @retval TRUE     The specified <Address, Port> pair is found.
530   @retval FALSE    Otherwise.
531 
532 **/
533 BOOLEAN
Udp6FindInstanceByPort(IN LIST_ENTRY * InstanceList,IN EFI_IPv6_ADDRESS * Address,IN UINT16 Port)534 Udp6FindInstanceByPort (
535   IN LIST_ENTRY        *InstanceList,
536   IN EFI_IPv6_ADDRESS  *Address,
537   IN UINT16            Port
538   )
539 {
540   LIST_ENTRY            *Entry;
541   UDP6_INSTANCE_DATA    *Instance;
542   EFI_UDP6_CONFIG_DATA  *ConfigData;
543 
544   NET_LIST_FOR_EACH (Entry, InstanceList) {
545     //
546     // Iterate all the udp instances.
547     //
548     Instance   = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link);
549     ConfigData = &Instance->ConfigData;
550 
551     if (!Instance->Configured || ConfigData->AcceptAnyPort) {
552       //
553       // If the instance is not configured, or the configdata of the instance indicates
554       // this instance accepts any port, skip it.
555       //
556       continue;
557     }
558 
559     if (EFI_IP6_EQUAL (&ConfigData->StationAddress, Address) &&
560         (ConfigData->StationPort == Port)
561         ) {
562       //
563       // If both the address and the port are the same, return TRUE.
564       //
565       return TRUE;
566     }
567   }
568 
569   //
570   // Return FALSE when matching fails.
571   //
572   return FALSE;
573 }
574 
575 
576 /**
577   This function tries to bind the udp instance according to the configured port
578   allocation strategy.
579 
580   @param[in]  InstanceList       Pointer to the head of the list linking the udp
581                                  instances.
582   @param[in]  ConfigData         Pointer to the ConfigData of the instance to be
583                                  bound.
584 
585   @retval EFI_SUCCESS            The bound operation completed successfully.
586   @retval EFI_ACCESS_DENIED      The <Address, Port> specified by the ConfigData is
587                                  already used by other instance.
588   @retval EFI_OUT_OF_RESOURCES   No available port resources.
589 
590 **/
591 EFI_STATUS
Udp6Bind(IN LIST_ENTRY * InstanceList,IN EFI_UDP6_CONFIG_DATA * ConfigData)592 Udp6Bind (
593   IN LIST_ENTRY            *InstanceList,
594   IN EFI_UDP6_CONFIG_DATA  *ConfigData
595   )
596 {
597   EFI_IPv6_ADDRESS  *StationAddress;
598   UINT16            StartPort;
599 
600   if (ConfigData->AcceptAnyPort) {
601     return EFI_SUCCESS;
602   }
603 
604   StationAddress = &ConfigData->StationAddress;
605 
606   if (ConfigData->StationPort != 0) {
607 
608     if (!ConfigData->AllowDuplicatePort &&
609         Udp6FindInstanceByPort (InstanceList, StationAddress, ConfigData->StationPort)
610         ) {
611       //
612       // Do not allow duplicate ports and the port is already used by other instance.
613       //
614       return EFI_ACCESS_DENIED;
615     }
616   } else {
617     //
618     // Select a random port for this instance.
619     //
620     if (ConfigData->AllowDuplicatePort) {
621       //
622       // Just pick up the random port if the instance allows duplicate port.
623       //
624       ConfigData->StationPort = mUdp6RandomPort;
625     } else {
626 
627       StartPort = mUdp6RandomPort;
628 
629       while (Udp6FindInstanceByPort (InstanceList, StationAddress, mUdp6RandomPort)) {
630 
631         mUdp6RandomPort++;
632         if (mUdp6RandomPort == 0) {
633           mUdp6RandomPort = UDP6_PORT_KNOWN;
634         }
635 
636         if (mUdp6RandomPort == StartPort) {
637           //
638           // No available port.
639           //
640           return EFI_OUT_OF_RESOURCES;
641         }
642       }
643 
644       ConfigData->StationPort = mUdp6RandomPort;
645     }
646 
647     mUdp6RandomPort++;
648     if (mUdp6RandomPort == 0) {
649       mUdp6RandomPort = UDP6_PORT_KNOWN;
650     }
651   }
652   return EFI_SUCCESS;
653 }
654 
655 
656 /**
657   This function is used to check whether the NewConfigData has any un-reconfigurable
658   parameters changed compared to the OldConfigData.
659 
660   @param[in]  OldConfigData    Pointer to the current ConfigData the udp instance
661                                uses.
662   @param[in]  NewConfigData    Pointer to the new ConfigData.
663 
664   @retval TRUE     The instance is reconfigurable according to the NewConfigData.
665   @retval FALSE    Otherwise.
666 
667 **/
668 BOOLEAN
Udp6IsReconfigurable(IN EFI_UDP6_CONFIG_DATA * OldConfigData,IN EFI_UDP6_CONFIG_DATA * NewConfigData)669 Udp6IsReconfigurable (
670   IN EFI_UDP6_CONFIG_DATA  *OldConfigData,
671   IN EFI_UDP6_CONFIG_DATA  *NewConfigData
672   )
673 {
674   if ((NewConfigData->AcceptAnyPort != OldConfigData->AcceptAnyPort) ||
675       (NewConfigData->AcceptPromiscuous != OldConfigData->AcceptPromiscuous) ||
676       (NewConfigData->AllowDuplicatePort != OldConfigData->AllowDuplicatePort)
677       ) {
678     //
679     // The receiving filter parameters cannot be changed.
680     //
681     return FALSE;
682   }
683 
684   if ((!NewConfigData->AcceptAnyPort) &&
685       (NewConfigData->StationPort != OldConfigData->StationPort)
686       ) {
687     //
688     // The port is not changeable.
689     //
690     return FALSE;
691   }
692 
693   if (!EFI_IP6_EQUAL (&NewConfigData->StationAddress, &OldConfigData->StationAddress)) {
694     //
695     //  The StationAddress is not the same.
696     //
697     return FALSE;
698   }
699 
700 
701   if (!EFI_IP6_EQUAL (&NewConfigData->RemoteAddress, &OldConfigData->RemoteAddress)) {
702     //
703     // The remoteaddress is not the same.
704     //
705     return FALSE;
706   }
707 
708   if (!NetIp6IsUnspecifiedAddr (&NewConfigData->RemoteAddress) &&
709       (NewConfigData->RemotePort != OldConfigData->RemotePort)
710       ) {
711     //
712     // The RemotePort differs if it's designated in the configdata.
713     //
714     return FALSE;
715   }
716 
717   //
718   // All checks pass, return TRUE.
719   //
720   return TRUE;
721 }
722 
723 
724 /**
725   This function builds the Ip6 configdata from the Udp6ConfigData.
726 
727   @param[in]       Udp6ConfigData         Pointer to the EFI_UDP6_CONFIG_DATA.
728   @param[in, out]  Ip6ConfigData          Pointer to the EFI_IP6_CONFIG_DATA.
729 
730 **/
731 VOID
Udp6BuildIp6ConfigData(IN EFI_UDP6_CONFIG_DATA * Udp6ConfigData,IN OUT EFI_IP6_CONFIG_DATA * Ip6ConfigData)732 Udp6BuildIp6ConfigData (
733   IN EFI_UDP6_CONFIG_DATA      *Udp6ConfigData,
734   IN OUT EFI_IP6_CONFIG_DATA   *Ip6ConfigData
735   )
736 {
737   CopyMem (
738     Ip6ConfigData,
739     &mIp6IoDefaultIpConfigData,
740     sizeof (EFI_IP6_CONFIG_DATA)
741     );
742   Ip6ConfigData->DefaultProtocol      = EFI_IP_PROTO_UDP;
743   Ip6ConfigData->AcceptPromiscuous    = Udp6ConfigData->AcceptPromiscuous;
744   IP6_COPY_ADDRESS (&Ip6ConfigData->StationAddress, &Udp6ConfigData->StationAddress);
745   IP6_COPY_ADDRESS (&Ip6ConfigData->DestinationAddress, &Udp6ConfigData->RemoteAddress);
746   //
747   // Use the -1 magic number to disable the receiving process of the ip instance.
748   //
749   Ip6ConfigData->ReceiveTimeout    = (UINT32) (-1);
750 }
751 
752 
753 /**
754   This function validates the TxToken. It returns the error code according to the spec.
755 
756   @param[in]  Instance           Pointer to the udp instance context data.
757   @param[in]  TxToken            Pointer to the token to be checked.
758 
759   @retval EFI_SUCCESS            The TxToken is valid.
760   @retval EFI_INVALID_PARAMETER  One or more of the following are TRUE:
761                                  Token.Event is NULL;
762                                  Token.Packet.TxData is NULL;
763                                  Token.Packet.TxData.FragmentCount is zero;
764                                  Token.Packet.TxData.DataLength is not equal to the
765                                  sum of fragment lengths;
766                                  One or more of the
767                                  Token.Packet.TxData.FragmentTable[].FragmentLength
768                                  fields is zero;
769                                  One or more of the
770                                  Token.Packet.TxData.FragmentTable[].FragmentBuffer
771                                  fields is NULL;
772                                  UdpSessionData.DestinationAddress are not valid
773                                  unicast IPv6 addresses if the UdpSessionData is
774                                  not NULL;
775                                  UdpSessionData.DestinationPort and
776                                  ConfigData.RemotePort are all zero if the
777                                  UdpSessionData is not NULL.
778   @retval EFI_BAD_BUFFER_SIZE    The data length is greater than the maximum UDP
779                                  packet size.
780 
781 **/
782 EFI_STATUS
Udp6ValidateTxToken(IN UDP6_INSTANCE_DATA * Instance,IN EFI_UDP6_COMPLETION_TOKEN * TxToken)783 Udp6ValidateTxToken (
784   IN UDP6_INSTANCE_DATA         *Instance,
785   IN EFI_UDP6_COMPLETION_TOKEN  *TxToken
786   )
787 {
788   EFI_UDP6_TRANSMIT_DATA  *TxData;
789   UINT32                  Index;
790   UINT32                  TotalLen;
791   EFI_UDP6_CONFIG_DATA    *ConfigData;
792   EFI_UDP6_SESSION_DATA   *UdpSessionData;
793 
794 
795   if (TxToken->Event == NULL) {
796     return EFI_INVALID_PARAMETER;
797   }
798 
799   TxData = TxToken->Packet.TxData;
800 
801   if ((TxData == NULL) || (TxData->FragmentCount == 0)) {
802     return EFI_INVALID_PARAMETER;
803   }
804 
805   TotalLen = 0;
806   for (Index = 0; Index < TxData->FragmentCount; Index++) {
807 
808     if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
809         (TxData->FragmentTable[Index].FragmentLength == 0)
810         ) {
811       //
812       // If the FragmentBuffer is NULL, or the FragmentLeng is zero.
813       //
814       return EFI_INVALID_PARAMETER;
815     }
816 
817     TotalLen += TxData->FragmentTable[Index].FragmentLength;
818   }
819 
820   if (TotalLen != TxData->DataLength) {
821     //
822     // The TotalLen calculated by adding all the FragmentLeng doesn't equal to the
823     // DataLength.
824     //
825     return EFI_INVALID_PARAMETER;
826   }
827 
828   ConfigData     = &Instance->ConfigData;
829   UdpSessionData = TxData->UdpSessionData;
830 
831   if (UdpSessionData != NULL) {
832 
833     if ((UdpSessionData->DestinationPort == 0) && (ConfigData->RemotePort == 0)) {
834       //
835       // Ambiguous; no available DestinationPort for this token.
836       //
837       return EFI_INVALID_PARAMETER;
838     }
839 
840     if (NetIp6IsUnspecifiedAddr (&UdpSessionData->DestinationAddress) &&
841         NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress)
842         ) {
843       //
844       // The DestinationAddress is not specified.
845       //
846       return EFI_INVALID_PARAMETER;
847     }
848 
849     if (!NetIp6IsUnspecifiedAddr (&UdpSessionData->DestinationAddress) &&
850         !NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress)
851         ) {
852       //
853       // The ConfigData.RemoteAddress is not zero and the UdpSessionData.DestinationAddress
854       // is not zero too.
855       //
856       return EFI_INVALID_PARAMETER;
857     }
858   } else if (NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress)) {
859     //
860     // The configured RemoteAddress is all zero, and the user doesn't override the
861     // destination address.
862     //
863     return EFI_INVALID_PARAMETER;
864   }
865 
866   if (TxData->DataLength > UDP6_MAX_DATA_SIZE) {
867     return EFI_BAD_BUFFER_SIZE;
868   }
869 
870   return EFI_SUCCESS;
871 }
872 
873 
874 /**
875   This function checks whether the specified Token duplicates the one in the Map.
876 
877   @param[in]  Map                Pointer to the NET_MAP.
878   @param[in]  Item               Pointer to the NET_MAP_ITEM contain the pointer to
879                                  the Token.
880   @param[in]  Context            Pointer to the Token to be checked.
881 
882   @retval EFI_SUCCESS            The Token specified by Context differs from the
883                                  one in the Item.
884   @retval EFI_ACCESS_DENIED      The Token duplicates with the one in the Item.
885 
886 **/
887 EFI_STATUS
888 EFIAPI
Udp6TokenExist(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)889 Udp6TokenExist (
890   IN NET_MAP       *Map,
891   IN NET_MAP_ITEM  *Item,
892   IN VOID          *Context
893   )
894 {
895   EFI_UDP6_COMPLETION_TOKEN  *Token;
896   EFI_UDP6_COMPLETION_TOKEN  *TokenInItem;
897 
898   Token       = (EFI_UDP6_COMPLETION_TOKEN *) Context;
899   TokenInItem = (EFI_UDP6_COMPLETION_TOKEN *) Item->Key;
900 
901   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
902     //
903     // The Token duplicates with the TokenInItem in case either the two pointers are the
904     // same, or the Events of these two tokens are the same.
905     //
906     return EFI_ACCESS_DENIED;
907   }
908 
909   return EFI_SUCCESS;
910 }
911 
912 
913 /**
914   This function calculates the checksum for the Packet, utilizing the pre-calculated
915   pseudo HeadSum to reduce some overhead.
916 
917   @param[in]  Packet           Pointer to the NET_BUF contains the udp datagram.
918   @param[in]  HeadSum          Checksum of the pseudo header, except the length
919                                field.
920 
921   @return The 16-bit checksum of this udp datagram.
922 
923 **/
924 UINT16
Udp6Checksum(IN NET_BUF * Packet,IN UINT16 HeadSum)925 Udp6Checksum (
926   IN NET_BUF *Packet,
927   IN UINT16  HeadSum
928   )
929 {
930   UINT16  Checksum;
931 
932   Checksum  = NetbufChecksum (Packet);
933   Checksum  = NetAddChecksum (Checksum, HeadSum);
934 
935   Checksum  = NetAddChecksum (Checksum, HTONS ((UINT16) Packet->TotalSize));
936   Checksum  = (UINT16) (~Checksum);
937   return Checksum;
938 }
939 
940 
941 /**
942   This function removes the specified Token from the TokenMap.
943 
944   @param[in]  TokenMap           Pointer to the NET_MAP containing the tokens.
945   @param[in]  Token              Pointer to the Token to be removed.
946 
947   @retval EFI_SUCCESS            The specified Token is removed from the TokenMap.
948   @retval EFI_NOT_FOUND          The specified Token is not found in the TokenMap.
949 
950 **/
951 EFI_STATUS
Udp6RemoveToken(IN NET_MAP * TokenMap,IN EFI_UDP6_COMPLETION_TOKEN * Token)952 Udp6RemoveToken (
953   IN NET_MAP                    *TokenMap,
954   IN EFI_UDP6_COMPLETION_TOKEN  *Token
955   )
956 {
957   NET_MAP_ITEM  *Item;
958 
959   //
960   // Find the Token first.
961   //
962   Item = NetMapFindKey (TokenMap, (VOID *) Token);
963 
964   if (Item != NULL) {
965     //
966     // Remove the token if it's found in the map.
967     //
968     NetMapRemoveItem (TokenMap, Item, NULL);
969 
970     return EFI_SUCCESS;
971   }
972   return EFI_NOT_FOUND;
973 }
974 
975 
976 /**
977   This function is the packet transmitting notify function registered to the IpIo
978   interface. It's called to signal the udp TxToken when IpIo layer completes the
979   transmitting of the udp datagram.
980 
981   If Context is NULL, then ASSERT().
982   If NotifyData is NULL, then ASSERT().
983 
984   @param[in]  Status            The completion status of the output udp datagram.
985   @param[in]  Context           Pointer to the context data.
986   @param[in]  Sender            Specify a EFI_IP6_PROTOCOL for sending.
987   @param[in]  NotifyData        Pointer to the notify data.
988 
989 **/
990 VOID
991 EFIAPI
Udp6DgramSent(IN EFI_STATUS Status,IN VOID * Context,IN IP_IO_IP_PROTOCOL Sender,IN VOID * NotifyData)992 Udp6DgramSent (
993   IN EFI_STATUS        Status,
994   IN VOID              *Context,
995   IN IP_IO_IP_PROTOCOL Sender,
996   IN VOID              *NotifyData
997   )
998 {
999   UDP6_INSTANCE_DATA         *Instance;
1000   EFI_UDP6_COMPLETION_TOKEN  *Token;
1001 
1002   ASSERT (Context != NULL && NotifyData != NULL);
1003 
1004   Instance = (UDP6_INSTANCE_DATA *) Context;
1005   Token    = (EFI_UDP6_COMPLETION_TOKEN *) NotifyData;
1006 
1007   if (Udp6RemoveToken (&Instance->TxTokens, Token) == EFI_SUCCESS) {
1008     //
1009     // The token may be cancelled. Only signal it if the remove operation succeeds.
1010     //
1011     Token->Status = Status;
1012     gBS->SignalEvent (Token->Event);
1013     DispatchDpc ();
1014   }
1015 }
1016 
1017 
1018 /**
1019   This function processes the received datagram passed up by the IpIo layer.
1020 
1021   If NetSession is NULL, then ASSERT().
1022   If Packet is NULL, then ASSERT().
1023   If Context is NULL, then ASSERT().
1024 
1025   @param[in]  Status            The status of this udp datagram.
1026   @param[in]  IcmpError         The IcmpError code, only available when Status is
1027                                 EFI_ICMP_ERROR.
1028   @param[in]  NetSession        Pointer to the EFI_NET_SESSION_DATA.
1029   @param[in]  Packet            Pointer to the NET_BUF containing the received udp
1030                                 datagram.
1031   @param[in]  Context           Pointer to the context data.
1032 
1033 **/
1034 VOID
1035 EFIAPI
Udp6DgramRcvd(IN EFI_STATUS Status,IN UINT8 IcmpError,IN EFI_NET_SESSION_DATA * NetSession,IN NET_BUF * Packet,IN VOID * Context)1036 Udp6DgramRcvd (
1037   IN EFI_STATUS            Status,
1038   IN UINT8                 IcmpError,
1039   IN EFI_NET_SESSION_DATA  *NetSession,
1040   IN NET_BUF               *Packet,
1041   IN VOID                  *Context
1042   )
1043 {
1044   ASSERT (NetSession != NULL && Packet != NULL && Context != NULL);
1045   NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE);
1046 
1047   //
1048   // IpIo only passes received packets with Status EFI_SUCCESS or EFI_ICMP_ERROR.
1049   //
1050   if (Status == EFI_SUCCESS) {
1051 
1052     //
1053     // Demultiplex the received datagram.
1054     //
1055     Udp6Demultiplex ((UDP6_SERVICE_DATA *) Context, NetSession, Packet);
1056   } else {
1057     //
1058     // Handle the ICMP6 Error packet.
1059     //
1060     Udp6IcmpHandler ((UDP6_SERVICE_DATA *) Context, IcmpError, NetSession, Packet);
1061   }
1062 
1063   //
1064   // Dispatch the DPC queued by the NotifyFunction of the rx token's events
1065   // that are signaled with received data.
1066   //
1067   DispatchDpc ();
1068 }
1069 
1070 
1071 /**
1072   This function removes the multicast group specified by Arg from the Map.
1073 
1074   @param[in]  Map                Pointer to the NET_MAP.
1075   @param[in]  Item               Pointer to the NET_MAP_ITEM.
1076   @param[in]  Arg                Pointer to the Arg, it's the pointer to a
1077                                  multicast IPv6 Address. This parameter is
1078                                  optional and may be NULL.
1079 
1080   @retval EFI_SUCCESS            The multicast address is removed.
1081   @retval EFI_ABORTED            The specified multicast address is removed, and the
1082                                  Arg is not NULL.
1083 
1084 **/
1085 EFI_STATUS
1086 EFIAPI
Udp6LeaveGroup(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Arg OPTIONAL)1087 Udp6LeaveGroup (
1088   IN NET_MAP       *Map,
1089   IN NET_MAP_ITEM  *Item,
1090   IN VOID          *Arg OPTIONAL
1091   )
1092 {
1093   EFI_IPv6_ADDRESS  *McastIp;
1094 
1095   McastIp = Arg;
1096 
1097   if ((McastIp != NULL) &&
1098       !EFI_IP6_EQUAL (McastIp, ((EFI_IPv6_ADDRESS *)Item->Key))
1099       ) {
1100     //
1101     // McastIp is not NULL and the multicast address contained in the Item
1102     // is not the same as McastIp.
1103     //
1104     return EFI_SUCCESS;
1105   }
1106 
1107   FreePool (Item->Key);
1108 
1109   //
1110   // Remove this Item.
1111   //
1112   NetMapRemoveItem (Map, Item, NULL);
1113 
1114   if (McastIp != NULL) {
1115     //
1116     // Return EFI_ABORTED in case McastIp is not NULL to terminate the iteration.
1117     //
1118     return EFI_ABORTED;
1119   }
1120 
1121   return EFI_SUCCESS;
1122 }
1123 
1124 
1125 /**
1126   This function cancel the token specified by Arg in the Map.
1127 
1128   @param[in]  Map             Pointer to the NET_MAP.
1129   @param[in]  Item            Pointer to the NET_MAP_ITEM.
1130   @param[in]  Arg             Pointer to the token to be cancelled. If NULL, all
1131                               the tokens in this Map will be cancelled.
1132                               This parameter is optional and may be NULL.
1133 
1134   @retval EFI_SUCCESS         The token is cancelled if Arg is NULL, or the token
1135                               is not the same as that in the Item, if Arg is not
1136                               NULL.
1137   @retval EFI_ABORTED         Arg is not NULL, and the token specified by Arg is
1138                               cancelled.
1139 
1140 **/
1141 EFI_STATUS
1142 EFIAPI
Udp6CancelTokens(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Arg OPTIONAL)1143 Udp6CancelTokens (
1144   IN NET_MAP       *Map,
1145   IN NET_MAP_ITEM  *Item,
1146   IN VOID          *Arg OPTIONAL
1147   )
1148 {
1149   EFI_UDP6_COMPLETION_TOKEN  *TokenToCancel;
1150   NET_BUF                    *Packet;
1151   IP_IO                      *IpIo;
1152 
1153   if ((Arg != NULL) && (Item->Key != Arg)) {
1154     return EFI_SUCCESS;
1155   }
1156 
1157   if (Item->Value != NULL) {
1158     //
1159     // If the token is a transmit token, the corresponding Packet is recorded in
1160     // Item->Value, invoke IpIo to cancel this packet first. The IpIoCancelTxToken
1161     // will invoke Udp6DgramSent, the token will be signaled and this Item will
1162     // be removed from the Map there.
1163     //
1164     Packet  = (NET_BUF *) (Item->Value);
1165     IpIo    = (IP_IO *) (*((UINTN *) &Packet->ProtoData[0]));
1166 
1167     IpIoCancelTxToken (IpIo, Packet);
1168   } else {
1169     //
1170     // The token is a receive token. Abort it and remove it from the Map.
1171     //
1172     TokenToCancel = (EFI_UDP6_COMPLETION_TOKEN *) Item->Key;
1173     NetMapRemoveItem (Map, Item, NULL);
1174 
1175     TokenToCancel->Status = EFI_ABORTED;
1176     gBS->SignalEvent (TokenToCancel->Event);
1177   }
1178 
1179   if (Arg != NULL) {
1180     return EFI_ABORTED;
1181   }
1182 
1183   return EFI_SUCCESS;
1184 }
1185 
1186 
1187 /**
1188   This function removes all the Wrap datas in the RcvdDgramQue.
1189 
1190   @param[in]  Instance    Pointer to the Udp6 Instance.
1191 
1192 **/
1193 VOID
Udp6FlushRcvdDgram(IN UDP6_INSTANCE_DATA * Instance)1194 Udp6FlushRcvdDgram (
1195   IN UDP6_INSTANCE_DATA  *Instance
1196   )
1197 {
1198   UDP6_RXDATA_WRAP  *Wrap;
1199 
1200   while (!IsListEmpty (&Instance->RcvdDgramQue)) {
1201     //
1202     // Iterate all the Wraps in the RcvdDgramQue.
1203     //
1204     Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP6_RXDATA_WRAP, Link);
1205 
1206     //
1207     // The Wrap will be removed from the RcvdDgramQue by this function call.
1208     //
1209     Udp6RecycleRxDataWrap (NULL, (VOID *) Wrap);
1210   }
1211 }
1212 
1213 
1214 
1215 /**
1216   Cancel Udp6 tokens from the Udp6 instance.
1217 
1218   @param[in]  Instance           Pointer to the udp instance context data.
1219   @param[in]  Token              Pointer to the token to be canceled. If NULL, all
1220                                  tokens in this instance will be cancelled.
1221                                  This parameter is optional and may be NULL.
1222 
1223   @retval EFI_SUCCESS            The Token is cancelled.
1224   @retval EFI_NOT_FOUND          The Token is not found.
1225 
1226 **/
1227 EFI_STATUS
Udp6InstanceCancelToken(IN UDP6_INSTANCE_DATA * Instance,IN EFI_UDP6_COMPLETION_TOKEN * Token OPTIONAL)1228 Udp6InstanceCancelToken (
1229   IN UDP6_INSTANCE_DATA         *Instance,
1230   IN EFI_UDP6_COMPLETION_TOKEN  *Token OPTIONAL
1231   )
1232 {
1233   EFI_STATUS  Status;
1234 
1235   //
1236   // Cancel this token from the TxTokens map.
1237   //
1238   Status = NetMapIterate (&Instance->TxTokens, Udp6CancelTokens, Token);
1239 
1240   if ((Token != NULL) && (Status == EFI_ABORTED)) {
1241     //
1242     // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from
1243     // the TxTokens and returns success.
1244     //
1245     return EFI_SUCCESS;
1246   }
1247 
1248   //
1249   // Try to cancel this token from the RxTokens map in condition either the Token
1250   // is NULL or the specified Token is not in TxTokens.
1251   //
1252   Status = NetMapIterate (&Instance->RxTokens, Udp6CancelTokens, Token);
1253 
1254   if ((Token != NULL) && (Status == EFI_SUCCESS)) {
1255     //
1256     // If Token isn't NULL and Status is EFI_SUCCESS, the token is neither in the
1257     // TxTokens nor the RxTokens, or say, it's not found.
1258     //
1259     return EFI_NOT_FOUND;
1260   }
1261 
1262   ASSERT ((Token != NULL) ||
1263           ((0 == NetMapGetCount (&Instance->TxTokens)) &&
1264           (0 == NetMapGetCount (&Instance->RxTokens)))
1265           );
1266 
1267   return EFI_SUCCESS;
1268 }
1269 
1270 
1271 /**
1272   This function checks if the received udp datagram matches with the Instance.
1273 
1274   @param[in]  Instance           Pointer to the udp instance context data.
1275   @param[in]  Udp6Session        Pointer to the EFI_UDP6_SESSION_DATA abstracted
1276                                  from the received udp datagram.
1277 
1278   @retval TRUE     The udp datagram matches the receiving requirements of the Instance.
1279   @retval FALSE    The udp datagram does not match the receiving requirements of the Instance.
1280 
1281 **/
1282 BOOLEAN
Udp6MatchDgram(IN UDP6_INSTANCE_DATA * Instance,IN EFI_UDP6_SESSION_DATA * Udp6Session)1283 Udp6MatchDgram (
1284   IN UDP6_INSTANCE_DATA     *Instance,
1285   IN EFI_UDP6_SESSION_DATA  *Udp6Session
1286   )
1287 {
1288   EFI_UDP6_CONFIG_DATA  *ConfigData;
1289   EFI_IPv6_ADDRESS      Destination;
1290 
1291   ConfigData = &Instance->ConfigData;
1292 
1293   if (ConfigData->AcceptPromiscuous) {
1294     //
1295     // Always matches if this instance is in the promiscuous state.
1296     //
1297     return TRUE;
1298   }
1299 
1300   if ((!ConfigData->AcceptAnyPort && (Udp6Session->DestinationPort != ConfigData->StationPort)) ||
1301       ((ConfigData->RemotePort != 0) && (Udp6Session->SourcePort != ConfigData->RemotePort))
1302       ) {
1303     //
1304     // The local port or the remote port doesn't match.
1305     //
1306     return FALSE;
1307   }
1308 
1309   if (!NetIp6IsUnspecifiedAddr (&ConfigData->RemoteAddress) &&
1310       !EFI_IP6_EQUAL (&ConfigData->RemoteAddress, &Udp6Session->SourceAddress)
1311       ) {
1312     //
1313     // This datagram doesn't come from the instance's specified sender.
1314     //
1315     return FALSE;
1316   }
1317 
1318   if (NetIp6IsUnspecifiedAddr (&ConfigData->StationAddress) ||
1319       EFI_IP6_EQUAL (&Udp6Session->DestinationAddress, &ConfigData->StationAddress)
1320       ) {
1321     //
1322     // The instance is configured to receive datagrams destinated to any station IP or
1323     // the destination address of this datagram matches the configured station IP.
1324     //
1325     return TRUE;
1326   }
1327 
1328   IP6_COPY_ADDRESS (&Destination, &Udp6Session->DestinationAddress);
1329 
1330   if (IP6_IS_MULTICAST (&Destination) &&
1331       (NULL != Udp6MapMultiCastAddr (&Instance->McastIps, &Destination))
1332       ) {
1333     //
1334     // It's a multicast packet and the multicast address is accepted by this instance.
1335     //
1336     return TRUE;
1337   }
1338 
1339   return FALSE;
1340 }
1341 
1342 
1343 /**
1344   This function removes the Wrap specified by Context and release relevant resources.
1345 
1346   @param[in]  Event                  The Event this notify function registered to.
1347   @param[in]  Context                Pointer to the context data.
1348 
1349 **/
1350 VOID
1351 EFIAPI
Udp6RecycleRxDataWrap(IN EFI_EVENT Event,IN VOID * Context)1352 Udp6RecycleRxDataWrap (
1353   IN EFI_EVENT  Event,
1354   IN VOID       *Context
1355   )
1356 {
1357   UDP6_RXDATA_WRAP  *Wrap;
1358 
1359   Wrap = (UDP6_RXDATA_WRAP *) Context;
1360 
1361   //
1362   // Remove the Wrap from the list it belongs to.
1363   //
1364   RemoveEntryList (&Wrap->Link);
1365 
1366   //
1367   // Free the Packet associated with this Wrap.
1368   //
1369   NetbufFree (Wrap->Packet);
1370 
1371   //
1372   // Close the event.
1373   //
1374   gBS->CloseEvent (Wrap->RxData.RecycleSignal);
1375 
1376   FreePool (Wrap);
1377 }
1378 
1379 
1380 /**
1381   This function wraps the Packet into RxData.
1382 
1383   @param[in]  Instance           Pointer to the instance context data.
1384   @param[in]  Packet             Pointer to the buffer containing the received
1385                                  datagram.
1386   @param[in]  RxData             Pointer to the EFI_UDP6_RECEIVE_DATA of this
1387                                  datagram.
1388 
1389   @return Pointer to the structure wrapping the RxData and the Packet. NULL will
1390           be returned if any error occurs.
1391 
1392 **/
1393 UDP6_RXDATA_WRAP *
Udp6WrapRxData(IN UDP6_INSTANCE_DATA * Instance,IN NET_BUF * Packet,IN EFI_UDP6_RECEIVE_DATA * RxData)1394 Udp6WrapRxData (
1395   IN UDP6_INSTANCE_DATA     *Instance,
1396   IN NET_BUF                *Packet,
1397   IN EFI_UDP6_RECEIVE_DATA  *RxData
1398   )
1399 {
1400   EFI_STATUS            Status;
1401   UDP6_RXDATA_WRAP      *Wrap;
1402 
1403   //
1404   // Allocate buffer for the Wrap.
1405   //
1406   Wrap = AllocateZeroPool (sizeof (UDP6_RXDATA_WRAP) +
1407          (Packet->BlockOpNum - 1) * sizeof (EFI_UDP6_FRAGMENT_DATA));
1408   if (Wrap == NULL) {
1409     return NULL;
1410   }
1411 
1412   InitializeListHead (&Wrap->Link);
1413 
1414   CopyMem (&Wrap->RxData, RxData, sizeof(EFI_UDP6_RECEIVE_DATA));
1415   //
1416   // Create the Recycle event.
1417   //
1418   Status = gBS->CreateEvent (
1419                   EVT_NOTIFY_SIGNAL,
1420                   TPL_NOTIFY,
1421                   Udp6RecycleRxDataWrap,
1422                   Wrap,
1423                   &Wrap->RxData.RecycleSignal
1424                   );
1425   if (EFI_ERROR (Status)) {
1426     FreePool (Wrap);
1427     return NULL;
1428   }
1429 
1430   Wrap->Packet      = Packet;
1431   Wrap->TimeoutTick = Instance->ConfigData.ReceiveTimeout;
1432 
1433   return Wrap;
1434 }
1435 
1436 
1437 /**
1438   This function enqueues the received datagram into the instances' receiving queues.
1439 
1440   @param[in]  Udp6Service        Pointer to the udp service context data.
1441   @param[in]  Packet             Pointer to the buffer containing the received
1442                                  datagram.
1443   @param[in]  RxData             Pointer to the EFI_UDP6_RECEIVE_DATA of this
1444                                  datagram.
1445 
1446   @return The times this datagram is enqueued.
1447 
1448 **/
1449 UINTN
Udp6EnqueueDgram(IN UDP6_SERVICE_DATA * Udp6Service,IN NET_BUF * Packet,IN EFI_UDP6_RECEIVE_DATA * RxData)1450 Udp6EnqueueDgram (
1451   IN UDP6_SERVICE_DATA      *Udp6Service,
1452   IN NET_BUF                *Packet,
1453   IN EFI_UDP6_RECEIVE_DATA  *RxData
1454   )
1455 {
1456   LIST_ENTRY          *Entry;
1457   UDP6_INSTANCE_DATA  *Instance;
1458   UDP6_RXDATA_WRAP    *Wrap;
1459   UINTN               Enqueued;
1460 
1461   Enqueued = 0;
1462 
1463   NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) {
1464     //
1465     // Iterate the instances.
1466     //
1467     Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link);
1468 
1469     if (!Instance->Configured) {
1470       continue;
1471     }
1472 
1473     if (Udp6MatchDgram (Instance, &RxData->UdpSession)) {
1474       //
1475       // Wrap the RxData and put this Wrap into the instances RcvdDgramQue.
1476       //
1477       Wrap = Udp6WrapRxData (Instance, Packet, RxData);
1478       if (Wrap == NULL) {
1479         continue;
1480       }
1481 
1482       NET_GET_REF (Packet);
1483 
1484       InsertTailList (&Instance->RcvdDgramQue, &Wrap->Link);
1485 
1486       Enqueued++;
1487     }
1488   }
1489 
1490   return Enqueued;
1491 }
1492 
1493 
1494 /**
1495   This function delivers the received datagrams to the specified instance.
1496 
1497   @param[in]  Instance               Pointer to the instance context data.
1498 
1499 **/
1500 VOID
Udp6InstanceDeliverDgram(IN UDP6_INSTANCE_DATA * Instance)1501 Udp6InstanceDeliverDgram (
1502   IN UDP6_INSTANCE_DATA  *Instance
1503   )
1504 {
1505   UDP6_RXDATA_WRAP           *Wrap;
1506   EFI_UDP6_COMPLETION_TOKEN  *Token;
1507   NET_BUF                    *Dup;
1508   EFI_UDP6_RECEIVE_DATA      *RxData;
1509   EFI_TPL                    OldTpl;
1510 
1511   if (!IsListEmpty (&Instance->RcvdDgramQue) &&
1512       !NetMapIsEmpty (&Instance->RxTokens)
1513       ) {
1514 
1515     Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP6_RXDATA_WRAP, Link);
1516 
1517     if (NET_BUF_SHARED (Wrap->Packet)) {
1518       //
1519       // Duplicate the Packet if it is shared between instances.
1520       //
1521       Dup = NetbufDuplicate (Wrap->Packet, NULL, 0);
1522       if (Dup == NULL) {
1523         return;
1524       }
1525 
1526       NetbufFree (Wrap->Packet);
1527 
1528       Wrap->Packet = Dup;
1529     }
1530 
1531     NetListRemoveHead (&Instance->RcvdDgramQue);
1532 
1533     Token = (EFI_UDP6_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);
1534 
1535     //
1536     // Build the FragmentTable and set the FragmentCount in RxData.
1537     //
1538     RxData                = &Wrap->RxData;
1539     RxData->FragmentCount = Wrap->Packet->BlockOpNum;
1540 
1541     NetbufBuildExt (
1542       Wrap->Packet,
1543       (NET_FRAGMENT *) RxData->FragmentTable,
1544       &RxData->FragmentCount
1545       );
1546 
1547     Token->Status        = EFI_SUCCESS;
1548     Token->Packet.RxData = &Wrap->RxData;
1549 
1550     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1551     InsertTailList (&Instance->DeliveredDgramQue, &Wrap->Link);
1552     gBS->RestoreTPL (OldTpl);
1553 
1554     gBS->SignalEvent (Token->Event);
1555   }
1556 }
1557 
1558 
1559 /**
1560   This function delivers the datagrams enqueued in the instances.
1561 
1562   @param[in]  Udp6Service            Pointer to the udp service context data.
1563 
1564 **/
1565 VOID
Udp6DeliverDgram(IN UDP6_SERVICE_DATA * Udp6Service)1566 Udp6DeliverDgram (
1567   IN UDP6_SERVICE_DATA  *Udp6Service
1568   )
1569 {
1570   LIST_ENTRY          *Entry;
1571   UDP6_INSTANCE_DATA  *Instance;
1572 
1573   NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) {
1574     //
1575     // Iterate the instances.
1576     //
1577     Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link);
1578 
1579     if (!Instance->Configured) {
1580       continue;
1581     }
1582 
1583     //
1584     // Deliver the datagrams of this instance.
1585     //
1586     Udp6InstanceDeliverDgram (Instance);
1587   }
1588 }
1589 
1590 
1591 /**
1592   This function demultiplexes the received udp datagram to the appropriate instances.
1593 
1594   @param[in]  Udp6Service        Pointer to the udp service context data.
1595   @param[in]  NetSession         Pointer to the EFI_NET_SESSION_DATA abstracted from
1596                                  the received datagram.
1597   @param[in]  Packet             Pointer to the buffer containing the received udp
1598                                  datagram.
1599 
1600 **/
1601 VOID
Udp6Demultiplex(IN UDP6_SERVICE_DATA * Udp6Service,IN EFI_NET_SESSION_DATA * NetSession,IN NET_BUF * Packet)1602 Udp6Demultiplex (
1603   IN UDP6_SERVICE_DATA     *Udp6Service,
1604   IN EFI_NET_SESSION_DATA  *NetSession,
1605   IN NET_BUF               *Packet
1606   )
1607 {
1608   EFI_UDP_HEADER        *Udp6Header;
1609   UINT16                 HeadSum;
1610   EFI_UDP6_RECEIVE_DATA  RxData;
1611   EFI_UDP6_SESSION_DATA  *Udp6Session;
1612   UINTN                  Enqueued;
1613 
1614   if (Packet->TotalSize < UDP6_HEADER_SIZE) {
1615     NetbufFree (Packet);
1616     return;
1617   }
1618 
1619   //
1620   // Get the datagram header from the packet buffer.
1621   //
1622   Udp6Header = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL);
1623   ASSERT (Udp6Header != NULL);
1624   if (Udp6Header == NULL) {
1625     NetbufFree (Packet);
1626     return;
1627   }
1628 
1629   if (Udp6Header->Checksum != 0) {
1630     //
1631     // check the checksum.
1632     //
1633     HeadSum = NetIp6PseudoHeadChecksum (
1634                 &NetSession->Source.v6,
1635                 &NetSession->Dest.v6,
1636                 EFI_IP_PROTO_UDP,
1637                 0
1638                 );
1639 
1640     if (Udp6Checksum (Packet, HeadSum) != 0) {
1641       //
1642       // Wrong checksum.
1643       //
1644       NetbufFree (Packet);
1645       return;
1646     }
1647   }
1648 
1649   Udp6Session                  = &RxData.UdpSession;
1650   Udp6Session->SourcePort      = NTOHS (Udp6Header->SrcPort);
1651   Udp6Session->DestinationPort = NTOHS (Udp6Header->DstPort);
1652 
1653   IP6_COPY_ADDRESS (&Udp6Session->SourceAddress, &NetSession->Source);
1654   IP6_COPY_ADDRESS (&Udp6Session->DestinationAddress, &NetSession->Dest);
1655 
1656   //
1657   // Trim the UDP header.
1658   //
1659   NetbufTrim (Packet, UDP6_HEADER_SIZE, TRUE);
1660 
1661   RxData.DataLength = (UINT32) Packet->TotalSize;
1662 
1663   //
1664   // Try to enqueue this datagram into the instances.
1665   //
1666   Enqueued = Udp6EnqueueDgram (Udp6Service, Packet, &RxData);
1667 
1668   if (Enqueued == 0) {
1669     //
1670     // Send the port unreachable ICMP packet before we free this NET_BUF
1671     //
1672     Udp6SendPortUnreach (Udp6Service->IpIo, NetSession, Udp6Header);
1673   }
1674 
1675   //
1676   // Try to free the packet before deliver it.
1677   //
1678   NetbufFree (Packet);
1679 
1680   if (Enqueued > 0) {
1681     //
1682     // Deliver the datagram.
1683     //
1684     Udp6DeliverDgram (Udp6Service);
1685   }
1686 }
1687 
1688 
1689 /**
1690   This function builds and sends out a icmp port unreachable message.
1691 
1692   @param[in]  IpIo               Pointer to the IP_IO instance.
1693   @param[in]  NetSession         Pointer to the EFI_NET_SESSION_DATA of the packet
1694                                  causes this icmp error message.
1695   @param[in]  Udp6Header         Pointer to the udp header of the datagram causes
1696                                  this icmp error message.
1697 
1698 **/
1699 VOID
Udp6SendPortUnreach(IN IP_IO * IpIo,IN EFI_NET_SESSION_DATA * NetSession,IN VOID * Udp6Header)1700 Udp6SendPortUnreach (
1701   IN IP_IO                 *IpIo,
1702   IN EFI_NET_SESSION_DATA  *NetSession,
1703   IN VOID                  *Udp6Header
1704   )
1705 {
1706   NET_BUF              *Packet;
1707   UINT32               Len;
1708   IP6_ICMP_ERROR_HEAD  *IcmpErrHdr;
1709   UINT8                *Ptr;
1710   IP_IO_OVERRIDE       Override;
1711   IP_IO_IP_INFO        *IpSender;
1712   EFI_IP6_MODE_DATA    *Ip6ModeData;
1713   EFI_STATUS           Status;
1714   EFI_IP6_PROTOCOL     *Ip6Protocol;
1715 
1716   Ip6ModeData = NULL;
1717 
1718   //
1719   // An ICMPv6 error message MUST NOT be originated as A packet destined to
1720   // 1) an IPv6 multicast address 2) The IPv6 Unspecified Address
1721   //
1722   if (NetSession->IpVersion == IP_VERSION_6) {
1723     if (NetIp6IsUnspecifiedAddr (&NetSession->Dest.v6) ||
1724       IP6_IS_MULTICAST (&NetSession->Dest.v6)
1725       ) {
1726       goto EXIT;
1727     }
1728   }
1729 
1730 
1731   IpSender    = IpIoFindSender (&IpIo, NetSession->IpVersion, &NetSession->Dest);
1732 
1733   //
1734   // Get the Ipv6 Mode Data.
1735   //
1736   Ip6ModeData = AllocateZeroPool (sizeof (EFI_IP6_MODE_DATA));
1737   ASSERT (Ip6ModeData != NULL);
1738   if (Ip6ModeData == NULL) {
1739     goto EXIT;
1740   }
1741 
1742   //
1743   // If not finding the related IpSender use the default IpIo to send out
1744   // the port unreachable ICMP message.
1745   //
1746   if (IpSender == NULL) {
1747     Ip6Protocol = IpIo->Ip.Ip6;
1748   } else {
1749     Ip6Protocol = IpSender->Ip.Ip6;
1750   }
1751 
1752   Status = Ip6Protocol->GetModeData (
1753                           Ip6Protocol,
1754                           Ip6ModeData,
1755                           NULL,
1756                           NULL
1757                           );
1758 
1759   if (EFI_ERROR (Status)) {
1760     goto EXIT;
1761   }
1762   //
1763   // The ICMP6 packet length, includes whole invoking packet and ICMP6 error header.
1764   //
1765   Len = NetSession->IpHdrLen +
1766         NTOHS(((EFI_UDP_HEADER *) Udp6Header)->Length) +
1767         sizeof (IP6_ICMP_ERROR_HEAD);
1768 
1769   //
1770   // If the ICMP6 packet length larger than IP MTU, adjust its length to MTU.
1771   //
1772   if (Ip6ModeData->MaxPacketSize < Len) {
1773     Len = Ip6ModeData->MaxPacketSize;
1774   }
1775 
1776   //
1777   // Allocate buffer for the icmp error message.
1778   //
1779   Packet = NetbufAlloc (Len);
1780   if (Packet == NULL) {
1781     goto EXIT;
1782   }
1783 
1784   //
1785   // Allocate space for the IP6_ICMP_ERROR_HEAD.
1786   //
1787   IcmpErrHdr = (IP6_ICMP_ERROR_HEAD *) NetbufAllocSpace (Packet, Len, FALSE);
1788   ASSERT (IcmpErrHdr != NULL);
1789   if (IcmpErrHdr == NULL) {
1790     goto EXIT;
1791   }
1792 
1793   //
1794   // Set the required fields for the icmp port unreachable message.
1795   //
1796   IcmpErrHdr->Head.Type     = ICMP_V6_DEST_UNREACHABLE;
1797   IcmpErrHdr->Head.Code     = ICMP_V6_PORT_UNREACHABLE;
1798   IcmpErrHdr->Head.Checksum = 0;
1799   IcmpErrHdr->Fourth        = 0;
1800 
1801   //
1802   // Copy as much of invoking Packet as possible without the ICMPv6 packet
1803   // exceeding the minimum Ipv6 MTU. The length of IP6_ICMP_ERROR_HEAD contains
1804   // the length of EFI_IP6_HEADER, so when using the length of IP6_ICMP_ERROR_HEAD
1805   // for pointer movement that fact should be considered.
1806   //
1807   Ptr = (VOID *) &IcmpErrHdr->Head;
1808   Ptr = (UINT8 *) (UINTN) ((UINTN) Ptr + sizeof (IP6_ICMP_ERROR_HEAD) - sizeof (EFI_IP6_HEADER));
1809   CopyMem (Ptr, NetSession->IpHdr.Ip6Hdr, NetSession->IpHdrLen);
1810   CopyMem (
1811     Ptr + NetSession->IpHdrLen,
1812     Udp6Header,
1813     Len - NetSession->IpHdrLen - sizeof (IP6_ICMP_ERROR_HEAD) + sizeof (EFI_IP6_HEADER)
1814     );
1815 
1816   //
1817   // Set the checksum as zero, and IP6 driver will calculate it with pseudo header.
1818   //
1819   IcmpErrHdr->Head.Checksum = 0;
1820 
1821   //
1822   // Fill the override data.
1823   //
1824   Override.Ip6OverrideData.FlowLabel     = 0;
1825   Override.Ip6OverrideData.HopLimit      = 255;
1826   Override.Ip6OverrideData.Protocol      = IP6_ICMP;
1827 
1828   //
1829   // Send out this icmp packet.
1830   //
1831   IpIoSend (IpIo, Packet, IpSender, NULL, NULL, &NetSession->Source, &Override);
1832 
1833   NetbufFree (Packet);
1834 
1835 EXIT:
1836   if (Ip6ModeData != NULL) {
1837     FreePool (Ip6ModeData);
1838   }
1839 }
1840 
1841 
1842 /**
1843   This function handles the received Icmp Error message and de-multiplexes it to the
1844   instance.
1845 
1846   @param[in]       Udp6Service        Pointer to the udp service context data.
1847   @param[in]       IcmpError          The icmp error code.
1848   @param[in]       NetSession         Pointer to the EFI_NET_SESSION_DATA abstracted
1849                                       from the received Icmp Error packet.
1850   @param[in, out]  Packet             Pointer to the Icmp Error packet.
1851 
1852 **/
1853 VOID
Udp6IcmpHandler(IN UDP6_SERVICE_DATA * Udp6Service,IN UINT8 IcmpError,IN EFI_NET_SESSION_DATA * NetSession,IN OUT NET_BUF * Packet)1854 Udp6IcmpHandler (
1855   IN UDP6_SERVICE_DATA     *Udp6Service,
1856   IN UINT8                 IcmpError,
1857   IN EFI_NET_SESSION_DATA  *NetSession,
1858   IN OUT NET_BUF           *Packet
1859   )
1860 {
1861   EFI_UDP_HEADER         *Udp6Header;
1862   EFI_UDP6_SESSION_DATA  Udp6Session;
1863   LIST_ENTRY             *Entry;
1864   UDP6_INSTANCE_DATA     *Instance;
1865 
1866   if (Packet->TotalSize < UDP6_HEADER_SIZE) {
1867     NetbufFree (Packet);
1868     return;
1869   }
1870 
1871   Udp6Header = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL);
1872   ASSERT (Udp6Header != NULL);
1873   if (Udp6Header == NULL) {
1874     NetbufFree (Packet);
1875     return;
1876   }
1877 
1878   IP6_COPY_ADDRESS (&Udp6Session.SourceAddress, &NetSession->Source);
1879   IP6_COPY_ADDRESS (&Udp6Session.DestinationAddress, &NetSession->Dest);
1880 
1881   Udp6Session.SourcePort      = NTOHS (Udp6Header->DstPort);
1882   Udp6Session.DestinationPort = NTOHS (Udp6Header->SrcPort);
1883 
1884   NET_LIST_FOR_EACH (Entry, &Udp6Service->ChildrenList) {
1885     //
1886     // Iterate all the instances.
1887     //
1888     Instance = NET_LIST_USER_STRUCT (Entry, UDP6_INSTANCE_DATA, Link);
1889 
1890     if (!Instance->Configured) {
1891       continue;
1892     }
1893 
1894     if (Udp6MatchDgram (Instance, &Udp6Session)) {
1895       //
1896       // Translate the Icmp Error code according to the udp spec.
1897       //
1898       Instance->IcmpError = IpIoGetIcmpErrStatus (IcmpError, IP_VERSION_6, NULL, NULL);
1899 
1900       if (IcmpError > ICMP_ERR_UNREACH_PORT) {
1901         Instance->IcmpError = EFI_ICMP_ERROR;
1902       }
1903 
1904       //
1905       // Notify the instance with the received Icmp Error.
1906       //
1907       Udp6ReportIcmpError (Instance);
1908 
1909       break;
1910     }
1911   }
1912 
1913   NetbufFree (Packet);
1914 }
1915 
1916 
1917 /**
1918   This function reports the received ICMP error.
1919 
1920   @param[in]  Instance          Pointer to the udp instance context data.
1921 
1922 **/
1923 VOID
Udp6ReportIcmpError(IN UDP6_INSTANCE_DATA * Instance)1924 Udp6ReportIcmpError (
1925   IN UDP6_INSTANCE_DATA  *Instance
1926   )
1927 {
1928   EFI_UDP6_COMPLETION_TOKEN  *Token;
1929 
1930   if (NetMapIsEmpty (&Instance->RxTokens)) {
1931     //
1932     // There are no receive tokens to deliver the ICMP error.
1933     //
1934     return;
1935   }
1936 
1937   if (EFI_ERROR (Instance->IcmpError)) {
1938     //
1939     // Try to get a RxToken from the RxTokens map.
1940     //
1941     Token = (EFI_UDP6_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);
1942 
1943     if (Token != NULL) {
1944       //
1945       // Report the error through the Token.
1946       //
1947       Token->Status = Instance->IcmpError;
1948       gBS->SignalEvent (Token->Event);
1949 
1950       //
1951       // Clear the IcmpError.
1952       //
1953       Instance->IcmpError = EFI_SUCCESS;
1954     }
1955   }
1956 }
1957 
1958 
1959 /**
1960   This function is a dummy ext-free function for the NET_BUF created for the output
1961   udp datagram.
1962 
1963   @param[in]  Context                Pointer to the context data.
1964 
1965 **/
1966 VOID
1967 EFIAPI
Udp6NetVectorExtFree(IN VOID * Context)1968 Udp6NetVectorExtFree (
1969   IN VOID  *Context
1970   )
1971 {
1972 }
1973 
1974 /**
1975   Find the key in the netmap.
1976 
1977   @param[in]  Map                    The netmap to search within.
1978   @param[in]  Key                    The key to search.
1979 
1980   @return The point to the item contains the Key, or NULL, if Key isn't in the map.
1981 
1982 **/
1983 NET_MAP_ITEM *
Udp6MapMultiCastAddr(IN NET_MAP * Map,IN VOID * Key)1984 Udp6MapMultiCastAddr (
1985   IN  NET_MAP               *Map,
1986   IN  VOID                  *Key
1987   )
1988 {
1989   LIST_ENTRY        *Entry;
1990   NET_MAP_ITEM      *Item;
1991   EFI_IPv6_ADDRESS  *Addr;
1992 
1993   ASSERT (Map != NULL);
1994   NET_LIST_FOR_EACH (Entry, &Map->Used) {
1995     Item  = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1996     Addr  = (EFI_IPv6_ADDRESS *) Item->Key;
1997     if (EFI_IP6_EQUAL (Addr, Key)) {
1998       return Item;
1999     }
2000   }
2001   return NULL;
2002 }
2003 
2004