]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_arp.c
Fix capitalization
[mirror_edk2.git] / EdkModulePkg / Universal / Network / PxeBc / Dxe / pxe_bc_arp.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
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 pxe_bc_arp.c\r
14\r
15Abstract:\r
16\r
17--*/\r
18\r
19\r
4cbd855e 20#include "Bc.h"\r
878ddf1f 21\r
22//\r
23// Definitions for ARP\r
24// Per RFC 826\r
25//\r
26STATIC ARP_HEADER ArpHeader;\r
27\r
28#pragma pack(1)\r
29STATIC struct {\r
30 UINT8 MediaHeader[14];\r
31 ARP_HEADER ArpHeader;\r
32 UINT8 ArpData[64];\r
33} ArpReplyPacket;\r
34#pragma pack()\r
35\r
36/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
37VOID\r
38InitArpHeader (\r
39 VOID\r
40 )\r
41/*++\r
42Routine description:\r
43 Initialize ARP packet header.\r
44\r
45Parameters:\r
46 none\r
47\r
48Returns:\r
49 none\r
50\r
51--*/\r
52{\r
53 ArpHeader.HwType = HTONS (ETHERNET_ADD_SPC);\r
54 ArpHeader.ProtType = HTONS (ETHER_TYPE_IP);\r
55 ArpHeader.HwAddLen = ENET_HWADDLEN;\r
56 ArpHeader.ProtAddLen = IPV4_PROTADDLEN;\r
57 ArpHeader.OpCode = HTONS (ARP_REQUEST);\r
58\r
59 CopyMem (&ArpReplyPacket.ArpHeader, &ArpHeader, sizeof (ARP_HEADER));\r
60}\r
61\r
62/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
63VOID\r
64HandleArpReceive (\r
65 IN PXE_BASECODE_DEVICE *Private,\r
66 IN ARP_PACKET *ArpPacketPtr,\r
67 IN VOID *MediaHeader\r
68 )\r
69/*++\r
70Routine description:\r
71 Process ARP packet.\r
72\r
73Parameters:\r
74 Private := Pointer to PxeBc interface\r
75 ArpPacketPtr := Pointer to ARP packet\r
76 MediaHeader := Pointer to media header.\r
77Returns:\r
78--*/\r
79{\r
80 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
81 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
82 EFI_MAC_ADDRESS TmpMacAddr;\r
83 UINTN Index;\r
84 UINT8 *SrcHwAddr;\r
85 UINT8 *SrcPrAddr;\r
86 UINT8 *DstHwAddr;\r
87 UINT8 *DstPrAddr;\r
88 UINT8 *TmpPtr;\r
89\r
90 //\r
91 //\r
92 //\r
93 PxeBcMode = Private->EfiBc.Mode;\r
94 SnpMode = Private->SimpleNetwork->Mode;\r
95\r
96 //\r
97 // For now only ethernet addresses are supported.\r
98 // This will need to be updated when other media\r
99 // layers are supported by PxeBc, Snp and UNDI.\r
100 //\r
101 if (ArpPacketPtr->ArpHeader.HwType != HTONS (ETHERNET_ADD_SPC)) {\r
102 return ;\r
103 }\r
104 //\r
105 // For now only IP protocol addresses are supported.\r
106 // This will need to be updated when other protocol\r
107 // types are supported by PxeBc, Snp and UNDI.\r
108 //\r
109 if (ArpPacketPtr->ArpHeader.ProtType != HTONS (ETHER_TYPE_IP)) {\r
110 return ;\r
111 }\r
112 //\r
113 // For now only SNP hardware address sizes are supported.\r
114 //\r
115 if (ArpPacketPtr->ArpHeader.HwAddLen != SnpMode->HwAddressSize) {\r
116 return ;\r
117 }\r
118 //\r
119 // For now only PxeBc protocol address sizes are supported.\r
120 //\r
121 if (ArpPacketPtr->ArpHeader.ProtAddLen != Private->IpLength) {\r
122 return ;\r
123 }\r
124 //\r
125 // Ignore out of range opcodes\r
126 //\r
127 switch (ArpPacketPtr->ArpHeader.OpCode) {\r
128 case HTONS (ARP_REPLY):\r
129 case HTONS (ARP_REQUEST):\r
130 break;\r
131\r
132 default:\r
133 return ;\r
134 }\r
135 //\r
136 // update entry in our ARP cache if we have it\r
137 //\r
138 SrcHwAddr = (UINT8 *) &ArpPacketPtr->SrcHardwareAddr;\r
139 SrcPrAddr = SrcHwAddr + SnpMode->HwAddressSize;\r
140\r
141 for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) {\r
142 if (CompareMem (\r
143 &PxeBcMode->ArpCache[Index].IpAddr,\r
144 SrcPrAddr,\r
145 Private->IpLength\r
146 )) {\r
147 continue;\r
148 }\r
149\r
150 CopyMem (\r
151 &PxeBcMode->ArpCache[Index].MacAddr,\r
152 SrcHwAddr,\r
153 SnpMode->HwAddressSize\r
154 );\r
155\r
156 break;\r
157 }\r
158 //\r
159 // Done if ARP packet was not for us.\r
160 //\r
161 DstHwAddr = SrcPrAddr + Private->IpLength;\r
162 DstPrAddr = DstHwAddr + SnpMode->HwAddressSize;\r
163\r
164 if (CompareMem (DstPrAddr, &PxeBcMode->StationIp, Private->IpLength)) {\r
165 return ;\r
166 //\r
167 // not for us\r
168 //\r
169 }\r
170 //\r
171 // for us - if we did not update entry, add it\r
172 //\r
173 if (Index == PxeBcMode->ArpCacheEntries) {\r
174 //\r
175 // if we have a full table, get rid of oldest\r
176 //\r
177 if (Index == PXE_ARP_CACHE_SIZE) {\r
178 Index = Private->OldestArpEntry;\r
179\r
180 if (++Private->OldestArpEntry == PXE_ARP_CACHE_SIZE) {\r
181 Private->OldestArpEntry = 0;\r
182 }\r
183 } else {\r
184 ++PxeBcMode->ArpCacheEntries;\r
185 }\r
186\r
187 CopyMem (\r
188 &PxeBcMode->ArpCache[Index].MacAddr,\r
189 SrcHwAddr,\r
190 SnpMode->HwAddressSize\r
191 );\r
192\r
193 CopyMem (\r
194 &PxeBcMode->ArpCache[Index].IpAddr,\r
195 SrcPrAddr,\r
196 Private->IpLength\r
197 );\r
198 }\r
199 //\r
200 // if this is not a request or we don't yet have an IP, finished\r
201 //\r
202 if (ArpPacketPtr->ArpHeader.OpCode != HTONS (ARP_REQUEST) || !Private->GoodStationIp) {\r
203 return ;\r
204 }\r
205 //\r
206 // Assemble ARP reply.\r
207 //\r
208 //\r
209 // Create media header. [ dest mac | src mac | prot ]\r
210 //\r
211 CopyMem (\r
212 &ArpReplyPacket.MediaHeader[0],\r
213 SrcHwAddr,\r
214 SnpMode->HwAddressSize\r
215 );\r
216\r
217 CopyMem (\r
218 &ArpReplyPacket.MediaHeader[SnpMode->HwAddressSize],\r
219 &SnpMode->CurrentAddress,\r
220 SnpMode->HwAddressSize\r
221 );\r
222\r
223 CopyMem (\r
224 &ArpReplyPacket.MediaHeader[2 * SnpMode->HwAddressSize],\r
225 &((UINT8 *) MediaHeader)[2 * SnpMode->HwAddressSize],\r
226 sizeof (UINT16)\r
227 );\r
228\r
229 //\r
230 // ARP reply header is almost filled in,\r
231 // just insert the correct opcode.\r
232 //\r
233 ArpReplyPacket.ArpHeader.OpCode = HTONS (ARP_REPLY);\r
234\r
235 //\r
236 // Now fill in ARP data. [ src mac | src prot | dest mac | dest prot ]\r
237 //\r
238 TmpPtr = ArpReplyPacket.ArpData;\r
239 CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);\r
240\r
241 TmpPtr += SnpMode->HwAddressSize;\r
242 CopyMem (TmpPtr, &PxeBcMode->StationIp, Private->IpLength);\r
243\r
244 TmpPtr += Private->IpLength;\r
245 CopyMem (TmpPtr, SrcHwAddr, SnpMode->HwAddressSize);\r
246\r
247 TmpPtr += SnpMode->HwAddressSize;\r
248 CopyMem (TmpPtr, SrcPrAddr, Private->IpLength);\r
249\r
250 //\r
251 // Now send out the ARP reply.\r
252 //\r
253 CopyMem (&TmpMacAddr, SrcHwAddr, sizeof (EFI_MAC_ADDRESS));\r
254\r
255 SendPacket (\r
256 Private,\r
257 &ArpReplyPacket.MediaHeader,\r
258 &ArpReplyPacket.ArpHeader,\r
259 sizeof (ARP_HEADER) + 2 * (Private->IpLength + SnpMode->HwAddressSize),\r
260 &TmpMacAddr,\r
261 PXE_PROTOCOL_ETHERNET_ARP,\r
262 EFI_PXE_BASE_CODE_FUNCTION_ARP\r
263 );\r
264\r
265 //\r
266 // Give time (100 microseconds) for ARP reply to get onto wire.\r
267 //\r
268 gBS->Stall (1000);\r
269}\r
270\r
271/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
272BOOLEAN\r
273GetHwAddr (\r
274 IN PXE_BASECODE_DEVICE *Private,\r
275 IN EFI_IP_ADDRESS *ProtocolAddrPtr,\r
276 OUT EFI_MAC_ADDRESS *HardwareAddrPtr\r
277 )\r
278/*++\r
279Routine description:\r
280 Locate IP address in ARP cache and return MAC address.\r
281\r
282Parameters:\r
283 Private := Pointer to PxeBc interface\r
284 ProtocolAddrPtr := Pointer to IP address\r
285 HardwareAddrPtr := Pointer to MAC address storage\r
286\r
287Returns:\r
288 TRUE := If IP address was found and MAC address was stored\r
289 FALSE := If IP address was not found\r
290--*/\r
291{\r
292 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
293 UINTN HardwareAddrLength;\r
294 UINTN Index;\r
295\r
296 PxeBcMode = Private->EfiBc.Mode;\r
297 HardwareAddrLength = Private->SimpleNetwork->Mode->HwAddressSize;\r
298\r
299 for (Index = 0; Index < PxeBcMode->ArpCacheEntries; ++Index) {\r
300 if (!CompareMem (\r
301 ProtocolAddrPtr,\r
302 &PxeBcMode->ArpCache[Index].IpAddr,\r
303 Private->IpLength\r
304 )) {\r
305 CopyMem (\r
306 HardwareAddrPtr,\r
307 &PxeBcMode->ArpCache[Index].MacAddr,\r
308 HardwareAddrLength\r
309 );\r
310\r
311 return TRUE;\r
312 }\r
313 }\r
314\r
315 return FALSE;\r
316}\r
317\r
318/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
319STATIC\r
320EFI_STATUS\r
321SendRequest (\r
322 IN PXE_BASECODE_DEVICE *Private,\r
323 IN EFI_IP_ADDRESS *ProtocolAddrPtr,\r
324 IN EFI_MAC_ADDRESS *HardwareAddrPtr\r
325 )\r
326/*++\r
327Routine description:\r
328 Transmit ARP request packet\r
329\r
330Parameters:\r
331 Private := Pointer to PxeBc interface\r
332 ProtocolAddrPtr := Pointer IP address to find\r
333 HardwareAddrPtr := Pointer to MAC address to find\r
334\r
335Returns:\r
336 EFI_SUCCESS := ARP request sent\r
337 other := ARP request could not be sent\r
338--*/\r
339{\r
340 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
341 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
342 ARP_PACKET *ArpPacket;\r
343 EFI_STATUS Status;\r
344 UINTN HardwareAddrLength;\r
345 UINT8 *SrcProtocolAddrPtr;\r
346 UINT8 *DestHardwareAddrptr;\r
347 UINT8 *DestProtocolAddrPtr;\r
348\r
349 //\r
350 //\r
351 //\r
352 PxeBcMode = Private->EfiBc.Mode;\r
353 SnpMode = Private->SimpleNetwork->Mode;\r
354 HardwareAddrLength = SnpMode->HwAddressSize;\r
355\r
356 //\r
357 // Allocate ARP buffer\r
358 //\r
359 if (Private->ArpBuffer == NULL) {\r
360 Status = gBS->AllocatePool (\r
361 EfiBootServicesData,\r
362 SnpMode->MediaHeaderSize + sizeof (ARP_PACKET),\r
363 (VOID **) &Private->ArpBuffer\r
364 );\r
365\r
366 if (EFI_ERROR (Status)) {\r
367 return Status;\r
368 }\r
369 }\r
370\r
371 ArpPacket = (VOID *) (Private->ArpBuffer + SnpMode->MediaHeaderSize);\r
372\r
373 //\r
374 // for now, only handle one kind of hw and pr address\r
375 //\r
376 ArpPacket->ArpHeader = ArpHeader;\r
377 ArpPacket->ArpHeader.HwAddLen = (UINT8) HardwareAddrLength;\r
378 ArpPacket->ArpHeader.ProtAddLen = (UINT8) Private->IpLength;\r
379\r
380 //\r
381 // rest more generic\r
382 //\r
383 SrcProtocolAddrPtr = (UINT8 *) (&ArpPacket->SrcHardwareAddr) + HardwareAddrLength;\r
384 DestHardwareAddrptr = SrcProtocolAddrPtr + Private->IpLength;\r
385 DestProtocolAddrPtr = DestHardwareAddrptr + HardwareAddrLength;\r
386\r
387 CopyMem (DestProtocolAddrPtr, ProtocolAddrPtr, Private->IpLength);\r
388 CopyMem (DestHardwareAddrptr, HardwareAddrPtr, HardwareAddrLength);\r
389 CopyMem (SrcProtocolAddrPtr, &PxeBcMode->StationIp, Private->IpLength);\r
390 CopyMem (\r
391 &ArpPacket->SrcHardwareAddr,\r
392 &SnpMode->CurrentAddress,\r
393 HardwareAddrLength\r
394 );\r
395\r
396 return SendPacket (\r
397 Private,\r
398 Private->ArpBuffer,\r
399 ArpPacket,\r
400 sizeof (ARP_HEADER) + ((Private->IpLength + HardwareAddrLength) << 1),\r
401 &SnpMode->BroadcastAddress,\r
402 PXE_PROTOCOL_ETHERNET_ARP,\r
403 EFI_PXE_BASE_CODE_FUNCTION_ARP\r
404 );\r
405}\r
406\r
407/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
408\r
409//\r
410// check for address - if not there, send ARP request, wait and check again\r
411// not how it would be done in a full system\r
412//\r
413#define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second\r
414 \r
415 ////////////////////////////////////////////////////////////\r
416//\r
417// BC Arp Routine\r
418//\r
419EFI_STATUS\r
420EFIAPI\r
421BcArp (\r
422 IN EFI_PXE_BASE_CODE_PROTOCOL * This,\r
423 IN EFI_IP_ADDRESS * ProtocolAddrPtr,\r
424 OUT EFI_MAC_ADDRESS * HardwareAddrPtr OPTIONAL\r
425 )\r
426/*++\r
427Routine description:\r
428 PxeBc ARP API.\r
429\r
430Parameters:\r
431 This := Pointer to PxeBc interface\r
432 ProtocolAddrPtr := Pointer to IP address to find\r
433 HardwareAddrPtr := Pointer to MAC address found.\r
434\r
435Returns:\r
436--*/\r
437{\r
438 EFI_MAC_ADDRESS Mac;\r
439 EFI_STATUS StatCode;\r
440 PXE_BASECODE_DEVICE *Private;\r
441\r
442 //\r
443 // Lock the instance data and make sure started\r
444 //\r
445 StatCode = EFI_SUCCESS;\r
446\r
447 if (This == NULL) {\r
448 DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));\r
449 return EFI_INVALID_PARAMETER;\r
450 }\r
451\r
452 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
453\r
454 if (Private == NULL) {\r
455 DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
456 return EFI_INVALID_PARAMETER;\r
457 }\r
458\r
459 EfiAcquireLock (&Private->Lock);\r
460\r
461 if (This->Mode == NULL || !This->Mode->Started) {\r
462 DEBUG ((EFI_D_ERROR, "BC was not started."));\r
463 EfiReleaseLock (&Private->Lock);\r
464 return EFI_NOT_STARTED;\r
465 }\r
466\r
467 DEBUG ((EFI_D_INFO, "\nBcArp()"));\r
468\r
469 //\r
470 // Issue BC command\r
471 //\r
472 if (ProtocolAddrPtr == NULL) {\r
473 DEBUG (\r
474 (EFI_D_INFO,\r
475 "\nBcArp() Exit #1 %Xh (%r)",\r
476 EFI_INVALID_PARAMETER,\r
477 EFI_INVALID_PARAMETER)\r
478 );\r
479\r
480 EfiReleaseLock (&Private->Lock);\r
481 return EFI_INVALID_PARAMETER;\r
482 }\r
483\r
484 if (HardwareAddrPtr == NULL) {\r
485 HardwareAddrPtr = &Mac;\r
486 }\r
487\r
488 ZeroMem (HardwareAddrPtr, Private->SimpleNetwork->Mode->HwAddressSize);\r
489\r
490 if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {\r
491 DEBUG (\r
492 (EFI_D_INFO,\r
493 "\nBcArp() Exit #2 %Xh (%r)",\r
494 EFI_SUCCESS,\r
495 EFI_SUCCESS)\r
496 );\r
497\r
498 EfiReleaseLock (&Private->Lock);\r
499 return EFI_SUCCESS;\r
500 }\r
501\r
502 StatCode = DoArp (Private, ProtocolAddrPtr, HardwareAddrPtr);\r
503\r
504 DEBUG ((EFI_D_INFO, "\nBcArp() Exit #3 %Xh (%r)", StatCode, StatCode));\r
505\r
506 EfiReleaseLock (&Private->Lock);\r
507 return StatCode;\r
508}\r
509\r
510/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
511EFI_STATUS\r
512DoArp (\r
513 IN PXE_BASECODE_DEVICE *Private,\r
514 IN EFI_IP_ADDRESS *ProtocolAddrPtr,\r
515 OUT EFI_MAC_ADDRESS *HardwareAddrPtr\r
516 )\r
517/*++\r
518Routine description:\r
519 Internal ARP implementation.\r
520\r
521Parameters:\r
522 Private := Pointer to PxeBc interface\r
523 ProtocolAddrPtr := Pointer to IP address to find\r
524 HardwareAddrPtr := Pointer to MAC address found\r
525\r
526Returns:\r
527 EFI_SUCCESS := MAC address found\r
528 other := MAC address could not be found\r
529--*/\r
530{\r
531 EFI_STATUS StatCode;\r
532 EFI_EVENT TimeoutEvent;\r
533 UINTN HeaderSize;\r
534 UINTN BufferSize;\r
535 UINT16 Protocol;\r
536\r
537 DEBUG ((EFI_D_INFO, "\nDoArp()"));\r
538\r
539 //\r
540 //\r
541 //\r
542 StatCode = SendRequest (Private, ProtocolAddrPtr, HardwareAddrPtr);\r
543\r
544 if (EFI_ERROR (StatCode)) {\r
545 DEBUG ((EFI_D_INFO, "\nDoArp() Exit #1 %Xh (%r)", StatCode, StatCode));\r
546 return StatCode;\r
547 }\r
548 //\r
549 //\r
550 //\r
551 StatCode = gBS->CreateEvent (\r
552 EFI_EVENT_TIMER,\r
553 EFI_TPL_CALLBACK,\r
554 NULL,\r
555 NULL,\r
556 &TimeoutEvent\r
557 );\r
558\r
559 if (EFI_ERROR (StatCode)) {\r
560 return StatCode;\r
561 }\r
562\r
563 StatCode = gBS->SetTimer (\r
564 TimeoutEvent,\r
565 TimerRelative,\r
566 ARP_REQUEST_TIMEOUT_MS * 10000\r
567 );\r
568\r
569 if (EFI_ERROR (StatCode)) {\r
570 gBS->CloseEvent (TimeoutEvent);\r
571 return StatCode;\r
572 }\r
573 //\r
574 //\r
575 //\r
576 for (;;) {\r
577 StatCode = WaitForReceive (\r
578 Private,\r
579 EFI_PXE_BASE_CODE_FUNCTION_ARP,\r
580 TimeoutEvent,\r
581 &HeaderSize,\r
582 &BufferSize,\r
583 &Protocol\r
584 );\r
585\r
586 if (EFI_ERROR (StatCode)) {\r
587 break;\r
588 }\r
589\r
590 if (Protocol != PXE_PROTOCOL_ETHERNET_ARP) {\r
591 continue;\r
592 }\r
593\r
594 HandleArpReceive (\r
595 Private,\r
596 (ARP_PACKET *) (Private->ReceiveBufferPtr + HeaderSize),\r
597 Private->ReceiveBufferPtr\r
598 );\r
599\r
600 if (GetHwAddr (Private, ProtocolAddrPtr, HardwareAddrPtr)) {\r
601 break;\r
602 }\r
603 }\r
604\r
605 DEBUG (\r
606 (EFI_D_INFO,\r
607 "\nDoArp() Exit #2 %Xh, (%r)",\r
608 StatCode,\r
609 StatCode)\r
610 );\r
611\r
612 gBS->CloseEvent (TimeoutEvent);\r
613\r
614 return StatCode;\r
615}\r
616\r
617/* eof - pxe_bc_arp.c */\r