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
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
312 IN PXE_BASECODE_DEVICE
*Private
,
313 IN EFI_IP_ADDRESS
*ProtocolAddrPtr
,
314 IN EFI_MAC_ADDRESS
*HardwareAddrPtr
317 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
318 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
319 ARP_PACKET
*ArpPacket
;
321 UINTN HardwareAddrLength
;
322 UINT8
*SrcProtocolAddrPtr
;
323 UINT8
*DestHardwareAddrptr
;
324 UINT8
*DestProtocolAddrPtr
;
329 PxeBcMode
= Private
->EfiBc
.Mode
;
330 SnpMode
= Private
->SimpleNetwork
->Mode
;
331 HardwareAddrLength
= SnpMode
->HwAddressSize
;
334 // Allocate ARP buffer
336 if (Private
->ArpBuffer
== NULL
) {
337 Status
= gBS
->AllocatePool (
339 SnpMode
->MediaHeaderSize
+ sizeof (ARP_PACKET
),
340 (VOID
**) &Private
->ArpBuffer
343 if (EFI_ERROR (Status
)) {
348 ArpPacket
= (VOID
*) (Private
->ArpBuffer
+ SnpMode
->MediaHeaderSize
);
351 // for now, only handle one kind of hw and pr address
353 ArpPacket
->ArpHeader
= ArpHeader
;
354 ArpPacket
->ArpHeader
.HwAddLen
= (UINT8
) HardwareAddrLength
;
355 ArpPacket
->ArpHeader
.ProtAddLen
= (UINT8
) Private
->IpLength
;
360 SrcProtocolAddrPtr
= (UINT8
*) (&ArpPacket
->SrcHardwareAddr
) + HardwareAddrLength
;
361 DestHardwareAddrptr
= SrcProtocolAddrPtr
+ Private
->IpLength
;
362 DestProtocolAddrPtr
= DestHardwareAddrptr
+ HardwareAddrLength
;
364 CopyMem (DestProtocolAddrPtr
, ProtocolAddrPtr
, Private
->IpLength
);
365 CopyMem (DestHardwareAddrptr
, HardwareAddrPtr
, HardwareAddrLength
);
366 CopyMem (SrcProtocolAddrPtr
, &PxeBcMode
->StationIp
, Private
->IpLength
);
368 &ArpPacket
->SrcHardwareAddr
,
369 &SnpMode
->CurrentAddress
,
377 sizeof (ARP_HEADER
) + ((Private
->IpLength
+ HardwareAddrLength
) << 1),
378 &SnpMode
->BroadcastAddress
,
379 PXE_PROTOCOL_ETHERNET_ARP
,
380 EFI_PXE_BASE_CODE_FUNCTION_ARP
384 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
387 // check for address - if not there, send ARP request, wait and check again
388 // not how it would be done in a full system
390 #define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second
392 ////////////////////////////////////////////////////////////
404 IN EFI_PXE_BASE_CODE_PROTOCOL
* This
,
405 IN EFI_IP_ADDRESS
* ProtocolAddrPtr
,
406 OUT EFI_MAC_ADDRESS
* HardwareAddrPtr OPTIONAL
411 PXE_BASECODE_DEVICE
*Private
;
414 // Lock the instance data and make sure started
416 StatCode
= EFI_SUCCESS
;
419 DEBUG ((DEBUG_ERROR
, "BC *This pointer == NULL"));
420 return EFI_INVALID_PARAMETER
;
423 Private
= CR (This
, PXE_BASECODE_DEVICE
, EfiBc
, PXE_BASECODE_DEVICE_SIGNATURE
);
425 if (Private
== NULL
) {
426 DEBUG ((DEBUG_ERROR
, "PXE_BASECODE_DEVICE poiner == NULL"));
427 return EFI_INVALID_PARAMETER
;
430 EfiAcquireLock (&Private
->Lock
);
432 if (This
->Mode
== NULL
|| !This
->Mode
->Started
) {
433 DEBUG ((DEBUG_ERROR
, "BC was not started."));
434 EfiReleaseLock (&Private
->Lock
);
435 return EFI_NOT_STARTED
;
438 DEBUG ((DEBUG_INFO
, "\nBcArp()"));
443 if (ProtocolAddrPtr
== NULL
) {
446 "\nBcArp() Exit #1 %Xh (%r)",
447 EFI_INVALID_PARAMETER
,
448 EFI_INVALID_PARAMETER
)
451 EfiReleaseLock (&Private
->Lock
);
452 return EFI_INVALID_PARAMETER
;
455 if (HardwareAddrPtr
== NULL
) {
456 HardwareAddrPtr
= &Mac
;
459 ZeroMem (HardwareAddrPtr
, Private
->SimpleNetwork
->Mode
->HwAddressSize
);
461 if (GetHwAddr (Private
, ProtocolAddrPtr
, HardwareAddrPtr
)) {
464 "\nBcArp() Exit #2 %Xh (%r)",
469 EfiReleaseLock (&Private
->Lock
);
473 StatCode
= DoArp (Private
, ProtocolAddrPtr
, HardwareAddrPtr
);
475 DEBUG ((DEBUG_INFO
, "\nBcArp() Exit #3 %Xh (%r)", StatCode
, StatCode
));
477 EfiReleaseLock (&Private
->Lock
);
481 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
485 @return EFI_SUCCESS := MAC address found
486 @return other := MAC address could not be found
491 IN PXE_BASECODE_DEVICE
*Private
,
492 IN EFI_IP_ADDRESS
*ProtocolAddrPtr
,
493 OUT EFI_MAC_ADDRESS
*HardwareAddrPtr
497 EFI_EVENT TimeoutEvent
;
502 DEBUG ((DEBUG_INFO
, "\nDoArp()"));
507 StatCode
= SendRequest (Private
, ProtocolAddrPtr
, HardwareAddrPtr
);
509 if (EFI_ERROR (StatCode
)) {
510 DEBUG ((DEBUG_INFO
, "\nDoArp() Exit #1 %Xh (%r)", StatCode
, StatCode
));
516 StatCode
= gBS
->CreateEvent (
524 if (EFI_ERROR (StatCode
)) {
528 StatCode
= gBS
->SetTimer (
531 ARP_REQUEST_TIMEOUT_MS
* 10000
534 if (EFI_ERROR (StatCode
)) {
535 gBS
->CloseEvent (TimeoutEvent
);
542 StatCode
= WaitForReceive (
544 EFI_PXE_BASE_CODE_FUNCTION_ARP
,
551 if (EFI_ERROR (StatCode
)) {
555 if (Protocol
!= PXE_PROTOCOL_ETHERNET_ARP
) {
561 (ARP_PACKET
*) (Private
->ReceiveBufferPtr
+ HeaderSize
),
562 Private
->ReceiveBufferPtr
565 if (GetHwAddr (Private
, ProtocolAddrPtr
, HardwareAddrPtr
)) {
572 "\nDoArp() Exit #2 %Xh, (%r)",
577 gBS
->CloseEvent (TimeoutEvent
);
582 /* eof - pxe_bc_arp.c */