1 /** @file
2   Implementation of EFI_IP6_PROTOCOL protocol interfaces.
3 
4   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
6 
7   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php.
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "Ip6Impl.h"
18 
19 EFI_IPSEC2_PROTOCOL    *mIpSec = NULL;
20 
21 EFI_IP6_PROTOCOL mEfiIp6ProtocolTemplete = {
22   EfiIp6GetModeData,
23   EfiIp6Configure,
24   EfiIp6Groups,
25   EfiIp6Routes,
26   EfiIp6Neighbors,
27   EfiIp6Transmit,
28   EfiIp6Receive,
29   EfiIp6Cancel,
30   EfiIp6Poll
31 };
32 
33 /**
34   Gets the current operational settings for this instance of the EFI IPv6 Protocol driver.
35 
36   The GetModeData() function returns the current operational mode data for this driver instance.
37   The data fields in EFI_IP6_MODE_DATA are read only. This function is used optionally to
38   retrieve the operational mode data of underlying networks or drivers.
39 
40   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
41   @param[out] Ip6ModeData        Pointer to the EFI IPv6 Protocol mode data structure.
42   @param[out] MnpConfigData      Pointer to the managed network configuration data structure.
43   @param[out] SnpModeData        Pointer to the simple network mode data structure.
44 
45   @retval EFI_SUCCESS            The operation completed successfully.
46   @retval EFI_INVALID_PARAMETER  This is NULL.
47   @retval EFI_OUT_OF_RESOURCES   The required mode data could not be allocated.
48 
49 **/
50 EFI_STATUS
51 EFIAPI
EfiIp6GetModeData(IN EFI_IP6_PROTOCOL * This,OUT EFI_IP6_MODE_DATA * Ip6ModeData OPTIONAL,OUT EFI_MANAGED_NETWORK_CONFIG_DATA * MnpConfigData OPTIONAL,OUT EFI_SIMPLE_NETWORK_MODE * SnpModeData OPTIONAL)52 EfiIp6GetModeData (
53   IN EFI_IP6_PROTOCOL                 *This,
54   OUT EFI_IP6_MODE_DATA               *Ip6ModeData     OPTIONAL,
55   OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData   OPTIONAL,
56   OUT EFI_SIMPLE_NETWORK_MODE         *SnpModeData     OPTIONAL
57   )
58 {
59   IP6_PROTOCOL              *IpInstance;
60   IP6_SERVICE               *IpSb;
61   IP6_INTERFACE             *IpIf;
62   EFI_IP6_CONFIG_DATA       *Config;
63   EFI_STATUS                Status;
64   EFI_TPL                   OldTpl;
65 
66   if (This == NULL) {
67     return EFI_INVALID_PARAMETER;
68   }
69 
70   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
71   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
72   IpSb       = IpInstance->Service;
73   IpIf       = IpInstance->Interface;
74 
75   if (IpSb->LinkLocalDadFail) {
76     return EFI_INVALID_PARAMETER;
77   }
78 
79   if (Ip6ModeData != NULL) {
80     //
81     // IsStarted is "whether the EfiIp6Configure has been called".
82     // IsConfigured is "whether the station address has been configured"
83     //
84     Ip6ModeData->IsStarted     = (BOOLEAN) (IpInstance->State == IP6_STATE_CONFIGED);
85     Ip6ModeData->MaxPacketSize = IpSb->MaxPacketSize;
86     CopyMem (&Ip6ModeData->ConfigData, &IpInstance->ConfigData, sizeof (EFI_IP6_CONFIG_DATA));
87     Ip6ModeData->IsConfigured  = FALSE;
88 
89     Ip6ModeData->AddressCount  = 0;
90     Ip6ModeData->AddressList   = NULL;
91 
92     Ip6ModeData->GroupCount    = IpInstance->GroupCount;
93     Ip6ModeData->GroupTable    = NULL;
94 
95     Ip6ModeData->RouteCount    = 0;
96     Ip6ModeData->RouteTable    = NULL;
97 
98     Ip6ModeData->NeighborCount = 0;
99     Ip6ModeData->NeighborCache = NULL;
100 
101     Ip6ModeData->PrefixCount   = 0;
102     Ip6ModeData->PrefixTable   = NULL;
103 
104     Ip6ModeData->IcmpTypeCount = 23;
105     Ip6ModeData->IcmpTypeList  = AllocateCopyPool (
106                                    Ip6ModeData->IcmpTypeCount * sizeof (EFI_IP6_ICMP_TYPE),
107                                    mIp6SupportedIcmp
108                                    );
109     if (Ip6ModeData->IcmpTypeList == NULL) {
110       Status = EFI_OUT_OF_RESOURCES;
111       goto Error;
112     }
113 
114     //
115     // Return the currently configured IPv6 addresses and corresponding prefix lengths.
116     //
117     Status = Ip6BuildEfiAddressList (
118                IpSb,
119                &Ip6ModeData->AddressCount,
120                &Ip6ModeData->AddressList
121                );
122     if (EFI_ERROR (Status)) {
123       goto Error;
124     }
125 
126     //
127     // Return the current station address for this IP child.
128     // If UseAnyStationAddress is set to TRUE, IP6 driver will
129     // select a source address from its address list. Otherwise use the
130     // StationAddress in config data.
131     //
132     if (Ip6ModeData->IsStarted) {
133       Config = &Ip6ModeData->ConfigData;
134 
135       if (IpIf->Configured || NetIp6IsUnspecifiedAddr (&Config->DestinationAddress)) {
136         Ip6ModeData->IsConfigured = TRUE;
137       } else {
138         Ip6ModeData->IsConfigured = FALSE;
139       }
140 
141       //
142       // Build a EFI route table for user from the internal route table.
143       //
144       Status = Ip6BuildEfiRouteTable (
145                  IpSb->RouteTable,
146                  &Ip6ModeData->RouteCount,
147                  &Ip6ModeData->RouteTable
148                  );
149 
150       if (EFI_ERROR (Status)) {
151         goto Error;
152       }
153     }
154 
155     if (Ip6ModeData->IsConfigured) {
156       //
157       // Return the joined multicast group addresses.
158       //
159       if (IpInstance->GroupCount != 0) {
160         Ip6ModeData->GroupTable = AllocateCopyPool (
161                                     IpInstance->GroupCount * sizeof (EFI_IPv6_ADDRESS),
162                                     IpInstance->GroupList
163                                     );
164         if (Ip6ModeData->GroupTable == NULL) {
165           Status = EFI_OUT_OF_RESOURCES;
166           goto Error;
167         }
168       }
169       //
170       // Return the neighbor cache entries
171       //
172       Status = Ip6BuildEfiNeighborCache (
173                  IpInstance,
174                  &Ip6ModeData->NeighborCount,
175                  &Ip6ModeData->NeighborCache
176                  );
177       if (EFI_ERROR (Status)) {
178         goto Error;
179       }
180 
181       //
182       // Return the prefix table entries
183       //
184       Status = Ip6BuildPrefixTable (
185                  IpInstance,
186                  &Ip6ModeData->PrefixCount,
187                  &Ip6ModeData->PrefixTable
188                  );
189       if (EFI_ERROR (Status)) {
190         goto Error;
191       }
192 
193     }
194   }
195 
196   //
197   // Get fresh mode data from MNP, since underlying media status may change
198   //
199   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, MnpConfigData, SnpModeData);
200 
201   goto Exit;
202 
203 Error:
204   if (Ip6ModeData != NULL) {
205     if (Ip6ModeData->AddressList != NULL) {
206       FreePool (Ip6ModeData->AddressList);
207     }
208 
209     if (Ip6ModeData->GroupTable != NULL) {
210       FreePool (Ip6ModeData->GroupTable);
211     }
212 
213     if (Ip6ModeData->RouteTable != NULL) {
214       FreePool (Ip6ModeData->RouteTable);
215     }
216 
217     if (Ip6ModeData->NeighborCache != NULL) {
218       FreePool (Ip6ModeData->NeighborCache);
219     }
220 
221     if (Ip6ModeData->PrefixTable != NULL) {
222       FreePool (Ip6ModeData->PrefixTable);
223     }
224 
225     if (Ip6ModeData->IcmpTypeList != NULL) {
226       FreePool (Ip6ModeData->IcmpTypeList);
227     }
228   }
229 
230 Exit:
231   gBS->RestoreTPL (OldTpl);
232   return Status;
233 }
234 
235 /**
236   Validate that Ipv6 address is OK to be used as station address or next hop address/ neighbor.
237 
238   @param[in]  IpSb               The IP6 service instance.
239   @param[in]  Ip                 The IPv6 address to validate.
240   @param[in]  Flag               If TRUE, validate if the address is OK to be used
241                                  as station address. If FALSE, validate if the
242                                  address is OK to be used as the next hop address/
243                                  neighbor.
244 
245   @retval TRUE                   The Ip address is valid and could be used.
246   @retval FALSE                  Invalid Ip address.
247 
248 **/
249 BOOLEAN
Ip6IsValidAddress(IN IP6_SERVICE * IpSb,IN EFI_IPv6_ADDRESS * Ip,IN BOOLEAN Flag)250 Ip6IsValidAddress (
251   IN IP6_SERVICE            *IpSb,
252   IN EFI_IPv6_ADDRESS       *Ip,
253   IN BOOLEAN                Flag
254   )
255 {
256   if (!NetIp6IsUnspecifiedAddr (Ip)) {
257     if (!NetIp6IsValidUnicast(Ip)) {
258       return FALSE;
259     }
260     if (Ip6IsOneOfSetAddress (IpSb, Ip, NULL, NULL)) {
261       return Flag;
262     }
263   } else {
264     return Flag;
265   }
266 
267   return (BOOLEAN) !Flag;
268 }
269 
270 /**
271   Validate whether the value of protocol is illegal or not. Protocol is the 'Next Header' field
272   in the last IPv6 extension header, or basic IPv6 header is there's no extension header.
273 
274   @param[in]  Protocol           Default value of 'Next Header'
275 
276   @retval TRUE                   The protocol is illegal.
277   @retval FALSE                  The protocol is legal.
278 
279 **/
280 BOOLEAN
Ip6IsIllegalProtocol(IN UINT8 Protocol)281 Ip6IsIllegalProtocol (
282   IN UINT8                  Protocol
283   )
284 {
285   if (Protocol == IP6_HOP_BY_HOP || Protocol == EFI_IP_PROTO_ICMP || Protocol == IP4_PROTO_IGMP) {
286     return TRUE;
287   }
288 
289   if (Protocol == 41 || Protocol == 43 || Protocol == 44 || Protocol == 59 || Protocol == 60 || Protocol == 124) {
290     return TRUE;
291   }
292 
293   return FALSE;
294 }
295 
296 /**
297   Intiialize the IP6_PROTOCOL structure to the unconfigured states.
298 
299   @param[in]       IpSb                   The IP6 service instance.
300   @param[in, out]  IpInstance             The IP6 child instance.
301 
302 **/
303 VOID
Ip6InitProtocol(IN IP6_SERVICE * IpSb,IN OUT IP6_PROTOCOL * IpInstance)304 Ip6InitProtocol (
305   IN IP6_SERVICE            *IpSb,
306   IN OUT IP6_PROTOCOL       *IpInstance
307   )
308 {
309   ASSERT ((IpSb != NULL) && (IpInstance != NULL));
310 
311   ZeroMem (IpInstance, sizeof (IP6_PROTOCOL));
312 
313   IpInstance->Signature = IP6_PROTOCOL_SIGNATURE;
314   IpInstance->State     = IP6_STATE_UNCONFIGED;
315   IpInstance->Service   = IpSb;
316   IpInstance->GroupList = NULL;
317   CopyMem (&IpInstance->Ip6Proto, &mEfiIp6ProtocolTemplete, sizeof (EFI_IP6_PROTOCOL));
318 
319   NetMapInit  (&IpInstance->RxTokens);
320   NetMapInit  (&IpInstance->TxTokens);
321   InitializeListHead (&IpInstance->Received);
322   InitializeListHead (&IpInstance->Delivered);
323 
324   EfiInitializeLock (&IpInstance->RecycleLock, TPL_NOTIFY);
325 }
326 
327 /**
328   Configure the IP6 child. If the child is already configured,
329   change the configuration parameter. Otherwise, configure it
330   for the first time. The caller should validate the configuration
331   before deliver them to it. It also don't do configure NULL.
332 
333   @param[in, out]  IpInstance         The IP6 child to configure.
334   @param[in]       Config             The configure data.
335 
336   @retval EFI_SUCCESS            The IP6 child is successfully configured.
337   @retval EFI_DEVICE_ERROR       Failed to free the pending transive or to
338                                  configure  underlying MNP, or other errors.
339   @retval EFI_NO_MAPPING         The IP6 child is configured to use the default
340                                  address, but the default address hasn't been
341                                  configured. The IP6 child doesn't need to be
342                                  reconfigured when the default address is configured.
343   @retval EFI_OUT_OF_RESOURCES   No more memory space is available.
344   @retval other                  Other error occurs.
345 
346 **/
347 EFI_STATUS
Ip6ConfigProtocol(IN OUT IP6_PROTOCOL * IpInstance,IN EFI_IP6_CONFIG_DATA * Config)348 Ip6ConfigProtocol (
349   IN OUT IP6_PROTOCOL        *IpInstance,
350   IN     EFI_IP6_CONFIG_DATA *Config
351   )
352 {
353   IP6_SERVICE               *IpSb;
354   IP6_INTERFACE             *IpIf;
355   EFI_STATUS                Status;
356   EFI_IP6_CONFIG_DATA       *Current;
357   IP6_ADDRESS_INFO          *AddressInfo;
358   BOOLEAN                   StationZero;
359   BOOLEAN                   DestZero;
360   EFI_IPv6_ADDRESS          Source;
361   BOOLEAN                   AddrOk;
362 
363   IpSb    = IpInstance->Service;
364   Current = &IpInstance->ConfigData;
365 
366   //
367   // User is changing packet filters. It must be stopped
368   // before the station address can be changed.
369   //
370   if (IpInstance->State == IP6_STATE_CONFIGED) {
371     //
372     // Cancel all the pending transmit/receive from upper layer
373     //
374     Status = Ip6Cancel (IpInstance, NULL);
375 
376     if (EFI_ERROR (Status)) {
377       return EFI_DEVICE_ERROR;
378     }
379 
380     CopyMem (Current, Config, sizeof (EFI_IP6_CONFIG_DATA));
381     return EFI_SUCCESS;
382   }
383 
384   //
385   // Set up the interface.
386   //
387   StationZero = NetIp6IsUnspecifiedAddr (&Config->StationAddress);
388   DestZero    = NetIp6IsUnspecifiedAddr (&Config->DestinationAddress);
389 
390   if (StationZero && DestZero) {
391     //
392     // StationAddress is still zero.
393     //
394 
395     NET_GET_REF (IpSb->DefaultInterface);
396     IpInstance->Interface = IpSb->DefaultInterface;
397     InsertTailList (&IpSb->DefaultInterface->IpInstances, &IpInstance->AddrLink);
398 
399     CopyMem (Current, Config, sizeof (EFI_IP6_CONFIG_DATA));
400     IpInstance->State = IP6_STATE_CONFIGED;
401 
402     return EFI_SUCCESS;
403   }
404 
405   if (StationZero && !DestZero) {
406     Status = Ip6SelectSourceAddress (IpSb, &Config->DestinationAddress, &Source);
407     if (EFI_ERROR (Status)) {
408       return Status;
409     }
410   } else {
411     IP6_COPY_ADDRESS (&Source, &Config->StationAddress);
412   }
413 
414   AddrOk = Ip6IsOneOfSetAddress (IpSb, &Source, &IpIf, &AddressInfo);
415   if (AddrOk) {
416     if (AddressInfo != NULL) {
417       IpInstance->PrefixLength = AddressInfo->PrefixLength;
418     } else {
419       IpInstance->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;
420     }
421   } else {
422     //
423     // The specified source address is not one of the addresses IPv6 maintains.
424     //
425     return EFI_INVALID_PARAMETER;
426   }
427 
428 
429   NET_GET_REF (IpIf);
430   IpInstance->Interface = IpIf;
431   InsertTailList (&IpIf->IpInstances, &IpInstance->AddrLink);
432 
433   CopyMem (Current, Config, sizeof (EFI_IP6_CONFIG_DATA));
434   IP6_COPY_ADDRESS (&Current->StationAddress, &Source);
435   IpInstance->State = IP6_STATE_CONFIGED;
436 
437   return EFI_SUCCESS;
438 }
439 
440 /**
441   Clean up the IP6 child, and release all the resources used by it.
442 
443   @param[in, out]  IpInstance    The IP6 child to clean up.
444 
445   @retval EFI_SUCCESS            The IP6 child is cleaned up.
446   @retval EFI_DEVICE_ERROR       Some resources failed to be released.
447 
448 **/
449 EFI_STATUS
Ip6CleanProtocol(IN OUT IP6_PROTOCOL * IpInstance)450 Ip6CleanProtocol (
451   IN OUT IP6_PROTOCOL            *IpInstance
452   )
453 {
454   if (EFI_ERROR (Ip6Cancel (IpInstance, NULL))) {
455     return EFI_DEVICE_ERROR;
456   }
457 
458   if (EFI_ERROR (Ip6Groups (IpInstance, FALSE, NULL))) {
459     return EFI_DEVICE_ERROR;
460   }
461 
462   //
463   // Some packets haven't been recycled. It is because either the
464   // user forgets to recycle the packets, or because the callback
465   // hasn't been called. Just leave it alone.
466   //
467   if (!IsListEmpty (&IpInstance->Delivered)) {
468     ;
469   }
470 
471   if (IpInstance->Interface != NULL) {
472     RemoveEntryList (&IpInstance->AddrLink);
473     Ip6CleanInterface (IpInstance->Interface, IpInstance);
474     IpInstance->Interface = NULL;
475   }
476 
477   if (IpInstance->GroupList != NULL) {
478     FreePool (IpInstance->GroupList);
479     IpInstance->GroupList   = NULL;
480     IpInstance->GroupCount  = 0;
481   }
482 
483   NetMapClean (&IpInstance->TxTokens);
484 
485   NetMapClean (&IpInstance->RxTokens);
486 
487   return EFI_SUCCESS;
488 }
489 
490 /**
491   Configure the MNP parameter used by IP. The IP driver uses one MNP
492   child to transmit/receive frames. By default, it configures MNP
493   to receive unicast/multicast/broadcast. Also, it will enable/disable
494   the promiscuous receive according to whether there is IP child
495   enable that or not. If Force is FALSE, it will iterate through
496   all the IP children to check whether the promiscuous receive
497   setting has been changed. If it hasn't been changed, it won't
498   reconfigure the MNP. If Force is TRUE, the MNP is configured
499   whether that is changed or not.
500 
501   @param[in]  IpSb               The IP6 service instance that is to be changed.
502   @param[in]  Force              Force the configuration or not.
503 
504   @retval EFI_SUCCESS            The MNP successfully configured/reconfigured.
505   @retval Others                 Configuration failed.
506 
507 **/
508 EFI_STATUS
Ip6ServiceConfigMnp(IN IP6_SERVICE * IpSb,IN BOOLEAN Force)509 Ip6ServiceConfigMnp (
510   IN IP6_SERVICE            *IpSb,
511   IN BOOLEAN                Force
512   )
513 {
514   LIST_ENTRY                *Entry;
515   LIST_ENTRY                *ProtoEntry;
516   IP6_INTERFACE             *IpIf;
517   IP6_PROTOCOL              *IpInstance;
518   BOOLEAN                   Reconfig;
519   BOOLEAN                   PromiscReceive;
520   EFI_STATUS                Status;
521 
522   Reconfig       = FALSE;
523   PromiscReceive = FALSE;
524 
525   if (!Force) {
526     //
527     // Iterate through the IP children to check whether promiscuous
528     // receive setting has been changed. Update the interface's receive
529     // filter also.
530     //
531     NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
532 
533       IpIf              = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
534       IpIf->PromiscRecv = FALSE;
535 
536       NET_LIST_FOR_EACH (ProtoEntry, &IpIf->IpInstances) {
537         IpInstance = NET_LIST_USER_STRUCT (ProtoEntry, IP6_PROTOCOL, AddrLink);
538 
539         if (IpInstance->ConfigData.AcceptPromiscuous) {
540           IpIf->PromiscRecv = TRUE;
541           PromiscReceive    = TRUE;
542         }
543       }
544     }
545 
546     //
547     // If promiscuous receive isn't changed, it isn't necessary to reconfigure.
548     //
549     if (PromiscReceive == IpSb->MnpConfigData.EnablePromiscuousReceive) {
550       return EFI_SUCCESS;
551     }
552 
553     Reconfig  = TRUE;
554     IpSb->MnpConfigData.EnablePromiscuousReceive = PromiscReceive;
555   }
556 
557   Status = IpSb->Mnp->Configure (IpSb->Mnp, &IpSb->MnpConfigData);
558 
559   //
560   // recover the original configuration if failed to set the configure.
561   //
562   if (EFI_ERROR (Status) && Reconfig) {
563     IpSb->MnpConfigData.EnablePromiscuousReceive = (BOOLEAN) !PromiscReceive;
564   }
565 
566   return Status;
567 }
568 
569 /**
570   Assigns an IPv6 address and subnet mask to this EFI IPv6 Protocol driver instance.
571 
572   The Configure() function is used to set, change, or reset the operational parameters and filter
573   settings for this EFI IPv6 Protocol instance. Until these parameters have been set, no network traffic
574   can be sent or received by this instance. Once the parameters have been reset (by calling this
575   function with Ip6ConfigData set to NULL), no more traffic can be sent or received until these
576   parameters have been set again. Each EFI IPv6 Protocol instance can be started and stopped
577   independently of each other by enabling or disabling their receive filter settings with the
578   Configure() function.
579 
580   If Ip6ConfigData.StationAddress is a valid non-zero IPv6 unicast address, it is required
581   to be one of the currently configured IPv6 addresses listed in the EFI IPv6 drivers, or else
582   EFI_INVALID_PARAMETER will be returned. If Ip6ConfigData.StationAddress is
583   unspecified, the IPv6 driver will bind a source address according to the source address selection
584   algorithm. Clients could frequently call GetModeData() to check get currently configured IPv6
585   address list in the EFI IPv6 driver. If both Ip6ConfigData.StationAddress and
586   Ip6ConfigData.Destination are unspecified, when transmitting the packet afterwards, the
587   source address filled in each outgoing IPv6 packet is decided based on the destination of this packet.
588 
589   If operational parameters are reset or changed, any pending transmit and receive requests will be
590   cancelled. Their completion token status will be set to EFI_ABORTED and their events will be
591   signaled.
592 
593   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
594   @param[in]  Ip6ConfigData      Pointer to the EFI IPv6 Protocol configuration data structure.
595                                  If NULL, reset the configuration data.
596 
597   @retval EFI_SUCCESS            The driver instance was successfully opened.
598   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
599                                  - This is NULL.
600                                  - Ip6ConfigData.StationAddress is neither zero nor
601                                    a unicast IPv6 address.
602                                  - Ip6ConfigData.StationAddress is neither zero nor
603                                    one of the configured IP addresses in the EFI IPv6 driver.
604                                  - Ip6ConfigData.DefaultProtocol is illegal.
605   @retval EFI_OUT_OF_RESOURCES   The EFI IPv6 Protocol driver instance data could not be allocated.
606   @retval EFI_NO_MAPPING         The IPv6 driver was responsible for choosing a source address for
607                                  this instance, but no source address was available for use.
608   @retval EFI_ALREADY_STARTED    The interface is already open and must be stopped before the IPv6
609                                  address or prefix length can be changed.
610   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred. The EFI IPv6
611                                  Protocol driver instance was not opened.
612   @retval EFI_UNSUPPORTED        Default protocol specified through
613                                  Ip6ConfigData.DefaulProtocol isn't supported.
614 
615 **/
616 EFI_STATUS
617 EFIAPI
EfiIp6Configure(IN EFI_IP6_PROTOCOL * This,IN EFI_IP6_CONFIG_DATA * Ip6ConfigData OPTIONAL)618 EfiIp6Configure (
619   IN EFI_IP6_PROTOCOL          *This,
620   IN EFI_IP6_CONFIG_DATA       *Ip6ConfigData OPTIONAL
621   )
622 {
623   IP6_PROTOCOL              *IpInstance;
624   EFI_IP6_CONFIG_DATA       *Current;
625   EFI_TPL                   OldTpl;
626   EFI_STATUS                Status;
627   IP6_SERVICE               *IpSb;
628 
629   //
630   // First, validate the parameters
631   //
632   if (This == NULL) {
633     return EFI_INVALID_PARAMETER;
634   }
635 
636   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
637   IpSb       = IpInstance->Service;
638 
639   if (IpSb->LinkLocalDadFail && Ip6ConfigData != NULL) {
640     return EFI_DEVICE_ERROR;
641   }
642 
643   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
644 
645   Status     = EFI_INVALID_PARAMETER;
646 
647   //
648   // Validate the configuration first.
649   //
650   if (Ip6ConfigData != NULL) {
651     //
652     // Check whether the station address is valid.
653     //
654     if (!Ip6IsValidAddress (IpSb, &Ip6ConfigData->StationAddress, TRUE)) {
655        goto Exit;
656     }
657     //
658     // Check whether the default protocol is valid.
659     //
660     if (Ip6IsIllegalProtocol (Ip6ConfigData->DefaultProtocol)) {
661       goto Exit;
662     }
663 
664     //
665     // User can only update packet filters when already configured.
666     // If it wants to change the station address, it must configure(NULL)
667     // the instance firstly.
668     //
669     if (IpInstance->State == IP6_STATE_CONFIGED) {
670       Current = &IpInstance->ConfigData;
671 
672       if (!EFI_IP6_EQUAL (&Current->StationAddress, &Ip6ConfigData->StationAddress)) {
673         Status = EFI_ALREADY_STARTED;
674         goto Exit;
675       }
676 
677       if (NetIp6IsUnspecifiedAddr (&Current->StationAddress) && IP6_NO_MAPPING (IpInstance)) {
678         Status = EFI_NO_MAPPING;
679         goto Exit;
680       }
681     }
682   }
683 
684   //
685   // Configure the instance or clean it up.
686   //
687   if (Ip6ConfigData != NULL) {
688     Status = Ip6ConfigProtocol (IpInstance, Ip6ConfigData);
689   } else {
690     Status = Ip6CleanProtocol (IpInstance);
691 
692     //
693     // Don't change the state if it is DESTROY, consider the following
694     // valid sequence: Mnp is unloaded-->Ip Stopped-->Udp Stopped,
695     // Configure (ThisIp, NULL). If the state is changed to UNCONFIGED,
696     // the unload fails miserably.
697     //
698     if (IpInstance->State == IP6_STATE_CONFIGED) {
699       IpInstance->State = IP6_STATE_UNCONFIGED;
700     }
701   }
702 
703   //
704   // Update the MNP's configure data. Ip6ServiceConfigMnp will check
705   // whether it is necessary to reconfigure the MNP.
706   //
707   Ip6ServiceConfigMnp (IpInstance->Service, FALSE);
708 
709 Exit:
710   gBS->RestoreTPL (OldTpl);
711   return Status;
712 }
713 
714 /**
715   Joins and leaves multicast groups.
716 
717   The Groups() function is used to join and leave multicast group sessions. Joining a group will
718   enable reception of matching multicast packets. Leaving a group will disable reception of matching
719   multicast packets. Source-Specific Multicast isn't required to be supported.
720 
721   If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left.
722 
723   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
724   @param[in]  JoinFlag           Set to TRUE to join the multicast group session, and FALSE to leave.
725   @param[in]  GroupAddress       Pointer to the IPv6 multicast address.
726                                  This is an optional parameter that may be NULL.
727 
728   @retval EFI_SUCCESS            The operation completed successfully.
729   @retval EFI_INVALID_PARAMETER  One or more of the following is TRUE:
730                                  - This is NULL.
731                                  - JoinFlag is TRUE and GroupAddress is NULL.
732                                  - GroupAddress is not NULL and *GroupAddress is
733                                    not a multicast IPv6 address.
734                                  - GroupAddress is not NULL and *GroupAddress is in the
735                                    range of SSM destination address.
736   @retval EFI_NOT_STARTED        This instance has not been started.
737   @retval EFI_OUT_OF_RESOURCES   System resources could not be allocated.
738   @retval EFI_UNSUPPORTED        This EFI IPv6 Protocol implementation does not support multicast groups.
739   @retval EFI_ALREADY_STARTED    The group address is already in the group table (when
740                                  JoinFlag is TRUE).
741   @retval EFI_NOT_FOUND          The group address is not in the group table (when JoinFlag is FALSE).
742   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
743 
744 **/
745 EFI_STATUS
746 EFIAPI
EfiIp6Groups(IN EFI_IP6_PROTOCOL * This,IN BOOLEAN JoinFlag,IN EFI_IPv6_ADDRESS * GroupAddress OPTIONAL)747 EfiIp6Groups (
748   IN EFI_IP6_PROTOCOL  *This,
749   IN BOOLEAN           JoinFlag,
750   IN EFI_IPv6_ADDRESS  *GroupAddress  OPTIONAL
751   )
752 {
753   EFI_TPL                   OldTpl;
754   EFI_STATUS                Status;
755   IP6_PROTOCOL              *IpInstance;
756   IP6_SERVICE               *IpSb;
757 
758   if ((This == NULL) || (JoinFlag && GroupAddress == NULL)) {
759     return EFI_INVALID_PARAMETER;
760   }
761 
762   if (GroupAddress != NULL && !IP6_IS_MULTICAST (GroupAddress)) {
763     return EFI_INVALID_PARAMETER;
764   }
765 
766   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
767   IpSb       = IpInstance->Service;
768 
769   if (IpSb->LinkLocalDadFail) {
770     return EFI_DEVICE_ERROR;
771   }
772 
773   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
774 
775   if (IpInstance->State != IP6_STATE_CONFIGED) {
776     Status = EFI_NOT_STARTED;
777     goto ON_EXIT;
778   }
779 
780   Status = Ip6Groups (IpInstance, JoinFlag, GroupAddress);
781 
782 ON_EXIT:
783   gBS->RestoreTPL (OldTpl);
784   return Status;
785 }
786 
787 /**
788   Adds and deletes routing table entries.
789 
790   The Routes() function adds a route to, or deletes a route from, the routing table.
791 
792   Routes are determined by comparing the leftmost PrefixLength bits of Destination with
793   the destination IPv6 address arithmetically. The gateway address must be on the same subnet as the
794   configured station address.
795 
796   The default route is added with Destination and PrefixLegth both set to all zeros. The
797   default route matches all destination IPv6 addresses that do not match any other routes.
798 
799   All EFI IPv6 Protocol instances share a routing table.
800 
801   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
802   @param[in]  DeleteRoute        Set to TRUE to delete this route from the routing table. Set to
803                                  FALSE to add this route to the routing table. Destination,
804                                  PrefixLength and Gateway are used as the key to each
805                                  route entry.
806   @param[in]  Destination        The address prefix of the subnet that needs to be routed.
807                                  This is an optional parameter that may be NULL.
808   @param[in]  PrefixLength       The prefix length of Destination. Ignored if Destination
809                                  is NULL.
810   @param[in]  GatewayAddress     The unicast gateway IPv6 address for this route.
811                                  This is an optional parameter that may be NULL.
812 
813   @retval EFI_SUCCESS            The operation completed successfully.
814   @retval EFI_NOT_STARTED        The driver instance has not been started.
815   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
816                                  - This is NULL.
817                                  - When DeleteRoute is TRUE, both Destination and
818                                    GatewayAddress are NULL.
819                                  - When DeleteRoute is FALSE, either Destination or
820                                    GatewayAddress is NULL.
821                                  - *GatewayAddress is not a valid unicast IPv6 address.
822                                  - *GatewayAddress is one of the local configured IPv6
823                                    addresses.
824   @retval EFI_OUT_OF_RESOURCES   Could not add the entry to the routing table.
825   @retval EFI_NOT_FOUND          This route is not in the routing table (when DeleteRoute is TRUE).
826   @retval EFI_ACCESS_DENIED      The route is already defined in the routing table (when
827                                  DeleteRoute is FALSE).
828 
829 **/
830 EFI_STATUS
831 EFIAPI
EfiIp6Routes(IN EFI_IP6_PROTOCOL * This,IN BOOLEAN DeleteRoute,IN EFI_IPv6_ADDRESS * Destination OPTIONAL,IN UINT8 PrefixLength,IN EFI_IPv6_ADDRESS * GatewayAddress OPTIONAL)832 EfiIp6Routes (
833   IN EFI_IP6_PROTOCOL    *This,
834   IN BOOLEAN             DeleteRoute,
835   IN EFI_IPv6_ADDRESS    *Destination    OPTIONAL,
836   IN UINT8               PrefixLength,
837   IN EFI_IPv6_ADDRESS    *GatewayAddress OPTIONAL
838   )
839 {
840   IP6_PROTOCOL              *IpInstance;
841   EFI_STATUS                Status;
842   EFI_TPL                   OldTpl;
843   IP6_SERVICE               *IpSb;
844 
845   if ((This == NULL) || (PrefixLength >= IP6_PREFIX_NUM)) {
846     return EFI_INVALID_PARAMETER;
847   }
848 
849   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
850   IpSb       = IpInstance->Service;
851 
852   if (IpSb->LinkLocalDadFail) {
853     return EFI_DEVICE_ERROR;
854   }
855 
856   if (IpInstance->State != IP6_STATE_CONFIGED) {
857     return EFI_NOT_STARTED;
858   }
859 
860   if (DeleteRoute && (Destination == NULL) && (GatewayAddress == NULL)) {
861     return EFI_INVALID_PARAMETER;
862   }
863 
864   if (!DeleteRoute && (Destination == NULL || GatewayAddress == NULL)) {
865     return EFI_INVALID_PARAMETER;
866   }
867 
868   if (GatewayAddress != NULL) {
869     if (!Ip6IsValidAddress (IpSb, GatewayAddress, FALSE)) {
870       return EFI_INVALID_PARAMETER;
871     }
872 
873     if (!NetIp6IsUnspecifiedAddr (GatewayAddress) &&
874         !NetIp6IsNetEqual (GatewayAddress, &IpInstance->ConfigData.StationAddress, PrefixLength)
875           ) {
876       return EFI_INVALID_PARAMETER;
877     }
878   }
879 
880   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
881 
882   //
883   // Update the route table
884   //
885   if (DeleteRoute) {
886     Status = Ip6DelRoute (IpSb->RouteTable, Destination, PrefixLength, GatewayAddress);
887   } else {
888     Status = Ip6AddRoute (IpSb->RouteTable, Destination, PrefixLength, GatewayAddress);
889   }
890 
891   gBS->RestoreTPL (OldTpl);
892   return Status;
893 }
894 
895 /**
896   Add or delete Neighbor cache entries.
897 
898   The Neighbors() function is used to add, update, or delete an entry from neighbor cache.
899   IPv6 neighbor cache entries are typically inserted and updated by the network protocol driver as
900   network traffic is processed. Most neighbor cache entries will timeout and be deleted if the network
901   traffic stops. Neighbor cache entries that were inserted by Neighbors() may be static (will not
902   timeout) or dynamic (will timeout).
903 
904   The implementation should follow the neighbor cache timeout mechanism which is defined in
905   RFC4861. The default neighbor cache timeout value should be tuned for the expected network
906   environment
907 
908   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
909   @param[in]  DeleteFlag         Set to TRUE to delete the specified cache entry, set to FALSE to
910                                  add (or update, if it already exists and Override is TRUE) the
911                                  specified cache entry. TargetIp6Address is used as the key
912                                  to find the requested cache entry.
913   @param[in]  TargetIp6Address   Pointer to the Target IPv6 address.
914   @param[in]  TargetLinkAddress  Pointer to the link-layer address of the target. Ignored if NULL.
915   @param[in]  Timeout            Time in 100-ns units that this entry will remain in the neighbor
916                                  cache, it will be deleted after Timeout. A value of zero means that
917                                  the entry is permanent. A non-zero value means that the entry is
918                                  dynamic.
919   @param[in]  Override           If TRUE, the cached link-layer address of the matching entry will
920                                  be overridden and updated; if FALSE, EFI_ACCESS_DENIED
921                                  will be returned if a corresponding cache entry already existed.
922 
923   @retval  EFI_SUCCESS           The data has been queued for transmission.
924   @retval  EFI_NOT_STARTED       This instance has not been started.
925   @retval  EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
926                                  - This is NULL.
927                                  - TargetIpAddress is NULL.
928                                  - *TargetLinkAddress is invalid when not NULL.
929                                  - *TargetIpAddress is not a valid unicast IPv6 address.
930                                  - *TargetIpAddress is one of the local configured IPv6
931                                    addresses.
932   @retval  EFI_OUT_OF_RESOURCES  Could not add the entry to the neighbor cache.
933   @retval  EFI_NOT_FOUND         This entry is not in the neighbor cache (when DeleteFlag  is
934                                  TRUE or when DeleteFlag  is FALSE while
935                                  TargetLinkAddress is NULL.).
936   @retval  EFI_ACCESS_DENIED     The to-be-added entry is already defined in the neighbor cache,
937                                  and that entry is tagged as un-overridden (when Override
938                                  is FALSE).
939 
940 **/
941 EFI_STATUS
942 EFIAPI
EfiIp6Neighbors(IN EFI_IP6_PROTOCOL * This,IN BOOLEAN DeleteFlag,IN EFI_IPv6_ADDRESS * TargetIp6Address,IN EFI_MAC_ADDRESS * TargetLinkAddress OPTIONAL,IN UINT32 Timeout,IN BOOLEAN Override)943 EfiIp6Neighbors (
944   IN EFI_IP6_PROTOCOL          *This,
945   IN BOOLEAN                   DeleteFlag,
946   IN EFI_IPv6_ADDRESS          *TargetIp6Address,
947   IN EFI_MAC_ADDRESS           *TargetLinkAddress OPTIONAL,
948   IN UINT32                    Timeout,
949   IN BOOLEAN                   Override
950   )
951 {
952   EFI_TPL                   OldTpl;
953   EFI_STATUS                Status;
954   IP6_PROTOCOL              *IpInstance;
955   IP6_SERVICE               *IpSb;
956 
957   if (This == NULL || TargetIp6Address == NULL) {
958     return EFI_INVALID_PARAMETER;
959   }
960 
961   if (NetIp6IsUnspecifiedAddr (TargetIp6Address)) {
962     return EFI_INVALID_PARAMETER;
963   }
964 
965   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
966   IpSb       = IpInstance->Service;
967 
968   if (IpSb->LinkLocalDadFail) {
969     return EFI_DEVICE_ERROR;
970   }
971 
972   if (!Ip6IsValidAddress (IpSb, TargetIp6Address, FALSE)) {
973     return EFI_INVALID_PARAMETER;
974   }
975 
976   if (TargetLinkAddress != NULL) {
977     if (!Ip6IsValidLinkAddress (IpSb, TargetLinkAddress)) {
978       return EFI_INVALID_PARAMETER;
979     }
980   }
981 
982   if (Ip6IsOneOfSetAddress (IpSb, TargetIp6Address, NULL, NULL)) {
983     return EFI_INVALID_PARAMETER;
984   }
985 
986   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
987   if (IpInstance->State != IP6_STATE_CONFIGED) {
988     Status = EFI_NOT_STARTED;
989     goto Exit;
990   }
991 
992   if (DeleteFlag) {
993     Status = Ip6DelNeighbor (IpInstance->Service, TargetIp6Address, TargetLinkAddress, Timeout, Override);
994   } else {
995     Status = Ip6AddNeighbor (IpInstance->Service, TargetIp6Address, TargetLinkAddress, Timeout, Override);
996   }
997 
998 Exit:
999   gBS->RestoreTPL (OldTpl);
1000   return Status;
1001 }
1002 
1003 /**
1004   Check whether the user's token or event has already
1005   been enqueue on IP6's list.
1006 
1007   @param[in]  Map                The container of either user's transmit or receive
1008                                  token.
1009   @param[in]  Item               Current item to check against.
1010   @param[in]  Context            The Token to check againist.
1011 
1012   @retval EFI_ACCESS_DENIED      The token or event has already been enqueued in IP
1013   @retval EFI_SUCCESS            The current item isn't the same token/event as the
1014                                  context.
1015 
1016 **/
1017 EFI_STATUS
1018 EFIAPI
Ip6TokenExist(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)1019 Ip6TokenExist (
1020   IN NET_MAP                *Map,
1021   IN NET_MAP_ITEM           *Item,
1022   IN VOID                   *Context
1023   )
1024 {
1025   EFI_IP6_COMPLETION_TOKEN  *Token;
1026   EFI_IP6_COMPLETION_TOKEN  *TokenInItem;
1027 
1028   Token       = (EFI_IP6_COMPLETION_TOKEN *) Context;
1029   TokenInItem = (EFI_IP6_COMPLETION_TOKEN *) Item->Key;
1030 
1031   if (Token == TokenInItem || Token->Event == TokenInItem->Event) {
1032     return EFI_ACCESS_DENIED;
1033   }
1034 
1035   return EFI_SUCCESS;
1036 }
1037 
1038 /**
1039   Validate the user's token against the current station address.
1040 
1041   @param[in]  Token              User's token to validate.
1042 
1043   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
1044   @retval EFI_BAD_BUFFER_SIZE    The user's option/data is too long.
1045   @retval EFI_SUCCESS            The token is OK.
1046 
1047 **/
1048 EFI_STATUS
Ip6TxTokenValid(IN EFI_IP6_COMPLETION_TOKEN * Token)1049 Ip6TxTokenValid (
1050   IN EFI_IP6_COMPLETION_TOKEN   *Token
1051   )
1052 {
1053   EFI_IP6_TRANSMIT_DATA     *TxData;
1054   UINT32                    Index;
1055   UINT32                    DataLength;
1056 
1057   if (Token == NULL || Token->Event == NULL) {
1058     return EFI_INVALID_PARAMETER;
1059   }
1060 
1061   TxData = Token->Packet.TxData;
1062 
1063   if (TxData == NULL || (TxData->ExtHdrsLength != 0 && TxData->ExtHdrs == NULL)) {
1064     return EFI_INVALID_PARAMETER;
1065   }
1066 
1067   if (TxData->FragmentCount == 0 || TxData->DataLength == 0) {
1068     return EFI_INVALID_PARAMETER;
1069   }
1070 
1071   for (DataLength = 0, Index = 0; Index < TxData->FragmentCount; Index++) {
1072     if (TxData->FragmentTable[Index].FragmentLength == 0 || TxData->FragmentTable[Index].FragmentBuffer == NULL) {
1073       return EFI_INVALID_PARAMETER;
1074     }
1075 
1076     DataLength += TxData->FragmentTable[Index].FragmentLength;
1077   }
1078 
1079   if (TxData->DataLength != DataLength) {
1080     return EFI_INVALID_PARAMETER;
1081   }
1082 
1083   //
1084   // TODO: Token.Packet.TxData.DataLength is too short to transmit.
1085   // return EFI_BUFFER_TOO_SMALL;
1086   //
1087 
1088   //
1089   // If Token.Packet.TxData.DataLength is beyond the maximum that which can be
1090   // described through the Fragment Offset field in Fragment header when performing
1091   // fragmentation.
1092   //
1093   if (TxData->DataLength > 64 * 1024) {
1094     return EFI_BAD_BUFFER_SIZE;
1095   }
1096 
1097   return EFI_SUCCESS;
1098 }
1099 
1100 /**
1101   The callback function for the net buffer which wraps the user's
1102   transmit token. Although  this function seems simple, there
1103   are some subtle aspects.
1104   When user requests the IP to transmit a packet by passing it a
1105   token, the token is wrapped in an IP6_TXTOKEN_WRAP and the data
1106   is wrapped in an net buffer. The net buffer's Free function is
1107   set to Ip6FreeTxToken. The Token and token wrap are added to the
1108   IP child's TxToken map. Then the buffer is passed to Ip6Output for
1109   transmission. If an error happened before that, the buffer
1110   is freed, which in turn frees the token wrap. The wrap may
1111   have been added to the TxToken map or not, and the user's event
1112   shouldn't be fired because we are still in the EfiIp6Transmit. If
1113   the buffer has been sent by Ip6Output, it should be removed from
1114   the TxToken map and user's event signaled. The token wrap and buffer
1115   are bound together. Check the comments in Ip6Output for information
1116   about IP fragmentation.
1117 
1118   @param[in]  Context                The token's wrap.
1119 
1120 **/
1121 VOID
1122 EFIAPI
Ip6FreeTxToken(IN VOID * Context)1123 Ip6FreeTxToken (
1124   IN VOID                   *Context
1125   )
1126 {
1127   IP6_TXTOKEN_WRAP          *Wrap;
1128   NET_MAP_ITEM              *Item;
1129 
1130   Wrap = (IP6_TXTOKEN_WRAP *) Context;
1131 
1132   //
1133   // Signal IpSecRecycleEvent to inform IPsec free the memory
1134   //
1135   if (Wrap->IpSecRecycleSignal != NULL) {
1136     gBS->SignalEvent (Wrap->IpSecRecycleSignal);
1137   }
1138 
1139   //
1140   // Find the token in the instance's map. EfiIp6Transmit put the
1141   // token to the map. If that failed, NetMapFindKey will return NULL.
1142   //
1143   Item = NetMapFindKey (&Wrap->IpInstance->TxTokens, Wrap->Token);
1144 
1145   if (Item != NULL) {
1146     NetMapRemoveItem (&Wrap->IpInstance->TxTokens, Item, NULL);
1147   }
1148 
1149   if (Wrap->Sent) {
1150     gBS->SignalEvent (Wrap->Token->Event);
1151 
1152     //
1153     // Dispatch the DPC queued by the NotifyFunction of Token->Event.
1154     //
1155     DispatchDpc ();
1156   }
1157 
1158   FreePool (Wrap);
1159 }
1160 
1161 
1162 /**
1163   The callback function to Ip6Output to update the transmit status.
1164 
1165   @param[in]  Packet           The user's transmit packet.
1166   @param[in]  IoStatus         The result of the transmission.
1167   @param[in]  Flag             Not used during transmission.
1168   @param[in]  Context          The token's wrap.
1169 
1170 **/
1171 VOID
Ip6OnPacketSent(IN NET_BUF * Packet,IN EFI_STATUS IoStatus,IN UINT32 Flag,IN VOID * Context)1172 Ip6OnPacketSent (
1173   IN NET_BUF                   *Packet,
1174   IN EFI_STATUS                IoStatus,
1175   IN UINT32                    Flag,
1176   IN VOID                      *Context
1177   )
1178 {
1179   IP6_TXTOKEN_WRAP             *Wrap;
1180 
1181   //
1182   // This is the transmission request from upper layer,
1183   // not the IP6 driver itself.
1184   //
1185   Wrap                = (IP6_TXTOKEN_WRAP *) Context;
1186   Wrap->Token->Status = IoStatus;
1187 
1188   NetbufFree (Wrap->Packet);
1189 }
1190 
1191 /**
1192   Places outgoing data packets into the transmit queue.
1193 
1194   The Transmit() function places a sending request in the transmit queue of this
1195   EFI IPv6 Protocol instance. Whenever the packet in the token is sent out or some
1196   errors occur, the event in the token will be signaled, and the status is updated.
1197 
1198   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
1199   @param[in]  Token              Pointer to the transmit token.
1200 
1201   @retval  EFI_SUCCESS           The data has been queued for transmission.
1202   @retval  EFI_NOT_STARTED       This instance has not been started.
1203   @retval  EFI_NO_MAPPING        The IPv6 driver was responsible for choosing
1204                                  a source address for this transmission,
1205                                  but no source address was available for use.
1206   @retval  EFI_INVALID_PARAMETER One or more of the following is TRUE:
1207                                  - This is NULL.
1208                                  - Token is NULL.
1209                                  - Token.Event is NULL.
1210                                  - Token.Packet.TxData is NULL.
1211                                  - Token.Packet.ExtHdrsLength is not zero and
1212                                    Token.Packet.ExtHdrs is NULL.
1213                                  - Token.Packet.FragmentCount is zero.
1214                                  - One or more of the Token.Packet.TxData.
1215                                    FragmentTable[].FragmentLength fields is zero.
1216                                  - One or more of the Token.Packet.TxData.
1217                                    FragmentTable[].FragmentBuffer fields is NULL.
1218                                  - Token.Packet.TxData.DataLength is zero or not
1219                                    equal to the sum of fragment lengths.
1220                                  - Token.Packet.TxData.DestinationAddress is non
1221                                    zero when DestinationAddress is configured as
1222                                    non-zero when doing Configure() for this
1223                                    EFI IPv6 protocol instance.
1224                                  - Token.Packet.TxData.DestinationAddress is
1225                                    unspecified when DestinationAddress is unspecified
1226                                    when doing Configure() for this EFI IPv6 protocol
1227                                    instance.
1228   @retval  EFI_ACCESS_DENIED     The transmit completion token with the same Token.
1229                                  Event was already in the transmit queue.
1230   @retval  EFI_NOT_READY         The completion token could not be queued because
1231                                  the transmit queue is full.
1232   @retval  EFI_NOT_FOUND         Not route is found to destination address.
1233   @retval  EFI_OUT_OF_RESOURCES  Could not queue the transmit data.
1234   @retval  EFI_BUFFER_TOO_SMALL  Token.Packet.TxData.TotalDataLength is too
1235                                  short to transmit.
1236   @retval  EFI_BAD_BUFFER_SIZE   If Token.Packet.TxData.DataLength is beyond the
1237                                  maximum that which can be described through the
1238                                  Fragment Offset field in Fragment header when
1239                                  performing fragmentation.
1240   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
1241 
1242 **/
1243 EFI_STATUS
1244 EFIAPI
EfiIp6Transmit(IN EFI_IP6_PROTOCOL * This,IN EFI_IP6_COMPLETION_TOKEN * Token)1245 EfiIp6Transmit (
1246   IN EFI_IP6_PROTOCOL          *This,
1247   IN EFI_IP6_COMPLETION_TOKEN  *Token
1248   )
1249 {
1250   IP6_SERVICE               *IpSb;
1251   IP6_PROTOCOL              *IpInstance;
1252   EFI_IP6_CONFIG_DATA       *Config;
1253   EFI_STATUS                Status;
1254   EFI_TPL                   OldTpl;
1255   EFI_IP6_HEADER            Head;
1256   EFI_IP6_TRANSMIT_DATA     *TxData;
1257   EFI_IP6_OVERRIDE_DATA     *Override;
1258   IP6_TXTOKEN_WRAP          *Wrap;
1259   UINT8                     *ExtHdrs;
1260 
1261   //
1262   // Check input parameters.
1263   //
1264   if (This == NULL) {
1265     return EFI_INVALID_PARAMETER;
1266   }
1267 
1268   ExtHdrs = NULL;
1269 
1270   Status = Ip6TxTokenValid (Token);
1271   if (EFI_ERROR (Status)) {
1272     return Status;
1273   }
1274 
1275   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
1276   IpSb       = IpInstance->Service;
1277 
1278   if (IpSb->LinkLocalDadFail) {
1279     return EFI_DEVICE_ERROR;
1280   }
1281 
1282   OldTpl     = gBS->RaiseTPL (TPL_CALLBACK);
1283 
1284   if (IpInstance->State != IP6_STATE_CONFIGED) {
1285     Status = EFI_NOT_STARTED;
1286     goto Exit;
1287   }
1288 
1289   Config = &IpInstance->ConfigData;
1290 
1291   //
1292   // Check whether the token or signal already existed.
1293   //
1294   if (EFI_ERROR (NetMapIterate (&IpInstance->TxTokens, Ip6TokenExist, Token))) {
1295     Status = EFI_ACCESS_DENIED;
1296     goto Exit;
1297   }
1298 
1299   //
1300   // Build the IP header, fill in the information from ConfigData or OverrideData
1301   //
1302   ZeroMem (&Head, sizeof(EFI_IP6_HEADER));
1303   TxData = Token->Packet.TxData;
1304   IP6_COPY_ADDRESS (&Head.SourceAddress, &Config->StationAddress);
1305   IP6_COPY_ADDRESS (&Head.DestinationAddress, &Config->DestinationAddress);
1306 
1307   Status = EFI_INVALID_PARAMETER;
1308 
1309   if (NetIp6IsUnspecifiedAddr (&TxData->DestinationAddress)) {
1310     if (NetIp6IsUnspecifiedAddr (&Config->DestinationAddress)) {
1311       goto Exit;
1312     }
1313 
1314     ASSERT (!NetIp6IsUnspecifiedAddr (&Config->StationAddress));
1315 
1316   } else {
1317     //
1318     // StationAddress is unspecified only when ConfigData.Dest is unspecified.
1319     // Use TxData.Dest to override the DestinationAddress.
1320     //
1321     if (!NetIp6IsUnspecifiedAddr (&Config->DestinationAddress)) {
1322       goto Exit;
1323     }
1324 
1325     if (NetIp6IsUnspecifiedAddr (&Config->StationAddress)) {
1326       Status = Ip6SelectSourceAddress (
1327                  IpSb,
1328                  &TxData->DestinationAddress,
1329                  &Head.SourceAddress
1330                  );
1331       if (EFI_ERROR (Status)) {
1332         goto Exit;
1333       }
1334     }
1335 
1336     IP6_COPY_ADDRESS (&Head.DestinationAddress, &TxData->DestinationAddress);
1337   }
1338 
1339   //
1340   // Fill in Head infos.
1341   //
1342   Head.NextHeader = Config->DefaultProtocol;
1343   if (TxData->ExtHdrsLength != 0) {
1344     Head.NextHeader = TxData->NextHeader;
1345   }
1346 
1347   if (TxData->OverrideData != NULL) {
1348     Override        = TxData->OverrideData;
1349     Head.NextHeader = Override->Protocol;
1350     Head.HopLimit   = Override->HopLimit;
1351     Head.FlowLabelL = HTONS ((UINT16) Override->FlowLabel);
1352     Head.FlowLabelH = (UINT8) ((Override->FlowLabel >> 16) & 0x0F);
1353   } else {
1354     Head.HopLimit   = Config->HopLimit;
1355     Head.FlowLabelL = HTONS ((UINT16) Config->FlowLabel);
1356     Head.FlowLabelH = (UINT8) ((Config->FlowLabel >> 16) & 0x0F);
1357   }
1358 
1359   Head.PayloadLength = HTONS ((UINT16) (TxData->ExtHdrsLength + TxData->DataLength));
1360 
1361   //
1362   // OK, it survives all the validation check. Wrap the token in
1363   // a IP6_TXTOKEN_WRAP and the data in a netbuf
1364   //
1365   Status = EFI_OUT_OF_RESOURCES;
1366   Wrap   = AllocateZeroPool (sizeof (IP6_TXTOKEN_WRAP));
1367   if (Wrap == NULL) {
1368     goto Exit;
1369   }
1370 
1371   Wrap->IpInstance  = IpInstance;
1372   Wrap->Token       = Token;
1373   Wrap->Sent        = FALSE;
1374   Wrap->Life        = IP6_US_TO_SEC (Config->TransmitTimeout);
1375   Wrap->Packet      = NetbufFromExt (
1376                         (NET_FRAGMENT *) TxData->FragmentTable,
1377                         TxData->FragmentCount,
1378                         IP6_MAX_HEADLEN,
1379                         0,
1380                         Ip6FreeTxToken,
1381                         Wrap
1382                         );
1383 
1384   if (Wrap->Packet == NULL) {
1385     FreePool (Wrap);
1386     goto Exit;
1387   }
1388 
1389   Token->Status = EFI_NOT_READY;
1390 
1391   Status = NetMapInsertTail (&IpInstance->TxTokens, Token, Wrap);
1392   if (EFI_ERROR (Status)) {
1393     //
1394     // NetbufFree will call Ip6FreeTxToken, which in turn will
1395     // free the IP6_TXTOKEN_WRAP. Now, the token wrap hasn't been
1396     // enqueued.
1397     //
1398     NetbufFree (Wrap->Packet);
1399     goto Exit;
1400   }
1401 
1402   //
1403   // Allocate a new buffer to store IPv6 extension headers to avoid updating
1404   // the original data in EFI_IP6_COMPLETION_TOKEN.
1405   //
1406   if (TxData->ExtHdrsLength != 0 && TxData->ExtHdrs != NULL) {
1407     ExtHdrs = (UINT8 *) AllocateCopyPool (TxData->ExtHdrsLength, TxData->ExtHdrs);
1408     if (ExtHdrs == NULL) {
1409       Status = EFI_OUT_OF_RESOURCES;
1410       goto Exit;
1411     }
1412   }
1413 
1414   //
1415   // Mark the packet sent before output it. Mark it not sent again if the
1416   // returned status is not EFI_SUCCESS;
1417   //
1418   Wrap->Sent = TRUE;
1419 
1420   Status = Ip6Output (
1421              IpSb,
1422              NULL,
1423              IpInstance,
1424              Wrap->Packet,
1425              &Head,
1426              ExtHdrs,
1427              TxData->ExtHdrsLength,
1428              Ip6OnPacketSent,
1429              Wrap
1430              );
1431   if (EFI_ERROR (Status)) {
1432     Wrap->Sent = FALSE;
1433     NetbufFree (Wrap->Packet);
1434   }
1435 
1436 Exit:
1437   gBS->RestoreTPL (OldTpl);
1438 
1439   if (ExtHdrs != NULL) {
1440     FreePool (ExtHdrs);
1441   }
1442 
1443   return Status;
1444 }
1445 
1446 /**
1447   Places a receiving request into the receiving queue.
1448 
1449   The Receive() function places a completion token into the receive packet queue.
1450   This function is always asynchronous.
1451 
1452   The Token.Event field in the completion token must be filled in by the caller
1453   and cannot be NULL. When the receive operation completes, the EFI IPv6 Protocol
1454   driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
1455   is signaled.
1456 
1457   Current Udp implementation creates an IP child for each Udp child.
1458   It initates a asynchronous receive immediately no matter whether
1459   there is no mapping or not. Therefore, disable the returning EFI_NO_MAPPING for now.
1460   To enable it, the following check must be performed:
1461 
1462   if (NetIp6IsUnspecifiedAddr (&Config->StationAddress) && IP6_NO_MAPPING (IpInstance)) {
1463     Status = EFI_NO_MAPPING;
1464     goto Exit;
1465   }
1466 
1467   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
1468   @param[in]  Token              Pointer to a token that is associated with the receive data descriptor.
1469 
1470   @retval EFI_SUCCESS            The receive completion token was cached.
1471   @retval EFI_NOT_STARTED        This EFI IPv6 Protocol instance has not been started.
1472   @retval EFI_NO_MAPPING         When IP6 driver responsible for binding source address to this instance,
1473                                  while no source address is available for use.
1474   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
1475                                  - This is NULL.
1476                                  - Token is NULL.
1477                                  - Token.Event is NULL.
1478   @retval EFI_OUT_OF_RESOURCES   The receive completion token could not be queued due to a lack of system
1479                                  resources (usually memory).
1480   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
1481                                  The EFI IPv6 Protocol instance has been reset to startup defaults.
1482   @retval EFI_ACCESS_DENIED      The receive completion token with the same Token.Event was already
1483                                  in the receive queue.
1484   @retval EFI_NOT_READY          The receive request could not be queued because the receive queue is full.
1485 
1486 **/
1487 EFI_STATUS
1488 EFIAPI
EfiIp6Receive(IN EFI_IP6_PROTOCOL * This,IN EFI_IP6_COMPLETION_TOKEN * Token)1489 EfiIp6Receive (
1490   IN EFI_IP6_PROTOCOL          *This,
1491   IN EFI_IP6_COMPLETION_TOKEN  *Token
1492   )
1493 {
1494   IP6_PROTOCOL              *IpInstance;
1495   EFI_STATUS                Status;
1496   EFI_TPL                   OldTpl;
1497   IP6_SERVICE               *IpSb;
1498 
1499   if (This == NULL || Token == NULL || Token->Event == NULL) {
1500     return EFI_INVALID_PARAMETER;
1501   }
1502 
1503   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
1504   IpSb       = IpInstance->Service;
1505 
1506   if (IpSb->LinkLocalDadFail) {
1507     return EFI_DEVICE_ERROR;
1508   }
1509 
1510   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1511 
1512   if (IpInstance->State != IP6_STATE_CONFIGED) {
1513     Status = EFI_NOT_STARTED;
1514     goto Exit;
1515   }
1516 
1517   //
1518   // Check whether the toke is already on the receive queue.
1519   //
1520   Status = NetMapIterate (&IpInstance->RxTokens, Ip6TokenExist, Token);
1521 
1522   if (EFI_ERROR (Status)) {
1523     Status = EFI_ACCESS_DENIED;
1524     goto Exit;
1525   }
1526 
1527   //
1528   // Queue the token then check whether there is pending received packet.
1529   //
1530   Status = NetMapInsertTail (&IpInstance->RxTokens, Token, NULL);
1531 
1532   if (EFI_ERROR (Status)) {
1533     goto Exit;
1534   }
1535 
1536   Status = Ip6InstanceDeliverPacket (IpInstance);
1537 
1538   //
1539   // Dispatch the DPC queued by the NotifyFunction of this instane's receive
1540   // event.
1541   //
1542   DispatchDpc ();
1543 
1544 Exit:
1545   gBS->RestoreTPL (OldTpl);
1546   return Status;
1547 }
1548 
1549 
1550 /**
1551   Cancel the transmitted but not recycled packet. If a matching
1552   token is found, it will call Ip6CancelPacket to cancel the
1553   packet. Ip6CancelPacket cancels all the fragments of the
1554   packet. When all the fragments are freed, the IP6_TXTOKEN_WRAP
1555   is deleted from the Map, and user's event is signalled.
1556   Because Ip6CancelPacket and other functions are all called in
1557   line, after Ip6CancelPacket returns, the Item has been freed.
1558 
1559   @param[in]  Map                The IP6 child's transmit queue.
1560   @param[in]  Item               The current transmitted packet to test.
1561   @param[in]  Context            The user's token to cancel.
1562 
1563   @retval EFI_SUCCESS            Continue to check the next Item.
1564   @retval EFI_ABORTED            The user's Token (Token != NULL) is cancelled.
1565 
1566 **/
1567 EFI_STATUS
1568 EFIAPI
Ip6CancelTxTokens(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)1569 Ip6CancelTxTokens (
1570   IN NET_MAP                *Map,
1571   IN NET_MAP_ITEM           *Item,
1572   IN VOID                   *Context
1573   )
1574 {
1575   EFI_IP6_COMPLETION_TOKEN  *Token;
1576   IP6_TXTOKEN_WRAP          *Wrap;
1577 
1578   Token = (EFI_IP6_COMPLETION_TOKEN *) Context;
1579 
1580   //
1581   // Return EFI_SUCCESS to check the next item in the map if
1582   // this one doesn't match.
1583   //
1584   if ((Token != NULL) && (Token != Item->Key)) {
1585     return EFI_SUCCESS;
1586   }
1587 
1588   Wrap = (IP6_TXTOKEN_WRAP *) Item->Value;
1589   ASSERT (Wrap != NULL);
1590 
1591   //
1592   // Don't access the Item, Wrap and Token's members after this point.
1593   // Item and wrap has been freed. And we no longer own the Token.
1594   //
1595   Ip6CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
1596 
1597   //
1598   // If only one item is to be cancel, return EFI_ABORTED to stop
1599   // iterating the map any more.
1600   //
1601   if (Token != NULL) {
1602     return EFI_ABORTED;
1603   }
1604 
1605   return EFI_SUCCESS;
1606 }
1607 
1608 
1609 /**
1610   Cancel the receive request. This is simple, because
1611   it is only enqueued in our local receive map.
1612 
1613   @param[in]  Map                The IP6 child's receive queue.
1614   @param[in]  Item               Current receive request to cancel.
1615   @param[in]  Context            The user's token to cancel.
1616 
1617 
1618   @retval EFI_SUCCESS            Continue to check the next receive request on the
1619                                  queue.
1620   @retval EFI_ABORTED            The user's token (token != NULL) has been
1621                                  cancelled.
1622 
1623 **/
1624 EFI_STATUS
1625 EFIAPI
Ip6CancelRxTokens(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Context)1626 Ip6CancelRxTokens (
1627   IN NET_MAP                *Map,
1628   IN NET_MAP_ITEM           *Item,
1629   IN VOID                   *Context
1630   )
1631 {
1632   EFI_IP6_COMPLETION_TOKEN  *Token;
1633   EFI_IP6_COMPLETION_TOKEN  *This;
1634 
1635   Token = (EFI_IP6_COMPLETION_TOKEN *) Context;
1636   This  = Item->Key;
1637 
1638   if ((Token != NULL) && (Token != This)) {
1639     return EFI_SUCCESS;
1640   }
1641 
1642   NetMapRemoveItem (Map, Item, NULL);
1643 
1644   This->Status        = EFI_ABORTED;
1645   This->Packet.RxData = NULL;
1646   gBS->SignalEvent (This->Event);
1647 
1648   if (Token != NULL) {
1649     return EFI_ABORTED;
1650   }
1651 
1652   return EFI_SUCCESS;
1653 }
1654 
1655 /**
1656   Cancel the user's receive/transmit request. It is the worker function of
1657   EfiIp6Cancel API.
1658 
1659   @param[in]  IpInstance         The IP6 child.
1660   @param[in]  Token              The token to cancel. If NULL, all token will be
1661                                  cancelled.
1662 
1663   @retval EFI_SUCCESS            The token is cancelled.
1664   @retval EFI_NOT_FOUND          The token isn't found on either the
1665                                  transmit/receive queue.
1666   @retval EFI_DEVICE_ERROR       Not all tokens are cancelled when Token is NULL.
1667 
1668 **/
1669 EFI_STATUS
Ip6Cancel(IN IP6_PROTOCOL * IpInstance,IN EFI_IP6_COMPLETION_TOKEN * Token OPTIONAL)1670 Ip6Cancel (
1671   IN IP6_PROTOCOL             *IpInstance,
1672   IN EFI_IP6_COMPLETION_TOKEN *Token          OPTIONAL
1673   )
1674 {
1675   EFI_STATUS                Status;
1676 
1677   //
1678   // First check the transmitted packet. Ip6CancelTxTokens returns
1679   // EFI_ABORTED to mean that the token has been cancelled when
1680   // token != NULL. So, return EFI_SUCCESS for this condition.
1681   //
1682   Status = NetMapIterate (&IpInstance->TxTokens, Ip6CancelTxTokens, Token);
1683   if (EFI_ERROR (Status)) {
1684     if ((Token != NULL) && (Status == EFI_ABORTED)) {
1685       return EFI_SUCCESS;
1686     }
1687 
1688     return Status;
1689   }
1690 
1691   //
1692   // Check the receive queue. Ip6CancelRxTokens also returns EFI_ABORT
1693   // for Token!=NULL and it is cancelled.
1694   //
1695   Status = NetMapIterate (&IpInstance->RxTokens, Ip6CancelRxTokens, Token);
1696   //
1697   // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
1698   // events.
1699   //
1700   DispatchDpc ();
1701   if (EFI_ERROR (Status)) {
1702     if ((Token != NULL) && (Status == EFI_ABORTED)) {
1703       return EFI_SUCCESS;
1704     }
1705 
1706     return Status;
1707   }
1708 
1709   //
1710   // OK, if the Token is found when Token != NULL, the NetMapIterate
1711   // will return EFI_ABORTED, which has been interrupted as EFI_SUCCESS.
1712   //
1713   if (Token != NULL) {
1714     return EFI_NOT_FOUND;
1715   }
1716 
1717   //
1718   // If Token == NULL, cancel all the tokens. return error if not
1719   // all of them are cancelled.
1720   //
1721   if (!NetMapIsEmpty (&IpInstance->TxTokens) || !NetMapIsEmpty (&IpInstance->RxTokens)) {
1722 
1723     return EFI_DEVICE_ERROR;
1724   }
1725 
1726   return EFI_SUCCESS;
1727 }
1728 
1729 /**
1730   Abort an asynchronous transmit or receive request.
1731 
1732   The Cancel() function is used to abort a pending transmit or receive request.
1733   If the token is in the transmit or receive request queues, after calling this
1734   function, Token->Status will be set to EFI_ABORTED, and then Token->Event will
1735   be signaled. If the token is not in one of the queues, which usually means the
1736   asynchronous operation has completed, this function will not signal the token,
1737   and EFI_NOT_FOUND is returned.
1738 
1739   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
1740   @param[in]  Token              Pointer to a token that has been issued by
1741                                  EFI_IP6_PROTOCOL.Transmit() or
1742                                  EFI_IP6_PROTOCOL.Receive(). If NULL, all pending
1743                                  tokens are aborted. Type EFI_IP6_COMPLETION_TOKEN is
1744                                  defined in EFI_IP6_PROTOCOL.Transmit().
1745 
1746   @retval EFI_SUCCESS            The asynchronous I/O request was aborted and
1747                                  Token->Event was signaled. When Token is NULL, all
1748                                  pending requests were aborted, and their events were signaled.
1749   @retval EFI_INVALID_PARAMETER  This is NULL.
1750   @retval EFI_NOT_STARTED        This instance has not been started.
1751   @retval EFI_NOT_FOUND          When Token is not NULL, the asynchronous I/O request was
1752                                  not found in the transmit or receive queue. It has either completed
1753                                  or was not issued by Transmit() and Receive().
1754   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
1755 
1756 **/
1757 EFI_STATUS
1758 EFIAPI
EfiIp6Cancel(IN EFI_IP6_PROTOCOL * This,IN EFI_IP6_COMPLETION_TOKEN * Token OPTIONAL)1759 EfiIp6Cancel (
1760   IN EFI_IP6_PROTOCOL          *This,
1761   IN EFI_IP6_COMPLETION_TOKEN  *Token    OPTIONAL
1762   )
1763 {
1764   IP6_PROTOCOL              *IpInstance;
1765   EFI_STATUS                Status;
1766   EFI_TPL                   OldTpl;
1767 
1768   if (This == NULL) {
1769     return EFI_INVALID_PARAMETER;
1770   }
1771 
1772   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
1773 
1774   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1775 
1776   if (IpInstance->State != IP6_STATE_CONFIGED) {
1777     Status = EFI_NOT_STARTED;
1778     goto Exit;
1779   }
1780 
1781   Status = Ip6Cancel (IpInstance, Token);
1782 
1783 Exit:
1784   gBS->RestoreTPL (OldTpl);
1785   return Status;
1786 }
1787 
1788 /**
1789   Polls for incoming data packets, and processes outgoing data packets.
1790 
1791   The Poll() function polls for incoming data packets and processes outgoing data
1792   packets. Network drivers and applications can call the EFI_IP6_PROTOCOL.Poll()
1793   function to increase the rate that data packets are moved between the communications
1794   device and the transmit and receive queues.
1795 
1796   In some systems the periodic timer event may not poll the underlying communications
1797   device fast enough to transmit and/or receive all data packets without missing
1798   incoming packets or dropping outgoing packets. Drivers and applications that are
1799   experiencing packet loss should try calling the EFI_IP6_PROTOCOL.Poll() function
1800   more often.
1801 
1802   @param[in]  This               Pointer to the EFI_IP6_PROTOCOL instance.
1803 
1804   @retval  EFI_SUCCESS           Incoming or outgoing data was processed.
1805   @retval  EFI_NOT_STARTED       This EFI IPv6 Protocol instance has not been started.
1806   @retval  EFI_INVALID_PARAMETER This is NULL.
1807   @retval  EFI_DEVICE_ERROR      An unexpected system error or network error occurred.
1808   @retval  EFI_NOT_READY         No incoming or outgoing data was processed.
1809   @retval  EFI_TIMEOUT           Data was dropped out of the transmit and/or receive queue.
1810                                  Consider increasing the polling rate.
1811 
1812 **/
1813 EFI_STATUS
1814 EFIAPI
EfiIp6Poll(IN EFI_IP6_PROTOCOL * This)1815 EfiIp6Poll (
1816   IN EFI_IP6_PROTOCOL          *This
1817   )
1818 {
1819   IP6_PROTOCOL                  *IpInstance;
1820   IP6_SERVICE                   *IpSb;
1821   EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;
1822 
1823   if (This == NULL) {
1824     return EFI_INVALID_PARAMETER;
1825   }
1826 
1827   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (This);
1828   IpSb       = IpInstance->Service;
1829 
1830   if (IpSb->LinkLocalDadFail) {
1831     return EFI_DEVICE_ERROR;
1832   }
1833 
1834   if (IpInstance->State == IP6_STATE_UNCONFIGED) {
1835     return EFI_NOT_STARTED;
1836   }
1837 
1838   Mnp = IpInstance->Service->Mnp;
1839 
1840   //
1841   // Don't lock the Poll function to enable the deliver of
1842   // the packet polled up.
1843   //
1844   return Mnp->Poll (Mnp);
1845 
1846 }
1847 
1848