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