3 Copyright (c) 2004, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 // Definitions for ARP
26 STATIC ARP_HEADER ArpHeader
;
30 UINT8 MediaHeader
[14];
36 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
48 ArpHeader
.HwType
= HTONS (ETHERNET_ADD_SPC
);
49 ArpHeader
.ProtType
= HTONS (ETHER_TYPE_IP
);
50 ArpHeader
.HwAddLen
= ENET_HWADDLEN
;
51 ArpHeader
.ProtAddLen
= IPV4_PROTADDLEN
;
52 ArpHeader
.OpCode
= HTONS (ARP_REQUEST
);
54 CopyMem (&ArpReplyPacket
.ArpHeader
, &ArpHeader
, sizeof (ARP_HEADER
));
57 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
65 IN PXE_BASECODE_DEVICE
*Private
,
66 IN ARP_PACKET
*ArpPacketPtr
,
70 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
71 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
72 EFI_MAC_ADDRESS TmpMacAddr
;
83 PxeBcMode
= Private
->EfiBc
.Mode
;
84 SnpMode
= Private
->SimpleNetwork
->Mode
;
87 // For now only ethernet addresses are supported.
88 // This will need to be updated when other media
89 // layers are supported by PxeBc, Snp and UNDI.
91 if (ArpPacketPtr
->ArpHeader
.HwType
!= HTONS (ETHERNET_ADD_SPC
)) {
95 // For now only IP protocol addresses are supported.
96 // This will need to be updated when other protocol
97 // types are supported by PxeBc, Snp and UNDI.
99 if (ArpPacketPtr
->ArpHeader
.ProtType
!= HTONS (ETHER_TYPE_IP
)) {
103 // For now only SNP hardware address sizes are supported.
105 if (ArpPacketPtr
->ArpHeader
.HwAddLen
!= SnpMode
->HwAddressSize
) {
109 // For now only PxeBc protocol address sizes are supported.
111 if (ArpPacketPtr
->ArpHeader
.ProtAddLen
!= Private
->IpLength
) {
115 // Ignore out of range opcodes
117 switch (ArpPacketPtr
->ArpHeader
.OpCode
) {
118 case HTONS (ARP_REPLY
):
119 case HTONS (ARP_REQUEST
):
126 // update entry in our ARP cache if we have it
128 SrcHwAddr
= (UINT8
*) &ArpPacketPtr
->SrcHardwareAddr
;
129 SrcPrAddr
= SrcHwAddr
+ SnpMode
->HwAddressSize
;
131 for (Index
= 0; Index
< PxeBcMode
->ArpCacheEntries
; ++Index
) {
133 &PxeBcMode
->ArpCache
[Index
].IpAddr
,
141 &PxeBcMode
->ArpCache
[Index
].MacAddr
,
143 SnpMode
->HwAddressSize
149 // Done if ARP packet was not for us.
151 DstHwAddr
= SrcPrAddr
+ Private
->IpLength
;
152 DstPrAddr
= DstHwAddr
+ SnpMode
->HwAddressSize
;
154 if (CompareMem (DstPrAddr
, &PxeBcMode
->StationIp
, Private
->IpLength
)) {
161 // for us - if we did not update entry, add it
163 if (Index
== PxeBcMode
->ArpCacheEntries
) {
165 // if we have a full table, get rid of oldest
167 if (Index
== PXE_ARP_CACHE_SIZE
) {
168 Index
= Private
->OldestArpEntry
;
170 if (++Private
->OldestArpEntry
== PXE_ARP_CACHE_SIZE
) {
171 Private
->OldestArpEntry
= 0;
174 ++PxeBcMode
->ArpCacheEntries
;
178 &PxeBcMode
->ArpCache
[Index
].MacAddr
,
180 SnpMode
->HwAddressSize
184 &PxeBcMode
->ArpCache
[Index
].IpAddr
,
190 // if this is not a request or we don't yet have an IP, finished
192 if (ArpPacketPtr
->ArpHeader
.OpCode
!= HTONS (ARP_REQUEST
) || !Private
->GoodStationIp
) {
196 // Assemble ARP reply.
199 // Create media header. [ dest mac | src mac | prot ]
202 &ArpReplyPacket
.MediaHeader
[0],
204 SnpMode
->HwAddressSize
208 &ArpReplyPacket
.MediaHeader
[SnpMode
->HwAddressSize
],
209 &SnpMode
->CurrentAddress
,
210 SnpMode
->HwAddressSize
214 &ArpReplyPacket
.MediaHeader
[2 * SnpMode
->HwAddressSize
],
215 &((UINT8
*) MediaHeader
)[2 * SnpMode
->HwAddressSize
],
220 // ARP reply header is almost filled in,
221 // just insert the correct opcode.
223 ArpReplyPacket
.ArpHeader
.OpCode
= HTONS (ARP_REPLY
);
226 // Now fill in ARP data. [ src mac | src prot | dest mac | dest prot ]
228 TmpPtr
= ArpReplyPacket
.ArpData
;
229 CopyMem (TmpPtr
, &SnpMode
->CurrentAddress
, SnpMode
->HwAddressSize
);
231 TmpPtr
+= SnpMode
->HwAddressSize
;
232 CopyMem (TmpPtr
, &PxeBcMode
->StationIp
, Private
->IpLength
);
234 TmpPtr
+= Private
->IpLength
;
235 CopyMem (TmpPtr
, SrcHwAddr
, SnpMode
->HwAddressSize
);
237 TmpPtr
+= SnpMode
->HwAddressSize
;
238 CopyMem (TmpPtr
, SrcPrAddr
, Private
->IpLength
);
241 // Now send out the ARP reply.
243 CopyMem (&TmpMacAddr
, SrcHwAddr
, sizeof (EFI_MAC_ADDRESS
));
247 &ArpReplyPacket
.MediaHeader
,
248 &ArpReplyPacket
.ArpHeader
,
249 sizeof (ARP_HEADER
) + 2 * (Private
->IpLength
+ SnpMode
->HwAddressSize
),
251 PXE_PROTOCOL_ETHERNET_ARP
,
252 EFI_PXE_BASE_CODE_FUNCTION_ARP
256 // Give time (100 microseconds) for ARP reply to get onto wire.
261 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
265 @return TRUE := If IP address was found and MAC address was stored
266 @return FALSE := If IP address was not found
271 IN PXE_BASECODE_DEVICE
*Private
,
272 IN EFI_IP_ADDRESS
*ProtocolAddrPtr
,
273 OUT EFI_MAC_ADDRESS
*HardwareAddrPtr
276 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
277 UINTN HardwareAddrLength
;
280 PxeBcMode
= Private
->EfiBc
.Mode
;
281 HardwareAddrLength
= Private
->SimpleNetwork
->Mode
->HwAddressSize
;
283 for (Index
= 0; Index
< PxeBcMode
->ArpCacheEntries
; ++Index
) {
286 &PxeBcMode
->ArpCache
[Index
].IpAddr
,
291 &PxeBcMode
->ArpCache
[Index
].MacAddr
,
302 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
306 @return EFI_SUCCESS := ARP request sent
307 @return other := ARP request could not be sent
313 IN PXE_BASECODE_DEVICE
*Private
,
314 IN EFI_IP_ADDRESS
*ProtocolAddrPtr
,
315 IN EFI_MAC_ADDRESS
*HardwareAddrPtr
318 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
319 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
320 ARP_PACKET
*ArpPacket
;
322 UINTN HardwareAddrLength
;
323 UINT8
*SrcProtocolAddrPtr
;
324 UINT8
*DestHardwareAddrptr
;
325 UINT8
*DestProtocolAddrPtr
;
330 PxeBcMode
= Private
->EfiBc
.Mode
;
331 SnpMode
= Private
->SimpleNetwork
->Mode
;
332 HardwareAddrLength
= SnpMode
->HwAddressSize
;
335 // Allocate ARP buffer
337 if (Private
->ArpBuffer
== NULL
) {
338 Status
= gBS
->AllocatePool (
340 SnpMode
->MediaHeaderSize
+ sizeof (ARP_PACKET
),
344 if (EFI_ERROR (Status
)) {
349 ArpPacket
= (VOID
*) (Private
->ArpBuffer
+ SnpMode
->MediaHeaderSize
);
352 // for now, only handle one kind of hw and pr address
354 ArpPacket
->ArpHeader
= ArpHeader
;
355 ArpPacket
->ArpHeader
.HwAddLen
= (UINT8
) HardwareAddrLength
;
356 ArpPacket
->ArpHeader
.ProtAddLen
= (UINT8
) Private
->IpLength
;
361 SrcProtocolAddrPtr
= (UINT8
*) (&ArpPacket
->SrcHardwareAddr
) + HardwareAddrLength
;
362 DestHardwareAddrptr
= SrcProtocolAddrPtr
+ Private
->IpLength
;
363 DestProtocolAddrPtr
= DestHardwareAddrptr
+ HardwareAddrLength
;
365 CopyMem (DestProtocolAddrPtr
, ProtocolAddrPtr
, Private
->IpLength
);
366 CopyMem (DestHardwareAddrptr
, HardwareAddrPtr
, HardwareAddrLength
);
367 CopyMem (SrcProtocolAddrPtr
, &PxeBcMode
->StationIp
, Private
->IpLength
);
369 &ArpPacket
->SrcHardwareAddr
,
370 &SnpMode
->CurrentAddress
,
378 sizeof (ARP_HEADER
) + ((Private
->IpLength
+ HardwareAddrLength
) << 1),
379 &SnpMode
->BroadcastAddress
,
380 PXE_PROTOCOL_ETHERNET_ARP
,
381 EFI_PXE_BASE_CODE_FUNCTION_ARP
385 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
388 // check for address - if not there, send ARP request, wait and check again
389 // not how it would be done in a full system
391 #define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second
393 ////////////////////////////////////////////////////////////
405 IN EFI_PXE_BASE_CODE_PROTOCOL
* This
,
406 IN EFI_IP_ADDRESS
* ProtocolAddrPtr
,
407 OUT EFI_MAC_ADDRESS
* HardwareAddrPtr OPTIONAL
412 PXE_BASECODE_DEVICE
*Private
;
415 // Lock the instance data and make sure started
417 StatCode
= EFI_SUCCESS
;
420 DEBUG ((DEBUG_ERROR
, "BC *This pointer == NULL"));
421 return EFI_INVALID_PARAMETER
;
424 Private
= CR (This
, PXE_BASECODE_DEVICE
, EfiBc
, PXE_BASECODE_DEVICE_SIGNATURE
);
426 if (Private
== NULL
) {
427 DEBUG ((DEBUG_ERROR
, "PXE_BASECODE_DEVICE poiner == NULL"));
428 return EFI_INVALID_PARAMETER
;
431 EfiAcquireLock (&Private
->Lock
);
433 if (This
->Mode
== NULL
|| !This
->Mode
->Started
) {
434 DEBUG ((DEBUG_ERROR
, "BC was not started."));
435 EfiReleaseLock (&Private
->Lock
);
436 return EFI_NOT_STARTED
;
439 DEBUG ((DEBUG_INFO
, "\nBcArp()"));
444 if (ProtocolAddrPtr
== NULL
) {
447 "\nBcArp() Exit #1 %Xh (%r)",
448 EFI_INVALID_PARAMETER
,
449 EFI_INVALID_PARAMETER
)
452 EfiReleaseLock (&Private
->Lock
);
453 return EFI_INVALID_PARAMETER
;
456 if (HardwareAddrPtr
== NULL
) {
457 HardwareAddrPtr
= &Mac
;
460 ZeroMem (HardwareAddrPtr
, Private
->SimpleNetwork
->Mode
->HwAddressSize
);
462 if (GetHwAddr (Private
, ProtocolAddrPtr
, HardwareAddrPtr
)) {
465 "\nBcArp() Exit #2 %Xh (%r)",
470 EfiReleaseLock (&Private
->Lock
);
474 StatCode
= DoArp (Private
, ProtocolAddrPtr
, HardwareAddrPtr
);
476 DEBUG ((DEBUG_INFO
, "\nBcArp() Exit #3 %Xh (%r)", StatCode
, StatCode
));
478 EfiReleaseLock (&Private
->Lock
);
482 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
486 @return EFI_SUCCESS := MAC address found
487 @return other := MAC address could not be found
492 IN PXE_BASECODE_DEVICE
*Private
,
493 IN EFI_IP_ADDRESS
*ProtocolAddrPtr
,
494 OUT EFI_MAC_ADDRESS
*HardwareAddrPtr
498 EFI_EVENT TimeoutEvent
;
503 DEBUG ((DEBUG_INFO
, "\nDoArp()"));
508 StatCode
= SendRequest (Private
, ProtocolAddrPtr
, HardwareAddrPtr
);
510 if (EFI_ERROR (StatCode
)) {
511 DEBUG ((DEBUG_INFO
, "\nDoArp() Exit #1 %Xh (%r)", StatCode
, StatCode
));
517 StatCode
= gBS
->CreateEvent (
525 if (EFI_ERROR (StatCode
)) {
529 StatCode
= gBS
->SetTimer (
532 ARP_REQUEST_TIMEOUT_MS
* 10000
535 if (EFI_ERROR (StatCode
)) {
536 gBS
->CloseEvent (TimeoutEvent
);
543 StatCode
= WaitForReceive (
545 EFI_PXE_BASE_CODE_FUNCTION_ARP
,
552 if (EFI_ERROR (StatCode
)) {
556 if (Protocol
!= PXE_PROTOCOL_ETHERNET_ARP
) {
562 (ARP_PACKET
*) (Private
->ReceiveBufferPtr
+ HeaderSize
),
563 Private
->ReceiveBufferPtr
566 if (GetHwAddr (Private
, ProtocolAddrPtr
, HardwareAddrPtr
)) {
573 "\nDoArp() Exit #2 %Xh, (%r)",
578 gBS
->CloseEvent (TimeoutEvent
);
583 /* eof - pxe_bc_arp.c */