2 * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
6 #include <boot/net/ARP.h>
9 #include <KernelExport.h>
11 #include <boot/net/ChainBuffer.h>
16 # define TRACE(x) dprintf x
23 ARPService::ARPService(EthernetService
*ethernet
)
24 : EthernetSubService(kARPServiceName
),
29 for (int i
= 0; i
< MAP_ENTRY_COUNT
; i
++)
30 fEntries
[i
].ip
= INADDR_ANY
;
34 ARPService::~ARPService()
37 fEthernet
->UnregisterEthernetSubService(this);
46 if (!fEthernet
->RegisterEthernetSubService(this))
53 ARPService::EthernetProtocol() const
58 // HandleEthernetPacket
60 ARPService::HandleEthernetPacket(EthernetService
*ethernet
,
61 const mac_addr_t
&targetAddress
, const void *data
, size_t size
)
63 TRACE(("ARPService::HandleEthernetPacket(): %lu - %lu bytes\n", size
,
66 if (size
< sizeof(arp_header
))
69 arp_header
*header
= (arp_header
*)data
;
70 // check packet validity
71 if (header
->hardware_format
!= htons(ARPHRD_ETHER
)
72 || header
->protocol_format
!= htons(ETHERTYPE_IP
)
73 || header
->hardware_length
!= sizeof(mac_addr_t
)
74 || header
->protocol_length
!= sizeof(ip_addr_t
)
76 || header
->sender_mac
== kNoMACAddress
77 || header
->sender_mac
== kBroadcastMACAddress
78 // do we support the opcode?
79 || (header
->opcode
!= htons(ARPOP_REQUEST
)
80 && header
->opcode
!= htons(ARPOP_REPLY
))) {
84 // if this is a request, we continue only, if we have the targeted IP
85 if (header
->opcode
== htons(ARPOP_REQUEST
)
86 && (fEthernet
->IPAddress() == INADDR_ANY
87 || header
->target_ip
!= htonl(fEthernet
->IPAddress()))) {
91 // if this is a reqly, we accept it only, if it was directly sent to us
92 if (header
->opcode
== htons(ARPOP_REPLY
)
93 && (targetAddress
!= fEthernet
->MACAddress()
94 || header
->target_mac
!= targetAddress
)) {
98 // if sender IP looks valid, enter the mapping
99 if (header
->sender_ip
!= htonl(INADDR_ANY
)
100 && header
->sender_ip
!= htonl(INADDR_BROADCAST
)) {
101 _PutEntry(ntohl(header
->sender_ip
), header
->sender_mac
);
104 // if this is a request, send a reply
105 if (header
->opcode
== htons(ARPOP_REQUEST
)) {
106 _SendARPPacket(ntohl(header
->sender_ip
), header
->sender_mac
,
113 ARPService::GetMACForIP(ip_addr_t ip
, mac_addr_t
&mac
)
115 TRACE(("ARPService::GetMACForIP(%08lx)\n", ip
));
117 if (ip
== INADDR_ANY
)
119 if (ip
== INADDR_BROADCAST
) {
120 mac
= kBroadcastMACAddress
;
121 TRACE(("ARPService::GetMACForIP(%08lx) done: %012llx\n", ip
,
127 if (MapEntry
*entry
= _FindEntry(ip
)) {
129 TRACE(("ARPService::GetMACForIP(%08lx) done: %012llx\n", ip
,
134 for (int i
= 0; i
< ARP_REQUEST_RETRY_COUNT
; i
++) {
136 status_t error
= _SendARPPacket(ip
, kBroadcastMACAddress
,
139 TRACE(("ARPService::GetMACForIP(%08lx) failed: sending failed\n",
144 bigtime_t startTime
= system_time();
146 fEthernet
->ProcessIncomingPackets();
149 if (MapEntry
*entry
= _FindEntry(ip
)) {
151 TRACE(("ARPService::GetMACForIP(%08lx) done: %012llx\n", ip
,
155 } while (system_time() - startTime
< ARP_REPLY_TIMEOUT
);
158 TRACE(("ARPService::GetMACForIP(%08lx) failed: no reply\n", ip
));
165 ARPService::_SendARPPacket(ip_addr_t ip
, const mac_addr_t
&mac
, uint16 opcode
)
167 // prepare ARP header
169 ChainBuffer
headerBuffer(&header
, sizeof(header
));
170 header
.hardware_format
= htons(ARPHRD_ETHER
);
171 header
.protocol_format
= htons(ETHERTYPE_IP
);
172 header
.hardware_length
= sizeof(mac_addr_t
);
173 header
.protocol_length
= sizeof(ip_addr_t
);
174 header
.opcode
= htons(opcode
);
175 header
.sender_mac
= fEthernet
->MACAddress();
176 header
.sender_ip
= htonl(fEthernet
->IPAddress());
177 header
.target_mac
= (mac
== kBroadcastMACAddress
? kNoMACAddress
: mac
);
178 header
.target_ip
= htonl(ip
);
180 return fEthernet
->Send(mac
, ETHERTYPE_ARP
, &headerBuffer
);
184 ARPService::MapEntry
*
185 ARPService::_FindEntry(ip_addr_t ip
)
187 if (ip
== INADDR_ANY
)
190 for (int i
= 0; i
< MAP_ENTRY_COUNT
; i
++) {
191 if (ip
== fEntries
[i
].ip
)
200 ARPService::_PutEntry(ip_addr_t ip
, const mac_addr_t
&mac
)
202 // find empty/oldest slot
203 MapEntry
*entry
= fEntries
;
204 for (int i
= 0; i
< MAP_ENTRY_COUNT
; i
++) {
205 if (fEntries
[i
].ip
== INADDR_ANY
) {
206 entry
= fEntries
+ i
;
210 if (fAge
- fEntries
[i
].age
> fAge
- entry
->age
)
211 entry
= fEntries
+ i
;