3 Copyright (c) 2006, 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 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
43 Initialize ARP packet header.
53 ArpHeader
.HwType
= HTONS (ETHERNET_ADD_SPC
);
54 ArpHeader
.ProtType
= HTONS (ETHER_TYPE_IP
);
55 ArpHeader
.HwAddLen
= ENET_HWADDLEN
;
56 ArpHeader
.ProtAddLen
= IPV4_PROTADDLEN
;
57 ArpHeader
.OpCode
= HTONS (ARP_REQUEST
);
59 CopyMem (&ArpReplyPacket
.ArpHeader
, &ArpHeader
, sizeof (ARP_HEADER
));
62 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
65 IN PXE_BASECODE_DEVICE
*Private
,
66 IN ARP_PACKET
*ArpPacketPtr
,
74 Private := Pointer to PxeBc interface
75 ArpPacketPtr := Pointer to ARP packet
76 MediaHeader := Pointer to media header.
80 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
81 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
82 EFI_MAC_ADDRESS TmpMacAddr
;
93 PxeBcMode
= Private
->EfiBc
.Mode
;
94 SnpMode
= Private
->SimpleNetwork
->Mode
;
97 // For now only ethernet addresses are supported.
98 // This will need to be updated when other media
99 // layers are supported by PxeBc, Snp and UNDI.
101 if (ArpPacketPtr
->ArpHeader
.HwType
!= HTONS (ETHERNET_ADD_SPC
)) {
105 // For now only IP protocol addresses are supported.
106 // This will need to be updated when other protocol
107 // types are supported by PxeBc, Snp and UNDI.
109 if (ArpPacketPtr
->ArpHeader
.ProtType
!= HTONS (ETHER_TYPE_IP
)) {
113 // For now only SNP hardware address sizes are supported.
115 if (ArpPacketPtr
->ArpHeader
.HwAddLen
!= SnpMode
->HwAddressSize
) {
119 // For now only PxeBc protocol address sizes are supported.
121 if (ArpPacketPtr
->ArpHeader
.ProtAddLen
!= Private
->IpLength
) {
125 // Ignore out of range opcodes
127 switch (ArpPacketPtr
->ArpHeader
.OpCode
) {
128 case HTONS (ARP_REPLY
):
129 case HTONS (ARP_REQUEST
):
136 // update entry in our ARP cache if we have it
138 SrcHwAddr
= (UINT8
*) &ArpPacketPtr
->SrcHardwareAddr
;
139 SrcPrAddr
= SrcHwAddr
+ SnpMode
->HwAddressSize
;
141 for (Index
= 0; Index
< PxeBcMode
->ArpCacheEntries
; ++Index
) {
143 &PxeBcMode
->ArpCache
[Index
].IpAddr
,
151 &PxeBcMode
->ArpCache
[Index
].MacAddr
,
153 SnpMode
->HwAddressSize
159 // Done if ARP packet was not for us.
161 DstHwAddr
= SrcPrAddr
+ Private
->IpLength
;
162 DstPrAddr
= DstHwAddr
+ SnpMode
->HwAddressSize
;
164 if (CompareMem (DstPrAddr
, &PxeBcMode
->StationIp
, Private
->IpLength
)) {
171 // for us - if we did not update entry, add it
173 if (Index
== PxeBcMode
->ArpCacheEntries
) {
175 // if we have a full table, get rid of oldest
177 if (Index
== PXE_ARP_CACHE_SIZE
) {
178 Index
= Private
->OldestArpEntry
;
180 if (++Private
->OldestArpEntry
== PXE_ARP_CACHE_SIZE
) {
181 Private
->OldestArpEntry
= 0;
184 ++PxeBcMode
->ArpCacheEntries
;
188 &PxeBcMode
->ArpCache
[Index
].MacAddr
,
190 SnpMode
->HwAddressSize
194 &PxeBcMode
->ArpCache
[Index
].IpAddr
,
200 // if this is not a request or we don't yet have an IP, finished
202 if (ArpPacketPtr
->ArpHeader
.OpCode
!= HTONS (ARP_REQUEST
) || !Private
->GoodStationIp
) {
206 // Assemble ARP reply.
209 // Create media header. [ dest mac | src mac | prot ]
212 &ArpReplyPacket
.MediaHeader
[0],
214 SnpMode
->HwAddressSize
218 &ArpReplyPacket
.MediaHeader
[SnpMode
->HwAddressSize
],
219 &SnpMode
->CurrentAddress
,
220 SnpMode
->HwAddressSize
224 &ArpReplyPacket
.MediaHeader
[2 * SnpMode
->HwAddressSize
],
225 &((UINT8
*) MediaHeader
)[2 * SnpMode
->HwAddressSize
],
230 // ARP reply header is almost filled in,
231 // just insert the correct opcode.
233 ArpReplyPacket
.ArpHeader
.OpCode
= HTONS (ARP_REPLY
);
236 // Now fill in ARP data. [ src mac | src prot | dest mac | dest prot ]
238 TmpPtr
= ArpReplyPacket
.ArpData
;
239 CopyMem (TmpPtr
, &SnpMode
->CurrentAddress
, SnpMode
->HwAddressSize
);
241 TmpPtr
+= SnpMode
->HwAddressSize
;
242 CopyMem (TmpPtr
, &PxeBcMode
->StationIp
, Private
->IpLength
);
244 TmpPtr
+= Private
->IpLength
;
245 CopyMem (TmpPtr
, SrcHwAddr
, SnpMode
->HwAddressSize
);
247 TmpPtr
+= SnpMode
->HwAddressSize
;
248 CopyMem (TmpPtr
, SrcPrAddr
, Private
->IpLength
);
251 // Now send out the ARP reply.
253 CopyMem (&TmpMacAddr
, SrcHwAddr
, sizeof (EFI_MAC_ADDRESS
));
257 &ArpReplyPacket
.MediaHeader
,
258 &ArpReplyPacket
.ArpHeader
,
259 sizeof (ARP_HEADER
) + 2 * (Private
->IpLength
+ SnpMode
->HwAddressSize
),
261 PXE_PROTOCOL_ETHERNET_ARP
,
262 EFI_PXE_BASE_CODE_FUNCTION_ARP
266 // Give time (100 microseconds) for ARP reply to get onto wire.
271 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
274 IN PXE_BASECODE_DEVICE
*Private
,
275 IN EFI_IP_ADDRESS
*ProtocolAddrPtr
,
276 OUT EFI_MAC_ADDRESS
*HardwareAddrPtr
280 Locate IP address in ARP cache and return MAC address.
283 Private := Pointer to PxeBc interface
284 ProtocolAddrPtr := Pointer to IP address
285 HardwareAddrPtr := Pointer to MAC address storage
288 TRUE := If IP address was found and MAC address was stored
289 FALSE := If IP address was not found
292 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
293 UINTN HardwareAddrLength
;
296 PxeBcMode
= Private
->EfiBc
.Mode
;
297 HardwareAddrLength
= Private
->SimpleNetwork
->Mode
->HwAddressSize
;
299 for (Index
= 0; Index
< PxeBcMode
->ArpCacheEntries
; ++Index
) {
302 &PxeBcMode
->ArpCache
[Index
].IpAddr
,
307 &PxeBcMode
->ArpCache
[Index
].MacAddr
,
318 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
322 IN PXE_BASECODE_DEVICE
*Private
,
323 IN EFI_IP_ADDRESS
*ProtocolAddrPtr
,
324 IN EFI_MAC_ADDRESS
*HardwareAddrPtr
328 Transmit ARP request packet
331 Private := Pointer to PxeBc interface
332 ProtocolAddrPtr := Pointer IP address to find
333 HardwareAddrPtr := Pointer to MAC address to find
336 EFI_SUCCESS := ARP request sent
337 other := ARP request could not be sent
340 EFI_PXE_BASE_CODE_MODE
*PxeBcMode
;
341 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
342 ARP_PACKET
*ArpPacket
;
344 UINTN HardwareAddrLength
;
345 UINT8
*SrcProtocolAddrPtr
;
346 UINT8
*DestHardwareAddrptr
;
347 UINT8
*DestProtocolAddrPtr
;
352 PxeBcMode
= Private
->EfiBc
.Mode
;
353 SnpMode
= Private
->SimpleNetwork
->Mode
;
354 HardwareAddrLength
= SnpMode
->HwAddressSize
;
357 // Allocate ARP buffer
359 if (Private
->ArpBuffer
== NULL
) {
360 Status
= gBS
->AllocatePool (
362 SnpMode
->MediaHeaderSize
+ sizeof (ARP_PACKET
),
363 (VOID
**) &Private
->ArpBuffer
366 if (EFI_ERROR (Status
)) {
371 ArpPacket
= (VOID
*) (Private
->ArpBuffer
+ SnpMode
->MediaHeaderSize
);
374 // for now, only handle one kind of hw and pr address
376 ArpPacket
->ArpHeader
= ArpHeader
;
377 ArpPacket
->ArpHeader
.HwAddLen
= (UINT8
) HardwareAddrLength
;
378 ArpPacket
->ArpHeader
.ProtAddLen
= (UINT8
) Private
->IpLength
;
383 SrcProtocolAddrPtr
= (UINT8
*) (&ArpPacket
->SrcHardwareAddr
) + HardwareAddrLength
;
384 DestHardwareAddrptr
= SrcProtocolAddrPtr
+ Private
->IpLength
;
385 DestProtocolAddrPtr
= DestHardwareAddrptr
+ HardwareAddrLength
;
387 CopyMem (DestProtocolAddrPtr
, ProtocolAddrPtr
, Private
->IpLength
);
388 CopyMem (DestHardwareAddrptr
, HardwareAddrPtr
, HardwareAddrLength
);
389 CopyMem (SrcProtocolAddrPtr
, &PxeBcMode
->StationIp
, Private
->IpLength
);
391 &ArpPacket
->SrcHardwareAddr
,
392 &SnpMode
->CurrentAddress
,
400 sizeof (ARP_HEADER
) + ((Private
->IpLength
+ HardwareAddrLength
) << 1),
401 &SnpMode
->BroadcastAddress
,
402 PXE_PROTOCOL_ETHERNET_ARP
,
403 EFI_PXE_BASE_CODE_FUNCTION_ARP
407 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
410 // check for address - if not there, send ARP request, wait and check again
411 // not how it would be done in a full system
413 #define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second
415 ////////////////////////////////////////////////////////////
422 IN EFI_PXE_BASE_CODE_PROTOCOL
* This
,
423 IN EFI_IP_ADDRESS
* ProtocolAddrPtr
,
424 OUT EFI_MAC_ADDRESS
* HardwareAddrPtr OPTIONAL
431 This := Pointer to PxeBc interface
432 ProtocolAddrPtr := Pointer to IP address to find
433 HardwareAddrPtr := Pointer to MAC address found.
440 PXE_BASECODE_DEVICE
*Private
;
443 // Lock the instance data and make sure started
445 StatCode
= EFI_SUCCESS
;
448 DEBUG ((EFI_D_ERROR
, "BC *This pointer == NULL"));
449 return EFI_INVALID_PARAMETER
;
452 Private
= CR (This
, PXE_BASECODE_DEVICE
, EfiBc
, PXE_BASECODE_DEVICE_SIGNATURE
);
454 if (Private
== NULL
) {
455 DEBUG ((EFI_D_ERROR
, "PXE_BASECODE_DEVICE poiner == NULL"));
456 return EFI_INVALID_PARAMETER
;
459 EfiAcquireLock (&Private
->Lock
);
461 if (This
->Mode
== NULL
|| !This
->Mode
->Started
) {
462 DEBUG ((EFI_D_ERROR
, "BC was not started."));
463 EfiReleaseLock (&Private
->Lock
);
464 return EFI_NOT_STARTED
;
467 DEBUG ((EFI_D_INFO
, "\nBcArp()"));
472 if (ProtocolAddrPtr
== NULL
) {
475 "\nBcArp() Exit #1 %Xh (%r)",
476 EFI_INVALID_PARAMETER
,
477 EFI_INVALID_PARAMETER
)
480 EfiReleaseLock (&Private
->Lock
);
481 return EFI_INVALID_PARAMETER
;
484 if (HardwareAddrPtr
== NULL
) {
485 HardwareAddrPtr
= &Mac
;
488 ZeroMem (HardwareAddrPtr
, Private
->SimpleNetwork
->Mode
->HwAddressSize
);
490 if (GetHwAddr (Private
, ProtocolAddrPtr
, HardwareAddrPtr
)) {
493 "\nBcArp() Exit #2 %Xh (%r)",
498 EfiReleaseLock (&Private
->Lock
);
502 StatCode
= DoArp (Private
, ProtocolAddrPtr
, HardwareAddrPtr
);
504 DEBUG ((EFI_D_INFO
, "\nBcArp() Exit #3 %Xh (%r)", StatCode
, StatCode
));
506 EfiReleaseLock (&Private
->Lock
);
510 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
513 IN PXE_BASECODE_DEVICE
*Private
,
514 IN EFI_IP_ADDRESS
*ProtocolAddrPtr
,
515 OUT EFI_MAC_ADDRESS
*HardwareAddrPtr
519 Internal ARP implementation.
522 Private := Pointer to PxeBc interface
523 ProtocolAddrPtr := Pointer to IP address to find
524 HardwareAddrPtr := Pointer to MAC address found
527 EFI_SUCCESS := MAC address found
528 other := MAC address could not be found
532 EFI_EVENT TimeoutEvent
;
537 DEBUG ((EFI_D_INFO
, "\nDoArp()"));
542 StatCode
= SendRequest (Private
, ProtocolAddrPtr
, HardwareAddrPtr
);
544 if (EFI_ERROR (StatCode
)) {
545 DEBUG ((EFI_D_INFO
, "\nDoArp() Exit #1 %Xh (%r)", StatCode
, StatCode
));
551 StatCode
= gBS
->CreateEvent (
559 if (EFI_ERROR (StatCode
)) {
563 StatCode
= gBS
->SetTimer (
566 ARP_REQUEST_TIMEOUT_MS
* 10000
569 if (EFI_ERROR (StatCode
)) {
570 gBS
->CloseEvent (TimeoutEvent
);
577 StatCode
= WaitForReceive (
579 EFI_PXE_BASE_CODE_FUNCTION_ARP
,
586 if (EFI_ERROR (StatCode
)) {
590 if (Protocol
!= PXE_PROTOCOL_ETHERNET_ARP
) {
596 (ARP_PACKET
*) (Private
->ReceiveBufferPtr
+ HeaderSize
),
597 Private
->ReceiveBufferPtr
600 if (GetHwAddr (Private
, ProtocolAddrPtr
, HardwareAddrPtr
)) {
607 "\nDoArp() Exit #2 %Xh, (%r)",
612 gBS
->CloseEvent (TimeoutEvent
);
617 /* eof - pxe_bc_arp.c */