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