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