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