1 /** @file
2   Contains all EFI_UDP6_PROTOCOL interfaces.
3 
4   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php.
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "Udp6Impl.h"
17 
18 EFI_UDP6_PROTOCOL  mUdp6Protocol = {
19   Udp6GetModeData,
20   Udp6Configure,
21   Udp6Groups,
22   Udp6Transmit,
23   Udp6Receive,
24   Udp6Cancel,
25   Udp6Poll
26 };
27 
28 
29 /**
30   This function copies the current operational settings of this EFI UDPv6 Protocol
31   instance into user-supplied buffers. This function is used optionally to retrieve
32   the operational mode data of underlying networks or drivers.
33 
34   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
35   @param[out] Udp6ConfigData     The buffer in which the current UDP configuration
36                                  data is returned. This parameter is optional and
37                                  may be NULL.
38   @param[out] Ip6ModeData        The buffer in which the current EFI IPv6 Protocol
39                                  mode data is returned. This parameter is optional
40                                  and may be NULL.
41   @param[out] MnpConfigData      The buffer in which the current managed network
42                                  configuration data is returned. This parameter is
43                                  optional and may be NULL.
44   @param[out] SnpModeData        The buffer in which the simple network mode data
45                                  is returned. This parameter is optional and may be NULL.
46 
47   @retval EFI_SUCCESS            The mode data was read.
48   @retval EFI_NOT_STARTED        When Udp6ConfigData is queried, no configuration
49                                  data is  available because this instance has not
50                                  been started.
51   @retval EFI_INVALID_PARAMETER  This is NULL.
52 
53 **/
54 EFI_STATUS
55 EFIAPI
Udp6GetModeData(IN EFI_UDP6_PROTOCOL * This,OUT EFI_UDP6_CONFIG_DATA * Udp6ConfigData OPTIONAL,OUT EFI_IP6_MODE_DATA * Ip6ModeData OPTIONAL,OUT EFI_MANAGED_NETWORK_CONFIG_DATA * MnpConfigData OPTIONAL,OUT EFI_SIMPLE_NETWORK_MODE * SnpModeData OPTIONAL)56 Udp6GetModeData (
57   IN  EFI_UDP6_PROTOCOL                *This,
58   OUT EFI_UDP6_CONFIG_DATA             *Udp6ConfigData OPTIONAL,
59   OUT EFI_IP6_MODE_DATA                *Ip6ModeData    OPTIONAL,
60   OUT EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData  OPTIONAL,
61   OUT EFI_SIMPLE_NETWORK_MODE          *SnpModeData    OPTIONAL
62   )
63 {
64   UDP6_INSTANCE_DATA  *Instance;
65   EFI_IP6_PROTOCOL    *Ip;
66   EFI_TPL             OldTpl;
67   EFI_STATUS          Status;
68 
69   if (This == NULL) {
70     return EFI_INVALID_PARAMETER;
71   }
72 
73   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
74 
75   if (!Instance->Configured && (Udp6ConfigData != NULL)) {
76     return EFI_NOT_STARTED;
77   }
78 
79   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
80 
81   if (Udp6ConfigData != NULL) {
82     //
83     // Set the Udp6ConfigData.
84     //
85     CopyMem (Udp6ConfigData, &Instance->ConfigData, sizeof (EFI_UDP6_CONFIG_DATA));
86   }
87 
88   Ip = Instance->IpInfo->Ip.Ip6;
89 
90   //
91   // Get the underlying Ip6ModeData, MnpConfigData and SnpModeData.
92   //
93   Status = Ip->GetModeData (Ip, Ip6ModeData, MnpConfigData, SnpModeData);
94 
95   gBS->RestoreTPL (OldTpl);
96 
97   return Status;
98 }
99 
100 
101 /**
102   This function is used to do the following:
103   Initialize and start this instance of the EFI UDPv6 Protocol.
104   Change the filtering rules and operational parameters.
105   Reset this instance of the EFI UDPv6 Protocol.
106 
107   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
108   @param[in]  UdpConfigData      Pointer to the buffer to set the configuration
109                                  data. This parameter is optional and may be NULL.
110 
111   @retval EFI_SUCCESS            The configuration settings were set, changed, or
112                                  reset successfully.
113   @retval EFI_NO_MAPPING         When the UdpConifgData.UseAnyStationAddress is set
114                                  to true and there is no address available for the IP6
115                                  driver to bind a source address to this instance.
116   @retval EFI_INVALID_PARAMETER  One or more following conditions are TRUE:
117                                  This is NULL.
118                                  UdpConfigData.StationAddress is not a valid
119                                  unicast IPv6 address.
120                                  UdpConfigData.RemoteAddress is not a valid unicast
121                                  IPv6  address if it is not zero.
122   @retval EFI_ALREADY_STARTED    The EFI UDPv6 Protocol instance is already
123                                  started/configured and must be stopped/reset
124                                  before it can be reconfigured. Only TrafficClass,
125                                  HopLimit, ReceiveTimeout, and  TransmitTimeout can
126                                  be reconfigured without stopping the  current
127                                  instance of the EFI UDPv6 Protocol.
128   @retval EFI_ACCESS_DENIED      UdpConfigData.AllowDuplicatePort is FALSE and
129                                  UdpConfigData.StationPort is already used by another
130                                  instance.
131   @retval EFI_OUT_OF_RESOURCES   The EFI UDPv6 Protocol driver cannot allocate
132                                  memory for this EFI UDPv6 Protocol instance.
133   @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred, and
134                                  this instance was not opened.
135 
136 **/
137 EFI_STATUS
138 EFIAPI
Udp6Configure(IN EFI_UDP6_PROTOCOL * This,IN EFI_UDP6_CONFIG_DATA * UdpConfigData OPTIONAL)139 Udp6Configure (
140   IN EFI_UDP6_PROTOCOL     *This,
141   IN EFI_UDP6_CONFIG_DATA  *UdpConfigData OPTIONAL
142   )
143 {
144   EFI_STATUS           Status;
145   UDP6_INSTANCE_DATA   *Instance;
146   UDP6_SERVICE_DATA    *Udp6Service;
147   EFI_TPL              OldTpl;
148   EFI_IPv6_ADDRESS     StationAddress;
149   EFI_IPv6_ADDRESS     RemoteAddress;
150   EFI_IP6_CONFIG_DATA  Ip6ConfigData;
151   EFI_IPv6_ADDRESS     LocalAddr;
152   EFI_IPv6_ADDRESS     RemoteAddr;
153 
154   if (This == NULL) {
155     return EFI_INVALID_PARAMETER;
156   }
157 
158   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
159 
160   if (!Instance->Configured && (UdpConfigData == NULL)) {
161     return EFI_SUCCESS;
162   }
163 
164   Udp6Service = Instance->Udp6Service;
165   Status      = EFI_SUCCESS;
166   ASSERT (Udp6Service != NULL);
167 
168   OldTpl      = gBS->RaiseTPL (TPL_CALLBACK);
169 
170   if (UdpConfigData != NULL) {
171 
172     IP6_COPY_ADDRESS (&StationAddress, &UdpConfigData->StationAddress);
173     IP6_COPY_ADDRESS (&RemoteAddress, &UdpConfigData->RemoteAddress);
174 
175     if ((!NetIp6IsUnspecifiedAddr (&StationAddress) && !NetIp6IsValidUnicast (&StationAddress)) ||
176         (!NetIp6IsUnspecifiedAddr (&RemoteAddress) && !NetIp6IsValidUnicast (&RemoteAddress))
177         ){
178       //
179       // If not use default address, and StationAddress is not a valid unicast
180       // if it is not IPv6 address or RemoteAddress is not a valid unicast IPv6
181       // address if it is not 0.
182       //
183       Status = EFI_INVALID_PARAMETER;
184       goto ON_EXIT;
185     }
186 
187     if (Instance->Configured) {
188       //
189       // The instance is already configured, try to do the re-configuration.
190       //
191       if (!Udp6IsReconfigurable (&Instance->ConfigData, UdpConfigData)) {
192         //
193         // If the new configuration data wants to change some unreconfigurable
194         // settings, return EFI_ALREADY_STARTED.
195         //
196         Status = EFI_ALREADY_STARTED;
197         goto ON_EXIT;
198       }
199 
200       //
201       // Save the reconfigurable parameters.
202       //
203       Instance->ConfigData.TrafficClass    = UdpConfigData->TrafficClass;
204       Instance->ConfigData.HopLimit        = UdpConfigData->HopLimit;
205       Instance->ConfigData.ReceiveTimeout  = UdpConfigData->ReceiveTimeout;
206       Instance->ConfigData.TransmitTimeout = UdpConfigData->TransmitTimeout;
207     } else {
208       //
209       // Construct the Ip configuration data from the UdpConfigData.
210       //
211       Udp6BuildIp6ConfigData (UdpConfigData, &Ip6ConfigData);
212 
213       //
214       // Configure the Ip instance wrapped in the IpInfo.
215       //
216       Status = IpIoConfigIp (Instance->IpInfo, &Ip6ConfigData);
217       if (EFI_ERROR (Status)) {
218         if (Status == EFI_NO_MAPPING) {
219           Instance->IsNoMapping = TRUE;
220         }
221 
222         goto ON_EXIT;
223       }
224 
225       Instance->IsNoMapping = FALSE;
226 
227       //
228       // Save the configuration data.
229       //
230       CopyMem (
231         &Instance->ConfigData,
232         UdpConfigData,
233         sizeof (EFI_UDP6_CONFIG_DATA)
234         );
235       IP6_COPY_ADDRESS (&Instance->ConfigData.StationAddress, &Ip6ConfigData.StationAddress);
236       //
237       // Try to allocate the required port resource.
238       //
239       Status = Udp6Bind (&Udp6Service->ChildrenList, &Instance->ConfigData);
240       if (EFI_ERROR (Status)) {
241         //
242         // Reset the ip instance if bind fails.
243         //
244         IpIoConfigIp (Instance->IpInfo, NULL);
245         goto ON_EXIT;
246       }
247 
248       //
249       // Pre calculate the checksum for the pseudo head, ignore the UDP length first.
250       //
251       IP6_COPY_ADDRESS (&LocalAddr, &Instance->ConfigData.StationAddress);
252       IP6_COPY_ADDRESS (&RemoteAddr, &Instance->ConfigData.RemoteAddress);
253 
254       Instance->HeadSum = NetIp6PseudoHeadChecksum (
255                             &LocalAddr,
256                             &RemoteAddr,
257                             EFI_IP_PROTO_UDP,
258                             0
259                             );
260 
261       Instance->Configured = TRUE;
262     }
263   } else {
264     //
265     // UdpConfigData is NULL, reset the instance.
266     //
267     Instance->Configured  = FALSE;
268     Instance->IsNoMapping = FALSE;
269 
270     //
271     // Reset the Ip instance wrapped in the IpInfo.
272     //
273     IpIoConfigIp (Instance->IpInfo, NULL);
274 
275     //
276     // Cancel all the user tokens.
277     //
278     Instance->Udp6Proto.Cancel (&Instance->Udp6Proto, NULL);
279 
280     //
281     // Remove the buffered RxData for this instance.
282     //
283     Udp6FlushRcvdDgram (Instance);
284 
285     ASSERT (IsListEmpty (&Instance->DeliveredDgramQue));
286   }
287 
288 ON_EXIT:
289 
290   gBS->RestoreTPL (OldTpl);
291 
292   return Status;
293 }
294 
295 
296 /**
297   This function is used to enable and disable the multicast group filtering.
298 
299   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
300   @param[in]  JoinFlag           Set to TRUE to join a multicast group. Set to
301                                  FALSE to leave one or all multicast groups.
302   @param[in]  MulticastAddress   Pointer to multicast group address to join or
303                                  leave. This parameter is optional and may be NULL.
304 
305   @retval EFI_SUCCESS            The operation completed successfully.
306   @retval EFI_NOT_STARTED        The EFI UDPv6 Protocol instance has not been
307                                  started.
308   @retval EFI_OUT_OF_RESOURCES   Could not allocate resources to join the group.
309   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
310                                  This is NULL.
311                                  JoinFlag is TRUE and MulticastAddress is NULL.
312                                  JoinFlag is TRUE and *MulticastAddress is not a
313                                  valid  multicast address.
314   @retval EFI_ALREADY_STARTED    The group address is already in the group table
315                                  (when JoinFlag is TRUE).
316   @retval EFI_NOT_FOUND          The group address is not in the group table (when
317                                  JoinFlag is FALSE).
318   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
319 
320 **/
321 EFI_STATUS
322 EFIAPI
Udp6Groups(IN EFI_UDP6_PROTOCOL * This,IN BOOLEAN JoinFlag,IN EFI_IPv6_ADDRESS * MulticastAddress OPTIONAL)323 Udp6Groups (
324   IN EFI_UDP6_PROTOCOL  *This,
325   IN BOOLEAN            JoinFlag,
326   IN EFI_IPv6_ADDRESS   *MulticastAddress OPTIONAL
327   )
328 {
329   EFI_STATUS          Status;
330   UDP6_INSTANCE_DATA  *Instance;
331   EFI_IP6_PROTOCOL    *Ip;
332   EFI_TPL             OldTpl;
333   EFI_IPv6_ADDRESS    *McastIp;
334 
335   if ((This == NULL) || (JoinFlag && (MulticastAddress == NULL))) {
336     return EFI_INVALID_PARAMETER;
337   }
338 
339   McastIp = NULL;
340 
341   if (JoinFlag) {
342     if (!IP6_IS_MULTICAST (MulticastAddress)) {
343       return EFI_INVALID_PARAMETER;
344     }
345 
346     McastIp = AllocateCopyPool (sizeof (EFI_IPv6_ADDRESS), MulticastAddress);
347     if (McastIp == NULL) {
348       return EFI_OUT_OF_RESOURCES;
349     }
350   }
351 
352   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
353   if (!Instance->Configured) {
354     return EFI_NOT_STARTED;
355   }
356 
357   Ip      = Instance->IpInfo->Ip.Ip6;
358 
359   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
360 
361   //
362   // Invoke the Ip instance the Udp6 instance consumes to do the group operation.
363   //
364   Status = Ip->Groups (Ip, JoinFlag, MulticastAddress);
365 
366   if (EFI_ERROR (Status)) {
367     goto ON_EXIT;
368   }
369 
370   //
371   // Keep a local copy of the configured multicast IPs because IpIo receives
372   // datagrams from the 0 station address IP instance and then UDP delivers to
373   // the matched instance. This copy of multicast IPs is used to avoid receive
374   // the mutlicast datagrams destinated to multicast IPs the other instances configured.
375   //
376   if (JoinFlag) {
377 
378     Status = NetMapInsertTail (&Instance->McastIps, (VOID *) McastIp, NULL);
379   } else {
380 
381     NetMapIterate (&Instance->McastIps, Udp6LeaveGroup, MulticastAddress);
382   }
383 
384 ON_EXIT:
385 
386   gBS->RestoreTPL (OldTpl);
387 
388   if (EFI_ERROR (Status)) {
389     if (McastIp != NULL) {
390       FreePool (McastIp);
391     }
392   }
393 
394   return Status;
395 }
396 
397 
398 
399 /**
400   This function places a sending request to this instance of the EFI UDPv6 Protocol,
401   alongside the transmit data that was filled by the user.
402 
403   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
404   @param[in]  Token              Pointer to the completion token that will be
405                                  placed into the transmit queue.
406 
407   @retval EFI_SUCCESS            The data was queued for transmission.
408   @retval EFI_NOT_STARTED        This EFI UDPv6 Protocol instance has not been
409                                  started.
410   @retval EFI_NO_MAPPING         The under-layer IPv6 driver was responsible for
411                                  choosing a source address for this instance, but
412                                  no  source address was available for use.
413   @retval EFI_INVALID_PARAMETER  One or more of the following are TRUE:
414                                  This is NULL.
415                                  Token is NULL. Token.Event is NULL.
416                                  Token.Packet.TxData is NULL.
417                                  Token.Packet.TxData.FragmentCount is zero.
418                                  Token.Packet.TxData.DataLength is not equal to the
419                                  sum of fragment lengths.
420                                  One or more of the
421                                  Token.Packet.TxData.FragmentTable[].FragmentLength
422                                  fields is zero.
423                                  One or more of the
424                                  Token.Packet.TxData.FragmentTable[].FragmentBuffer
425                                  fields is NULL. One or more of the
426                                  Token.Packet.TxData.UdpSessionData.DestinationAddres
427                                  are not valid unicast IPv6
428                                  addresses if the  UdpSessionData is not NULL.
429                                  Token.Packet.TxData.UdpSessionData.
430                                  DestinationAddress is NULL
431                                  Token.Packet.TxData.UdpSessionData.
432                                  DestinatioPort
433                                  is zero.
434                                  Token.Packet.TxData.UdpSessionData is NULL and this
435                                  instance's UdpConfigData.RemoteAddress  is unspecified.
436   @retval EFI_ACCESS_DENIED      The transmit completion token with the same
437                                  Token.Event is already in the transmit queue.
438   @retval EFI_NOT_READY          The completion token could not be queued because
439                                  the transmit queue is full.
440   @retval EFI_OUT_OF_RESOURCES   Could not queue the transmit data.
441   @retval EFI_NOT_FOUND          There is no route to the destination network or
442                                  address.
443   @retval EFI_BAD_BUFFER_SIZE    The data length is greater than the maximum UDP
444                                  packet size. Or, the length of the IP header + UDP
445                                  header + data length is greater than MTU if
446                                  DoNotFragment is TRUE.
447 
448 **/
449 EFI_STATUS
450 EFIAPI
Udp6Transmit(IN EFI_UDP6_PROTOCOL * This,IN EFI_UDP6_COMPLETION_TOKEN * Token)451 Udp6Transmit (
452   IN EFI_UDP6_PROTOCOL          *This,
453   IN EFI_UDP6_COMPLETION_TOKEN  *Token
454   )
455 {
456   EFI_STATUS              Status;
457   UDP6_INSTANCE_DATA      *Instance;
458   EFI_TPL                 OldTpl;
459   NET_BUF                 *Packet;
460   EFI_UDP_HEADER          *Udp6Header;
461   EFI_UDP6_CONFIG_DATA    *ConfigData;
462   EFI_IPv6_ADDRESS        Source;
463   EFI_IPv6_ADDRESS        Destination;
464   EFI_UDP6_TRANSMIT_DATA  *TxData;
465   EFI_UDP6_SESSION_DATA   *UdpSessionData;
466   UDP6_SERVICE_DATA       *Udp6Service;
467   IP_IO_OVERRIDE          Override;
468   UINT16                  HeadSum;
469   EFI_IP_ADDRESS          IpDestAddr;
470 
471   if ((This == NULL) || (Token == NULL)) {
472     return EFI_INVALID_PARAMETER;
473   }
474 
475   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
476 
477   if (!Instance->Configured) {
478     return EFI_NOT_STARTED;
479   }
480 
481   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
482 
483   //
484   // Validate the Token, if the token is invalid return the error code.
485   //
486   Status = Udp6ValidateTxToken (Instance, Token);
487   if (EFI_ERROR (Status)) {
488     goto ON_EXIT;
489   }
490 
491   if (EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp6TokenExist, Token)) ||
492       EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp6TokenExist, Token))
493       ){
494     //
495     // Try to find a duplicate token in the two token maps, if found, return
496     // EFI_ACCESS_DENIED.
497     //
498     Status = EFI_ACCESS_DENIED;
499     goto ON_EXIT;
500   }
501 
502   TxData = Token->Packet.TxData;
503 
504   //
505   // Create a net buffer to hold the user buffer and the udp header.
506   //
507   Packet = NetbufFromExt (
508              (NET_FRAGMENT *) TxData->FragmentTable,
509              TxData->FragmentCount,
510              UDP6_HEADER_SIZE,
511              0,
512              Udp6NetVectorExtFree,
513              NULL
514              );
515   if (Packet == NULL) {
516     Status = EFI_OUT_OF_RESOURCES;
517     goto ON_EXIT;
518   }
519 
520   //
521   // Store the IpIo in ProtoData.
522   //
523   Udp6Service                        = Instance->Udp6Service;
524   *((UINTN *) &Packet->ProtoData[0]) = (UINTN) (Udp6Service->IpIo);
525 
526   Udp6Header = (EFI_UDP_HEADER *) NetbufAllocSpace (Packet, UDP6_HEADER_SIZE, TRUE);
527   ASSERT (Udp6Header != NULL);
528   ConfigData = &Instance->ConfigData;
529 
530   //
531   // Fill the udp header.
532   //
533   Udp6Header->SrcPort      = HTONS (ConfigData->StationPort);
534   Udp6Header->DstPort      = HTONS (ConfigData->RemotePort);
535   Udp6Header->Length       = HTONS ((UINT16) Packet->TotalSize);
536   Udp6Header->Checksum     = 0;
537   //
538   // Set the UDP Header in NET_BUF, this UDP header is for IP6 can fast get the
539   // Udp header for pseudoHeadCheckSum.
540   //
541   Packet->Udp    = Udp6Header;
542   UdpSessionData = TxData->UdpSessionData;
543 
544   if (UdpSessionData != NULL) {
545     //
546     // Set the Destination according to the specified
547     // UdpSessionData.
548     //
549 
550     if (UdpSessionData->DestinationPort != 0) {
551       Udp6Header->DstPort = HTONS (UdpSessionData->DestinationPort);
552     }
553 
554     IP6_COPY_ADDRESS (&Source, &ConfigData->StationAddress);
555     if (!NetIp6IsUnspecifiedAddr (&UdpSessionData->DestinationAddress)) {
556       IP6_COPY_ADDRESS (&Destination, &UdpSessionData->DestinationAddress);
557     } else {
558       IP6_COPY_ADDRESS (&Destination, &ConfigData->RemoteAddress);
559     }
560 
561     //
562     //Calculate the pseudo head checksum using the overridden parameters.
563     //
564     if (!NetIp6IsUnspecifiedAddr (&ConfigData->StationAddress)) {
565       HeadSum = NetIp6PseudoHeadChecksum (
566                   &Source,
567                   &Destination,
568                   EFI_IP_PROTO_UDP,
569                   0
570                   );
571 
572       //
573       // calculate the checksum.
574       //
575       Udp6Header->Checksum = Udp6Checksum (Packet, HeadSum);
576       if (Udp6Header->Checksum == 0) {
577         //
578         // If the calculated checksum is 0, fill the Checksum field with all ones.
579         //
580         Udp6Header->Checksum = 0XFFFF;
581       }
582     } else {
583       //
584       // Set the checksum is zero if the ConfigData->StationAddress is unspcified
585       // and the Ipv6 will fill the correct value of this checksum.
586       //
587       Udp6Header->Checksum = 0;
588 
589     }
590   } else {
591     //
592     // UdpSessionData is NULL, use the address and port information previously configured.
593     //
594     IP6_COPY_ADDRESS (&Destination, &ConfigData->RemoteAddress);
595 
596     HeadSum = Instance->HeadSum;
597     //
598     // calculate the checksum.
599     //
600     Udp6Header->Checksum = Udp6Checksum (Packet, HeadSum);
601     if (Udp6Header->Checksum == 0) {
602       //
603       // If the calculated checksum is 0, fill the Checksum field with all ones.
604       //
605       Udp6Header->Checksum = 0xffff;
606     }
607   }
608 
609 
610 
611   //
612   // Fill the IpIo Override data.
613   //
614   Override.Ip6OverrideData.Protocol  = EFI_IP_PROTO_UDP;
615   Override.Ip6OverrideData.HopLimit  = ConfigData->HopLimit;
616   Override.Ip6OverrideData.FlowLabel = 0;
617 
618   //
619   // Save the token into the TxToken map.
620   //
621   Status = NetMapInsertTail (&Instance->TxTokens, Token, Packet);
622   if (EFI_ERROR (Status)) {
623     goto FREE_PACKET;
624   }
625 
626   //
627   // Send out this datagram through IpIo.
628   //
629   if (UdpSessionData != NULL){
630     IP6_COPY_ADDRESS (&(IpDestAddr.v6), &Destination);
631   } else {
632     ZeroMem (&IpDestAddr.v6, sizeof (EFI_IPv6_ADDRESS));
633   }
634 
635   Status = IpIoSend (
636              Udp6Service->IpIo,
637              Packet,
638              Instance->IpInfo,
639              Instance,
640              Token,
641              &IpDestAddr,
642              &Override
643              );
644   if (EFI_ERROR (Status)) {
645     //
646     // Remove this token from the TxTokens.
647     //
648     Udp6RemoveToken (&Instance->TxTokens, Token);
649   }
650 
651 FREE_PACKET:
652 
653   NetbufFree (Packet);
654 
655 ON_EXIT:
656 
657   gBS->RestoreTPL (OldTpl);
658 
659   return Status;
660 }
661 
662 
663 /**
664   This function places a completion token into the receive packet queue. This function
665   is always asynchronous.
666 
667   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
668   @param[in]  Token              Pointer to a token that is associated with the
669                                  receive data descriptor.
670 
671   @retval EFI_SUCCESS            The receive completion token was cached.
672   @retval EFI_NOT_STARTED        This EFI UDPv6 Protocol instance has not been
673                                  started.
674   @retval EFI_NO_MAPPING         When using a default address, configuration (DHCP,
675                                  BOOTP, RARP, etc.) is not finished yet.
676   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
677                                  This is NULL. Token is NULL. Token.Event is NULL.
678   @retval EFI_OUT_OF_RESOURCES   The receive completion token could not be queued
679                                  due to a lack of system resources (usually
680                                  memory).
681   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
682                                  The EFI UDPv6 Protocol instance has been reset to
683                                  startup defaults.
684   @retval EFI_ACCESS_DENIED      A receive completion token with the same
685                                  Token.Event is already in the receive queue.
686   @retval EFI_NOT_READY          The receive request could not be queued because
687                                  the receive  queue is full.
688 
689 **/
690 EFI_STATUS
691 EFIAPI
Udp6Receive(IN EFI_UDP6_PROTOCOL * This,IN EFI_UDP6_COMPLETION_TOKEN * Token)692 Udp6Receive (
693   IN EFI_UDP6_PROTOCOL          *This,
694   IN EFI_UDP6_COMPLETION_TOKEN  *Token
695   )
696 {
697   EFI_STATUS          Status;
698   UDP6_INSTANCE_DATA  *Instance;
699   EFI_TPL             OldTpl;
700 
701   if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
702     return EFI_INVALID_PARAMETER;
703   }
704 
705   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
706 
707   if (!Instance->Configured) {
708     return EFI_NOT_STARTED;
709   }
710 
711   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
712 
713   if (EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp6TokenExist, Token)) ||
714       EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp6TokenExist, Token))
715       ){
716     //
717     // Return EFI_ACCESS_DENIED if the specified token is already in the TxTokens or
718     // RxTokens map.
719     //
720     Status = EFI_ACCESS_DENIED;
721     goto ON_EXIT;
722   }
723 
724   Token->Packet.RxData = NULL;
725 
726   //
727   // Save the token into the RxTokens map.
728   //
729   Status = NetMapInsertTail (&Instance->RxTokens, Token, NULL);
730   if (EFI_ERROR (Status)) {
731     Status = EFI_NOT_READY;
732     goto ON_EXIT;
733   }
734 
735   //
736   // If there is an icmp error, report it.
737   //
738   Udp6ReportIcmpError (Instance);
739 
740   //
741   // Try to delivered the received datagrams.
742   //
743   Udp6InstanceDeliverDgram (Instance);
744 
745   //
746   // Dispatch the DPC queued by the NotifyFunction of Token->Event.
747   //
748   DispatchDpc ();
749 
750 ON_EXIT:
751 
752   gBS->RestoreTPL (OldTpl);
753 
754   return Status;
755 }
756 
757 
758 /**
759   This function is used to abort a pending transmit or receive request.
760 
761   @param[in]  This               Pointer to the EFI_UDP6_PROTOCOL instance.
762   @param[in]  Token              Pointer to a token that has been issued by
763                                  EFI_UDP6_PROTOCOL.Transmit() or
764                                  EFI_UDP6_PROTOCOL.Receive(). This parameter is
765                                  optional and may be NULL.
766 
767   @retval EFI_SUCCESS            The asynchronous I/O request was aborted, and
768                                  Token.Event was  signaled. When Token is NULL, all
769                                  pending requests are aborted and their events are
770                                  signaled.
771   @retval EFI_INVALID_PARAMETER  This is NULL.
772   @retval EFI_NOT_STARTED        This instance has not been started.
773   @retval EFI_NO_MAPPING         When using the default address, configuration
774                                  (DHCP, BOOTP, RARP, etc.) is not finished yet.
775   @retval EFI_NOT_FOUND          When Token is not NULL, the asynchronous I/O
776                                  request is not found in the transmit or receive
777                                  queue. It is either completed or not issued by
778                                  Transmit() or Receive().
779 
780 **/
781 EFI_STATUS
782 EFIAPI
Udp6Cancel(IN EFI_UDP6_PROTOCOL * This,IN EFI_UDP6_COMPLETION_TOKEN * Token OPTIONAL)783 Udp6Cancel (
784   IN EFI_UDP6_PROTOCOL          *This,
785   IN EFI_UDP6_COMPLETION_TOKEN  *Token OPTIONAL
786   )
787 {
788   EFI_STATUS          Status;
789   UDP6_INSTANCE_DATA  *Instance;
790   EFI_TPL             OldTpl;
791 
792   if (This == NULL) {
793     return EFI_INVALID_PARAMETER;
794   }
795 
796   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
797 
798   if (!Instance->Configured) {
799     return EFI_NOT_STARTED;
800   }
801 
802   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
803 
804   //
805   // Cancle the tokens specified by Token for this instance.
806   //
807   Status = Udp6InstanceCancelToken (Instance, Token);
808 
809   //
810   // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.
811   //
812   DispatchDpc ();
813 
814   gBS->RestoreTPL (OldTpl);
815 
816   return Status;
817 }
818 
819 
820 /**
821   This function can be used by network drivers and applications to increase the rate that
822   data packets are moved between the communications device and the transmit/receive queues.
823 
824   @param[in] This                Pointer to the EFI_UDP6_PROTOCOL instance.
825 
826   @retval EFI_SUCCESS            Incoming or outgoing data was processed.
827   @retval EFI_INVALID_PARAMETER  This is NULL.
828   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
829   @retval EFI_TIMEOUT            Data was dropped out of the transmit and/or
830                                  receive queue.
831 
832 **/
833 EFI_STATUS
834 EFIAPI
Udp6Poll(IN EFI_UDP6_PROTOCOL * This)835 Udp6Poll (
836   IN EFI_UDP6_PROTOCOL  *This
837   )
838 {
839   UDP6_INSTANCE_DATA  *Instance;
840   EFI_IP6_PROTOCOL    *Ip;
841 
842   if (This == NULL) {
843     return EFI_INVALID_PARAMETER;
844   }
845 
846   Instance = UDP6_INSTANCE_DATA_FROM_THIS (This);
847   Ip       = Instance->IpInfo->Ip.Ip6;
848 
849   //
850   // Invode the Ip instance consumed by the udp instance to do the poll operation.
851   //
852   return Ip->Poll (Ip);
853 }
854