BaseTools:Change the path of the file that Binary Cache
[mirror_edk2.git] / MdeModulePkg / Universal / Network / ArpDxe / ArpImpl.c
1 /** @file\r
2   The implementation of the ARP protocol.\r
3 \r
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6 \r
7 **/\r
8 \r
9 #include "ArpImpl.h"\r
10 \r
11 //\r
12 // Global variable of EFI ARP Protocol Interface.\r
13 //\r
14 EFI_ARP_PROTOCOL  mEfiArpProtocolTemplate = {\r
15   ArpConfigure,\r
16   ArpAdd,\r
17   ArpFind,\r
18   ArpDelete,\r
19   ArpFlush,\r
20   ArpRequest,\r
21   ArpCancel\r
22 };\r
23 \r
24 \r
25 /**\r
26   Initialize the instance context data.\r
27 \r
28   @param[in]   ArpService        Pointer to the arp service context data this\r
29                                  instance belongs to.\r
30   @param[out]  Instance          Pointer to the instance context data.\r
31 \r
32   @return None.\r
33 \r
34 **/\r
35 VOID\r
36 ArpInitInstance (\r
37   IN  ARP_SERVICE_DATA   *ArpService,\r
38   OUT ARP_INSTANCE_DATA  *Instance\r
39   )\r
40 {\r
41   NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);\r
42 \r
43   Instance->Signature  = ARP_INSTANCE_DATA_SIGNATURE;\r
44   Instance->ArpService = ArpService;\r
45 \r
46   CopyMem (&Instance->ArpProto, &mEfiArpProtocolTemplate, sizeof (Instance->ArpProto));\r
47 \r
48   Instance->Configured = FALSE;\r
49   Instance->InDestroy  = FALSE;\r
50 \r
51   InitializeListHead (&Instance->List);\r
52 }\r
53 \r
54 \r
55 /**\r
56   Process the Arp packets received from Mnp, the procedure conforms to RFC826.\r
57 \r
58   @param[in]  Context            Pointer to the context data registerd to the\r
59                                  Event.\r
60 \r
61   @return None.\r
62 \r
63 **/\r
64 VOID\r
65 EFIAPI\r
66 ArpOnFrameRcvdDpc (\r
67   IN VOID       *Context\r
68   )\r
69 {\r
70   EFI_STATUS                            Status;\r
71   ARP_SERVICE_DATA                      *ArpService;\r
72   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *RxToken;\r
73   EFI_MANAGED_NETWORK_RECEIVE_DATA      *RxData;\r
74   ARP_HEAD                              *Head;\r
75   ARP_ADDRESS                           ArpAddress;\r
76   ARP_CACHE_ENTRY                       *CacheEntry;\r
77   LIST_ENTRY                            *Entry;\r
78   ARP_INSTANCE_DATA                     *Instance;\r
79   EFI_ARP_CONFIG_DATA                   *ConfigData;\r
80   NET_ARP_ADDRESS                       SenderAddress[2];\r
81   BOOLEAN                               ProtoMatched;\r
82   BOOLEAN                               IsTarget;\r
83   BOOLEAN                               MergeFlag;\r
84 \r
85   ArpService = (ARP_SERVICE_DATA *)Context;\r
86   NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);\r
87 \r
88   RxToken = &ArpService->RxToken;\r
89 \r
90   if (RxToken->Status == EFI_ABORTED) {\r
91     //\r
92     // The Token is aborted, possibly by arp itself, just return and the receiving\r
93     // process is stopped.\r
94     //\r
95     return;\r
96   }\r
97 \r
98   if (EFI_ERROR (RxToken->Status)) {\r
99     //\r
100     // Restart the receiving if any other error Status occurs.\r
101     //\r
102     goto RESTART_RECEIVE;\r
103   }\r
104 \r
105   //\r
106   // Status is EFI_SUCCESS, process the received frame.\r
107   //\r
108   RxData = RxToken->Packet.RxData;\r
109   //\r
110   // Sanity check.\r
111   //\r
112   if (RxData->DataLength < sizeof (ARP_HEAD)) {\r
113     //\r
114     // Restart the receiving if packet size is not correct.\r
115     //\r
116     goto RESTART_RECEIVE;\r
117   }\r
118 \r
119   //\r
120   // Convert the byte order of the multi-byte fields.\r
121   //\r
122   Head   = (ARP_HEAD *) RxData->PacketData;\r
123   Head->HwType    = NTOHS (Head->HwType);\r
124   Head->ProtoType = NTOHS (Head->ProtoType);\r
125   Head->OpCode    = NTOHS (Head->OpCode);\r
126 \r
127   if (RxData->DataLength < (sizeof (ARP_HEAD) + 2 * Head->HwAddrLen + 2 * Head->ProtoAddrLen)) {\r
128     goto RESTART_RECEIVE;\r
129   }\r
130 \r
131   if ((Head->HwType != ArpService->SnpMode.IfType) ||\r
132     (Head->HwAddrLen != ArpService->SnpMode.HwAddressSize) ||\r
133     (RxData->ProtocolType != ARP_ETHER_PROTO_TYPE)) {\r
134     //\r
135     // The hardware type or the hardware address length doesn't match.\r
136     // There is a sanity check for the protocol type too.\r
137     //\r
138     goto RECYCLE_RXDATA;\r
139   }\r
140 \r
141   //\r
142   // Set the pointers to the addresses contained in the arp packet.\r
143   //\r
144   ArpAddress.SenderHwAddr    = (UINT8 *)(Head + 1);\r
145   ArpAddress.SenderProtoAddr = ArpAddress.SenderHwAddr + Head->HwAddrLen;\r
146   ArpAddress.TargetHwAddr    = ArpAddress.SenderProtoAddr + Head->ProtoAddrLen;\r
147   ArpAddress.TargetProtoAddr = ArpAddress.TargetHwAddr + Head->HwAddrLen;\r
148 \r
149   SenderAddress[Hardware].Type       = Head->HwType;\r
150   SenderAddress[Hardware].Length     = Head->HwAddrLen;\r
151   SenderAddress[Hardware].AddressPtr = ArpAddress.SenderHwAddr;\r
152 \r
153   SenderAddress[Protocol].Type       = Head->ProtoType;\r
154   SenderAddress[Protocol].Length     = Head->ProtoAddrLen;\r
155   SenderAddress[Protocol].AddressPtr = ArpAddress.SenderProtoAddr;\r
156 \r
157   //\r
158   // First, check the denied cache table.\r
159   //\r
160   CacheEntry = ArpFindDeniedCacheEntry (\r
161                  ArpService,\r
162                  &SenderAddress[Protocol],\r
163                  &SenderAddress[Hardware]\r
164                  );\r
165   if (CacheEntry != NULL) {\r
166     //\r
167     // This address (either hardware or protocol address, or both) is configured to\r
168     // be a deny entry, silently skip the normal process.\r
169     //\r
170     goto RECYCLE_RXDATA;\r
171   }\r
172 \r
173   ProtoMatched = FALSE;\r
174   IsTarget     = FALSE;\r
175   Instance     = NULL;\r
176   NET_LIST_FOR_EACH (Entry, &ArpService->ChildrenList) {\r
177     //\r
178     // Iterate all the children.\r
179     //\r
180     Instance = NET_LIST_USER_STRUCT (Entry, ARP_INSTANCE_DATA, List);\r
181     NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);\r
182     ConfigData = &Instance->ConfigData;\r
183 \r
184     if ((Instance->Configured) &&\r
185       (Head->ProtoType == ConfigData->SwAddressType) &&\r
186       (Head->ProtoAddrLen == ConfigData->SwAddressLength)) {\r
187       //\r
188       // The protocol type is matched for the received arp packet.\r
189       //\r
190       ProtoMatched = TRUE;\r
191       if (0 == CompareMem (\r
192                  (VOID *)ArpAddress.TargetProtoAddr,\r
193                  ConfigData->StationAddress,\r
194                  ConfigData->SwAddressLength\r
195                  )) {\r
196         //\r
197         // The arp driver has the target address required by the received arp packet.\r
198         //\r
199         IsTarget = TRUE;\r
200         break;\r
201       }\r
202     }\r
203   }\r
204 \r
205   if (!ProtoMatched) {\r
206     //\r
207     // Protocol type unmatchable, skip.\r
208     //\r
209     goto RECYCLE_RXDATA;\r
210   }\r
211 \r
212   //\r
213   // Check whether the sender's address information is already in the cache.\r
214   //\r
215   MergeFlag  = FALSE;\r
216   CacheEntry = ArpFindNextCacheEntryInTable (\r
217                  &ArpService->ResolvedCacheTable,\r
218                  NULL,\r
219                  ByProtoAddress,\r
220                  &SenderAddress[Protocol],\r
221                  NULL\r
222                  );\r
223   if (CacheEntry != NULL) {\r
224     //\r
225     // Update the entry with the new information.\r
226     //\r
227     ArpFillAddressInCacheEntry (CacheEntry, &SenderAddress[Hardware], NULL);\r
228     CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;\r
229     MergeFlag = TRUE;\r
230   }\r
231 \r
232   if (!IsTarget) {\r
233     //\r
234     // This arp packet isn't targeted to us, skip now.\r
235     //\r
236     goto RECYCLE_RXDATA;\r
237   }\r
238 \r
239   if (!MergeFlag) {\r
240     //\r
241     // Add the triplet <protocol type, sender protocol address, sender hardware address>\r
242     // to the translation table.\r
243     //\r
244     CacheEntry = ArpFindNextCacheEntryInTable (\r
245                    &ArpService->PendingRequestTable,\r
246                    NULL,\r
247                    ByProtoAddress,\r
248                    &SenderAddress[Protocol],\r
249                    NULL\r
250                    );\r
251     if (CacheEntry == NULL) {\r
252       //\r
253       // Allocate a new CacheEntry.\r
254       //\r
255       CacheEntry = ArpAllocCacheEntry (NULL);\r
256       if (CacheEntry == NULL) {\r
257         goto RECYCLE_RXDATA;\r
258       }\r
259     }\r
260 \r
261     if (!IsListEmpty (&CacheEntry->List)) {\r
262       RemoveEntryList (&CacheEntry->List);\r
263     }\r
264 \r
265     //\r
266     // Fill the addresses into the CacheEntry.\r
267     //\r
268     ArpFillAddressInCacheEntry (\r
269       CacheEntry,\r
270       &SenderAddress[Hardware],\r
271       &SenderAddress[Protocol]\r
272       );\r
273 \r
274     //\r
275     // Inform the user.\r
276     //\r
277     ArpAddressResolved (CacheEntry, NULL, NULL);\r
278 \r
279     //\r
280     // Add this entry into the ResolvedCacheTable\r
281     //\r
282     InsertHeadList (&ArpService->ResolvedCacheTable, &CacheEntry->List);\r
283   }\r
284 \r
285   if (Head->OpCode == ARP_OPCODE_REQUEST) {\r
286     //\r
287     // Send back the ARP Reply. If we reach here, Instance is not NULL and CacheEntry\r
288     // is not NULL.\r
289     //\r
290     ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REPLY);\r
291   }\r
292 \r
293 RECYCLE_RXDATA:\r
294 \r
295   //\r
296   // Signal Mnp to recycle the RxData.\r
297   //\r
298   gBS->SignalEvent (RxData->RecycleEvent);\r
299 \r
300 RESTART_RECEIVE:\r
301 \r
302   //\r
303   // Continue to receive packets from Mnp.\r
304   //\r
305   Status = ArpService->Mnp->Receive (ArpService->Mnp, RxToken);\r
306 \r
307   DEBUG_CODE (\r
308     if (EFI_ERROR (Status)) {\r
309       DEBUG ((EFI_D_ERROR, "ArpOnFrameRcvd: ArpService->Mnp->Receive "\r
310         "failed, %r\n.", Status));\r
311     }\r
312   );\r
313 }\r
314 \r
315 /**\r
316   Queue ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK.\r
317 \r
318   @param[in]  Event                  The Event this notify function registered to.\r
319   @param[in]  Context                Pointer to the context data registerd to the\r
320                                      Event.\r
321 \r
322   @return None.\r
323 \r
324 **/\r
325 VOID\r
326 EFIAPI\r
327 ArpOnFrameRcvd (\r
328   IN EFI_EVENT  Event,\r
329   IN VOID       *Context\r
330   )\r
331 {\r
332   //\r
333   // Request ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK\r
334   //\r
335   QueueDpc (TPL_CALLBACK, ArpOnFrameRcvdDpc, Context);\r
336 }\r
337 \r
338 /**\r
339   Process the already sent arp packets.\r
340 \r
341   @param[in]  Context                Pointer to the context data registerd to the\r
342                                      Event.\r
343 \r
344   @return None.\r
345 \r
346 **/\r
347 VOID\r
348 EFIAPI\r
349 ArpOnFrameSentDpc (\r
350   IN VOID       *Context\r
351   )\r
352 {\r
353   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TxToken;\r
354   EFI_MANAGED_NETWORK_TRANSMIT_DATA     *TxData;\r
355 \r
356   ASSERT (Context != NULL);\r
357 \r
358   TxToken = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *)Context;\r
359   TxData  = TxToken->Packet.TxData;\r
360 \r
361   DEBUG_CODE (\r
362     if (EFI_ERROR (TxToken->Status)) {\r
363       DEBUG ((EFI_D_ERROR, "ArpOnFrameSent: TxToken->Status, %r.\n", TxToken->Status));\r
364     }\r
365   );\r
366 \r
367   //\r
368   // Free the allocated memory and close the event.\r
369   //\r
370   FreePool (TxData->FragmentTable[0].FragmentBuffer);\r
371   FreePool (TxData);\r
372   gBS->CloseEvent (TxToken->Event);\r
373   FreePool (TxToken);\r
374 }\r
375 \r
376 /**\r
377   Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK.\r
378 \r
379   @param[in]  Event                  The Event this notify function registered to.\r
380   @param[in]  Context                Pointer to the context data registerd to the\r
381                                      Event.\r
382 \r
383   @return None.\r
384 \r
385 **/\r
386 VOID\r
387 EFIAPI\r
388 ArpOnFrameSent (\r
389   IN EFI_EVENT  Event,\r
390   IN VOID       *Context\r
391   )\r
392 {\r
393   //\r
394   // Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK\r
395   //\r
396   QueueDpc (TPL_CALLBACK, ArpOnFrameSentDpc, Context);\r
397 }\r
398 \r
399 \r
400 /**\r
401   Process the arp cache olding and drive the retrying arp requests.\r
402 \r
403   @param[in]  Event                  The Event this notify function registered to.\r
404   @param[in]  Context                Pointer to the context data registerd to the\r
405                                      Event.\r
406 \r
407   @return None.\r
408 \r
409 **/\r
410 VOID\r
411 EFIAPI\r
412 ArpTimerHandler (\r
413   IN EFI_EVENT  Event,\r
414   IN VOID       *Context\r
415   )\r
416 {\r
417   ARP_SERVICE_DATA      *ArpService;\r
418   LIST_ENTRY            *Entry;\r
419   LIST_ENTRY            *NextEntry;\r
420   LIST_ENTRY            *ContextEntry;\r
421   ARP_CACHE_ENTRY       *CacheEntry;\r
422   USER_REQUEST_CONTEXT  *RequestContext;\r
423 \r
424   ASSERT (Context != NULL);\r
425   ArpService = (ARP_SERVICE_DATA *)Context;\r
426 \r
427   //\r
428   // Iterate all the pending requests to see whether a retry is needed to send out\r
429   // or the request finally fails because the retry time reaches the limitation.\r
430   //\r
431   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {\r
432     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
433 \r
434     if (CacheEntry->NextRetryTime <= ARP_PERIODIC_TIMER_INTERVAL) {\r
435       //\r
436       // Timeout, if we can retry more, send out the request again, otherwise abort\r
437       // this request.\r
438       //\r
439       if (CacheEntry->RetryCount == 0) {\r
440         //\r
441         // Abort this request.\r
442         //\r
443         ArpAddressResolved (CacheEntry, NULL, NULL);\r
444         ASSERT (IsListEmpty (&CacheEntry->UserRequestList));\r
445 \r
446         RemoveEntryList (&CacheEntry->List);\r
447         FreePool (CacheEntry);\r
448       } else {\r
449         //\r
450         // resend the ARP request.\r
451         //\r
452         ASSERT (!IsListEmpty(&CacheEntry->UserRequestList));\r
453 \r
454         ContextEntry   = CacheEntry->UserRequestList.ForwardLink;\r
455         RequestContext = NET_LIST_USER_STRUCT (ContextEntry, USER_REQUEST_CONTEXT, List);\r
456 \r
457         ArpSendFrame (RequestContext->Instance, CacheEntry, ARP_OPCODE_REQUEST);\r
458 \r
459         CacheEntry->RetryCount--;\r
460         CacheEntry->NextRetryTime = RequestContext->Instance->ConfigData.RetryTimeOut;\r
461       }\r
462     } else {\r
463       //\r
464       // Update the NextRetryTime.\r
465       //\r
466       CacheEntry->NextRetryTime -= ARP_PERIODIC_TIMER_INTERVAL;\r
467     }\r
468   }\r
469 \r
470   //\r
471   // Check the timeouts for the DeniedCacheTable.\r
472   //\r
473   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->DeniedCacheTable) {\r
474     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
475     ASSERT (IsListEmpty (&CacheEntry->UserRequestList));\r
476 \r
477     if (CacheEntry->DefaultDecayTime == 0) {\r
478       //\r
479       // It's a static entry, skip it.\r
480       //\r
481       continue;\r
482     }\r
483 \r
484     if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {\r
485       //\r
486       // Time out, remove it.\r
487       //\r
488       RemoveEntryList (&CacheEntry->List);\r
489       FreePool (CacheEntry);\r
490     } else {\r
491       //\r
492       // Update the DecayTime.\r
493       //\r
494       CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;\r
495     }\r
496   }\r
497 \r
498   //\r
499   // Check the timeouts for the ResolvedCacheTable.\r
500   //\r
501   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->ResolvedCacheTable) {\r
502     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
503     ASSERT (IsListEmpty (&CacheEntry->UserRequestList));\r
504 \r
505     if (CacheEntry->DefaultDecayTime == 0) {\r
506       //\r
507       // It's a static entry, skip it.\r
508       //\r
509       continue;\r
510     }\r
511 \r
512     if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {\r
513       //\r
514       // Time out, remove it.\r
515       //\r
516       RemoveEntryList (&CacheEntry->List);\r
517       FreePool (CacheEntry);\r
518     } else {\r
519       //\r
520       // Update the DecayTime.\r
521       //\r
522       CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;\r
523     }\r
524   }\r
525 }\r
526 \r
527 \r
528 /**\r
529   Match the two NET_ARP_ADDRESSes.\r
530 \r
531   @param[in]  AddressOne             Pointer to the first address to match.\r
532   @param[in]  AddressTwo             Pointer to the second address to match.\r
533 \r
534   @return The two addresses match or not.\r
535 \r
536 **/\r
537 BOOLEAN\r
538 ArpMatchAddress (\r
539   IN NET_ARP_ADDRESS  *AddressOne,\r
540   IN NET_ARP_ADDRESS  *AddressTwo\r
541   )\r
542 {\r
543   ASSERT (AddressOne != NULL && AddressTwo != NULL);\r
544 \r
545   if ((AddressOne->Type != AddressTwo->Type) ||\r
546     (AddressOne->Length != AddressTwo->Length)) {\r
547     //\r
548     // Either Type or Length doesn't match.\r
549     //\r
550     return FALSE;\r
551   }\r
552 \r
553   if ((AddressOne->AddressPtr != NULL) &&\r
554     (CompareMem (\r
555       AddressOne->AddressPtr,\r
556       AddressTwo->AddressPtr,\r
557       AddressOne->Length\r
558       ) != 0)) {\r
559     //\r
560     // The address is not the same.\r
561     //\r
562     return FALSE;\r
563   }\r
564 \r
565   return TRUE;\r
566 }\r
567 \r
568 \r
569 /**\r
570   Find the CacheEntry which matches the requirements in the specified CacheTable.\r
571 \r
572   @param[in]  CacheTable             Pointer to the arp cache table.\r
573   @param[in]  StartEntry             Pointer to the start entry this search begins with\r
574                                      in the cache table.\r
575   @param[in]  FindOpType             The search type.\r
576   @param[in]  ProtocolAddress        Pointer to the protocol address to match.\r
577   @param[in]  HardwareAddress        Pointer to the hardware address to match.\r
578 \r
579   @return Pointer to the matched arp cache entry, if NULL, no match is found.\r
580 \r
581 **/\r
582 ARP_CACHE_ENTRY *\r
583 ArpFindNextCacheEntryInTable (\r
584   IN LIST_ENTRY        *CacheTable,\r
585   IN LIST_ENTRY        *StartEntry,\r
586   IN FIND_OPTYPE       FindOpType,\r
587   IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,\r
588   IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL\r
589   )\r
590 {\r
591   LIST_ENTRY       *Entry;\r
592   ARP_CACHE_ENTRY  *CacheEntry;\r
593 \r
594   if (StartEntry == NULL) {\r
595     //\r
596     // Start from the beginning of the table if no StartEntry is specified.\r
597     //\r
598     StartEntry = CacheTable;\r
599   }\r
600 \r
601   for (Entry = StartEntry->ForwardLink; Entry != CacheTable; Entry = Entry->ForwardLink) {\r
602     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
603 \r
604     if ((FindOpType & MATCH_SW_ADDRESS) != 0) {\r
605       //\r
606       // Find by the software address.\r
607       //\r
608       if (!ArpMatchAddress (ProtocolAddress, &CacheEntry->Addresses[Protocol])) {\r
609         //\r
610         // The ProtocolAddress doesn't match, continue to the next cache entry.\r
611         //\r
612         continue;\r
613       }\r
614     }\r
615 \r
616     if ((FindOpType & MATCH_HW_ADDRESS) != 0) {\r
617       //\r
618       // Find by the hardware address.\r
619       //\r
620       if (!ArpMatchAddress (HardwareAddress, &CacheEntry->Addresses[Hardware])) {\r
621         //\r
622         // The HardwareAddress doesn't match, continue to the next cache entry.\r
623         //\r
624         continue;\r
625       }\r
626     }\r
627 \r
628     //\r
629     // The CacheEntry meets the requirements now, return this entry.\r
630     //\r
631     return CacheEntry;\r
632   }\r
633 \r
634   //\r
635   // No matching.\r
636   //\r
637   return NULL;\r
638 }\r
639 \r
640 \r
641 /**\r
642   Find the CacheEntry, using ProtocolAddress or HardwareAddress or both, as the keyword,\r
643   in the DeniedCacheTable.\r
644 \r
645   @param[in]  ArpService             Pointer to the arp service context data.\r
646   @param[in]  ProtocolAddress        Pointer to the protocol address.\r
647   @param[in]  HardwareAddress        Pointer to the hardware address.\r
648 \r
649   @return Pointer to the matched cache entry, if NULL no match is found.\r
650 \r
651 **/\r
652 ARP_CACHE_ENTRY *\r
653 ArpFindDeniedCacheEntry (\r
654   IN ARP_SERVICE_DATA  *ArpService,\r
655   IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,\r
656   IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL\r
657   )\r
658 {\r
659   ARP_CACHE_ENTRY  *CacheEntry;\r
660 \r
661   ASSERT ((ProtocolAddress != NULL) || (HardwareAddress != NULL));\r
662   NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);\r
663 \r
664   CacheEntry = NULL;\r
665 \r
666   if ((ProtocolAddress != NULL) && (ProtocolAddress->AddressPtr != NULL)) {\r
667     //\r
668     // Find the cache entry in the DeniedCacheTable by the protocol address.\r
669     //\r
670     CacheEntry = ArpFindNextCacheEntryInTable (\r
671                    &ArpService->DeniedCacheTable,\r
672                    NULL,\r
673                    ByProtoAddress,\r
674                    ProtocolAddress,\r
675                    NULL\r
676                    );\r
677     if (CacheEntry != NULL) {\r
678       //\r
679       // There is a match.\r
680       //\r
681       return CacheEntry;\r
682     }\r
683   }\r
684 \r
685   if ((HardwareAddress != NULL) && (HardwareAddress->AddressPtr != NULL)) {\r
686     //\r
687     // Find the cache entry in the DeniedCacheTable by the hardware address.\r
688     //\r
689     CacheEntry = ArpFindNextCacheEntryInTable (\r
690                    &ArpService->DeniedCacheTable,\r
691                    NULL,\r
692                    ByHwAddress,\r
693                    NULL,\r
694                    HardwareAddress\r
695                    );\r
696   }\r
697 \r
698   return CacheEntry;\r
699 }\r
700 \r
701 \r
702 /**\r
703   Allocate a cache entry and initialize it.\r
704 \r
705   @param[in]  Instance               Pointer to the instance context data.\r
706 \r
707   @return Pointer to the new created cache entry.\r
708 \r
709 **/\r
710 ARP_CACHE_ENTRY *\r
711 ArpAllocCacheEntry (\r
712   IN ARP_INSTANCE_DATA  *Instance\r
713   )\r
714 {\r
715   ARP_CACHE_ENTRY  *CacheEntry;\r
716   NET_ARP_ADDRESS  *Address;\r
717   UINT16           Index;\r
718 \r
719   //\r
720   // Allocate memory for the cache entry.\r
721   //\r
722   CacheEntry = AllocatePool (sizeof (ARP_CACHE_ENTRY));\r
723   if (CacheEntry == NULL) {\r
724     return NULL;\r
725   }\r
726 \r
727   //\r
728   // Init the lists.\r
729   //\r
730   InitializeListHead (&CacheEntry->List);\r
731   InitializeListHead (&CacheEntry->UserRequestList);\r
732 \r
733   for (Index = 0; Index < 2; Index++) {\r
734     //\r
735     // Init the address pointers to point to the concrete buffer.\r
736     //\r
737     Address = &CacheEntry->Addresses[Index];\r
738     Address->AddressPtr = Address->Buffer.ProtoAddress;\r
739   }\r
740 \r
741   //\r
742   // Zero the hardware address first.\r
743   //\r
744   ZeroMem (CacheEntry->Addresses[Hardware].AddressPtr, ARP_MAX_HARDWARE_ADDRESS_LEN);\r
745 \r
746   if (Instance != NULL) {\r
747     //\r
748     // Inherit the parameters from the instance configuration.\r
749     //\r
750     CacheEntry->RetryCount       = Instance->ConfigData.RetryCount;\r
751     CacheEntry->NextRetryTime    = Instance->ConfigData.RetryTimeOut;\r
752     CacheEntry->DefaultDecayTime = Instance->ConfigData.EntryTimeOut;\r
753     CacheEntry->DecayTime        = Instance->ConfigData.EntryTimeOut;\r
754   } else {\r
755     //\r
756     // Use the default parameters if this cache entry isn't allocate in a\r
757     // instance's  scope.\r
758     //\r
759     CacheEntry->RetryCount       = ARP_DEFAULT_RETRY_COUNT;\r
760     CacheEntry->NextRetryTime    = ARP_DEFAULT_RETRY_INTERVAL;\r
761     CacheEntry->DefaultDecayTime = ARP_DEFAULT_TIMEOUT_VALUE;\r
762     CacheEntry->DecayTime        = ARP_DEFAULT_TIMEOUT_VALUE;\r
763   }\r
764 \r
765   return CacheEntry;\r
766 }\r
767 \r
768 \r
769 /**\r
770   Turn the CacheEntry into the resolved status.\r
771 \r
772   @param[in]  CacheEntry             Pointer to the resolved cache entry.\r
773   @param[in]  Instance               Pointer to the instance context data.\r
774   @param[in]  UserEvent              Pointer to the UserEvent to notify.\r
775 \r
776   @return The count of notifications sent to the instance.\r
777 \r
778 **/\r
779 UINTN\r
780 ArpAddressResolved (\r
781   IN ARP_CACHE_ENTRY    *CacheEntry,\r
782   IN ARP_INSTANCE_DATA  *Instance OPTIONAL,\r
783   IN EFI_EVENT          UserEvent OPTIONAL\r
784   )\r
785 {\r
786   LIST_ENTRY            *Entry;\r
787   LIST_ENTRY            *NextEntry;\r
788   USER_REQUEST_CONTEXT  *Context;\r
789   UINTN                 Count;\r
790 \r
791   Count = 0;\r
792 \r
793   //\r
794   // Iterate all the linked user requests to notify them.\r
795   //\r
796   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &CacheEntry->UserRequestList) {\r
797     Context = NET_LIST_USER_STRUCT (Entry, USER_REQUEST_CONTEXT, List);\r
798 \r
799     if (((Instance == NULL) || (Context->Instance == Instance)) &&\r
800       ((UserEvent == NULL) || (Context->UserRequestEvent == UserEvent))) {\r
801       //\r
802       // Copy the address to the user-provided buffer and notify the user.\r
803       //\r
804       CopyMem (\r
805         Context->UserHwAddrBuffer,\r
806         CacheEntry->Addresses[Hardware].AddressPtr,\r
807         CacheEntry->Addresses[Hardware].Length\r
808         );\r
809       gBS->SignalEvent (Context->UserRequestEvent);\r
810 \r
811       //\r
812       // Remove this user request and free the context data.\r
813       //\r
814       RemoveEntryList (&Context->List);\r
815       FreePool (Context);\r
816 \r
817       Count++;\r
818     }\r
819   }\r
820 \r
821   //\r
822   // Dispatch the DPCs queued by the NotifyFunction of the Context->UserRequestEvent.\r
823   //\r
824   DispatchDpc ();\r
825 \r
826   return Count;\r
827 }\r
828 \r
829 \r
830 /**\r
831   Fill the addresses in the CacheEntry using the information passed in by\r
832   HwAddr and SwAddr.\r
833 \r
834   @param[in]  CacheEntry             Pointer to the cache entry.\r
835   @param[in]  HwAddr                 Pointer to the software address.\r
836   @param[in]  SwAddr                 Pointer to the hardware address.\r
837 \r
838   @return None.\r
839 \r
840 **/\r
841 VOID\r
842 ArpFillAddressInCacheEntry (\r
843   IN ARP_CACHE_ENTRY  *CacheEntry,\r
844   IN NET_ARP_ADDRESS  *HwAddr OPTIONAL,\r
845   IN NET_ARP_ADDRESS  *SwAddr OPTIONAL\r
846   )\r
847 {\r
848   NET_ARP_ADDRESS  *Address[2];\r
849   NET_ARP_ADDRESS  *CacheAddress;\r
850   UINT32           Index;\r
851 \r
852   Address[Hardware] = HwAddr;\r
853   Address[Protocol] = SwAddr;\r
854 \r
855   for (Index = 0; Index < 2; Index++) {\r
856     if (Address[Index] != NULL) {\r
857       //\r
858       // Fill the address if the passed in pointer is not NULL.\r
859       //\r
860       CacheAddress = &CacheEntry->Addresses[Index];\r
861 \r
862       CacheAddress->Type   = Address[Index]->Type;\r
863       CacheAddress->Length = Address[Index]->Length;\r
864 \r
865       if (Address[Index]->AddressPtr != NULL) {\r
866         //\r
867         // Copy it if the AddressPtr points to some buffer.\r
868         //\r
869         CopyMem (\r
870           CacheAddress->AddressPtr,\r
871           Address[Index]->AddressPtr,\r
872           CacheAddress->Length\r
873           );\r
874       } else {\r
875         //\r
876         // Zero the corresponding address buffer in the CacheEntry.\r
877         //\r
878         ZeroMem (CacheAddress->AddressPtr, CacheAddress->Length);\r
879       }\r
880     }\r
881   }\r
882 }\r
883 \r
884 \r
885 /**\r
886   Configure the instance using the ConfigData. ConfigData is already validated.\r
887 \r
888   @param[in]  Instance           Pointer to the instance context data to be\r
889                                  configured.\r
890   @param[in]  ConfigData         Pointer to the configuration data used to\r
891                                  configure the instance.\r
892 \r
893   @retval EFI_SUCCESS            The instance is configured with the ConfigData.\r
894   @retval EFI_ACCESS_DENIED      The instance is already configured and the\r
895                                  ConfigData tries to reset some unchangeable\r
896                                  fields.\r
897   @retval EFI_INVALID_PARAMETER  The ConfigData provides a non-unicast IPv4 address\r
898                                  when the SwAddressType is IPv4.\r
899   @retval EFI_OUT_OF_RESOURCES   The instance fails to configure due to memory\r
900                                  limitation.\r
901 \r
902 **/\r
903 EFI_STATUS\r
904 ArpConfigureInstance (\r
905   IN ARP_INSTANCE_DATA    *Instance,\r
906   IN EFI_ARP_CONFIG_DATA  *ConfigData OPTIONAL\r
907   )\r
908 {\r
909   EFI_ARP_CONFIG_DATA  *OldConfigData;\r
910   IP4_ADDR             Ip;\r
911 \r
912   OldConfigData = &Instance->ConfigData;\r
913 \r
914   if (ConfigData != NULL) {\r
915 \r
916     if (Instance->Configured) {\r
917       //\r
918       // The instance is configured, check the unchangeable fields.\r
919       //\r
920       if ((OldConfigData->SwAddressType != ConfigData->SwAddressType) ||\r
921         (OldConfigData->SwAddressLength != ConfigData->SwAddressLength) ||\r
922         (CompareMem (\r
923            OldConfigData->StationAddress,\r
924            ConfigData->StationAddress,\r
925            OldConfigData->SwAddressLength\r
926            ) != 0)) {\r
927         //\r
928         // Deny the unallowed changes.\r
929         //\r
930         return EFI_ACCESS_DENIED;\r
931       }\r
932     } else {\r
933       //\r
934       // The instance is not configured.\r
935       //\r
936 \r
937       if (ConfigData->SwAddressType == IPV4_ETHER_PROTO_TYPE) {\r
938         CopyMem (&Ip, ConfigData->StationAddress, sizeof (IP4_ADDR));\r
939 \r
940         if (IP4_IS_UNSPECIFIED (Ip) || IP4_IS_LOCAL_BROADCAST (Ip)) {\r
941           //\r
942           // The station address should not be zero or broadcast address.\r
943           //\r
944           return EFI_INVALID_PARAMETER;\r
945         }\r
946       }\r
947 \r
948       //\r
949       // Save the configuration.\r
950       //\r
951       CopyMem (OldConfigData, ConfigData, sizeof (*OldConfigData));\r
952 \r
953       OldConfigData->StationAddress = AllocatePool (OldConfigData->SwAddressLength);\r
954       if (OldConfigData->StationAddress == NULL) {\r
955         DEBUG ((EFI_D_ERROR, "ArpConfigInstance: AllocatePool for the StationAddress "\r
956           "failed.\n"));\r
957         return EFI_OUT_OF_RESOURCES;\r
958       }\r
959 \r
960       //\r
961       // Save the StationAddress.\r
962       //\r
963       CopyMem (\r
964         OldConfigData->StationAddress,\r
965         ConfigData->StationAddress,\r
966         OldConfigData->SwAddressLength\r
967         );\r
968 \r
969       //\r
970       // Set the state to configured.\r
971       //\r
972       Instance->Configured = TRUE;\r
973     }\r
974 \r
975     //\r
976     // Use the implementation specific values if the following field is zero.\r
977     //\r
978     OldConfigData->EntryTimeOut = (ConfigData->EntryTimeOut == 0) ?\r
979       ARP_DEFAULT_TIMEOUT_VALUE : ConfigData->EntryTimeOut;\r
980 \r
981     OldConfigData->RetryCount   = (ConfigData->RetryCount == 0) ?\r
982       ARP_DEFAULT_RETRY_COUNT : ConfigData->RetryCount;\r
983 \r
984     OldConfigData->RetryTimeOut = (ConfigData->RetryTimeOut == 0) ?\r
985       ARP_DEFAULT_RETRY_INTERVAL : ConfigData->RetryTimeOut;\r
986   } else {\r
987     //\r
988     // Reset the configuration.\r
989     //\r
990 \r
991     if (Instance->Configured) {\r
992       //\r
993       // Cancel the arp requests issued by this instance.\r
994       //\r
995       Instance->ArpProto.Cancel (&Instance->ArpProto, NULL, NULL);\r
996 \r
997       //\r
998       // Free the buffer previously allocated to hold the station address.\r
999       //\r
1000       FreePool (OldConfigData->StationAddress);\r
1001     }\r
1002 \r
1003     Instance->Configured = FALSE;\r
1004   }\r
1005 \r
1006   return EFI_SUCCESS;\r
1007 }\r
1008 \r
1009 \r
1010 /**\r
1011   Send out an arp frame using the CachEntry and the ArpOpCode.\r
1012 \r
1013   @param[in]  Instance               Pointer to the instance context data.\r
1014   @param[in]  CacheEntry             Pointer to the configuration data used to\r
1015                                      configure the instance.\r
1016   @param[in]  ArpOpCode              The opcode used to send out this Arp frame, either\r
1017                                      request or reply.\r
1018 \r
1019   @return None.\r
1020 \r
1021 **/\r
1022 VOID\r
1023 ArpSendFrame (\r
1024   IN ARP_INSTANCE_DATA  *Instance,\r
1025   IN ARP_CACHE_ENTRY    *CacheEntry,\r
1026   IN UINT16             ArpOpCode\r
1027   )\r
1028 {\r
1029   EFI_STATUS                            Status;\r
1030   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TxToken;\r
1031   EFI_MANAGED_NETWORK_TRANSMIT_DATA     *TxData;\r
1032   UINT32                                TotalLength;\r
1033   UINT8                                 *Packet;\r
1034   ARP_SERVICE_DATA                      *ArpService;\r
1035   EFI_SIMPLE_NETWORK_MODE               *SnpMode;\r
1036   EFI_ARP_CONFIG_DATA                   *ConfigData;\r
1037   UINT8                                 *TmpPtr;\r
1038   ARP_HEAD                              *ArpHead;\r
1039 \r
1040   ASSERT ((Instance != NULL) && (CacheEntry != NULL));\r
1041 \r
1042   //\r
1043   // Allocate memory for the TxToken.\r
1044   //\r
1045   TxToken = AllocatePool (sizeof(EFI_MANAGED_NETWORK_COMPLETION_TOKEN));\r
1046   if (TxToken == NULL) {\r
1047     DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxToken failed.\n"));\r
1048     return;\r
1049   }\r
1050 \r
1051   TxToken->Event = NULL;\r
1052   TxData         = NULL;\r
1053   Packet         = NULL;\r
1054 \r
1055   //\r
1056   // Create the event for this TxToken.\r
1057   //\r
1058   Status = gBS->CreateEvent (\r
1059                   EVT_NOTIFY_SIGNAL,\r
1060                   TPL_NOTIFY,\r
1061                   ArpOnFrameSent,\r
1062                   (VOID *)TxToken,\r
1063                   &TxToken->Event\r
1064                   );\r
1065   if (EFI_ERROR (Status)) {\r
1066     DEBUG ((EFI_D_ERROR, "ArpSendFrame: CreateEvent failed for TxToken->Event.\n"));\r
1067     goto CLEAN_EXIT;\r
1068   }\r
1069 \r
1070   //\r
1071   // Allocate memory for the TxData used in the TxToken.\r
1072   //\r
1073   TxData = AllocatePool (sizeof(EFI_MANAGED_NETWORK_TRANSMIT_DATA));\r
1074   if (TxData == NULL) {\r
1075     DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxData failed.\n"));\r
1076     goto CLEAN_EXIT;\r
1077   }\r
1078 \r
1079   ArpService = Instance->ArpService;\r
1080   SnpMode    = &ArpService->SnpMode;\r
1081   ConfigData = &Instance->ConfigData;\r
1082 \r
1083   //\r
1084   // Calculate the buffer length for this arp frame.\r
1085   //\r
1086   TotalLength = SnpMode->MediaHeaderSize + sizeof (ARP_HEAD) +\r
1087                 2 * (ConfigData->SwAddressLength + SnpMode->HwAddressSize);\r
1088 \r
1089   //\r
1090   // Allocate buffer for the arp frame.\r
1091   //\r
1092   Packet = AllocatePool (TotalLength);\r
1093   if (Packet == NULL) {\r
1094     DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for Packet failed.\n"));\r
1095     ASSERT (Packet != NULL);\r
1096   }\r
1097 \r
1098   TmpPtr = Packet;\r
1099 \r
1100   //\r
1101   // The destination MAC address.\r
1102   //\r
1103   if (ArpOpCode == ARP_OPCODE_REQUEST) {\r
1104     CopyMem (TmpPtr, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);\r
1105   } else {\r
1106     CopyMem (\r
1107       TmpPtr,\r
1108       CacheEntry->Addresses[Hardware].AddressPtr,\r
1109       SnpMode->HwAddressSize\r
1110       );\r
1111   }\r
1112   TmpPtr += SnpMode->HwAddressSize;\r
1113 \r
1114   //\r
1115   // The source MAC address.\r
1116   //\r
1117   CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);\r
1118   TmpPtr += SnpMode->HwAddressSize;\r
1119 \r
1120   //\r
1121   // The ethernet protocol type.\r
1122   //\r
1123   *(UINT16 *)TmpPtr = HTONS (ARP_ETHER_PROTO_TYPE);\r
1124   TmpPtr            += 2;\r
1125 \r
1126   //\r
1127   // The ARP Head.\r
1128   //\r
1129   ArpHead               = (ARP_HEAD *) TmpPtr;\r
1130   ArpHead->HwType       = HTONS ((UINT16)SnpMode->IfType);\r
1131   ArpHead->ProtoType    = HTONS (ConfigData->SwAddressType);\r
1132   ArpHead->HwAddrLen    = (UINT8)SnpMode->HwAddressSize;\r
1133   ArpHead->ProtoAddrLen = ConfigData->SwAddressLength;\r
1134   ArpHead->OpCode       = HTONS (ArpOpCode);\r
1135   TmpPtr                += sizeof (ARP_HEAD);\r
1136 \r
1137   //\r
1138   // The sender hardware address.\r
1139   //\r
1140   CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);\r
1141   TmpPtr += SnpMode->HwAddressSize;\r
1142 \r
1143   //\r
1144   // The sender protocol address.\r
1145   //\r
1146   CopyMem (TmpPtr, ConfigData->StationAddress, ConfigData->SwAddressLength);\r
1147   TmpPtr += ConfigData->SwAddressLength;\r
1148 \r
1149   //\r
1150   // The target hardware address.\r
1151   //\r
1152   CopyMem (\r
1153     TmpPtr,\r
1154     CacheEntry->Addresses[Hardware].AddressPtr,\r
1155     SnpMode->HwAddressSize\r
1156     );\r
1157   TmpPtr += SnpMode->HwAddressSize;\r
1158 \r
1159   //\r
1160   // The target protocol address.\r
1161   //\r
1162   CopyMem (\r
1163     TmpPtr,\r
1164     CacheEntry->Addresses[Protocol].AddressPtr,\r
1165     ConfigData->SwAddressLength\r
1166     );\r
1167 \r
1168   //\r
1169   // Set all the fields of the TxData.\r
1170   //\r
1171   TxData->DestinationAddress = NULL;\r
1172   TxData->SourceAddress      = NULL;\r
1173   TxData->ProtocolType       = 0;\r
1174   TxData->DataLength         = TotalLength - SnpMode->MediaHeaderSize;\r
1175   TxData->HeaderLength       = (UINT16) SnpMode->MediaHeaderSize;\r
1176   TxData->FragmentCount      = 1;\r
1177 \r
1178   TxData->FragmentTable[0].FragmentBuffer = Packet;\r
1179   TxData->FragmentTable[0].FragmentLength = TotalLength;\r
1180 \r
1181   //\r
1182   // Associate the TxData with the TxToken.\r
1183   //\r
1184   TxToken->Packet.TxData = TxData;\r
1185   TxToken->Status        = EFI_NOT_READY;\r
1186 \r
1187   //\r
1188   // Send out this arp packet by Mnp.\r
1189   //\r
1190   Status = ArpService->Mnp->Transmit (ArpService->Mnp, TxToken);\r
1191   if (EFI_ERROR (Status)) {\r
1192     DEBUG ((EFI_D_ERROR, "Mnp->Transmit failed, %r.\n", Status));\r
1193     goto CLEAN_EXIT;\r
1194   }\r
1195 \r
1196   return;\r
1197 \r
1198 CLEAN_EXIT:\r
1199 \r
1200   if (Packet != NULL) {\r
1201     FreePool (Packet);\r
1202   }\r
1203 \r
1204   if (TxData != NULL) {\r
1205     FreePool (TxData);\r
1206   }\r
1207 \r
1208   if (TxToken->Event != NULL) {\r
1209     gBS->CloseEvent (TxToken->Event);\r
1210   }\r
1211 \r
1212   FreePool (TxToken);\r
1213 }\r
1214 \r
1215 \r
1216 /**\r
1217   Delete the cache entries in the specified CacheTable, using the BySwAddress,\r
1218   SwAddressType, AddressBuffer combination as the matching key, if Force is TRUE,\r
1219   the cache is deleted event it's a static entry.\r
1220 \r
1221   @param[in]  CacheTable             Pointer to the cache table to do the deletion.\r
1222   @param[in]  BySwAddress            Delete the cache entry by software address or by\r
1223                                      hardware address.\r
1224   @param[in]  SwAddressType          The software address used to do the deletion.\r
1225   @param[in]  AddressBuffer          Pointer to the buffer containing the address to\r
1226                                      match for the deletion.\r
1227   @param[in]  Force                  This deletion is forced or not.\r
1228 \r
1229   @return The count of the deleted cache entries.\r
1230 \r
1231 **/\r
1232 UINTN\r
1233 ArpDeleteCacheEntryInTable (\r
1234   IN LIST_ENTRY      *CacheTable,\r
1235   IN BOOLEAN         BySwAddress,\r
1236   IN UINT16          SwAddressType,\r
1237   IN UINT8           *AddressBuffer OPTIONAL,\r
1238   IN BOOLEAN         Force\r
1239   )\r
1240 {\r
1241   LIST_ENTRY       *Entry;\r
1242   LIST_ENTRY       *NextEntry;\r
1243   ARP_CACHE_ENTRY  *CacheEntry;\r
1244   UINTN            Count;\r
1245 \r
1246   Count = 0;\r
1247 \r
1248   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, CacheTable) {\r
1249     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
1250 \r
1251     if ((CacheEntry->DefaultDecayTime == 0) && !Force) {\r
1252       //\r
1253       // It's a static entry and we are not forced to delete it, skip.\r
1254       //\r
1255       continue;\r
1256     }\r
1257 \r
1258     if (BySwAddress) {\r
1259       if (SwAddressType == CacheEntry->Addresses[Protocol].Type) {\r
1260         //\r
1261         // Protocol address type matched. Check the address.\r
1262         //\r
1263         if ((AddressBuffer == NULL) ||\r
1264           (CompareMem (\r
1265              AddressBuffer,\r
1266              CacheEntry->Addresses[Protocol].AddressPtr,\r
1267              CacheEntry->Addresses[Protocol].Length\r
1268              ) == 0)) {\r
1269           //\r
1270           // Address matched.\r
1271           //\r
1272           goto MATCHED;\r
1273         }\r
1274       }\r
1275     } else {\r
1276       if ((AddressBuffer == NULL) ||\r
1277         (CompareMem (\r
1278            AddressBuffer,\r
1279            CacheEntry->Addresses[Hardware].AddressPtr,\r
1280            CacheEntry->Addresses[Hardware].Length\r
1281            ) == 0)) {\r
1282         //\r
1283         // Address matched.\r
1284         //\r
1285         goto MATCHED;\r
1286       }\r
1287     }\r
1288 \r
1289     continue;\r
1290 \r
1291 MATCHED:\r
1292 \r
1293     //\r
1294     // Delete this entry.\r
1295     //\r
1296     RemoveEntryList (&CacheEntry->List);\r
1297     ASSERT (IsListEmpty (&CacheEntry->UserRequestList));\r
1298     FreePool (CacheEntry);\r
1299 \r
1300     Count++;\r
1301   }\r
1302 \r
1303   return Count;\r
1304 }\r
1305 \r
1306 \r
1307 /**\r
1308   Delete cache entries in all the cache tables.\r
1309 \r
1310   @param[in]  Instance               Pointer to the instance context data.\r
1311   @param[in]  BySwAddress            Delete the cache entry by software address or by\r
1312                                      hardware address.\r
1313   @param[in]  AddressBuffer          Pointer to the buffer containing the address to\r
1314                                      match for the deletion.\r
1315   @param[in]  Force                  This deletion is forced or not.\r
1316 \r
1317   @return The count of the deleted cache entries.\r
1318 \r
1319 **/\r
1320 UINTN\r
1321 ArpDeleteCacheEntry (\r
1322   IN ARP_INSTANCE_DATA  *Instance,\r
1323   IN BOOLEAN            BySwAddress,\r
1324   IN UINT8              *AddressBuffer OPTIONAL,\r
1325   IN BOOLEAN            Force\r
1326   )\r
1327 {\r
1328   ARP_SERVICE_DATA  *ArpService;\r
1329   UINTN             Count;\r
1330 \r
1331   NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);\r
1332 \r
1333   ArpService = Instance->ArpService;\r
1334 \r
1335   //\r
1336   // Delete the cache entries in the DeniedCacheTable.\r
1337   //\r
1338   Count = ArpDeleteCacheEntryInTable (\r
1339             &ArpService->DeniedCacheTable,\r
1340             BySwAddress,\r
1341             Instance->ConfigData.SwAddressType,\r
1342             AddressBuffer,\r
1343             Force\r
1344             );\r
1345 \r
1346   //\r
1347   // Delete the cache entries inthe ResolvedCacheTable.\r
1348   //\r
1349   Count += ArpDeleteCacheEntryInTable (\r
1350              &ArpService->ResolvedCacheTable,\r
1351              BySwAddress,\r
1352              Instance->ConfigData.SwAddressType,\r
1353              AddressBuffer,\r
1354              Force\r
1355              );\r
1356 \r
1357   return Count;\r
1358 }\r
1359 \r
1360 \r
1361 /**\r
1362   Cancel the arp request.\r
1363 \r
1364   @param[in]  Instance               Pointer to the instance context data.\r
1365   @param[in]  TargetSwAddress        Pointer to the buffer containing the target\r
1366                                      software address to match the arp request.\r
1367   @param[in]  UserEvent              The user event used to notify this request\r
1368                                      cancellation.\r
1369 \r
1370   @return The count of the cancelled requests.\r
1371 \r
1372 **/\r
1373 UINTN\r
1374 ArpCancelRequest (\r
1375   IN ARP_INSTANCE_DATA  *Instance,\r
1376   IN VOID               *TargetSwAddress OPTIONAL,\r
1377   IN EFI_EVENT          UserEvent        OPTIONAL\r
1378   )\r
1379 {\r
1380   ARP_SERVICE_DATA  *ArpService;\r
1381   LIST_ENTRY        *Entry;\r
1382   LIST_ENTRY        *NextEntry;\r
1383   ARP_CACHE_ENTRY   *CacheEntry;\r
1384   UINTN             Count;\r
1385 \r
1386   NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);\r
1387 \r
1388   ArpService = Instance->ArpService;\r
1389 \r
1390   Count = 0;\r
1391   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {\r
1392     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
1393 \r
1394     if ((TargetSwAddress == NULL) ||\r
1395       (CompareMem (\r
1396          TargetSwAddress,\r
1397          CacheEntry->Addresses[Protocol].AddressPtr,\r
1398          CacheEntry->Addresses[Protocol].Length\r
1399          ) == 0)) {\r
1400       //\r
1401       // This request entry matches the TargetSwAddress or all requests are to be\r
1402       // cancelled as TargetSwAddress is NULL.\r
1403       //\r
1404       Count += ArpAddressResolved (CacheEntry, Instance, UserEvent);\r
1405 \r
1406       if (IsListEmpty (&CacheEntry->UserRequestList)) {\r
1407         //\r
1408         // No user requests any more, remove this request cache entry.\r
1409         //\r
1410         RemoveEntryList (&CacheEntry->List);\r
1411         FreePool (CacheEntry);\r
1412       }\r
1413     }\r
1414   }\r
1415 \r
1416   return Count;\r
1417 }\r
1418 \r
1419 \r
1420 /**\r
1421   Find the cache entry in the cache table.\r
1422 \r
1423   @param[in]  Instance           Pointer to the instance context data.\r
1424   @param[in]  BySwAddress        Set to TRUE to look for matching software protocol\r
1425                                  addresses. Set to FALSE to look for matching\r
1426                                  hardware protocol addresses.\r
1427   @param[in]  AddressBuffer      Pointer to address buffer. Set to NULL to match\r
1428                                  all addresses.\r
1429   @param[out] EntryLength        The size of an entry in the entries buffer.\r
1430   @param[out] EntryCount         The number of ARP cache entries that are found by\r
1431                                  the specified criteria.\r
1432   @param[out] Entries            Pointer to the buffer that will receive the ARP\r
1433                                  cache entries.\r
1434   @param[in]  Refresh            Set to TRUE to refresh the timeout value of the\r
1435                                  matching ARP cache entry.\r
1436 \r
1437   @retval EFI_SUCCESS            The requested ARP cache entries are copied into\r
1438                                  the buffer.\r
1439   @retval EFI_NOT_FOUND          No matching entries found.\r
1440   @retval EFI_OUT_OF_RESOURCE    There is a memory allocation failure.\r
1441 \r
1442 **/\r
1443 EFI_STATUS\r
1444 ArpFindCacheEntry (\r
1445   IN ARP_INSTANCE_DATA   *Instance,\r
1446   IN BOOLEAN             BySwAddress,\r
1447   IN VOID                *AddressBuffer OPTIONAL,\r
1448   OUT UINT32             *EntryLength   OPTIONAL,\r
1449   OUT UINT32             *EntryCount    OPTIONAL,\r
1450   OUT EFI_ARP_FIND_DATA  **Entries      OPTIONAL,\r
1451   IN BOOLEAN             Refresh\r
1452   )\r
1453 {\r
1454   EFI_STATUS         Status;\r
1455   ARP_SERVICE_DATA   *ArpService;\r
1456   NET_ARP_ADDRESS    MatchAddress;\r
1457   FIND_OPTYPE        FindOpType;\r
1458   LIST_ENTRY         *StartEntry;\r
1459   ARP_CACHE_ENTRY    *CacheEntry;\r
1460   NET_MAP            FoundEntries;\r
1461   UINT32             FoundCount;\r
1462   EFI_ARP_FIND_DATA  *FindData;\r
1463   LIST_ENTRY         *CacheTable;\r
1464   UINT32             FoundEntryLength;\r
1465 \r
1466   ArpService = Instance->ArpService;\r
1467 \r
1468   //\r
1469   // Init the FounEntries used to hold the found cache entries.\r
1470   //\r
1471   NetMapInit (&FoundEntries);\r
1472 \r
1473   //\r
1474   // Set the MatchAddress.\r
1475   //\r
1476   if (BySwAddress) {\r
1477     MatchAddress.Type   = Instance->ConfigData.SwAddressType;\r
1478     MatchAddress.Length = Instance->ConfigData.SwAddressLength;\r
1479     FindOpType          = ByProtoAddress;\r
1480   } else {\r
1481     MatchAddress.Type   = ArpService->SnpMode.IfType;\r
1482     MatchAddress.Length = (UINT8)ArpService->SnpMode.HwAddressSize;\r
1483     FindOpType          = ByHwAddress;\r
1484   }\r
1485 \r
1486   MatchAddress.AddressPtr = AddressBuffer;\r
1487 \r
1488   //\r
1489   // Search the DeniedCacheTable\r
1490   //\r
1491   StartEntry = NULL;\r
1492   while (TRUE) {\r
1493     //\r
1494     // Try to find the matched entries in the DeniedCacheTable.\r
1495     //\r
1496     CacheEntry = ArpFindNextCacheEntryInTable (\r
1497                    &ArpService->DeniedCacheTable,\r
1498                    StartEntry,\r
1499                    FindOpType,\r
1500                    &MatchAddress,\r
1501                    &MatchAddress\r
1502                    );\r
1503     if (CacheEntry == NULL) {\r
1504       //\r
1505       // Once the CacheEntry is NULL, there are no more matches.\r
1506       //\r
1507       break;\r
1508     }\r
1509 \r
1510     //\r
1511     // Insert the found entry into the map.\r
1512     //\r
1513     NetMapInsertTail (\r
1514       &FoundEntries,\r
1515       (VOID *)CacheEntry,\r
1516       (VOID *)&ArpService->DeniedCacheTable\r
1517       );\r
1518 \r
1519     //\r
1520     // Let the next search start from this cache entry.\r
1521     //\r
1522     StartEntry = &CacheEntry->List;\r
1523 \r
1524     if (Refresh) {\r
1525       //\r
1526       // Refresh the DecayTime if needed.\r
1527       //\r
1528       CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;\r
1529     }\r
1530   }\r
1531 \r
1532   //\r
1533   // Search the ResolvedCacheTable\r
1534   //\r
1535   StartEntry = NULL;\r
1536   while (TRUE) {\r
1537     CacheEntry = ArpFindNextCacheEntryInTable (\r
1538                    &ArpService->ResolvedCacheTable,\r
1539                    StartEntry,\r
1540                    FindOpType,\r
1541                    &MatchAddress,\r
1542                    &MatchAddress\r
1543                    );\r
1544     if (CacheEntry == NULL) {\r
1545       //\r
1546       // Once the CacheEntry is NULL, there are no more matches.\r
1547       //\r
1548       break;\r
1549     }\r
1550 \r
1551     //\r
1552     // Insert the found entry into the map.\r
1553     //\r
1554     NetMapInsertTail (\r
1555       &FoundEntries,\r
1556       (VOID *)CacheEntry,\r
1557       (VOID *)&ArpService->ResolvedCacheTable\r
1558       );\r
1559 \r
1560     //\r
1561     // Let the next search start from this cache entry.\r
1562     //\r
1563     StartEntry = &CacheEntry->List;\r
1564 \r
1565     if (Refresh) {\r
1566       //\r
1567       // Refresh the DecayTime if needed.\r
1568       //\r
1569       CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;\r
1570     }\r
1571   }\r
1572 \r
1573   Status = EFI_SUCCESS;\r
1574 \r
1575   FoundCount = (UINT32) NetMapGetCount (&FoundEntries);\r
1576   if (FoundCount == 0) {\r
1577     Status = EFI_NOT_FOUND;\r
1578     goto CLEAN_EXIT;\r
1579   }\r
1580 \r
1581   //\r
1582   // Found the entry length, make sure its 8 bytes alignment.\r
1583   //\r
1584   FoundEntryLength = (((sizeof (EFI_ARP_FIND_DATA) + Instance->ConfigData.SwAddressLength +\r
1585                        ArpService->SnpMode.HwAddressSize) + 3) & ~(0x3));\r
1586 \r
1587   if (EntryLength != NULL) {\r
1588     *EntryLength = FoundEntryLength;\r
1589   }\r
1590 \r
1591   if (EntryCount != NULL) {\r
1592     //\r
1593     // Return the found entry count.\r
1594     //\r
1595     *EntryCount = FoundCount;\r
1596   }\r
1597 \r
1598   if (Entries == NULL) {\r
1599     goto CLEAN_EXIT;\r
1600   }\r
1601 \r
1602   //\r
1603   // Allocate buffer to copy the found entries.\r
1604   //\r
1605   FindData = AllocatePool (FoundCount * FoundEntryLength);\r
1606   if (FindData == NULL) {\r
1607     DEBUG ((EFI_D_ERROR, "ArpFindCacheEntry: Failed to allocate memory.\n"));\r
1608     Status = EFI_OUT_OF_RESOURCES;\r
1609     goto CLEAN_EXIT;\r
1610   }\r
1611 \r
1612   //\r
1613   // Return the address to the user.\r
1614   //\r
1615   *Entries = FindData;\r
1616 \r
1617   //\r
1618   // Dump the entries.\r
1619   //\r
1620   while (!NetMapIsEmpty (&FoundEntries)) {\r
1621     //\r
1622     // Get a cache entry from the map.\r
1623     //\r
1624     CacheEntry = NetMapRemoveHead (&FoundEntries, (VOID **)&CacheTable);\r
1625 \r
1626     //\r
1627     // Set the fields in FindData.\r
1628     //\r
1629     FindData->Size            = FoundEntryLength;\r
1630     FindData->DenyFlag        = (BOOLEAN)(CacheTable == &ArpService->DeniedCacheTable);\r
1631     FindData->StaticFlag      = (BOOLEAN)(CacheEntry->DefaultDecayTime == 0);\r
1632     FindData->HwAddressType   = ArpService->SnpMode.IfType;\r
1633     FindData->SwAddressType   = Instance->ConfigData.SwAddressType;\r
1634     FindData->HwAddressLength = (UINT8)ArpService->SnpMode.HwAddressSize;\r
1635     FindData->SwAddressLength = Instance->ConfigData.SwAddressLength;\r
1636 \r
1637     //\r
1638     // Copy the software address.\r
1639     //\r
1640     CopyMem (\r
1641       FindData + 1,\r
1642       CacheEntry->Addresses[Protocol].AddressPtr,\r
1643       FindData->SwAddressLength\r
1644       );\r
1645 \r
1646     //\r
1647     // Copy the hardware address.\r
1648     //\r
1649     CopyMem (\r
1650       (UINT8 *)(FindData + 1) + FindData->SwAddressLength,\r
1651       CacheEntry->Addresses[Hardware].AddressPtr,\r
1652       FindData->HwAddressLength\r
1653       );\r
1654 \r
1655     //\r
1656     // Slip to the next FindData.\r
1657     //\r
1658     FindData = (EFI_ARP_FIND_DATA *)((UINT8 *)FindData + FoundEntryLength);\r
1659   }\r
1660 \r
1661 CLEAN_EXIT:\r
1662 \r
1663   NetMapClean (&FoundEntries);\r
1664 \r
1665   return Status;\r
1666 }\r
1667 \r