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