3 Copyright (c) 2006 - 2007, 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
;
343 UINTN HardwareAddrLength
;
344 UINT8
*SrcProtocolAddrPtr
;
345 UINT8
*DestHardwareAddrptr
;
346 UINT8
*DestProtocolAddrPtr
;
351 PxeBcMode
= Private
->EfiBc
.Mode
;
352 SnpMode
= Private
->SimpleNetwork
->Mode
;
353 HardwareAddrLength
= SnpMode
->HwAddressSize
;
356 // Allocate ARP buffer
358 if (Private
->ArpBuffer
== NULL
) {
359 Private
->ArpBuffer
= AllocatePool (SnpMode
->MediaHeaderSize
+ sizeof (ARP_PACKET
));
360 if (Private
->ArpBuffer
== NULL
) {
361 return EFI_OUT_OF_RESOURCES
;
365 ArpPacket
= (VOID
*) (Private
->ArpBuffer
+ SnpMode
->MediaHeaderSize
);
368 // for now, only handle one kind of hw and pr address
370 ArpPacket
->ArpHeader
= ArpHeader
;
371 ArpPacket
->ArpHeader
.HwAddLen
= (UINT8
) HardwareAddrLength
;
372 ArpPacket
->ArpHeader
.ProtAddLen
= (UINT8
) Private
->IpLength
;
377 SrcProtocolAddrPtr
= (UINT8
*) (&ArpPacket
->SrcHardwareAddr
) + HardwareAddrLength
;
378 DestHardwareAddrptr
= SrcProtocolAddrPtr
+ Private
->IpLength
;
379 DestProtocolAddrPtr
= DestHardwareAddrptr
+ HardwareAddrLength
;
381 CopyMem (DestProtocolAddrPtr
, ProtocolAddrPtr
, Private
->IpLength
);
382 CopyMem (DestHardwareAddrptr
, HardwareAddrPtr
, HardwareAddrLength
);
383 CopyMem (SrcProtocolAddrPtr
, &PxeBcMode
->StationIp
, Private
->IpLength
);
385 &ArpPacket
->SrcHardwareAddr
,
386 &SnpMode
->CurrentAddress
,
394 sizeof (ARP_HEADER
) + ((Private
->IpLength
+ HardwareAddrLength
) << 1),
395 &SnpMode
->BroadcastAddress
,
396 PXE_PROTOCOL_ETHERNET_ARP
,
397 EFI_PXE_BASE_CODE_FUNCTION_ARP
401 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
404 // check for address - if not there, send ARP request, wait and check again
405 // not how it would be done in a full system
407 #define ARP_REQUEST_TIMEOUT_MS 500 // try for half a second
409 ////////////////////////////////////////////////////////////
416 IN EFI_PXE_BASE_CODE_PROTOCOL
* This
,
417 IN EFI_IP_ADDRESS
* ProtocolAddrPtr
,
418 OUT EFI_MAC_ADDRESS
* HardwareAddrPtr OPTIONAL
425 This := Pointer to PxeBc interface
426 ProtocolAddrPtr := Pointer to IP address to find
427 HardwareAddrPtr := Pointer to MAC address found.
434 PXE_BASECODE_DEVICE
*Private
;
437 // Lock the instance data and make sure started
439 StatCode
= EFI_SUCCESS
;
442 DEBUG ((EFI_D_ERROR
, "BC *This pointer == NULL"));
443 return EFI_INVALID_PARAMETER
;
446 Private
= CR (This
, PXE_BASECODE_DEVICE
, EfiBc
, PXE_BASECODE_DEVICE_SIGNATURE
);
448 if (Private
== NULL
) {
449 DEBUG ((EFI_D_ERROR
, "PXE_BASECODE_DEVICE poiner == NULL"));
450 return EFI_INVALID_PARAMETER
;
453 EfiAcquireLock (&Private
->Lock
);
455 if (This
->Mode
== NULL
|| !This
->Mode
->Started
) {
456 DEBUG ((EFI_D_ERROR
, "BC was not started."));
457 EfiReleaseLock (&Private
->Lock
);
458 return EFI_NOT_STARTED
;
461 DEBUG ((EFI_D_INFO
, "\nBcArp()"));
466 if (ProtocolAddrPtr
== NULL
) {
469 "\nBcArp() Exit #1 %Xh (%r)",
470 EFI_INVALID_PARAMETER
,
471 EFI_INVALID_PARAMETER
)
474 EfiReleaseLock (&Private
->Lock
);
475 return EFI_INVALID_PARAMETER
;
478 if (HardwareAddrPtr
== NULL
) {
479 HardwareAddrPtr
= &Mac
;
482 ZeroMem (HardwareAddrPtr
, Private
->SimpleNetwork
->Mode
->HwAddressSize
);
484 if (GetHwAddr (Private
, ProtocolAddrPtr
, HardwareAddrPtr
)) {
487 "\nBcArp() Exit #2 %Xh (%r)",
492 EfiReleaseLock (&Private
->Lock
);
496 StatCode
= DoArp (Private
, ProtocolAddrPtr
, HardwareAddrPtr
);
498 DEBUG ((EFI_D_INFO
, "\nBcArp() Exit #3 %Xh (%r)", StatCode
, StatCode
));
500 EfiReleaseLock (&Private
->Lock
);
504 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
507 IN PXE_BASECODE_DEVICE
*Private
,
508 IN EFI_IP_ADDRESS
*ProtocolAddrPtr
,
509 OUT EFI_MAC_ADDRESS
*HardwareAddrPtr
513 Internal ARP implementation.
516 Private := Pointer to PxeBc interface
517 ProtocolAddrPtr := Pointer to IP address to find
518 HardwareAddrPtr := Pointer to MAC address found
521 EFI_SUCCESS := MAC address found
522 other := MAC address could not be found
526 EFI_EVENT TimeoutEvent
;
531 DEBUG ((EFI_D_INFO
, "\nDoArp()"));
536 StatCode
= SendRequest (Private
, ProtocolAddrPtr
, HardwareAddrPtr
);
538 if (EFI_ERROR (StatCode
)) {
539 DEBUG ((EFI_D_INFO
, "\nDoArp() Exit #1 %Xh (%r)", StatCode
, StatCode
));
545 StatCode
= gBS
->CreateEvent (
553 if (EFI_ERROR (StatCode
)) {
557 StatCode
= gBS
->SetTimer (
560 ARP_REQUEST_TIMEOUT_MS
* 10000
563 if (EFI_ERROR (StatCode
)) {
564 gBS
->CloseEvent (TimeoutEvent
);
571 StatCode
= WaitForReceive (
573 EFI_PXE_BASE_CODE_FUNCTION_ARP
,
580 if (EFI_ERROR (StatCode
)) {
584 if (Protocol
!= PXE_PROTOCOL_ETHERNET_ARP
) {
590 (ARP_PACKET
*) (Private
->ReceiveBufferPtr
+ HeaderSize
),
591 Private
->ReceiveBufferPtr
594 if (GetHwAddr (Private
, ProtocolAddrPtr
, HardwareAddrPtr
)) {
601 "\nDoArp() Exit #2 %Xh, (%r)",
606 gBS
->CloseEvent (TimeoutEvent
);
611 /* eof - pxe_bc_arp.c */