]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/ArpDxe/ArpImpl.c
add security check.
[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
894d038a 4Copyright (c) 2006 - 2009, Intel Corporation.<BR>\r
772db4bb 5All rights reserved. This program and the accompanying materials\r
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
55 Instance->Destroyed = FALSE;\r
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
328 NetLibQueueDpc (TPL_CALLBACK, ArpOnFrameRcvdDpc, Context);\r
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
e48e37fc 363 gBS->FreePool (TxData->FragmentTable[0].FragmentBuffer);\r
364 gBS->FreePool (TxData);\r
772db4bb 365 gBS->CloseEvent (TxToken->Event);\r
e48e37fc 366 gBS->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
389 NetLibQueueDpc (TPL_CALLBACK, ArpOnFrameSentDpc, Context);\r
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
440 gBS->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
482 gBS->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
510 gBS->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
536 if ((AddressOne->Type != AddressTwo->Type) ||\r
537 (AddressOne->Length != AddressTwo->Length)) {\r
538 //\r
539 // Either Type or Length doesn't match.\r
540 //\r
541 return FALSE;\r
542 }\r
543\r
544 if ((AddressOne->AddressPtr != NULL) &&\r
e48e37fc 545 (CompareMem (\r
772db4bb 546 AddressOne->AddressPtr,\r
547 AddressTwo->AddressPtr,\r
548 AddressOne->Length\r
549 ) != 0)) {\r
550 //\r
551 // The address is not the same.\r
552 //\r
553 return FALSE;\r
554 }\r
555\r
556 return TRUE;\r
557}\r
558\r
559\r
560/**\r
561 Find the CacheEntry which matches the requirements in the specified CacheTable.\r
562\r
c6d0ee4b 563 @param[in] CacheTable Pointer to the arp cache table.\r
564 @param[in] StartEntry Pointer to the start entry this search begins with\r
565 in the cache table.\r
566 @param[in] FindOpType The search type.\r
567 @param[in] ProtocolAddress Pointer to the protocol address to match.\r
568 @param[in] HardwareAddress Pointer to the hardware address to match.\r
772db4bb 569\r
570 @return Pointer to the matched arp cache entry, if NULL, no match is found.\r
571\r
572**/\r
573ARP_CACHE_ENTRY *\r
574ArpFindNextCacheEntryInTable (\r
e48e37fc 575 IN LIST_ENTRY *CacheTable,\r
576 IN LIST_ENTRY *StartEntry,\r
772db4bb 577 IN FIND_OPTYPE FindOpType,\r
578 IN NET_ARP_ADDRESS *ProtocolAddress OPTIONAL,\r
579 IN NET_ARP_ADDRESS *HardwareAddress OPTIONAL\r
580 )\r
581{\r
e48e37fc 582 LIST_ENTRY *Entry;\r
772db4bb 583 ARP_CACHE_ENTRY *CacheEntry;\r
584\r
585 if (StartEntry == NULL) {\r
586 //\r
587 // Start from the beginning of the table if no StartEntry is specified.\r
588 //\r
589 StartEntry = CacheTable;\r
590 }\r
591\r
592 for (Entry = StartEntry->ForwardLink; Entry != CacheTable; Entry = Entry->ForwardLink) {\r
593 CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
594\r
7bce0c5a 595 if ((FindOpType & MATCH_SW_ADDRESS) != 0) {\r
772db4bb 596 //\r
597 // Find by the software address.\r
598 //\r
599 if (!ArpMatchAddress (ProtocolAddress, &CacheEntry->Addresses[Protocol])) {\r
600 //\r
601 // The ProtocolAddress doesn't match, continue to the next cache entry.\r
602 //\r
603 continue;\r
604 }\r
605 }\r
606\r
7bce0c5a 607 if ((FindOpType & MATCH_HW_ADDRESS) != 0) {\r
772db4bb 608 //\r
609 // Find by the hardware address.\r
610 //\r
611 if (!ArpMatchAddress (HardwareAddress, &CacheEntry->Addresses[Hardware])) {\r
612 //\r
613 // The HardwareAddress doesn't match, continue to the next cache entry.\r
614 //\r
615 continue;\r
616 }\r
617 }\r
618\r
619 //\r
620 // The CacheEntry meets the requirements now, return this entry.\r
621 //\r
622 return CacheEntry;\r
623 }\r
624\r
625 //\r
626 // No matching.\r
627 //\r
628 return NULL;\r
629}\r
630\r
631\r
632/**\r
633 Find the CacheEntry, using ProtocolAddress or HardwareAddress or both, as the keyword,\r
634 in the DeniedCacheTable.\r
635\r
c6d0ee4b 636 @param[in] ArpService Pointer to the arp service context data.\r
637 @param[in] ProtocolAddress Pointer to the protocol address.\r
638 @param[in] HardwareAddress Pointer to the hardware address.\r
772db4bb 639\r
640 @return Pointer to the matched cache entry, if NULL no match is found.\r
641\r
642**/\r
643ARP_CACHE_ENTRY *\r
644ArpFindDeniedCacheEntry (\r
645 IN ARP_SERVICE_DATA *ArpService,\r
646 IN NET_ARP_ADDRESS *ProtocolAddress OPTIONAL,\r
647 IN NET_ARP_ADDRESS *HardwareAddress OPTIONAL\r
648 )\r
649{\r
650 ARP_CACHE_ENTRY *CacheEntry;\r
651\r
652 ASSERT ((ProtocolAddress != NULL) || (HardwareAddress != NULL));\r
653 NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);\r
654\r
655 CacheEntry = NULL;\r
656\r
657 if ((ProtocolAddress != NULL) && (ProtocolAddress->AddressPtr != NULL)) {\r
658 //\r
659 // Find the cache entry in the DeniedCacheTable by the protocol address.\r
660 //\r
661 CacheEntry = ArpFindNextCacheEntryInTable (\r
662 &ArpService->DeniedCacheTable,\r
663 NULL,\r
664 ByProtoAddress,\r
665 ProtocolAddress,\r
666 NULL\r
667 );\r
668 if (CacheEntry != NULL) {\r
669 //\r
670 // There is a match.\r
671 //\r
672 return CacheEntry;\r
673 }\r
674 }\r
675\r
676 if ((HardwareAddress != NULL) && (HardwareAddress->AddressPtr != NULL)) {\r
677 //\r
678 // Find the cache entry in the DeniedCacheTable by the hardware address.\r
679 //\r
680 CacheEntry = ArpFindNextCacheEntryInTable (\r
681 &ArpService->DeniedCacheTable,\r
682 NULL,\r
683 ByHwAddress,\r
684 NULL,\r
685 HardwareAddress\r
686 );\r
687 }\r
688\r
689 return CacheEntry;\r
690}\r
691\r
692\r
693/**\r
694 Allocate a cache entry and initialize it.\r
695\r
c6d0ee4b 696 @param[in] Instance Pointer to the instance context data.\r
772db4bb 697\r
698 @return Pointer to the new created cache entry.\r
699\r
700**/\r
701ARP_CACHE_ENTRY *\r
702ArpAllocCacheEntry (\r
703 IN ARP_INSTANCE_DATA *Instance\r
704 )\r
705{\r
706 ARP_CACHE_ENTRY *CacheEntry;\r
707 NET_ARP_ADDRESS *Address;\r
708 UINT16 Index;\r
709\r
710 //\r
711 // Allocate memory for the cache entry.\r
712 //\r
e48e37fc 713 CacheEntry = AllocatePool (sizeof (ARP_CACHE_ENTRY));\r
772db4bb 714 if (CacheEntry == NULL) {\r
715 return NULL;\r
716 }\r
717\r
718 //\r
719 // Init the lists.\r
720 //\r
e48e37fc 721 InitializeListHead (&CacheEntry->List);\r
722 InitializeListHead (&CacheEntry->UserRequestList);\r
772db4bb 723\r
724 for (Index = 0; Index < 2; Index++) {\r
725 //\r
726 // Init the address pointers to point to the concrete buffer.\r
727 //\r
728 Address = &CacheEntry->Addresses[Index];\r
729 Address->AddressPtr = Address->Buffer.ProtoAddress;\r
730 }\r
731\r
732 //\r
733 // Zero the hardware address first.\r
734 //\r
e48e37fc 735 ZeroMem (CacheEntry->Addresses[Hardware].AddressPtr, ARP_MAX_HARDWARE_ADDRESS_LEN);\r
772db4bb 736\r
737 if (Instance != NULL) {\r
738 //\r
739 // Inherit the parameters from the instance configuration.\r
740 //\r
741 CacheEntry->RetryCount = Instance->ConfigData.RetryCount;\r
742 CacheEntry->NextRetryTime = Instance->ConfigData.RetryTimeOut;\r
743 CacheEntry->DefaultDecayTime = Instance->ConfigData.EntryTimeOut;\r
744 CacheEntry->DecayTime = Instance->ConfigData.EntryTimeOut;\r
745 } else {\r
746 //\r
747 // Use the default parameters if this cache entry isn't allocate in a\r
748 // instance's scope.\r
749 //\r
750 CacheEntry->RetryCount = ARP_DEFAULT_RETRY_COUNT;\r
751 CacheEntry->NextRetryTime = ARP_DEFAULT_RETRY_INTERVAL;\r
752 CacheEntry->DefaultDecayTime = ARP_DEFAULT_TIMEOUT_VALUE;\r
753 CacheEntry->DecayTime = ARP_DEFAULT_TIMEOUT_VALUE;\r
754 }\r
755\r
756 return CacheEntry;\r
757}\r
758\r
759\r
760/**\r
761 Turn the CacheEntry into the resolved status.\r
762\r
c6d0ee4b 763 @param[in] CacheEntry Pointer to the resolved cache entry.\r
764 @param[in] Instance Pointer to the instance context data.\r
765 @param[in] UserEvent Pointer to the UserEvent to notify.\r
772db4bb 766\r
767 @return The count of notifications sent to the instance.\r
768\r
769**/\r
770UINTN\r
771ArpAddressResolved (\r
772 IN ARP_CACHE_ENTRY *CacheEntry,\r
773 IN ARP_INSTANCE_DATA *Instance OPTIONAL,\r
774 IN EFI_EVENT UserEvent OPTIONAL\r
775 )\r
776{\r
e48e37fc 777 LIST_ENTRY *Entry;\r
778 LIST_ENTRY *NextEntry;\r
772db4bb 779 USER_REQUEST_CONTEXT *Context;\r
780 UINTN Count;\r
781\r
782 Count = 0;\r
783\r
784 //\r
785 // Iterate all the linked user requests to notify them.\r
786 //\r
787 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &CacheEntry->UserRequestList) {\r
788 Context = NET_LIST_USER_STRUCT (Entry, USER_REQUEST_CONTEXT, List);\r
789\r
790 if (((Instance == NULL) || (Context->Instance == Instance)) &&\r
791 ((UserEvent == NULL) || (Context->UserRequestEvent == UserEvent))) {\r
792 //\r
793 // Copy the address to the user-provided buffer and notify the user.\r
794 //\r
e48e37fc 795 CopyMem (\r
772db4bb 796 Context->UserHwAddrBuffer,\r
797 CacheEntry->Addresses[Hardware].AddressPtr,\r
798 CacheEntry->Addresses[Hardware].Length\r
799 );\r
800 gBS->SignalEvent (Context->UserRequestEvent);\r
801\r
802 //\r
803 // Remove this user request and free the context data.\r
804 //\r
e48e37fc 805 RemoveEntryList (&Context->List);\r
806 gBS->FreePool (Context);\r
772db4bb 807\r
808 Count++;\r
809 }\r
810 }\r
811\r
36ee91ca 812 //\r
813 // Dispatch the DPCs queued by the NotifyFunction of the Context->UserRequestEvent.\r
814 //\r
815 NetLibDispatchDpc ();\r
816\r
772db4bb 817 return Count;\r
818}\r
819\r
820\r
821/**\r
822 Fill the addresses in the CacheEntry using the information passed in by\r
823 HwAddr and SwAddr.\r
824\r
c6d0ee4b 825 @param[in] CacheEntry Pointer to the cache entry.\r
826 @param[in] HwAddr Pointer to the software address.\r
827 @param[in] SwAddr Pointer to the hardware address.\r
772db4bb 828\r
829 @return None.\r
830\r
831**/\r
832VOID\r
833ArpFillAddressInCacheEntry (\r
834 IN ARP_CACHE_ENTRY *CacheEntry,\r
835 IN NET_ARP_ADDRESS *HwAddr OPTIONAL,\r
836 IN NET_ARP_ADDRESS *SwAddr OPTIONAL\r
837 )\r
838{\r
839 NET_ARP_ADDRESS *Address[2];\r
840 NET_ARP_ADDRESS *CacheAddress;\r
841 UINT32 Index;\r
842\r
843 Address[Hardware] = HwAddr;\r
844 Address[Protocol] = SwAddr;\r
845\r
846 for (Index = 0; Index < 2; Index++) {\r
847 if (Address[Index] != NULL) {\r
848 //\r
849 // Fill the address if the passed in pointer is not NULL.\r
850 //\r
851 CacheAddress = &CacheEntry->Addresses[Index];\r
852\r
853 CacheAddress->Type = Address[Index]->Type;\r
854 CacheAddress->Length = Address[Index]->Length;\r
855\r
856 if (Address[Index]->AddressPtr != NULL) {\r
857 //\r
858 // Copy it if the AddressPtr points to some buffer.\r
859 //\r
e48e37fc 860 CopyMem (\r
772db4bb 861 CacheAddress->AddressPtr,\r
862 Address[Index]->AddressPtr,\r
863 CacheAddress->Length\r
864 );\r
865 } else {\r
866 //\r
867 // Zero the corresponding address buffer in the CacheEntry.\r
868 //\r
e48e37fc 869 ZeroMem (CacheAddress->AddressPtr, CacheAddress->Length);\r
772db4bb 870 }\r
871 }\r
872 }\r
873}\r
874\r
875\r
876/**\r
877 Configure the instance using the ConfigData. ConfigData is already validated.\r
878\r
c6d0ee4b 879 @param[in] Instance Pointer to the instance context data to be\r
772db4bb 880 configured.\r
c6d0ee4b 881 @param[in] ConfigData Pointer to the configuration data used to\r
772db4bb 882 configure the instance.\r
883\r
884 @retval EFI_SUCCESS The instance is configured with the ConfigData.\r
885 @retval EFI_ACCESS_DENIED The instance is already configured and the\r
886 ConfigData tries to reset some unchangeable\r
887 fields.\r
888 @retval EFI_INVALID_PARAMETER The ConfigData provides a non-unicast IPv4 address\r
889 when the SwAddressType is IPv4.\r
890 @retval EFI_OUT_OF_RESOURCES The instance fails to configure due to memory\r
891 limitation.\r
892\r
893**/\r
894EFI_STATUS\r
895ArpConfigureInstance (\r
896 IN ARP_INSTANCE_DATA *Instance,\r
897 IN EFI_ARP_CONFIG_DATA *ConfigData OPTIONAL\r
898 )\r
899{\r
900 EFI_ARP_CONFIG_DATA *OldConfigData;\r
901 IP4_ADDR Ip;\r
902\r
903 OldConfigData = &Instance->ConfigData;\r
904\r
905 if (ConfigData != NULL) {\r
906\r
907 if (Instance->Configured) {\r
908 //\r
909 // The instance is configured, check the unchangeable fields.\r
910 //\r
911 if ((OldConfigData->SwAddressType != ConfigData->SwAddressType) ||\r
912 (OldConfigData->SwAddressLength != ConfigData->SwAddressLength) ||\r
e48e37fc 913 (CompareMem (\r
772db4bb 914 OldConfigData->StationAddress,\r
915 ConfigData->StationAddress,\r
916 OldConfigData->SwAddressLength\r
917 ) != 0)) {\r
918 //\r
919 // Deny the unallowed changes.\r
920 //\r
921 return EFI_ACCESS_DENIED;\r
922 }\r
923 } else {\r
924 //\r
925 // The instance is not configured.\r
926 //\r
927\r
7bce0c5a 928 if (ConfigData->SwAddressType == IPV4_ETHER_PROTO_TYPE) {\r
e48e37fc 929 CopyMem (&Ip, ConfigData->StationAddress, sizeof (IP4_ADDR));\r
772db4bb 930\r
931 if (!Ip4IsUnicast (NTOHL (Ip), 0)) {\r
932 //\r
933 // The station address is not a valid IPv4 unicast address.\r
934 //\r
935 return EFI_INVALID_PARAMETER;\r
936 }\r
937 }\r
938\r
939 //\r
940 // Save the configuration.\r
941 //\r
687a2e5f 942 CopyMem (OldConfigData, ConfigData, sizeof (*OldConfigData));\r
772db4bb 943\r
e48e37fc 944 OldConfigData->StationAddress = AllocatePool (OldConfigData->SwAddressLength);\r
772db4bb 945 if (OldConfigData->StationAddress == NULL) {\r
e48e37fc 946 DEBUG ((EFI_D_ERROR, "ArpConfigInstance: AllocatePool for the StationAddress "\r
772db4bb 947 "failed.\n"));\r
948 return EFI_OUT_OF_RESOURCES;\r
949 }\r
950\r
951 //\r
952 // Save the StationAddress.\r
953 //\r
e48e37fc 954 CopyMem (\r
772db4bb 955 OldConfigData->StationAddress,\r
956 ConfigData->StationAddress,\r
957 OldConfigData->SwAddressLength\r
958 );\r
959\r
960 //\r
961 // Set the state to configured.\r
962 //\r
963 Instance->Configured = TRUE;\r
964 }\r
965\r
966 //\r
967 // Use the implementation specific values if the following field is zero.\r
968 //\r
969 OldConfigData->EntryTimeOut = (ConfigData->EntryTimeOut == 0) ?\r
970 ARP_DEFAULT_TIMEOUT_VALUE : ConfigData->EntryTimeOut;\r
971\r
972 OldConfigData->RetryCount = (ConfigData->RetryCount == 0) ?\r
973 ARP_DEFAULT_RETRY_COUNT : ConfigData->RetryCount;\r
974\r
975 OldConfigData->RetryTimeOut = (ConfigData->RetryTimeOut == 0) ?\r
976 ARP_DEFAULT_RETRY_INTERVAL : ConfigData->RetryTimeOut;\r
977 } else {\r
978 //\r
979 // Reset the configuration.\r
980 //\r
981\r
982 if (Instance->Configured) {\r
983 //\r
984 // Cancel the arp requests issued by this instance.\r
985 //\r
36ee91ca 986 Instance->ArpProto.Cancel (&Instance->ArpProto, NULL, NULL);\r
772db4bb 987\r
988 //\r
989 // Free the buffer previously allocated to hold the station address.\r
990 //\r
e48e37fc 991 gBS->FreePool (OldConfigData->StationAddress);\r
772db4bb 992 }\r
993\r
994 Instance->Configured = FALSE;\r
995 }\r
996\r
997 return EFI_SUCCESS;\r
998}\r
999\r
1000\r
1001/**\r
1002 Send out an arp frame using the CachEntry and the ArpOpCode.\r
1003\r
c6d0ee4b 1004 @param[in] Instance Pointer to the instance context data.\r
1005 @param[in] CacheEntry Pointer to the configuration data used to\r
1006 configure the instance.\r
1007 @param[in] ArpOpCode The opcode used to send out this Arp frame, either\r
1008 request or reply.\r
772db4bb 1009\r
1010 @return None.\r
1011\r
1012**/\r
1013VOID\r
1014ArpSendFrame (\r
1015 IN ARP_INSTANCE_DATA *Instance,\r
1016 IN ARP_CACHE_ENTRY *CacheEntry,\r
1017 IN UINT16 ArpOpCode\r
1018 )\r
1019{\r
1020 EFI_STATUS Status;\r
1021 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *TxToken;\r
1022 EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;\r
1023 UINT32 TotalLength;\r
1024 UINT8 *Packet;\r
1025 ARP_SERVICE_DATA *ArpService;\r
1026 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
1027 EFI_ARP_CONFIG_DATA *ConfigData;\r
1028 UINT8 *TmpPtr;\r
1029 ARP_HEAD *ArpHead;\r
1030\r
1031 ASSERT ((Instance != NULL) && (CacheEntry != NULL));\r
1032\r
1033 //\r
1034 // Allocate memory for the TxToken.\r
1035 //\r
e48e37fc 1036 TxToken = AllocatePool (sizeof(EFI_MANAGED_NETWORK_COMPLETION_TOKEN));\r
772db4bb 1037 if (TxToken == NULL) {\r
e48e37fc 1038 DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxToken failed.\n"));\r
772db4bb 1039 return;\r
1040 }\r
1041\r
1042 TxToken->Event = NULL;\r
1043 TxData = NULL;\r
1044 Packet = NULL;\r
1045\r
1046 //\r
1047 // Create the event for this TxToken.\r
1048 //\r
1049 Status = gBS->CreateEvent (\r
1050 EVT_NOTIFY_SIGNAL,\r
e48e37fc 1051 TPL_NOTIFY,\r
772db4bb 1052 ArpOnFrameSent,\r
1053 (VOID *)TxToken,\r
1054 &TxToken->Event\r
1055 );\r
1056 if (EFI_ERROR (Status)) {\r
e48e37fc 1057 DEBUG ((EFI_D_ERROR, "ArpSendFrame: CreateEvent failed for TxToken->Event.\n"));\r
772db4bb 1058 goto CLEAN_EXIT;\r
1059 }\r
1060\r
1061 //\r
1062 // Allocate memory for the TxData used in the TxToken.\r
1063 //\r
e48e37fc 1064 TxData = AllocatePool (sizeof(EFI_MANAGED_NETWORK_TRANSMIT_DATA));\r
772db4bb 1065 if (TxData == NULL) {\r
e48e37fc 1066 DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxData failed.\n"));\r
772db4bb 1067 goto CLEAN_EXIT;\r
1068 }\r
1069\r
1070 ArpService = Instance->ArpService;\r
1071 SnpMode = &ArpService->SnpMode;\r
1072 ConfigData = &Instance->ConfigData;\r
1073\r
1074 //\r
1075 // Calculate the buffer length for this arp frame.\r
1076 //\r
1077 TotalLength = SnpMode->MediaHeaderSize + sizeof (ARP_HEAD) +\r
1078 2 * (ConfigData->SwAddressLength + SnpMode->HwAddressSize);\r
1079\r
1080 //\r
1081 // Allocate buffer for the arp frame.\r
1082 //\r
e48e37fc 1083 Packet = AllocatePool (TotalLength);\r
772db4bb 1084 if (Packet == NULL) {\r
e48e37fc 1085 DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for Packet failed.\n"));\r
894d038a 1086 ASSERT (Packet != NULL);\r
772db4bb 1087 }\r
1088\r
1089 TmpPtr = Packet;\r
1090\r
1091 //\r
1092 // The destination MAC address.\r
1093 //\r
1094 if (ArpOpCode == ARP_OPCODE_REQUEST) {\r
e48e37fc 1095 CopyMem (TmpPtr, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);\r
772db4bb 1096 } else {\r
e48e37fc 1097 CopyMem (\r
772db4bb 1098 TmpPtr,\r
1099 CacheEntry->Addresses[Hardware].AddressPtr,\r
1100 SnpMode->HwAddressSize\r
1101 );\r
1102 }\r
1103 TmpPtr += SnpMode->HwAddressSize;\r
1104\r
1105 //\r
1106 // The source MAC address.\r
1107 //\r
e48e37fc 1108 CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);\r
772db4bb 1109 TmpPtr += SnpMode->HwAddressSize;\r
1110\r
1111 //\r
1112 // The ethernet protocol type.\r
1113 //\r
1114 *(UINT16 *)TmpPtr = HTONS (ARP_ETHER_PROTO_TYPE);\r
1115 TmpPtr += 2;\r
1116\r
1117 //\r
1118 // The ARP Head.\r
1119 //\r
1120 ArpHead = (ARP_HEAD *) TmpPtr;\r
1121 ArpHead->HwType = HTONS ((UINT16)SnpMode->IfType);\r
1122 ArpHead->ProtoType = HTONS (ConfigData->SwAddressType);\r
1123 ArpHead->HwAddrLen = (UINT8)SnpMode->HwAddressSize;\r
1124 ArpHead->ProtoAddrLen = ConfigData->SwAddressLength;\r
1125 ArpHead->OpCode = HTONS (ArpOpCode);\r
1126 TmpPtr += sizeof (ARP_HEAD);\r
1127\r
1128 //\r
1129 // The sender hardware address.\r
1130 //\r
e48e37fc 1131 CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);\r
772db4bb 1132 TmpPtr += SnpMode->HwAddressSize;\r
1133\r
1134 //\r
1135 // The sender protocol address.\r
1136 //\r
e48e37fc 1137 CopyMem (TmpPtr, ConfigData->StationAddress, ConfigData->SwAddressLength);\r
772db4bb 1138 TmpPtr += ConfigData->SwAddressLength;\r
1139\r
1140 //\r
1141 // The target hardware address.\r
1142 //\r
e48e37fc 1143 CopyMem (\r
772db4bb 1144 TmpPtr,\r
1145 CacheEntry->Addresses[Hardware].AddressPtr,\r
1146 SnpMode->HwAddressSize\r
1147 );\r
1148 TmpPtr += SnpMode->HwAddressSize;\r
1149\r
1150 //\r
1151 // The target protocol address.\r
1152 //\r
e48e37fc 1153 CopyMem (\r
772db4bb 1154 TmpPtr,\r
1155 CacheEntry->Addresses[Protocol].AddressPtr,\r
1156 ConfigData->SwAddressLength\r
1157 );\r
1158\r
1159 //\r
1160 // Set all the fields of the TxData.\r
1161 //\r
1162 TxData->DestinationAddress = NULL;\r
1163 TxData->SourceAddress = NULL;\r
1164 TxData->ProtocolType = 0;\r
1165 TxData->DataLength = TotalLength - SnpMode->MediaHeaderSize;\r
1166 TxData->HeaderLength = (UINT16) SnpMode->MediaHeaderSize;\r
1167 TxData->FragmentCount = 1;\r
1168\r
1169 TxData->FragmentTable[0].FragmentBuffer = Packet;\r
1170 TxData->FragmentTable[0].FragmentLength = TotalLength;\r
1171\r
1172 //\r
1173 // Associate the TxData with the TxToken.\r
1174 //\r
1175 TxToken->Packet.TxData = TxData;\r
1176 TxToken->Status = EFI_NOT_READY;\r
1177\r
1178 //\r
1179 // Send out this arp packet by Mnp.\r
1180 //\r
1181 Status = ArpService->Mnp->Transmit (ArpService->Mnp, TxToken);\r
1182 if (EFI_ERROR (Status)) {\r
e48e37fc 1183 DEBUG ((EFI_D_ERROR, "Mnp->Transmit failed, %r.\n", Status));\r
772db4bb 1184 goto CLEAN_EXIT;\r
1185 }\r
1186\r
1187 return;\r
1188\r
1189CLEAN_EXIT:\r
1190\r
1191 if (Packet != NULL) {\r
e48e37fc 1192 gBS->FreePool (Packet);\r
772db4bb 1193 }\r
1194\r
1195 if (TxData != NULL) {\r
e48e37fc 1196 gBS->FreePool (TxData);\r
772db4bb 1197 }\r
1198\r
1199 if (TxToken->Event != NULL) {\r
1200 gBS->CloseEvent (TxToken->Event);\r
1201 }\r
1202\r
e48e37fc 1203 gBS->FreePool (TxToken);\r
772db4bb 1204}\r
1205\r
1206\r
1207/**\r
1208 Delete the cache entries in the specified CacheTable, using the BySwAddress,\r
1209 SwAddressType, AddressBuffer combination as the matching key, if Force is TRUE,\r
1210 the cache is deleted event it's a static entry.\r
1211\r
c6d0ee4b 1212 @param[in] CacheTable Pointer to the cache table to do the deletion.\r
1213 @param[in] BySwAddress Delete the cache entry by software address or by\r
1214 hardware address.\r
1215 @param[in] SwAddressType The software address used to do the deletion.\r
1216 @param[in] AddressBuffer Pointer to the buffer containing the address to\r
1217 match for the deletion.\r
1218 @param[in] Force This deletion is forced or not.\r
772db4bb 1219\r
1220 @return The count of the deleted cache entries.\r
1221\r
1222**/\r
772db4bb 1223UINTN\r
1224ArpDeleteCacheEntryInTable (\r
e48e37fc 1225 IN LIST_ENTRY *CacheTable,\r
772db4bb 1226 IN BOOLEAN BySwAddress,\r
1227 IN UINT16 SwAddressType,\r
1228 IN UINT8 *AddressBuffer OPTIONAL,\r
1229 IN BOOLEAN Force\r
1230 )\r
1231{\r
e48e37fc 1232 LIST_ENTRY *Entry;\r
1233 LIST_ENTRY *NextEntry;\r
772db4bb 1234 ARP_CACHE_ENTRY *CacheEntry;\r
1235 UINTN Count;\r
1236\r
1237 Count = 0;\r
1238\r
1239 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, CacheTable) {\r
1240 CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
1241\r
1242 if ((CacheEntry->DefaultDecayTime == 0) && !Force) {\r
1243 //\r
1244 // It's a static entry and we are not forced to delete it, skip.\r
1245 //\r
1246 continue;\r
1247 }\r
1248\r
1249 if (BySwAddress) {\r
1250 if (SwAddressType == CacheEntry->Addresses[Protocol].Type) {\r
1251 //\r
1252 // Protocol address type matched. Check the address.\r
1253 //\r
1254 if ((AddressBuffer == NULL) ||\r
e48e37fc 1255 (CompareMem (\r
772db4bb 1256 AddressBuffer,\r
1257 CacheEntry->Addresses[Protocol].AddressPtr,\r
1258 CacheEntry->Addresses[Protocol].Length\r
1259 ) == 0)) {\r
1260 //\r
1261 // Address matched.\r
1262 //\r
1263 goto MATCHED;\r
1264 }\r
1265 }\r
1266 } else {\r
1267 if ((AddressBuffer == NULL) ||\r
e48e37fc 1268 (CompareMem (\r
772db4bb 1269 AddressBuffer,\r
1270 CacheEntry->Addresses[Hardware].AddressPtr,\r
1271 CacheEntry->Addresses[Hardware].Length\r
1272 ) == 0)) {\r
1273 //\r
1274 // Address matched.\r
1275 //\r
1276 goto MATCHED;\r
1277 }\r
1278 }\r
1279\r
1280 continue;\r
1281\r
1282MATCHED:\r
1283\r
1284 //\r
1285 // Delete this entry.\r
1286 //\r
e48e37fc 1287 RemoveEntryList (&CacheEntry->List);\r
1288 ASSERT (IsListEmpty (&CacheEntry->UserRequestList));\r
1289 gBS->FreePool (CacheEntry);\r
772db4bb 1290\r
1291 Count++;\r
1292 }\r
1293\r
1294 return Count;\r
1295}\r
1296\r
1297\r
1298/**\r
1299 Delete cache entries in all the cache tables.\r
1300\r
c6d0ee4b 1301 @param[in] Instance Pointer to the instance context data.\r
1302 @param[in] BySwAddress Delete the cache entry by software address or by\r
1303 hardware address.\r
1304 @param[in] AddressBuffer Pointer to the buffer containing the address to\r
1305 match for the deletion.\r
1306 @param[in] Force This deletion is forced or not.\r
772db4bb 1307\r
1308 @return The count of the deleted cache entries.\r
1309\r
1310**/\r
1311UINTN\r
1312ArpDeleteCacheEntry (\r
1313 IN ARP_INSTANCE_DATA *Instance,\r
1314 IN BOOLEAN BySwAddress,\r
1315 IN UINT8 *AddressBuffer OPTIONAL,\r
1316 IN BOOLEAN Force\r
1317 )\r
1318{\r
1319 ARP_SERVICE_DATA *ArpService;\r
1320 UINTN Count;\r
1321\r
1322 NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);\r
1323\r
1324 ArpService = Instance->ArpService;\r
1325\r
1326 //\r
1327 // Delete the cache entries in the DeniedCacheTable.\r
1328 //\r
1329 Count = ArpDeleteCacheEntryInTable (\r
1330 &ArpService->DeniedCacheTable,\r
1331 BySwAddress,\r
1332 Instance->ConfigData.SwAddressType,\r
1333 AddressBuffer,\r
1334 Force\r
1335 );\r
1336\r
1337 //\r
1338 // Delete the cache entries inthe ResolvedCacheTable.\r
1339 //\r
1340 Count += ArpDeleteCacheEntryInTable (\r
1341 &ArpService->ResolvedCacheTable,\r
1342 BySwAddress,\r
1343 Instance->ConfigData.SwAddressType,\r
1344 AddressBuffer,\r
1345 Force\r
1346 );\r
1347\r
1348 return Count;\r
1349}\r
1350\r
1351\r
1352/**\r
1353 Cancel the arp request.\r
1354\r
c6d0ee4b 1355 @param[in] Instance Pointer to the instance context data.\r
1356 @param[in] TargetSwAddress Pointer to the buffer containing the target\r
1357 software address to match the arp request.\r
1358 @param[in] UserEvent The user event used to notify this request\r
1359 cancellation.\r
772db4bb 1360\r
1361 @return The count of the cancelled requests.\r
1362\r
1363**/\r
1364UINTN\r
1365ArpCancelRequest (\r
1366 IN ARP_INSTANCE_DATA *Instance,\r
1367 IN VOID *TargetSwAddress OPTIONAL,\r
1368 IN EFI_EVENT UserEvent OPTIONAL\r
1369 )\r
1370{\r
1371 ARP_SERVICE_DATA *ArpService;\r
e48e37fc 1372 LIST_ENTRY *Entry;\r
1373 LIST_ENTRY *NextEntry;\r
772db4bb 1374 ARP_CACHE_ENTRY *CacheEntry;\r
1375 UINTN Count;\r
1376\r
1377 NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);\r
1378\r
1379 ArpService = Instance->ArpService;\r
1380\r
1381 Count = 0;\r
1382 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {\r
1383 CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);\r
1384\r
1385 if ((TargetSwAddress == NULL) ||\r
e48e37fc 1386 (CompareMem (\r
772db4bb 1387 TargetSwAddress,\r
1388 CacheEntry->Addresses[Protocol].AddressPtr,\r
1389 CacheEntry->Addresses[Protocol].Length\r
1390 ) == 0)) {\r
1391 //\r
1392 // This request entry matches the TargetSwAddress or all requests are to be\r
1393 // cancelled as TargetSwAddress is NULL.\r
1394 //\r
1395 Count += ArpAddressResolved (CacheEntry, Instance, UserEvent);\r
1396\r
e48e37fc 1397 if (IsListEmpty (&CacheEntry->UserRequestList)) {\r
772db4bb 1398 //\r
1399 // No user requests any more, remove this request cache entry.\r
1400 //\r
e48e37fc 1401 RemoveEntryList (&CacheEntry->List);\r
1402 gBS->FreePool (CacheEntry);\r
772db4bb 1403 }\r
1404 }\r
1405 }\r
1406\r
1407 return Count;\r
1408}\r
1409\r
1410\r
1411/**\r
1412 Find the cache entry in the cache table.\r
1413\r
c6d0ee4b 1414 @param[in] Instance Pointer to the instance context data.\r
1415 @param[in] BySwAddress Set to TRUE to look for matching software protocol\r
772db4bb 1416 addresses. Set to FALSE to look for matching\r
1417 hardware protocol addresses.\r
c6d0ee4b 1418 @param[in] AddressBuffer Pointer to address buffer. Set to NULL to match\r
772db4bb 1419 all addresses.\r
c6d0ee4b 1420 @param[out] EntryLength The size of an entry in the entries buffer.\r
1421 @param[out] EntryCount The number of ARP cache entries that are found by\r
772db4bb 1422 the specified criteria.\r
c6d0ee4b 1423 @param[out] Entries Pointer to the buffer that will receive the ARP\r
772db4bb 1424 cache entries.\r
c6d0ee4b 1425 @param[in] Refresh Set to TRUE to refresh the timeout value of the\r
772db4bb 1426 matching ARP cache entry.\r
1427\r
1428 @retval EFI_SUCCESS The requested ARP cache entries are copied into\r
1429 the buffer.\r
1430 @retval EFI_NOT_FOUND No matching entries found.\r
1431 @retval EFI_OUT_OF_RESOURCE There is a memory allocation failure.\r
1432\r
1433**/\r
1434EFI_STATUS\r
1435ArpFindCacheEntry (\r
1436 IN ARP_INSTANCE_DATA *Instance,\r
1437 IN BOOLEAN BySwAddress,\r
1438 IN VOID *AddressBuffer OPTIONAL,\r
1439 OUT UINT32 *EntryLength OPTIONAL,\r
1440 OUT UINT32 *EntryCount OPTIONAL,\r
1441 OUT EFI_ARP_FIND_DATA **Entries OPTIONAL,\r
1442 IN BOOLEAN Refresh\r
1443 )\r
1444{\r
1445 EFI_STATUS Status;\r
1446 ARP_SERVICE_DATA *ArpService;\r
1447 NET_ARP_ADDRESS MatchAddress;\r
1448 FIND_OPTYPE FindOpType;\r
e48e37fc 1449 LIST_ENTRY *StartEntry;\r
772db4bb 1450 ARP_CACHE_ENTRY *CacheEntry;\r
1451 NET_MAP FoundEntries;\r
1452 UINT32 FoundCount;\r
1453 EFI_ARP_FIND_DATA *FindData;\r
e48e37fc 1454 LIST_ENTRY *CacheTable;\r
894d038a 1455 UINT32 FoundEntryLength;\r
772db4bb 1456\r
1457 ArpService = Instance->ArpService;\r
1458\r
1459 //\r
1460 // Init the FounEntries used to hold the found cache entries.\r
1461 //\r
1462 NetMapInit (&FoundEntries);\r
1463\r
1464 //\r
1465 // Set the MatchAddress.\r
1466 //\r
1467 if (BySwAddress) {\r
1468 MatchAddress.Type = Instance->ConfigData.SwAddressType;\r
1469 MatchAddress.Length = Instance->ConfigData.SwAddressLength;\r
1470 FindOpType = ByProtoAddress;\r
1471 } else {\r
1472 MatchAddress.Type = ArpService->SnpMode.IfType;\r
1473 MatchAddress.Length = (UINT8)ArpService->SnpMode.HwAddressSize;\r
1474 FindOpType = ByHwAddress;\r
1475 }\r
1476\r
1477 MatchAddress.AddressPtr = AddressBuffer;\r
1478\r
1479 //\r
1480 // Search the DeniedCacheTable\r
1481 //\r
1482 StartEntry = NULL;\r
1483 while (TRUE) {\r
1484 //\r
1485 // Try to find the matched entries in the DeniedCacheTable.\r
1486 //\r
1487 CacheEntry = ArpFindNextCacheEntryInTable (\r
1488 &ArpService->DeniedCacheTable,\r
1489 StartEntry,\r
1490 FindOpType,\r
1491 &MatchAddress,\r
1492 &MatchAddress\r
1493 );\r
1494 if (CacheEntry == NULL) {\r
1495 //\r
1496 // Once the CacheEntry is NULL, there are no more matches.\r
1497 //\r
1498 break;\r
1499 }\r
1500\r
1501 //\r
1502 // Insert the found entry into the map.\r
1503 //\r
1504 NetMapInsertTail (\r
1505 &FoundEntries,\r
1506 (VOID *)CacheEntry,\r
1507 (VOID *)&ArpService->DeniedCacheTable\r
1508 );\r
1509\r
1510 //\r
1511 // Let the next search start from this cache entry.\r
1512 //\r
1513 StartEntry = &CacheEntry->List;\r
1514\r
1515 if (Refresh) {\r
1516 //\r
1517 // Refresh the DecayTime if needed.\r
1518 //\r
1519 CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;\r
1520 }\r
1521 }\r
1522\r
1523 //\r
1524 // Search the ResolvedCacheTable\r
1525 //\r
1526 StartEntry = NULL;\r
1527 while (TRUE) {\r
1528 CacheEntry = ArpFindNextCacheEntryInTable (\r
1529 &ArpService->ResolvedCacheTable,\r
1530 StartEntry,\r
1531 FindOpType,\r
1532 &MatchAddress,\r
1533 &MatchAddress\r
1534 );\r
1535 if (CacheEntry == NULL) {\r
1536 //\r
1537 // Once the CacheEntry is NULL, there are no more matches.\r
1538 //\r
1539 break;\r
1540 }\r
1541\r
1542 //\r
1543 // Insert the found entry into the map.\r
1544 //\r
1545 NetMapInsertTail (\r
1546 &FoundEntries,\r
1547 (VOID *)CacheEntry,\r
1548 (VOID *)&ArpService->ResolvedCacheTable\r
1549 );\r
1550\r
1551 //\r
1552 // Let the next search start from this cache entry.\r
1553 //\r
1554 StartEntry = &CacheEntry->List;\r
1555\r
1556 if (Refresh) {\r
1557 //\r
1558 // Refresh the DecayTime if needed.\r
1559 //\r
1560 CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;\r
1561 }\r
1562 }\r
1563\r
1564 Status = EFI_SUCCESS;\r
1565\r
1566 FoundCount = (UINT32) NetMapGetCount (&FoundEntries);\r
1567 if (FoundCount == 0) {\r
1568 Status = EFI_NOT_FOUND;\r
1569 goto CLEAN_EXIT;\r
1570 }\r
1571\r
894d038a 1572 //\r
1573 // Found the entry length, make sure its 8 bytes alignment.\r
1574 //\r
1575 FoundEntryLength = (((sizeof (EFI_ARP_FIND_DATA) + Instance->ConfigData.SwAddressLength +\r
1576 ArpService->SnpMode.HwAddressSize) + 3) & ~(0x3));\r
1577\r
772db4bb 1578 if (EntryLength != NULL) {\r
894d038a 1579 *EntryLength = FoundEntryLength;\r
772db4bb 1580 }\r
1581\r
1582 if (EntryCount != NULL) {\r
1583 //\r
1584 // Return the found entry count.\r
1585 //\r
1586 *EntryCount = FoundCount;\r
1587 }\r
1588\r
1589 if (Entries == NULL) {\r
1590 goto CLEAN_EXIT;\r
1591 }\r
1592\r
1593 //\r
1594 // Allocate buffer to copy the found entries.\r
1595 //\r
894d038a 1596 FindData = AllocatePool (FoundCount * FoundEntryLength);\r
772db4bb 1597 if (FindData == NULL) {\r
e48e37fc 1598 DEBUG ((EFI_D_ERROR, "ArpFindCacheEntry: Failed to allocate memory.\n"));\r
772db4bb 1599 Status = EFI_OUT_OF_RESOURCES;\r
1600 goto CLEAN_EXIT;\r
1601 }\r
1602\r
1603 //\r
1604 // Return the address to the user.\r
1605 //\r
1606 *Entries = FindData;\r
1607\r
1608 //\r
1609 // Dump the entries.\r
1610 //\r
1611 while (!NetMapIsEmpty (&FoundEntries)) {\r
1612 //\r
1613 // Get a cache entry from the map.\r
1614 //\r
1615 CacheEntry = NetMapRemoveHead (&FoundEntries, (VOID **)&CacheTable);\r
1616\r
1617 //\r
1618 // Set the fields in FindData.\r
1619 //\r
1620 FindData->Size = *EntryLength;\r
1621 FindData->DenyFlag = (BOOLEAN)(CacheTable == &ArpService->DeniedCacheTable);\r
1622 FindData->StaticFlag = (BOOLEAN)(CacheEntry->DefaultDecayTime == 0);\r
1623 FindData->HwAddressType = ArpService->SnpMode.IfType;\r
1624 FindData->SwAddressType = Instance->ConfigData.SwAddressType;\r
1625 FindData->HwAddressLength = (UINT8)ArpService->SnpMode.HwAddressSize;\r
1626 FindData->SwAddressLength = Instance->ConfigData.SwAddressLength;\r
1627\r
1628 //\r
1629 // Copy the software address.\r
1630 //\r
e48e37fc 1631 CopyMem (\r
772db4bb 1632 FindData + 1,\r
1633 CacheEntry->Addresses[Protocol].AddressPtr,\r
1634 FindData->SwAddressLength\r
1635 );\r
1636\r
1637 //\r
1638 // Copy the hardware address.\r
1639 //\r
e48e37fc 1640 CopyMem (\r
772db4bb 1641 (UINT8 *)(FindData + 1) + FindData->SwAddressLength,\r
1642 CacheEntry->Addresses[Hardware].AddressPtr,\r
1643 FindData->HwAddressLength\r
1644 );\r
1645\r
1646 //\r
1647 // Slip to the next FindData.\r
1648 //\r
1649 FindData = (EFI_ARP_FIND_DATA *)((UINT8 *)FindData + *EntryLength);\r
1650 }\r
1651\r
1652CLEAN_EXIT:\r
1653\r
1654 NetMapClean (&FoundEntries);\r
1655\r
1656 return Status;\r
1657}\r
1658\r