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