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