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