xref: /haiku/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp (revision 3cb015b1ee509d69c643506e8ff573808c86dcfc)
1 /*
2  * Copyright 2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 //! Ethernet Address Resolution Protocol, see RFC 826.
10 
11 
12 #include <arp_control.h>
13 #include <net_datalink_protocol.h>
14 #include <net_device.h>
15 #include <net_datalink.h>
16 #include <net_stack.h>
17 #include <NetBufferUtilities.h>
18 
19 #include <generic_syscall.h>
20 #include <util/AutoLock.h>
21 #include <util/khash.h>
22 
23 #include <ByteOrder.h>
24 #include <KernelExport.h>
25 
26 #include <net/if.h>
27 #include <net/if_dl.h>
28 #include <net/if_types.h>
29 #include <new>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/sockio.h>
33 
34 
35 //#define TRACE_ARP
36 #ifdef TRACE_ARP
37 #	define TRACE(x) dprintf x
38 #else
39 #	define TRACE(x) ;
40 #endif
41 
42 
43 struct arp_header {
44 	uint16		hardware_type;
45 	uint16		protocol_type;
46 	uint8		hardware_length;
47 	uint8		protocol_length;
48 	uint16		opcode;
49 
50 	// TODO: this should be a variable length header, but for our current
51 	//	usage (Ethernet/IPv4), this should work fine.
52 	uint8		hardware_sender[6];
53 	in_addr_t	protocol_sender;
54 	uint8		hardware_target[6];
55 	in_addr_t	protocol_target;
56 } _PACKED;
57 
58 #define ARP_OPCODE_REQUEST	1
59 #define ARP_OPCODE_REPLY	2
60 
61 #define ARP_HARDWARE_TYPE_ETHER	1
62 
63 struct arp_entry {
64 	arp_entry	*next;
65 	in_addr_t	protocol_address;
66 	sockaddr_dl	hardware_address;
67 	uint32		flags;
68 	sem_id		resolved_sem;
69 	net_buffer	*request_buffer;
70 	net_timer	timer;
71 	uint32		timer_state;
72 	bigtime_t	timestamp;
73 	net_datalink_protocol *protocol;
74 
75 	static int Compare(void *_entry, const void *_key);
76 	static uint32 Hash(void *_entry, const void *_key, uint32 range);
77 	static arp_entry *Lookup(in_addr_t protocolAddress);
78 	static arp_entry *Add(in_addr_t protocolAddress, sockaddr_dl *hardwareAddress,
79 		uint32 flags);
80 };
81 
82 // see arp_control.h for flags
83 
84 #define ARP_NO_STATE				0
85 #define ARP_STATE_REQUEST			1
86 #define ARP_STATE_LAST_REQUEST		5
87 #define ARP_STATE_REQUEST_FAILED	6
88 #define ARP_STATE_REMOVE_FAILED		7
89 #define ARP_STATE_STALE				8
90 
91 #define ARP_STALE_TIMEOUT	30 * 60000000LL		// 30 minutes
92 #define ARP_REJECT_TIMEOUT	20000000LL			// 20 seconds
93 #define ARP_REQUEST_TIMEOUT	1000000LL			// 1 second
94 
95 struct arp_protocol : net_datalink_protocol {
96 };
97 
98 
99 static void arp_timer(struct net_timer *timer, void *data);
100 
101 struct net_buffer_module_info *gBufferModule;
102 static net_stack_module_info *sStackModule;
103 static hash_table *sCache;
104 static benaphore sCacheLock;
105 static bool sIgnoreReplies;
106 
107 
108 /*static*/ int
109 arp_entry::Compare(void *_entry, const void *_key)
110 {
111 	arp_entry *entry = (arp_entry *)_entry;
112 	in_addr_t key = (in_addr_t)_key;
113 
114 	if (entry->protocol_address == key)
115 		return 0;
116 
117 	return 1;
118 }
119 
120 
121 /*static*/ uint32
122 arp_entry::Hash(void *_entry, const void *_key, uint32 range)
123 {
124 	arp_entry *entry = (arp_entry *)_entry;
125 	in_addr_t key = (in_addr_t)_key;
126 
127 // TODO: check if this makes a good hash...
128 #define HASH(o) (((o >> 24) ^ (o >> 16) ^ (o >> 8) ^ o) % range)
129 
130 #ifdef TRACE_ARP
131 	in_addr_t a = entry ? entry->protocol_address : key;
132 	dprintf("%ld.%ld.%ld.%ld: Hash: %lu\n", a >> 24, (a >> 16) & 0xff,
133 		(a >> 8) & 0xff, a & 0xff, HASH(a));
134 #endif
135 
136 	if (entry != NULL)
137 		return HASH(entry->protocol_address);
138 
139 	return HASH(key);
140 #undef HASH
141 }
142 
143 
144 /*static*/ arp_entry *
145 arp_entry::Lookup(in_addr_t address)
146 {
147 	return (arp_entry *)hash_lookup(sCache, (void *)address);
148 }
149 
150 
151 /*static*/ arp_entry *
152 arp_entry::Add(in_addr_t protocolAddress, sockaddr_dl *hardwareAddress,
153 	uint32 flags)
154 {
155 	arp_entry *entry = new (std::nothrow) arp_entry;
156 	if (entry == NULL)
157 		return NULL;
158 
159 	entry->protocol_address = protocolAddress;
160 	entry->flags = flags;
161 	entry->timestamp = system_time();
162 	entry->protocol = NULL;
163 	entry->request_buffer = NULL;
164 	entry->timer_state = ARP_NO_STATE;
165 	sStackModule->init_timer(&entry->timer, arp_timer, entry);
166 
167 	if (hardwareAddress != NULL) {
168 		// this entry is already resolved
169 		entry->hardware_address = *hardwareAddress;
170 		entry->hardware_address.sdl_e_type = ETHER_TYPE_IP;
171 		entry->resolved_sem = -1;
172 	} else {
173 		// this entry still needs to be resolved
174 		entry->hardware_address.sdl_alen = 0;
175 
176 		char name[32];
177 		snprintf(name, sizeof(name), "arp %08lx", protocolAddress);
178 		entry->resolved_sem = create_sem(0, name);
179 		if (entry->resolved_sem < B_OK) {
180 			delete entry;
181 			return NULL;
182 		}
183 	}
184 	if (entry->hardware_address.sdl_len != sizeof(sockaddr_dl)) {
185 		// explicitly set correct length in case our caller hasn't...
186 		entry->hardware_address.sdl_len = sizeof(sockaddr_dl);
187 	}
188 
189 	if (hash_insert(sCache, entry) != B_OK) {
190 		delete entry;
191 		return NULL;
192 	}
193 
194 	return entry;
195 }
196 
197 
198 //	#pragma mark -
199 
200 
201 /*!
202 	Updates the entry determined by \a protocolAddress with the specified
203 	\a hardwareAddress.
204 	If such an entry does not exist yet, a new entry is added. If you try
205 	to update a local existing entry but didn't ask for it (by setting
206 	\a flags to ARP_FLAG_LOCAL), an error is returned.
207 
208 	This function does not lock the cache - you have to do it yourself
209 	before calling it.
210 */
211 status_t
212 arp_update_entry(in_addr_t protocolAddress, sockaddr_dl *hardwareAddress,
213 	uint32 flags, arp_entry **_entry = NULL)
214 {
215 	arp_entry *entry = arp_entry::Lookup(protocolAddress);
216 	if (entry != NULL) {
217 		// We disallow updating of entries that had been resolved before,
218 		// but to a different address.
219 		// Right now, you have to manually purge the ARP entries (or wait some
220 		// time) to let us switch to the new address.
221 		if (entry->hardware_address.sdl_alen != 0
222 			&& memcmp(LLADDR(&entry->hardware_address), hardwareAddress, ETHER_ADDRESS_LENGTH)) {
223 			dprintf("ARP host %08lx updated with different hardware address %02x:%02x:%02x:%02x:%02x:%02x.\n",
224 				protocolAddress, hardwareAddress->sdl_data[0] & 0xff, hardwareAddress->sdl_data[1] & 0xff,
225 				hardwareAddress->sdl_data[2] & 0xff, hardwareAddress->sdl_data[3] & 0xff,
226 				hardwareAddress->sdl_data[4] & 0xff, hardwareAddress->sdl_data[5] & 0xff);
227 			return B_ERROR;
228 		}
229 
230 		entry->hardware_address = *hardwareAddress;
231 		entry->timestamp = system_time();
232 	} else {
233 		entry = arp_entry::Add(protocolAddress, hardwareAddress, flags);
234 		if (entry == NULL)
235 			return B_NO_MEMORY;
236 	}
237 
238 	// if someone was waiting for this ARP request to be resolved
239 	if (entry->resolved_sem >= B_OK) {
240 		delete_sem(entry->resolved_sem);
241 		entry->resolved_sem = -1;
242 	}
243 
244 	if (entry->request_buffer != NULL) {
245 		gBufferModule->free(entry->request_buffer);
246 		entry->request_buffer = NULL;
247 	}
248 
249 	if ((entry->flags & ARP_FLAG_PERMANENT) == 0) {
250 		// (re)start the stale timer
251 		entry->timer_state = ARP_STATE_STALE;
252 		sStackModule->set_timer(&entry->timer, ARP_STALE_TIMEOUT);
253 	}
254 
255 	if (_entry)
256 		*_entry = entry;
257 
258 	return B_OK;
259 }
260 
261 
262 static status_t
263 arp_update_local(net_datalink_protocol *protocol)
264 {
265 	net_interface *interface = protocol->interface;
266 	in_addr_t inetAddress;
267 
268 	if (interface->address == NULL) {
269 		// interface has not yet been set
270 		inetAddress = INADDR_ANY;
271 	} else
272 		inetAddress = ((sockaddr_in *)interface->address)->sin_addr.s_addr;
273 
274 	sockaddr_dl address;
275 	address.sdl_len = sizeof(sockaddr_dl);
276 	address.sdl_family = AF_DLI;
277 	address.sdl_type = IFT_ETHER;
278 	address.sdl_e_type = ETHER_TYPE_IP;
279 	address.sdl_nlen = 0;
280 	address.sdl_slen = 0;
281 	address.sdl_alen = interface->device->address.length;
282 	memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen);
283 
284 	arp_entry *entry;
285 	status_t status = arp_update_entry(inetAddress, &address,
286 		ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry);
287 	if (status == B_OK)
288 		entry->protocol = protocol;
289 
290 	return status;
291 }
292 
293 
294 static status_t
295 handle_arp_request(net_buffer *buffer, arp_header &header)
296 {
297 	BenaphoreLocker locker(sCacheLock);
298 
299 	if (!sIgnoreReplies) {
300 		arp_update_entry(header.protocol_sender, (sockaddr_dl *)&buffer->source, 0);
301 			// remember the address of the sender as we might need it later
302 	}
303 
304 	// check if this request is for us
305 
306 	arp_entry *entry = arp_entry::Lookup(header.protocol_target);
307 	if (entry == NULL || (entry->flags & (ARP_FLAG_LOCAL | ARP_FLAG_PUBLISH)) == 0) {
308 		// We're not the one to answer this request
309 		// TODO: instead of letting the other's request time-out, can we reply
310 		//	failure somehow?
311 		TRACE(("  not for us\n"));
312 		return B_ERROR;
313 	}
314 
315 	// send a reply (by reusing the buffer we got)
316 
317 	TRACE(("  send reply!\n"));
318 	header.opcode = htons(ARP_OPCODE_REPLY);
319 
320 	memcpy(header.hardware_target, header.hardware_sender, ETHER_ADDRESS_LENGTH);
321 	header.protocol_target = header.protocol_sender;
322 	memcpy(header.hardware_sender, LLADDR(&entry->hardware_address), ETHER_ADDRESS_LENGTH);
323 	header.protocol_sender = entry->protocol_address;
324 
325 	// exchange source and destination address
326 	memcpy(LLADDR((sockaddr_dl *)&buffer->source), header.hardware_sender,
327 		ETHER_ADDRESS_LENGTH);
328 	memcpy(LLADDR((sockaddr_dl *)&buffer->destination), header.hardware_target,
329 		ETHER_ADDRESS_LENGTH);
330 
331 	buffer->flags = 0;
332 		// make sure this won't be a broadcast message
333 
334 	return entry->protocol->next->module->send_data(entry->protocol->next, buffer);
335 }
336 
337 
338 static void
339 handle_arp_reply(net_buffer *buffer, arp_header &header)
340 {
341 	if (sIgnoreReplies)
342 		return;
343 
344 	BenaphoreLocker locker(sCacheLock);
345 	arp_update_entry(header.protocol_sender, (sockaddr_dl *)&buffer->source, 0);
346 }
347 
348 
349 static status_t
350 arp_receive(void *cookie, net_buffer *buffer)
351 {
352 	TRACE(("ARP receive\n"));
353 
354 	NetBufferHeader<arp_header> bufferHeader(buffer);
355 	if (bufferHeader.Status() < B_OK)
356 		return bufferHeader.Status();
357 
358 	arp_header &header = bufferHeader.Data();
359 	uint16 opcode = ntohs(header.opcode);
360 
361 #ifdef TRACE_ARP
362 	dprintf("  hw sender: %02x:%02x:%02x:%02x:%02x:%02x\n",
363 		header.hardware_sender[0], header.hardware_sender[1], header.hardware_sender[2],
364 		header.hardware_sender[3], header.hardware_sender[4], header.hardware_sender[5]);
365 	dprintf("  proto sender: %ld.%ld.%ld.%ld\n", header.protocol_sender >> 24, (header.protocol_sender >> 16) & 0xff,
366 		(header.protocol_sender >> 8) & 0xff, header.protocol_sender & 0xff);
367 	dprintf("  hw target: %02x:%02x:%02x:%02x:%02x:%02x\n",
368 		header.hardware_target[0], header.hardware_target[1], header.hardware_target[2],
369 		header.hardware_target[3], header.hardware_target[4], header.hardware_target[5]);
370 	dprintf("  proto target: %ld.%ld.%ld.%ld\n", header.protocol_target >> 24, (header.protocol_target >> 16) & 0xff,
371 		(header.protocol_target >> 8) & 0xff, header.protocol_target & 0xff);
372 #endif
373 
374 	if (ntohs(header.protocol_type) != ETHER_TYPE_IP
375 		|| ntohs(header.hardware_type) != ARP_HARDWARE_TYPE_ETHER)
376 		return B_BAD_TYPE;
377 
378 	// check if the packet is okay
379 
380 	if (header.hardware_length != ETHER_ADDRESS_LENGTH
381 		|| header.protocol_length != sizeof(in_addr_t))
382 		return B_BAD_DATA;
383 
384 	bufferHeader.Detach();
385 
386 	// handle packet
387 
388 	switch (opcode) {
389 		case ARP_OPCODE_REQUEST:
390 			TRACE(("  got ARP request\n"));
391 			if (handle_arp_request(buffer, header) == B_OK) {
392 				// the function will take care of the buffer if everything went well
393 				return B_OK;
394 			}
395 			break;
396 		case ARP_OPCODE_REPLY:
397 			TRACE(("  got ARP reply\n"));
398 			handle_arp_reply(buffer, header);
399 			break;
400 
401 		default:
402 			dprintf("unknown ARP opcode %d\n", opcode);
403 			return B_ERROR;
404 	}
405 
406 	gBufferModule->free(buffer);
407 	return B_OK;
408 }
409 
410 
411 static void
412 arp_timer(struct net_timer *timer, void *data)
413 {
414 	arp_entry *entry = (arp_entry *)data;
415 	TRACE(("ARP timer %ld, entry %p!\n", entry->timer_state, entry));
416 
417 	switch (entry->timer_state) {
418 		case ARP_NO_STATE:
419 			// who are you kidding?
420 			break;
421 
422 		case ARP_STATE_REQUEST_FAILED:
423 			// requesting the ARP entry failed, we keep it around for a while, though,
424 			// so that we won't try to request the same address again too soon.
425 			TRACE(("  requesting ARP entry %p failed!\n", entry));
426 			entry->timer_state = ARP_STATE_REMOVE_FAILED;
427 			entry->flags |= ARP_FLAG_REJECT;
428 			sStackModule->set_timer(&entry->timer, ARP_REJECT_TIMEOUT);
429 			break;
430 
431 		case ARP_STATE_REMOVE_FAILED:
432 		case ARP_STATE_STALE:
433 			// the entry has aged so much that we're going to remove it
434 			TRACE(("  remove ARP entry %p!\n", entry));
435 
436 			benaphore_lock(&sCacheLock);
437 			hash_remove(sCache, entry);
438 			benaphore_unlock(&sCacheLock);
439 
440 			delete entry;
441 
442 			break;
443 		default:
444 			if (entry->timer_state > ARP_STATE_LAST_REQUEST)
445 				break;
446 
447 			TRACE(("  send request for ARP entry %p!\n", entry));
448 			net_buffer *request = entry->request_buffer;
449 			if (entry->timer_state < ARP_STATE_LAST_REQUEST) {
450 				// we'll still need our buffer, so in order to prevent it being
451 				// freed by a successful send, we need to clone it
452 				request = gBufferModule->clone(request, true);
453 				if (request == NULL) {
454 					// cloning failed - that means we won't be able to send as
455 					// many requests as originally planned
456 					request = entry->request_buffer;
457 					entry->timer_state = ARP_STATE_LAST_REQUEST;
458 				}
459 			}
460 
461 			// we're trying to resolve the address, so keep sending requests
462 			status_t status = entry->protocol->next->module->send_data(
463 				entry->protocol->next, request);
464 			if (status < B_OK)
465 				gBufferModule->free(request);
466 
467 			if (entry->timer_state == ARP_STATE_LAST_REQUEST) {
468 				// buffer has been freed on send
469 				entry->request_buffer = NULL;
470 			}
471 
472 			entry->timer_state++;
473 			sStackModule->set_timer(&entry->timer, ARP_REQUEST_TIMEOUT);
474 	}
475 }
476 
477 
478 /*!
479 	Checks if the ARP \a entry has already been resolved. If it wasn't yet,
480 	and MSG_DONTWAIT is not set in \a flags, it will wait for the entry to
481 	become resolved.
482 	You need to have the sCacheLock held when calling this function - but
483 	note that the lock may be interrupted (in which case entry is updated).
484 */
485 static status_t
486 arp_check_resolved(arp_entry **_entry, uint32 flags)
487 {
488 	arp_entry *entry = *_entry;
489 
490 	if ((entry->flags & ARP_FLAG_REJECT) != 0)
491 		return EHOSTUNREACH;
492 
493 	if (entry->resolved_sem < B_OK)
494 		return B_OK;
495 
496 	// we need to wait for this entry to become resolved
497 
498 	if ((flags & MSG_DONTWAIT) != 0)
499 		return B_ERROR;
500 
501 	// store information we cannot access anymore after having unlocked the cache
502 	sem_id waitSem = entry->resolved_sem;
503 	in_addr_t address = entry->protocol_address;
504 
505 	benaphore_unlock(&sCacheLock);
506 
507 	status_t status = acquire_sem_etc(waitSem, 1, B_RELATIVE_TIMEOUT, 5 * 1000000);
508 
509 	benaphore_lock(&sCacheLock);
510 
511 	if (status == B_TIMED_OUT)
512 		return EHOSTUNREACH;
513 
514 	// retrieve the entry again, as we reacquired the cache lock
515 	entry = arp_entry::Lookup(address);
516 	if (entry == NULL)
517 		return B_ERROR;
518 
519 	*_entry = entry;
520 	return B_OK;
521 }
522 
523 
524 /*!
525 	Address resolver function: prepares and sends the ARP request necessary
526 	to retrieve the hardware address for \a address.
527 	You need to have the sCacheLock held when calling this function - but
528 	note that the lock will be interrupted here if everything goes well.
529 */
530 static status_t
531 arp_resolve(net_datalink_protocol *protocol, in_addr_t address, arp_entry **_entry)
532 {
533 	// create an unresolved ARP entry as a placeholder
534 	arp_entry *entry = arp_entry::Add(address, NULL, 0);
535 	if (entry == NULL)
536 		return B_NO_MEMORY;
537 
538 	// prepare ARP request
539 
540 	entry->request_buffer = gBufferModule->create(256);
541 	if (entry->request_buffer == NULL) {
542 		// TODO: do something with the entry
543 		return B_NO_MEMORY;
544 	}
545 
546 	NetBufferPrepend<arp_header> bufferHeader(entry->request_buffer);
547 	status_t status = bufferHeader.Status();
548 	if (status < B_OK) {
549 		// TODO: do something with the entry
550 		return status;
551 	}
552 
553 	// prepare ARP header
554 
555 	net_device *device = protocol->interface->device;
556 	arp_header &header = bufferHeader.Data();
557 
558 	header.hardware_type = htons(ARP_HARDWARE_TYPE_ETHER);
559 	header.protocol_type = htons(ETHER_TYPE_IP);
560 	header.hardware_length = ETHER_ADDRESS_LENGTH;
561 	header.protocol_length = sizeof(in_addr_t);
562 	header.opcode = htons(ARP_OPCODE_REQUEST);
563 
564 	memcpy(header.hardware_sender, device->address.data, ETHER_ADDRESS_LENGTH);
565 	if (protocol->interface->address != NULL)
566 		header.protocol_sender = ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr;
567 	else
568 		header.protocol_sender = 0;
569 			// TODO: test if this actually works - maybe we should use INADDR_BROADCAST instead
570 	memset(header.hardware_target, 0, ETHER_ADDRESS_LENGTH);
571 	header.protocol_target = address;
572 
573 	// prepare source and target addresses
574 
575 	struct sockaddr_dl &source = *(struct sockaddr_dl *)&entry->request_buffer->source;
576 	source.sdl_len = sizeof(sockaddr_dl);
577 	source.sdl_family = AF_DLI;
578 	source.sdl_index = device->index;
579 	source.sdl_type = IFT_ETHER;
580 	source.sdl_e_type = ETHER_TYPE_ARP;
581 	source.sdl_nlen = source.sdl_slen = 0;
582 	source.sdl_alen = ETHER_ADDRESS_LENGTH;
583 	memcpy(source.sdl_data, device->address.data, ETHER_ADDRESS_LENGTH);
584 
585 	entry->request_buffer->flags = MSG_BCAST;
586 		// this is a broadcast packet, we don't need to fill in the destination
587 
588 	entry->protocol = protocol;
589 	entry->timer_state = ARP_STATE_REQUEST;
590 	sStackModule->set_timer(&entry->timer, 0);
591 		// start request timer
592 
593 	sem_id waitSem = entry->resolved_sem;
594 	benaphore_unlock(&sCacheLock);
595 
596 	status = acquire_sem_etc(waitSem, 1, B_RELATIVE_TIMEOUT, 5 * 1000000);
597 		// wait for the entry to become resolved
598 
599 	benaphore_lock(&sCacheLock);
600 
601 	// retrieve the entry again, as we reacquired the cache lock
602 	entry = arp_entry::Lookup(address);
603 	if (entry == NULL)
604 		return B_ERROR;
605 
606 	if (status == B_TIMED_OUT) {
607 		// we didn't get a response, mark ARP entry as non-existant
608 		entry->flags = ARP_FLAG_REJECT;
609 		// TODO: remove the ARP entry after some time
610 		return EHOSTUNREACH;
611 	}
612 
613 	*_entry = entry;
614 	return B_OK;
615 }
616 
617 
618 static status_t
619 arp_control(const char *subsystem, uint32 function,
620 	void *buffer, size_t bufferSize)
621 {
622 	struct arp_control control;
623 	if (bufferSize != sizeof(struct arp_control))
624 		return B_BAD_VALUE;
625 	if (user_memcpy(&control, buffer, sizeof(struct arp_control)) < B_OK)
626 		return B_BAD_ADDRESS;
627 
628 	BenaphoreLocker locker(sCacheLock);
629 
630 	switch (function) {
631 		case ARP_SET_ENTRY:
632 			sockaddr_dl hardwareAddress;
633 
634 			hardwareAddress.sdl_len = sizeof(sockaddr_dl);
635 			hardwareAddress.sdl_family = AF_DLI;
636 			hardwareAddress.sdl_index = 0;
637 			hardwareAddress.sdl_type = IFT_ETHER;
638 			hardwareAddress.sdl_e_type = ETHER_TYPE_IP;
639 			hardwareAddress.sdl_nlen = hardwareAddress.sdl_slen = 0;
640 			hardwareAddress.sdl_alen = ETHER_ADDRESS_LENGTH;
641 			memcpy(hardwareAddress.sdl_data, control.ethernet_address, ETHER_ADDRESS_LENGTH);
642 
643 			return arp_update_entry(control.address, &hardwareAddress,
644 				control.flags & (ARP_FLAG_PUBLISH | ARP_FLAG_PERMANENT | ARP_FLAG_REJECT));
645 
646 		case ARP_GET_ENTRY:
647 		{
648 			arp_entry *entry = arp_entry::Lookup(control.address);
649 			if (entry == NULL || entry->resolved_sem < B_OK)
650 				return B_ENTRY_NOT_FOUND;
651 
652 			memcpy(control.ethernet_address, entry->hardware_address.sdl_data,
653 				ETHER_ADDRESS_LENGTH);
654 			control.flags = entry->flags;
655 			return user_memcpy(buffer, &control, sizeof(struct arp_control));
656 		}
657 
658 		case ARP_GET_ENTRIES:
659 		{
660 			hash_iterator iterator;
661 			hash_open(sCache, &iterator);
662 
663 			arp_entry *entry;
664 			uint32 i = 0;
665 			while ((entry = (arp_entry *)hash_next(sCache, &iterator)) != NULL
666 				&& i < control.cookie) {
667 				i++;
668 			}
669 			hash_close(sCache, &iterator, false);
670 
671 			if (entry == NULL)
672 				return B_ENTRY_NOT_FOUND;
673 
674 			control.cookie++;
675 			control.address = entry->protocol_address;
676 			memcpy(control.ethernet_address, entry->hardware_address.sdl_data,
677 				ETHER_ADDRESS_LENGTH);
678 			control.flags = entry->flags;
679 
680 			return user_memcpy(buffer, &control, sizeof(struct arp_control));
681 		}
682 
683 		case ARP_DELETE_ENTRY:
684 		{
685 			arp_entry *entry = arp_entry::Lookup(control.address);
686 			if (entry == NULL || entry->resolved_sem < B_OK)
687 				return B_ENTRY_NOT_FOUND;
688 			if ((entry->flags & ARP_FLAG_LOCAL) != 0)
689 				return B_BAD_VALUE;
690 
691 			// schedule a timer to remove this entry
692 			entry->timer_state = ARP_STATE_REMOVE_FAILED;
693 			sStackModule->set_timer(&entry->timer, 0);
694 			return B_OK;
695 		}
696 
697 		case ARP_FLUSH_ENTRIES:
698 		{
699 			hash_iterator iterator;
700 			hash_open(sCache, &iterator);
701 
702 			arp_entry *entry;
703 			while ((entry = (arp_entry *)hash_next(sCache, &iterator)) != NULL) {
704 				// we never flush local ARP entries
705 				if ((entry->flags & ARP_FLAG_LOCAL) != 0)
706 					continue;
707 
708 				// schedule a timer to remove this entry
709 				entry->timer_state = ARP_STATE_REMOVE_FAILED;
710 				sStackModule->set_timer(&entry->timer, 0);
711 			}
712 			hash_close(sCache, &iterator, false);
713 			return B_OK;
714 		}
715 
716 		case ARP_IGNORE_REPLIES:
717 			sIgnoreReplies = control.flags != 0;
718 			return B_OK;
719 	}
720 
721 	return B_BAD_VALUE;
722 }
723 
724 
725 static status_t
726 arp_init()
727 {
728 	status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule);
729 	if (status < B_OK)
730 		return status;
731 	status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule);
732 	if (status < B_OK)
733 		goto err1;
734 
735 	status = benaphore_init(&sCacheLock, "arp cache");
736 	if (status < B_OK)
737 		goto err2;
738 
739 	sCache = hash_init(64, offsetof(struct arp_entry, next),
740 		&arp_entry::Compare, &arp_entry::Hash);
741 	if (sCache == NULL) {
742 		status = B_NO_MEMORY;
743 		goto err3;
744 	}
745 
746 	register_generic_syscall(ARP_SYSCALLS, arp_control, 1, 0);
747 	return B_OK;
748 
749 err3:
750 	benaphore_destroy(&sCacheLock);
751 err2:
752 	put_module(NET_BUFFER_MODULE_NAME);
753 err1:
754 	put_module(NET_STACK_MODULE_NAME);
755 	return status;
756 }
757 
758 
759 static status_t
760 arp_uninit()
761 {
762 	unregister_generic_syscall(ARP_SYSCALLS, 1);
763 
764 	put_module(NET_BUFFER_MODULE_NAME);
765 	put_module(NET_STACK_MODULE_NAME);
766 	return B_OK;
767 }
768 
769 
770 //	#pragma mark -
771 
772 
773 status_t
774 arp_init_protocol(struct net_interface *interface, net_datalink_protocol **_protocol)
775 {
776 	// We currently only support a single family and type!
777 	if (interface->domain->family != AF_INET
778 		|| interface->device->type != IFT_ETHER)
779 		return B_BAD_TYPE;
780 
781 	status_t status = sStackModule->register_device_handler(interface->device,
782 		ETHER_FRAME_TYPE | ETHER_TYPE_ARP, &arp_receive, NULL);
783 	if (status == B_OK) {
784 		// We also register the domain as a handler for deframed packets;
785 		// while the ethernet_frame module is not really connected to our
786 		// domain, we are.
787 		status = sStackModule->register_domain_device_handler(interface->device,
788 			ETHER_FRAME_TYPE | ETHER_TYPE_IP, interface->domain);
789 	}
790 
791 	if (status < B_OK)
792 		return status;
793 
794 	arp_protocol *protocol = new (std::nothrow) arp_protocol;
795 	if (protocol == NULL)
796 		return B_NO_MEMORY;
797 
798 	*_protocol = protocol;
799 	return B_OK;
800 }
801 
802 
803 status_t
804 arp_uninit_protocol(net_datalink_protocol *protocol)
805 {
806 	sStackModule->unregister_device_handler(protocol->interface->device,
807 		ETHER_FRAME_TYPE | ETHER_TYPE_ARP);
808 	sStackModule->unregister_device_handler(protocol->interface->device,
809 		ETHER_FRAME_TYPE | ETHER_TYPE_IP);
810 
811 	delete protocol;
812 	return B_OK;
813 }
814 
815 
816 status_t
817 arp_send_data(net_datalink_protocol *protocol,
818 	net_buffer *buffer)
819 {
820 	{
821 		BenaphoreLocker locker(sCacheLock);
822 
823 		// Lookup source (us)
824 		// TODO: this could be cached - the lookup isn't really needed at all
825 
826 		arp_entry *entry = arp_entry::Lookup(
827 			((struct sockaddr_in *)&buffer->source)->sin_addr.s_addr);
828 		if (entry == NULL)
829 			return B_ERROR;
830 
831 		memcpy(&buffer->source, &entry->hardware_address,
832 			entry->hardware_address.sdl_len);
833 
834 		if ((buffer->flags & MSG_BCAST) == 0) {
835 			// Lookup destination (we may need to wait for this)
836 			entry = arp_entry::Lookup(
837 				((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr);
838 			if (entry == NULL) {
839 				// The ARP entry does not yet exist, if we're allowed to wait,
840 				// we'll send an ARP request and try to change that.
841 				if ((buffer->flags & MSG_DONTWAIT) != 0) {
842 					// TODO: implement delaying packet send after ARP response!
843 					return B_ERROR;
844 				}
845 
846 				status_t status = arp_resolve(protocol,
847 					((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr, &entry);
848 				if (status < B_OK)
849 					return status;
850 			} else {
851 				// The entry exists, but we have to check if it has already been
852 				// resolved and is valid.
853 				status_t status = arp_check_resolved(&entry, buffer->flags);
854 				if (status < B_OK)
855 					return status;
856 			}
857 
858 			memcpy(&buffer->destination, &entry->hardware_address,
859 				entry->hardware_address.sdl_len);
860 		}
861 	}
862 
863 	return protocol->next->module->send_data(protocol->next, buffer);
864 }
865 
866 
867 status_t
868 arp_up(net_datalink_protocol *_protocol)
869 {
870 	arp_protocol *protocol = (arp_protocol *)_protocol;
871 	status_t status = protocol->next->module->interface_up(protocol->next);
872 	if (status < B_OK)
873 		return status;
874 
875 	// cache this device's address for later use
876 
877 	status = arp_update_local(protocol);
878 	if (status < B_OK) {
879 		protocol->next->module->interface_down(protocol->next);
880 		return status;
881 	}
882 
883 	return B_OK;
884 }
885 
886 
887 void
888 arp_down(net_datalink_protocol *protocol)
889 {
890 	// remove local ARP entry from the cache
891 
892 	if (protocol->interface->address != NULL) {
893 		BenaphoreLocker locker(sCacheLock);
894 
895 		arp_entry *entry = arp_entry::Lookup(
896 			((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr);
897 		if (entry != NULL) {
898 			hash_remove(sCache, entry);
899 			delete entry;
900 		}
901 	}
902 
903 	protocol->next->module->interface_down(protocol->next);
904 }
905 
906 
907 status_t
908 arp_control(net_datalink_protocol *protocol,
909 	int32 op, void *argument, size_t length)
910 {
911 	if (op == SIOCSIFADDR && (protocol->interface->flags & IFF_UP) != 0) {
912 		// The interface may get a new address, so we need to update our
913 		// local entries.
914 		bool hasOldAddress = false;
915 		in_addr_t oldAddress = 0;
916 		if (protocol->interface->address != NULL) {
917 			oldAddress = ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr;
918 			hasOldAddress = true;
919 		}
920 
921 		status_t status = protocol->next->module->control(protocol->next,
922 			SIOCSIFADDR, argument, length);
923 		if (status < B_OK)
924 			return status;
925 
926 		arp_update_local(protocol);
927 
928 		if (oldAddress == ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr
929 			|| !hasOldAddress)
930 			return B_OK;
931 
932 		// remove previous address from cache
933 		// TODO: we should be able to do this (add/remove) in one atomic operation!
934 
935 		BenaphoreLocker locker(sCacheLock);
936 
937 		arp_entry *entry = arp_entry::Lookup(oldAddress);
938 		if (entry != NULL) {
939 			hash_remove(sCache, entry);
940 			delete entry;
941 		}
942 
943 		return B_OK;
944 	}
945 
946 	return protocol->next->module->control(protocol->next,
947 		op, argument, length);
948 }
949 
950 
951 static status_t
952 arp_std_ops(int32 op, ...)
953 {
954 	switch (op) {
955 		case B_MODULE_INIT:
956 			return arp_init();
957 		case B_MODULE_UNINIT:
958 			return arp_uninit();
959 
960 		default:
961 			return B_ERROR;
962 	}
963 }
964 
965 
966 static net_datalink_protocol_module_info sARPModule = {
967 	{
968 		"network/datalink_protocols/arp/v1",
969 		0,
970 		arp_std_ops
971 	},
972 	arp_init_protocol,
973 	arp_uninit_protocol,
974 	arp_send_data,
975 	arp_up,
976 	arp_down,
977 	arp_control,
978 };
979 
980 module_info *modules[] = {
981 	(module_info *)&sARPModule,
982 	NULL
983 };
984