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