xref: /haiku/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp (revision c7509fce9db782326f159843f1b028b5f5dcb1d2)
1 /*
2  * Copyright 2006-2007, 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),
223 				LLADDR(hardwareAddress), ETHER_ADDRESS_LENGTH)) {
224 			dprintf("ARP host %08lx updated with different hardware address %02x:%02x:%02x:%02x:%02x:%02x.\n",
225 				protocolAddress,
226 				hardwareAddress->sdl_data[0], hardwareAddress->sdl_data[1],
227 				hardwareAddress->sdl_data[2], hardwareAddress->sdl_data[3],
228 				hardwareAddress->sdl_data[4], hardwareAddress->sdl_data[5]);
229 			return B_ERROR;
230 		}
231 
232 		entry->hardware_address = *hardwareAddress;
233 		entry->timestamp = system_time();
234 	} else {
235 		entry = arp_entry::Add(protocolAddress, hardwareAddress, flags);
236 		if (entry == NULL)
237 			return B_NO_MEMORY;
238 	}
239 
240 	// if someone was waiting for this ARP request to be resolved
241 	if (entry->resolved_sem >= B_OK) {
242 		delete_sem(entry->resolved_sem);
243 		entry->resolved_sem = -1;
244 	}
245 
246 	if (entry->request_buffer != NULL) {
247 		gBufferModule->free(entry->request_buffer);
248 		entry->request_buffer = NULL;
249 	}
250 
251 	if ((entry->flags & ARP_FLAG_PERMANENT) == 0) {
252 		// (re)start the stale timer
253 		entry->timer_state = ARP_STATE_STALE;
254 		sStackModule->set_timer(&entry->timer, ARP_STALE_TIMEOUT);
255 	}
256 
257 	if (_entry)
258 		*_entry = entry;
259 
260 	return B_OK;
261 }
262 
263 
264 static status_t
265 arp_update_local(net_datalink_protocol *protocol)
266 {
267 	net_interface *interface = protocol->interface;
268 	in_addr_t inetAddress;
269 
270 	if (interface->address == NULL) {
271 		// interface has not yet been set
272 		inetAddress = INADDR_ANY;
273 	} else
274 		inetAddress = ((sockaddr_in *)interface->address)->sin_addr.s_addr;
275 
276 	sockaddr_dl address;
277 	address.sdl_len = sizeof(sockaddr_dl);
278 	address.sdl_family = AF_DLI;
279 	address.sdl_type = IFT_ETHER;
280 	address.sdl_e_type = ETHER_TYPE_IP;
281 	address.sdl_nlen = 0;
282 	address.sdl_slen = 0;
283 	address.sdl_alen = interface->device->address.length;
284 	memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen);
285 
286 	arp_entry *entry;
287 	status_t status = arp_update_entry(inetAddress, &address,
288 		ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry);
289 	if (status == B_OK)
290 		entry->protocol = protocol;
291 
292 	return status;
293 }
294 
295 
296 static status_t
297 handle_arp_request(net_buffer *buffer, arp_header &header)
298 {
299 	BenaphoreLocker locker(sCacheLock);
300 
301 	if (!sIgnoreReplies) {
302 		arp_update_entry(header.protocol_sender, (sockaddr_dl *)&buffer->source, 0);
303 			// remember the address of the sender as we might need it later
304 	}
305 
306 	// check if this request is for us
307 
308 	arp_entry *entry = arp_entry::Lookup(header.protocol_target);
309 	if (entry == NULL || (entry->flags & (ARP_FLAG_LOCAL | ARP_FLAG_PUBLISH)) == 0) {
310 		// We're not the one to answer this request
311 		// TODO: instead of letting the other's request time-out, can we reply
312 		//	failure somehow?
313 		TRACE(("  not for us\n"));
314 		return B_ERROR;
315 	}
316 
317 	// send a reply (by reusing the buffer we got)
318 
319 	TRACE(("  send reply!\n"));
320 	header.opcode = htons(ARP_OPCODE_REPLY);
321 
322 	memcpy(header.hardware_target, header.hardware_sender, ETHER_ADDRESS_LENGTH);
323 	header.protocol_target = header.protocol_sender;
324 	memcpy(header.hardware_sender, LLADDR(&entry->hardware_address), ETHER_ADDRESS_LENGTH);
325 	header.protocol_sender = entry->protocol_address;
326 
327 	// exchange source and destination address
328 	memcpy(LLADDR((sockaddr_dl *)&buffer->source), header.hardware_sender,
329 		ETHER_ADDRESS_LENGTH);
330 	memcpy(LLADDR((sockaddr_dl *)&buffer->destination), header.hardware_target,
331 		ETHER_ADDRESS_LENGTH);
332 
333 	buffer->flags = 0;
334 		// make sure this won't be a broadcast message
335 
336 	return entry->protocol->next->module->send_data(entry->protocol->next, buffer);
337 }
338 
339 
340 static void
341 handle_arp_reply(net_buffer *buffer, arp_header &header)
342 {
343 	if (sIgnoreReplies)
344 		return;
345 
346 	BenaphoreLocker locker(sCacheLock);
347 	arp_update_entry(header.protocol_sender, (sockaddr_dl *)&buffer->source, 0);
348 }
349 
350 
351 static status_t
352 arp_receive(void *cookie, net_buffer *buffer)
353 {
354 	TRACE(("ARP receive\n"));
355 
356 	NetBufferHeaderReader<arp_header> bufferHeader(buffer);
357 	if (bufferHeader.Status() < B_OK)
358 		return bufferHeader.Status();
359 
360 	arp_header &header = bufferHeader.Data();
361 	uint16 opcode = ntohs(header.opcode);
362 
363 #ifdef TRACE_ARP
364 	dprintf("  hw sender: %02x:%02x:%02x:%02x:%02x:%02x\n",
365 		header.hardware_sender[0], header.hardware_sender[1], header.hardware_sender[2],
366 		header.hardware_sender[3], header.hardware_sender[4], header.hardware_sender[5]);
367 	dprintf("  proto sender: %ld.%ld.%ld.%ld\n", header.protocol_sender >> 24, (header.protocol_sender >> 16) & 0xff,
368 		(header.protocol_sender >> 8) & 0xff, header.protocol_sender & 0xff);
369 	dprintf("  hw target: %02x:%02x:%02x:%02x:%02x:%02x\n",
370 		header.hardware_target[0], header.hardware_target[1], header.hardware_target[2],
371 		header.hardware_target[3], header.hardware_target[4], header.hardware_target[5]);
372 	dprintf("  proto target: %ld.%ld.%ld.%ld\n", header.protocol_target >> 24, (header.protocol_target >> 16) & 0xff,
373 		(header.protocol_target >> 8) & 0xff, header.protocol_target & 0xff);
374 #endif
375 
376 	if (ntohs(header.protocol_type) != ETHER_TYPE_IP
377 		|| ntohs(header.hardware_type) != ARP_HARDWARE_TYPE_ETHER)
378 		return B_BAD_TYPE;
379 
380 	// check if the packet is okay
381 
382 	if (header.hardware_length != ETHER_ADDRESS_LENGTH
383 		|| header.protocol_length != sizeof(in_addr_t))
384 		return B_BAD_DATA;
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 
784 	if (status < B_OK)
785 		return status;
786 
787 	arp_protocol *protocol = new (std::nothrow) arp_protocol;
788 	if (protocol == NULL)
789 		return B_NO_MEMORY;
790 
791 	*_protocol = protocol;
792 	return B_OK;
793 }
794 
795 
796 status_t
797 arp_uninit_protocol(net_datalink_protocol *protocol)
798 {
799 	sStackModule->unregister_device_handler(protocol->interface->device,
800 		ETHER_FRAME_TYPE | ETHER_TYPE_ARP);
801 	sStackModule->unregister_device_handler(protocol->interface->device,
802 		ETHER_FRAME_TYPE | ETHER_TYPE_IP);
803 
804 	delete protocol;
805 	return B_OK;
806 }
807 
808 
809 status_t
810 arp_send_data(net_datalink_protocol *protocol,
811 	net_buffer *buffer)
812 {
813 	{
814 		BenaphoreLocker locker(sCacheLock);
815 
816 		// Lookup source (us)
817 		// TODO: this could be cached - the lookup isn't really needed at all
818 
819 		arp_entry *entry = arp_entry::Lookup(
820 			((struct sockaddr_in *)&buffer->source)->sin_addr.s_addr);
821 		if (entry == NULL)
822 			return B_ERROR;
823 
824 		memcpy(&buffer->source, &entry->hardware_address,
825 			entry->hardware_address.sdl_len);
826 
827 		if ((buffer->flags & MSG_BCAST) == 0) {
828 			// Lookup destination (we may need to wait for this)
829 			entry = arp_entry::Lookup(
830 				((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr);
831 			if (entry == NULL) {
832 				// The ARP entry does not yet exist, if we're allowed to wait,
833 				// we'll send an ARP request and try to change that.
834 				if ((buffer->flags & MSG_DONTWAIT) != 0) {
835 					// TODO: implement delaying packet send after ARP response!
836 					return B_ERROR;
837 				}
838 
839 				status_t status = arp_resolve(protocol,
840 					((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr, &entry);
841 				if (status < B_OK)
842 					return status;
843 			} else {
844 				// The entry exists, but we have to check if it has already been
845 				// resolved and is valid.
846 				status_t status = arp_check_resolved(&entry, buffer->flags);
847 				if (status < B_OK)
848 					return status;
849 			}
850 
851 			memcpy(&buffer->destination, &entry->hardware_address,
852 				entry->hardware_address.sdl_len);
853 		}
854 	}
855 
856 	return protocol->next->module->send_data(protocol->next, buffer);
857 }
858 
859 
860 status_t
861 arp_up(net_datalink_protocol *_protocol)
862 {
863 	arp_protocol *protocol = (arp_protocol *)_protocol;
864 	status_t status = protocol->next->module->interface_up(protocol->next);
865 	if (status < B_OK)
866 		return status;
867 
868 	// cache this device's address for later use
869 
870 	status = arp_update_local(protocol);
871 	if (status < B_OK) {
872 		protocol->next->module->interface_down(protocol->next);
873 		return status;
874 	}
875 
876 	return B_OK;
877 }
878 
879 
880 void
881 arp_down(net_datalink_protocol *protocol)
882 {
883 	// remove local ARP entry from the cache
884 
885 	if (protocol->interface->address != NULL) {
886 		BenaphoreLocker locker(sCacheLock);
887 
888 		arp_entry *entry = arp_entry::Lookup(
889 			((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr);
890 		if (entry != NULL) {
891 			hash_remove(sCache, entry);
892 			delete entry;
893 		}
894 	}
895 
896 	protocol->next->module->interface_down(protocol->next);
897 }
898 
899 
900 status_t
901 arp_control(net_datalink_protocol *protocol,
902 	int32 op, void *argument, size_t length)
903 {
904 	if (op == SIOCSIFADDR && (protocol->interface->flags & IFF_UP) != 0) {
905 		// The interface may get a new address, so we need to update our
906 		// local entries.
907 		bool hasOldAddress = false;
908 		in_addr_t oldAddress = 0;
909 		if (protocol->interface->address != NULL) {
910 			oldAddress = ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr;
911 			hasOldAddress = true;
912 		}
913 
914 		status_t status = protocol->next->module->control(protocol->next,
915 			SIOCSIFADDR, argument, length);
916 		if (status < B_OK)
917 			return status;
918 
919 		arp_update_local(protocol);
920 
921 		if (oldAddress == ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr
922 			|| !hasOldAddress)
923 			return B_OK;
924 
925 		// remove previous address from cache
926 		// TODO: we should be able to do this (add/remove) in one atomic operation!
927 
928 		BenaphoreLocker locker(sCacheLock);
929 
930 		arp_entry *entry = arp_entry::Lookup(oldAddress);
931 		if (entry != NULL) {
932 			hash_remove(sCache, entry);
933 			delete entry;
934 		}
935 
936 		return B_OK;
937 	}
938 
939 	return protocol->next->module->control(protocol->next,
940 		op, argument, length);
941 }
942 
943 
944 static status_t
945 arp_std_ops(int32 op, ...)
946 {
947 	switch (op) {
948 		case B_MODULE_INIT:
949 			return arp_init();
950 		case B_MODULE_UNINIT:
951 			return arp_uninit();
952 
953 		default:
954 			return B_ERROR;
955 	}
956 }
957 
958 
959 static net_datalink_protocol_module_info sARPModule = {
960 	{
961 		"network/datalink_protocols/arp/v1",
962 		0,
963 		arp_std_ops
964 	},
965 	arp_init_protocol,
966 	arp_uninit_protocol,
967 	arp_send_data,
968 	arp_up,
969 	arp_down,
970 	arp_control,
971 };
972 
973 module_info *modules[] = {
974 	(module_info *)&sARPModule,
975 	NULL
976 };
977