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