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