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