1 /** @file
2 
3 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "Udp4Impl.h"
16 
17 EFI_UDP4_PROTOCOL  mUdp4Protocol = {
18   Udp4GetModeData,
19   Udp4Configure,
20   Udp4Groups,
21   Udp4Routes,
22   Udp4Transmit,
23   Udp4Receive,
24   Udp4Cancel,
25   Udp4Poll
26 };
27 
28 
29 /**
30   Reads the current operational settings.
31 
32   The GetModeData() function copies the current operational settings of this EFI
33   UDPv4 Protocol instance into user-supplied buffers. This function is used
34   optionally to retrieve the operational mode data of underlying networks or
35   drivers.
36 
37   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
38   @param[out] Udp4ConfigData    Pointer to the buffer to receive the current configuration data.
39   @param[out] Ip4ModeData       Pointer to the EFI IPv4 Protocol mode data structure.
40   @param[out] MnpConfigData     Pointer to the managed network configuration data structure.
41   @param[out] SnpModeData       Pointer to the simple network mode data structure.
42 
43   @retval EFI_SUCCESS           The mode data was read.
44   @retval EFI_NOT_STARTED       When Udp4ConfigData is queried, no configuration data is
45                                 available because this instance has not been started.
46   @retval EFI_INVALID_PARAMETER This is NULL.
47 
48 **/
49 EFI_STATUS
50 EFIAPI
Udp4GetModeData(IN EFI_UDP4_PROTOCOL * This,OUT EFI_UDP4_CONFIG_DATA * Udp4ConfigData OPTIONAL,OUT EFI_IP4_MODE_DATA * Ip4ModeData OPTIONAL,OUT EFI_MANAGED_NETWORK_CONFIG_DATA * MnpConfigData OPTIONAL,OUT EFI_SIMPLE_NETWORK_MODE * SnpModeData OPTIONAL)51 Udp4GetModeData (
52   IN  EFI_UDP4_PROTOCOL                *This,
53   OUT EFI_UDP4_CONFIG_DATA             *Udp4ConfigData OPTIONAL,
54   OUT EFI_IP4_MODE_DATA                *Ip4ModeData    OPTIONAL,
55   OUT EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData  OPTIONAL,
56   OUT EFI_SIMPLE_NETWORK_MODE          *SnpModeData    OPTIONAL
57   )
58 {
59   UDP4_INSTANCE_DATA  *Instance;
60   EFI_IP4_PROTOCOL    *Ip;
61   EFI_TPL             OldTpl;
62   EFI_STATUS          Status;
63 
64   if (This == NULL) {
65     return EFI_INVALID_PARAMETER;
66   }
67 
68   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
69 
70   if (!Instance->Configured && (Udp4ConfigData != NULL)) {
71     return EFI_NOT_STARTED;
72   }
73 
74   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
75 
76   if (Udp4ConfigData != NULL) {
77     //
78     // Set the Udp4ConfigData.
79     //
80     CopyMem (Udp4ConfigData, &Instance->ConfigData, sizeof (*Udp4ConfigData));
81   }
82 
83   Ip = Instance->IpInfo->Ip.Ip4;
84 
85   //
86   // Get the underlying Ip4ModeData, MnpConfigData and SnpModeData.
87   //
88   Status = Ip->GetModeData (Ip, Ip4ModeData, MnpConfigData, SnpModeData);
89 
90   gBS->RestoreTPL (OldTpl);
91 
92   return Status;
93 }
94 
95 
96 /**
97   Initializes, changes, or resets the operational parameters for this instance of the EFI UDPv4
98   Protocol.
99 
100   The Configure() function is used to do the following:
101   * Initialize and start this instance of the EFI UDPv4 Protocol.
102   * Change the filtering rules and operational parameters.
103   * Reset this instance of the EFI UDPv4 Protocol.
104   Until these parameters are initialized, no network traffic can be sent or
105   received by this instance. This instance can be also reset by calling Configure()
106   with UdpConfigData set to NULL. Once reset, the receiving queue and transmitting
107   queue are flushed and no traffic is allowed through this instance.
108   With different parameters in UdpConfigData, Configure() can be used to bind
109   this instance to specified port.
110 
111   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
112   @param[in]  UdpConfigData     Pointer to the buffer to receive the current configuration data.
113 
114   @retval EFI_SUCCESS           The configuration settings were set, changed, or reset successfully.
115   @retval EFI_NO_MAPPING        When using a default address, configuration (DHCP, BOOTP,
116                                 RARP, etc.) is not finished yet.
117   @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE:
118   @retval EFI_ALREADY_STARTED   The EFI UDPv4 Protocol instance is already started/configured
119                                 and must be stopped/reset before it can be reconfigured.
120   @retval EFI_ACCESS_DENIED     UdpConfigData. AllowDuplicatePort is FALSE
121                                 and UdpConfigData.StationPort is already used by
122                                 other instance.
123   @retval EFI_OUT_OF_RESOURCES  The EFI UDPv4 Protocol driver cannot allocate memory for this
124                                 EFI UDPv4 Protocol instance.
125   @retval EFI_DEVICE_ERROR      An unexpected network or system error occurred and this instance
126                                  was not opened.
127 
128 **/
129 EFI_STATUS
130 EFIAPI
Udp4Configure(IN EFI_UDP4_PROTOCOL * This,IN EFI_UDP4_CONFIG_DATA * UdpConfigData OPTIONAL)131 Udp4Configure (
132   IN EFI_UDP4_PROTOCOL     *This,
133   IN EFI_UDP4_CONFIG_DATA  *UdpConfigData OPTIONAL
134   )
135 {
136   EFI_STATUS           Status;
137   UDP4_INSTANCE_DATA   *Instance;
138   UDP4_SERVICE_DATA    *Udp4Service;
139   EFI_TPL              OldTpl;
140   IP4_ADDR             StationAddress;
141   IP4_ADDR             SubnetMask;
142   IP4_ADDR             RemoteAddress;
143   EFI_IP4_CONFIG_DATA  Ip4ConfigData;
144   IP4_ADDR             LocalAddr;
145   IP4_ADDR             RemoteAddr;
146 
147   if (This == NULL) {
148     return EFI_INVALID_PARAMETER;
149   }
150 
151   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
152 
153   if (!Instance->Configured && (UdpConfigData == NULL)) {
154     return EFI_SUCCESS;
155   }
156 
157   Udp4Service = Instance->Udp4Service;
158   Status      = EFI_SUCCESS;
159 
160   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
161 
162   if (UdpConfigData != NULL) {
163 
164     CopyMem (&StationAddress, &UdpConfigData->StationAddress, sizeof (IP4_ADDR));
165     CopyMem (&SubnetMask, &UdpConfigData->SubnetMask, sizeof (IP4_ADDR));
166     CopyMem (&RemoteAddress, &UdpConfigData->RemoteAddress, sizeof (IP4_ADDR));
167 
168     StationAddress = NTOHL (StationAddress);
169     SubnetMask     = NTOHL (SubnetMask);
170     RemoteAddress  = NTOHL (RemoteAddress);
171 
172 
173     if (!UdpConfigData->UseDefaultAddress &&
174         (!IP4_IS_VALID_NETMASK (SubnetMask) ||
175          !((StationAddress == 0) || NetIp4IsUnicast (StationAddress, SubnetMask)) ||
176          IP4_IS_LOCAL_BROADCAST (RemoteAddress))) {
177       //
178       // Don't use default address, and subnet mask is invalid or StationAddress is not
179       // a valid unicast IPv4 address or RemoteAddress is not a valid unicast IPv4 address
180       // if it is not 0.
181       //
182       Status = EFI_INVALID_PARAMETER;
183       goto ON_EXIT;
184     }
185 
186     if (Instance->Configured) {
187       //
188       // The instance is already configured, try to do the re-configuration.
189       //
190       if (!Udp4IsReconfigurable (&Instance->ConfigData, UdpConfigData)) {
191         //
192         // If the new configuration data wants to change some unreconfigurable
193         // settings, return EFI_ALREADY_STARTED.
194         //
195         Status = EFI_ALREADY_STARTED;
196         goto ON_EXIT;
197       }
198 
199       //
200       // Save the reconfigurable parameters.
201       //
202       Instance->ConfigData.TypeOfService   = UdpConfigData->TypeOfService;
203       Instance->ConfigData.TimeToLive      = UdpConfigData->TimeToLive;
204       Instance->ConfigData.DoNotFragment   = UdpConfigData->DoNotFragment;
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       Udp4BuildIp4ConfigData (UdpConfigData, &Ip4ConfigData);
212 
213       //
214       // Configure the Ip instance wrapped in the IpInfo.
215       //
216       Status = IpIoConfigIp (Instance->IpInfo, &Ip4ConfigData);
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 (&Instance->ConfigData, UdpConfigData, sizeof (Instance->ConfigData));
231       IP4_COPY_ADDRESS (&Instance->ConfigData.StationAddress, &Ip4ConfigData.StationAddress);
232       IP4_COPY_ADDRESS (&Instance->ConfigData.SubnetMask, &Ip4ConfigData.SubnetMask);
233 
234       //
235       // Try to allocate the required port resource.
236       //
237       Status = Udp4Bind (&Udp4Service->ChildrenList, &Instance->ConfigData);
238       if (EFI_ERROR (Status)) {
239         //
240         // Reset the ip instance if bind fails.
241         //
242         IpIoConfigIp (Instance->IpInfo, NULL);
243         goto ON_EXIT;
244       }
245 
246       //
247       // Pre calculate the checksum for the pseudo head, ignore the UDP length first.
248       //
249       CopyMem (&LocalAddr, &Instance->ConfigData.StationAddress, sizeof (IP4_ADDR));
250       CopyMem (&RemoteAddr, &Instance->ConfigData.RemoteAddress, sizeof (IP4_ADDR));
251       Instance->HeadSum = NetPseudoHeadChecksum (
252                             LocalAddr,
253                             RemoteAddr,
254                             EFI_IP_PROTO_UDP,
255                             0
256                             );
257 
258       Instance->Configured = TRUE;
259     }
260   } else {
261     //
262     // UdpConfigData is NULL, reset the instance.
263     //
264     Instance->Configured  = FALSE;
265     Instance->IsNoMapping = FALSE;
266 
267     //
268     // Reset the Ip instance wrapped in the IpInfo.
269     //
270     IpIoConfigIp (Instance->IpInfo, NULL);
271 
272     //
273     // Cancel all the user tokens.
274     //
275     Instance->Udp4Proto.Cancel (&Instance->Udp4Proto, NULL);
276 
277     //
278     // Remove the buffered RxData for this instance.
279     //
280     Udp4FlushRcvdDgram (Instance);
281 
282     ASSERT (IsListEmpty (&Instance->DeliveredDgramQue));
283   }
284 
285 ON_EXIT:
286 
287   gBS->RestoreTPL (OldTpl);
288 
289   return Status;
290 }
291 
292 
293 /**
294   Joins and leaves multicast groups.
295 
296   The Groups() function is used to enable and disable the multicast group
297   filtering. If the JoinFlag is FALSE and the MulticastAddress is NULL, then all
298   currently joined groups are left.
299 
300   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
301   @param[in]  JoinFlag          Set to TRUE to join a multicast group. Set to FALSE to leave one
302                                 or all multicast groups.
303   @param[in]  MulticastAddress  Pointer to multicast group address to join or leave.
304 
305   @retval EFI_SUCCESS           The operation completed successfully.
306   @retval EFI_NOT_STARTED       The EFI UDPv4 Protocol instance has not been started.
307   @retval EFI_NO_MAPPING        When using a default address, configuration (DHCP, BOOTP,
308                                 RARP, etc.) is not finished yet.
309   @retval EFI_OUT_OF_RESOURCES  Could not allocate resources to join the group.
310   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
311                                 - This is NULL.
312                                 - JoinFlag is TRUE and MulticastAddress is NULL.
313                                 - JoinFlag is TRUE and *MulticastAddress is not
314                                   a valid multicast address.
315   @retval EFI_ALREADY_STARTED   The group address is already in the group table (when
316                                 JoinFlag is TRUE).
317   @retval EFI_NOT_FOUND         The group address is not in the group table (when JoinFlag is
318                                 FALSE).
319   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
320 
321 **/
322 EFI_STATUS
323 EFIAPI
Udp4Groups(IN EFI_UDP4_PROTOCOL * This,IN BOOLEAN JoinFlag,IN EFI_IPv4_ADDRESS * MulticastAddress OPTIONAL)324 Udp4Groups (
325   IN EFI_UDP4_PROTOCOL  *This,
326   IN BOOLEAN            JoinFlag,
327   IN EFI_IPv4_ADDRESS   *MulticastAddress OPTIONAL
328   )
329 {
330   EFI_STATUS          Status;
331   UDP4_INSTANCE_DATA  *Instance;
332   EFI_IP4_PROTOCOL    *Ip;
333   EFI_TPL             OldTpl;
334   IP4_ADDR            McastIp;
335 
336   if ((This == NULL) || (JoinFlag && (MulticastAddress == NULL))) {
337     return EFI_INVALID_PARAMETER;
338   }
339 
340   McastIp = 0;
341   if (JoinFlag) {
342     CopyMem (&McastIp, MulticastAddress, sizeof (IP4_ADDR));
343 
344     if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {
345       return EFI_INVALID_PARAMETER;
346     }
347   }
348 
349   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
350 
351   if (Instance->IsNoMapping) {
352     return EFI_NO_MAPPING;
353   }
354 
355   if (!Instance->Configured) {
356     return EFI_NOT_STARTED;
357   }
358 
359   Ip = Instance->IpInfo->Ip.Ip4;
360 
361   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
362 
363   //
364   // Invoke the Ip instance the Udp4 instance consumes to do the group operation.
365   //
366   Status = Ip->Groups (Ip, JoinFlag, MulticastAddress);
367 
368   if (EFI_ERROR (Status)) {
369     goto ON_EXIT;
370   }
371 
372   //
373   // Keep a local copy of the configured multicast IPs because IpIo receives
374   // datagrams from the 0 station address IP instance and then UDP delivers to
375   // the matched instance. This copy of multicast IPs is used to avoid receive
376   // the mutlicast datagrams destined to multicast IPs the other instances configured.
377   //
378   if (JoinFlag) {
379 
380     NetMapInsertTail (&Instance->McastIps, (VOID *) (UINTN) McastIp, NULL);
381   } else {
382 
383     NetMapIterate (&Instance->McastIps, Udp4LeaveGroup, MulticastAddress);
384   }
385 
386 ON_EXIT:
387 
388   gBS->RestoreTPL (OldTpl);
389 
390   return Status;
391 }
392 
393 
394 /**
395   Adds and deletes routing table entries.
396 
397   The Routes() function adds a route to or deletes a route from the routing table.
398   Routes are determined by comparing the SubnetAddress with the destination IP
399   address and arithmetically AND-ing it with the SubnetMask. The gateway address
400   must be on the same subnet as the configured station address.
401   The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
402   The default route matches all destination IP addresses that do not match any
403   other routes.
404   A zero GatewayAddress is a nonroute. Packets are sent to the destination IP
405   address if it can be found in the Address Resolution Protocol (ARP) cache or
406   on the local subnet. One automatic nonroute entry will be inserted into the
407   routing table for outgoing packets that are addressed to a local subnet
408   (gateway address of 0.0.0.0).
409   Each instance of the EFI UDPv4 Protocol has its own independent routing table.
410   Instances of the EFI UDPv4 Protocol that use the default IP address will also
411   have copies of the routing table provided by the EFI_IP4_CONFIG_PROTOCOL. These
412   copies will be updated automatically whenever the IP driver reconfigures its
413   instances; as a result, the previous modification to these copies will be lost.
414 
415   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
416   @param[in]  DeleteRoute       Set to TRUE to delete this route from the routing table.
417                                 Set to FALSE to add this route to the routing table.
418   @param[in]  SubnetAddress     The destination network address that needs to be routed.
419   @param[in]  SubnetMask        The subnet mask of SubnetAddress.
420   @param[in]  GatewayAddress    The gateway IP address for this route.
421 
422   @retval EFI_SUCCESS           The operation completed successfully.
423   @retval EFI_NOT_STARTED       The EFI UDPv4 Protocol instance has not been started.
424   @retval EFI_NO_MAPPING        When using a default address, configuration (DHCP, BOOTP,
425                                 - RARP, etc.) is not finished yet.
426   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
427   @retval EFI_OUT_OF_RESOURCES  Could not add the entry to the routing table.
428   @retval EFI_NOT_FOUND         This route is not in the routing table.
429   @retval EFI_ACCESS_DENIED     The route is already defined in the routing table.
430 
431 **/
432 EFI_STATUS
433 EFIAPI
Udp4Routes(IN EFI_UDP4_PROTOCOL * This,IN BOOLEAN DeleteRoute,IN EFI_IPv4_ADDRESS * SubnetAddress,IN EFI_IPv4_ADDRESS * SubnetMask,IN EFI_IPv4_ADDRESS * GatewayAddress)434 Udp4Routes (
435   IN EFI_UDP4_PROTOCOL  *This,
436   IN BOOLEAN            DeleteRoute,
437   IN EFI_IPv4_ADDRESS   *SubnetAddress,
438   IN EFI_IPv4_ADDRESS   *SubnetMask,
439   IN EFI_IPv4_ADDRESS   *GatewayAddress
440   )
441 {
442   UDP4_INSTANCE_DATA  *Instance;
443   EFI_IP4_PROTOCOL    *Ip;
444 
445   if (This == NULL) {
446     return EFI_INVALID_PARAMETER;
447   }
448 
449   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
450 
451   if (Instance->IsNoMapping) {
452     return EFI_NO_MAPPING;
453   }
454 
455   if (!Instance->Configured) {
456     return EFI_NOT_STARTED;
457   }
458 
459   Ip = Instance->IpInfo->Ip.Ip4;
460 
461   //
462   // Invoke the Ip instance the Udp4 instance consumes to do the actual operation.
463   //
464   return Ip->Routes (Ip, DeleteRoute, SubnetAddress, SubnetMask, GatewayAddress);
465 }
466 
467 
468 /**
469   Queues outgoing data packets into the transmit queue.
470 
471   The Transmit() function places a sending request to this instance of the EFI
472   UDPv4 Protocol, alongside the transmit data that was filled by the user. Whenever
473   the packet in the token is sent out or some errors occur, the Token.Event will
474   be signaled and Token.Status is updated. Providing a proper notification function
475   and context for the event will enable the user to receive the notification and
476   transmitting status.
477 
478   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
479   @param[in]  Token             Pointer to the completion token that will be placed into the
480                                 transmit queue.
481 
482   @retval EFI_SUCCESS           The data has been queued for transmission.
483   @retval EFI_NOT_STARTED       This EFI UDPv4 Protocol instance has not been started.
484   @retval EFI_NO_MAPPING        When using a default address, configuration (DHCP, BOOTP,
485                                 RARP, etc.) is not finished yet.
486   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
487   @retval EFI_ACCESS_DENIED     The transmit completion token with the same
488                                 Token.Event was already in the transmit queue.
489   @retval EFI_NOT_READY         The completion token could not be queued because the
490                                 transmit queue is full.
491   @retval EFI_OUT_OF_RESOURCES  Could not queue the transmit data.
492   @retval EFI_NOT_FOUND         There is no route to the destination network or address.
493   @retval EFI_BAD_BUFFER_SIZE   The data length is greater than the maximum UDP packet
494                                 size. Or the length of the IP header + UDP header + data
495                                 length is greater than MTU if DoNotFragment is TRUE.
496 
497 **/
498 EFI_STATUS
499 EFIAPI
Udp4Transmit(IN EFI_UDP4_PROTOCOL * This,IN EFI_UDP4_COMPLETION_TOKEN * Token)500 Udp4Transmit (
501   IN EFI_UDP4_PROTOCOL          *This,
502   IN EFI_UDP4_COMPLETION_TOKEN  *Token
503   )
504 {
505   EFI_STATUS              Status;
506   UDP4_INSTANCE_DATA      *Instance;
507   EFI_TPL                 OldTpl;
508   NET_BUF                 *Packet;
509   EFI_UDP_HEADER         *Udp4Header;
510   EFI_UDP4_CONFIG_DATA    *ConfigData;
511   IP4_ADDR                Source;
512   IP4_ADDR                Destination;
513   EFI_UDP4_TRANSMIT_DATA  *TxData;
514   EFI_UDP4_SESSION_DATA   *UdpSessionData;
515   UDP4_SERVICE_DATA       *Udp4Service;
516   IP_IO_OVERRIDE          Override;
517   UINT16                  HeadSum;
518   EFI_IP_ADDRESS          IpDestAddr;
519 
520   if ((This == NULL) || (Token == NULL)) {
521     return EFI_INVALID_PARAMETER;
522   }
523 
524   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
525 
526   if (Instance->IsNoMapping) {
527     return EFI_NO_MAPPING;
528   }
529 
530   if (!Instance->Configured) {
531     return EFI_NOT_STARTED;
532   }
533 
534   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
535 
536   //
537   // Validate the Token, if the token is invalid return the error code.
538   //
539   Status = Udp4ValidateTxToken (Instance, Token);
540   if (EFI_ERROR (Status)) {
541     goto ON_EXIT;
542   }
543 
544   if (EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token)) ||
545     EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token))) {
546     //
547     // Try to find a duplicate token in the two token maps, if found, return
548     // EFI_ACCESS_DENIED.
549     //
550     Status = EFI_ACCESS_DENIED;
551     goto ON_EXIT;
552   }
553 
554   TxData = Token->Packet.TxData;
555 
556   //
557   // Create a net buffer to hold the user buffer and the udp header.
558   //
559   Packet = NetbufFromExt (
560              (NET_FRAGMENT *)TxData->FragmentTable,
561              TxData->FragmentCount,
562              UDP4_HEADER_SIZE,
563              0,
564              Udp4NetVectorExtFree,
565              NULL
566              );
567   if (Packet == NULL) {
568     Status = EFI_OUT_OF_RESOURCES;
569     goto ON_EXIT;
570   }
571 
572   //
573   // Store the IpIo in ProtoData.
574   //
575   Udp4Service = Instance->Udp4Service;
576   *((UINTN *) &Packet->ProtoData[0]) = (UINTN) (Udp4Service->IpIo);
577 
578   Udp4Header = (EFI_UDP_HEADER *) NetbufAllocSpace (Packet, UDP4_HEADER_SIZE, TRUE);
579   ASSERT (Udp4Header != NULL);
580 
581   ConfigData = &Instance->ConfigData;
582 
583   //
584   // Fill the udp header.
585   //
586   Udp4Header->SrcPort      = HTONS (ConfigData->StationPort);
587   Udp4Header->DstPort      = HTONS (ConfigData->RemotePort);
588   Udp4Header->Length       = HTONS ((UINT16) Packet->TotalSize);
589   Udp4Header->Checksum     = 0;
590 
591   UdpSessionData = TxData->UdpSessionData;
592   IP4_COPY_ADDRESS (&Override.Ip4OverrideData.SourceAddress, &ConfigData->StationAddress);
593 
594   if (UdpSessionData != NULL) {
595     //
596     // Set the SourceAddress, SrcPort and Destination according to the specified
597     // UdpSessionData.
598     //
599     if (!EFI_IP4_EQUAL (&UdpSessionData->SourceAddress, &mZeroIp4Addr)) {
600       IP4_COPY_ADDRESS (&Override.Ip4OverrideData.SourceAddress, &UdpSessionData->SourceAddress);
601     }
602 
603     if (UdpSessionData->SourcePort != 0) {
604       Udp4Header->SrcPort = HTONS (UdpSessionData->SourcePort);
605     }
606 
607     if (UdpSessionData->DestinationPort != 0) {
608       Udp4Header->DstPort = HTONS (UdpSessionData->DestinationPort);
609     }
610 
611     CopyMem (&Source, &Override.Ip4OverrideData.SourceAddress, sizeof (IP4_ADDR));
612     CopyMem (&Destination, &UdpSessionData->DestinationAddress, sizeof (IP4_ADDR));
613 
614     //
615     // calculate the pseudo head checksum using the overridden parameters.
616     //
617     HeadSum = NetPseudoHeadChecksum (
618                 Source,
619                 Destination,
620                 EFI_IP_PROTO_UDP,
621                 0
622                 );
623   } else {
624     //
625     // UdpSessionData is NULL, use the address and port information previously configured.
626     //
627     CopyMem (&Destination, &ConfigData->RemoteAddress, sizeof (IP4_ADDR));
628 
629     HeadSum = Instance->HeadSum;
630   }
631 
632   //
633   // calculate the checksum.
634   //
635   Udp4Header->Checksum = Udp4Checksum (Packet, HeadSum);
636   if (Udp4Header->Checksum == 0) {
637     //
638     // If the calculated checksum is 0, fill the Checksum field with all ones.
639     //
640     Udp4Header->Checksum = 0xffff;
641   }
642 
643   //
644   // Fill the IpIo Override data.
645   //
646   if (TxData->GatewayAddress != NULL) {
647     IP4_COPY_ADDRESS (&Override.Ip4OverrideData.GatewayAddress, TxData->GatewayAddress);
648   } else {
649     ZeroMem (&Override.Ip4OverrideData.GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
650   }
651 
652   Override.Ip4OverrideData.Protocol                 = EFI_IP_PROTO_UDP;
653   Override.Ip4OverrideData.TypeOfService            = ConfigData->TypeOfService;
654   Override.Ip4OverrideData.TimeToLive               = ConfigData->TimeToLive;
655   Override.Ip4OverrideData.DoNotFragment            = ConfigData->DoNotFragment;
656 
657   //
658   // Save the token into the TxToken map.
659   //
660   Status = NetMapInsertTail (&Instance->TxTokens, Token, Packet);
661   if (EFI_ERROR (Status)) {
662     goto FREE_PACKET;
663   }
664 
665   //
666   // Send out this datagram through IpIo.
667   //
668   IpDestAddr.Addr[0] = Destination;
669   Status = IpIoSend (
670              Udp4Service->IpIo,
671              Packet,
672              Instance->IpInfo,
673              Instance,
674              Token,
675              &IpDestAddr,
676              &Override
677              );
678   if (EFI_ERROR (Status)) {
679     //
680     // Remove this token from the TxTokens.
681     //
682     Udp4RemoveToken (&Instance->TxTokens, Token);
683   }
684 
685 FREE_PACKET:
686 
687   NetbufFree (Packet);
688 
689 ON_EXIT:
690 
691   gBS->RestoreTPL (OldTpl);
692 
693   return Status;
694 }
695 
696 
697 /**
698   Places an asynchronous receive request into the receiving queue.
699 
700   The Receive() function places a completion token into the receive packet queue.
701   This function is always asynchronous.
702   The caller must fill in the Token.Event field in the completion token, and this
703   field cannot be NULL. When the receive operation completes, the EFI UDPv4 Protocol
704   driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
705   is signaled. Providing a proper notification function and context for the event
706   will enable the user to receive the notification and receiving status. That
707   notification function is guaranteed to not be re-entered.
708 
709   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
710   @param[in]  Token             Pointer to a token that is associated with
711                                 the receive data descriptor.
712 
713   @retval EFI_SUCCESS           The receive completion token was cached.
714   @retval EFI_NOT_STARTED       This EFI UDPv4 Protocol instance has not been started.
715   @retval EFI_NO_MAPPING        When using a default address, configuration (DHCP, BOOTP, RARP, etc.)
716                                 is not finished yet.
717   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
718   @retval EFI_OUT_OF_RESOURCES  The receive completion token could not be queued due to a lack of system
719                                 resources (usually memory).
720   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
721   @retval EFI_ACCESS_DENIED     A receive completion token with the same Token.Event was already in
722                                 the receive queue.
723   @retval EFI_NOT_READY         The receive request could not be queued because the receive queue is full.
724 
725 **/
726 EFI_STATUS
727 EFIAPI
Udp4Receive(IN EFI_UDP4_PROTOCOL * This,IN EFI_UDP4_COMPLETION_TOKEN * Token)728 Udp4Receive (
729   IN EFI_UDP4_PROTOCOL          *This,
730   IN EFI_UDP4_COMPLETION_TOKEN  *Token
731   )
732 {
733   EFI_STATUS          Status;
734   UDP4_INSTANCE_DATA  *Instance;
735   EFI_TPL             OldTpl;
736 
737   if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
738     return EFI_INVALID_PARAMETER;
739   }
740 
741   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
742 
743   if (Instance->IsNoMapping) {
744     return EFI_NO_MAPPING;
745   }
746 
747   if (!Instance->Configured) {
748     return EFI_NOT_STARTED;
749   }
750 
751   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
752 
753   if (EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token))||
754     EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token))) {
755     //
756     // Return EFI_ACCESS_DENIED if the specified token is already in the TxTokens or
757     // RxTokens map.
758     //
759     Status = EFI_ACCESS_DENIED;
760     goto ON_EXIT;
761   }
762 
763   Token->Packet.RxData = NULL;
764 
765   //
766   // Save the token into the RxTokens map.
767   //
768   Status = NetMapInsertTail (&Instance->RxTokens, Token, NULL);
769   if (EFI_ERROR (Status)) {
770     Status = EFI_NOT_READY;
771     goto ON_EXIT;
772   }
773 
774   //
775   // If there is an icmp error, report it.
776   //
777   Udp4ReportIcmpError (Instance);
778 
779   //
780   // Try to deliver the received datagrams.
781   //
782   Udp4InstanceDeliverDgram (Instance);
783 
784   //
785   // Dispatch the DPC queued by the NotifyFunction of Token->Event.
786   //
787   DispatchDpc ();
788 
789 ON_EXIT:
790 
791   gBS->RestoreTPL (OldTpl);
792 
793   return Status;
794 }
795 
796 
797 /**
798   Aborts an asynchronous transmit or receive request.
799 
800   The Cancel() function is used to abort a pending transmit or receive request.
801   If the token is in the transmit or receive request queues, after calling this
802   function, Token.Status will be set to EFI_ABORTED and then Token.Event will be
803   signaled. If the token is not in one of the queues, which usually means that
804   the asynchronous operation has completed, this function will not signal the
805   token and EFI_NOT_FOUND is returned.
806 
807   @param[in]  This  Pointer to the EFI_UDP4_PROTOCOL instance.
808   @param[in]  Token Pointer to a token that has been issued by
809                     EFI_UDP4_PROTOCOL.Transmit() or
810                     EFI_UDP4_PROTOCOL.Receive().If NULL, all pending
811                     tokens are aborted.
812 
813   @retval  EFI_SUCCESS           The asynchronous I/O request was aborted and Token.Event
814                                  was signaled. When Token is NULL, all pending requests are
815                                  aborted and their events are signaled.
816   @retval  EFI_INVALID_PARAMETER This is NULL.
817   @retval  EFI_NOT_STARTED       This instance has not been started.
818   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
819                                  RARP, etc.) is not finished yet.
820   @retval  EFI_NOT_FOUND         When Token is not NULL, the asynchronous I/O request was
821                                  not found in the transmit or receive queue. It has either completed
822                                  or was not issued by Transmit() and Receive().
823 
824 **/
825 EFI_STATUS
826 EFIAPI
Udp4Cancel(IN EFI_UDP4_PROTOCOL * This,IN EFI_UDP4_COMPLETION_TOKEN * Token OPTIONAL)827 Udp4Cancel (
828   IN EFI_UDP4_PROTOCOL          *This,
829   IN EFI_UDP4_COMPLETION_TOKEN  *Token OPTIONAL
830   )
831 {
832   EFI_STATUS          Status;
833   UDP4_INSTANCE_DATA  *Instance;
834   EFI_TPL             OldTpl;
835 
836   if (This == NULL) {
837     return EFI_INVALID_PARAMETER;
838   }
839 
840   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
841 
842   if (Instance->IsNoMapping) {
843     return EFI_NO_MAPPING;
844   }
845 
846   if (!Instance->Configured) {
847     return EFI_NOT_STARTED;
848   }
849 
850   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
851 
852   //
853   // Cancle the tokens specified by Token for this instance.
854   //
855   Status = Udp4InstanceCancelToken (Instance, Token);
856 
857   //
858   // Dispatch the DPC queued by the NotifyFunction of the cancelled token's events.
859   //
860   DispatchDpc ();
861 
862   gBS->RestoreTPL (OldTpl);
863 
864   return Status;
865 }
866 
867 
868 /**
869   Polls for incoming data packets and processes outgoing data packets.
870 
871   The Poll() function can be used by network drivers and applications to increase
872   the rate that data packets are moved between the communications device and the
873   transmit and receive queues.
874   In some systems, the periodic timer event in the managed network driver may not
875   poll the underlying communications device fast enough to transmit and/or receive
876   all data packets without missing incoming packets or dropping outgoing packets.
877   Drivers and applications that are experiencing packet loss should try calling
878   the Poll() function more often.
879 
880   @param[in]  This  Pointer to the EFI_UDP4_PROTOCOL instance.
881 
882   @retval EFI_SUCCESS           Incoming or outgoing data was processed.
883   @retval EFI_INVALID_PARAMETER This is NULL.
884   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
885   @retval EFI_TIMEOUT           Data was dropped out of the transmit and/or receive queue.
886 
887 **/
888 EFI_STATUS
889 EFIAPI
Udp4Poll(IN EFI_UDP4_PROTOCOL * This)890 Udp4Poll (
891   IN EFI_UDP4_PROTOCOL  *This
892   )
893 {
894   UDP4_INSTANCE_DATA  *Instance;
895   EFI_IP4_PROTOCOL    *Ip;
896 
897   if (This == NULL) {
898     return EFI_INVALID_PARAMETER;
899   }
900 
901   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
902   Ip       = Instance->IpInfo->Ip.Ip4;
903 
904   //
905   // Invode the Ip instance consumed by the udp instance to do the poll operation.
906   //
907   return Ip->Poll (Ip);
908 }
909