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